Merged V4.1-BUG-FIX to HEAD

40605: ALF-15273: Merged PATCHES/V4.0.1 to V4.1-BUG-FIX
      40132: ALF-15376:  Activiti schema updates fail when hibernate.default_schema is set with ORA-00942. 
         - Corrected schema case to uppercase when database is Oracle.
      40235: ALF-15367: Reverse merged the following revisions because the fix is deemed not robust enough.
         40132: ALF-15376:  Activiti schema updates fail when hibernate.default_schema is set with ORA-00942. 
            - Corrected schema case to uppercase when database is Oracle.
         40041: ALF-15376: Merged V4.1-BUG-FIX to PATCHES/V4.0.1
            39969: Merged DEV/BELARUS-V4.1-BUG-FIX-2012_07_09 to V4.1-BUG-FIX:
               ALF-15273 : Activiti schema updates fail when hibernate.default_schema is set with ORA-00942. The Activiti database is now correctly initialized with the correct "hibernate.default_schema"
      40470: ALF-15376: how to debug the creation of Activiti tables (ACT_) when upgrading to 4.X
         - added more logging to Activiti schema creation
      40471: ALF-15376: Activiti schema updates fail when hibernate.default_schema is set with ORA-00942
         - Ignore hibernate.default_schema and determine default schema from the Connection DatabaseMetaData
         - Provided the Activiti schema initializer with the default schema information
         - Provided countAppliedPatches() with default schema information
      40501: ALF-15376: Improved webapp logging.properties to use a console handler so that it doesn't suppress absolutely everything and we can selectively turn on logging!
   40608: Fix for ALF-4274 - JSF - Paste action does not work when browse.jsp is overrided
   40611: GERMAN: Translation updates based on EN r40604
   40612: SPANISH: Translation updates based on EN r40604
   40613: FRENCH: Translation updates based on EN r40604
   40614: ITALIAN: Translation updates based on EN r40604
   40615: JAPANESE: Translation updates based on EN r40604
   40616: DUTCH: Translation updates based on EN r40604
   40617: CHINESE: Translation updates based on EN r40604
   40629: ALF-15321: upgrade Activiti to fix logging
   40632: Fix for ALF-15487 Search not working for queries containing 3-digit versions
   Fix for ALF-15356 SOLR doesn't support searching by cm:name of file with underscore and dots
   40655: Fix for ALF-14752 - Collapse Links part at the WCM details page lead to error.
   40662: Eclipse classpath fixes
   40663: Merged DEV to V4.1-BUG-FIX
      40661: ALF-15318 (part 2): It's possible to log in by disabled user (NTLM with SSO in a clustered env)
         The onValidateFailed() methods were moved to BaseSSOAuthenticationFilter to response with a 401 for a disabled user.
   40665: ALF-15448: Merged V3.4-BUG-FIX (3.4.11) to V4.1-BUG-FIX (4.1.1)
      40664: ALF-15578 CLONE 3.4.11: LibreOffice 3.6 startup on Mac fails 
   40685: Merged PATCHES/V4.0.2 to V4.1-BUG-FIX
      39274: Merged DEV to V4.0.2 (4.0.2.4)
         << Unable to merge code as supplied as it introduced a change to a public API, which would break alfresco.log
            if the RM AMP was installed See RM-452 >>
         39166: ALF-15583 / ALF-14584: autoVersionOnUpdateProps=true does not increment the version label after checkout/checkin
            'VersionableAspectTest' has been modified in accordance with concept: several modifications of node in
      	  a single transaction are interpreted as a single version. Each operation in the test which should provide
      	  a new version have been made atomic
         39089: ALF-15583 / ALF-14584: autoVersionOnUpdateProps=true does not increment the version label after checkout/checkin
            Check of lock has been corrected since 'cm:lockable' aspect doesn't indicate lock state:
            - 'LockService' service has been extended with 'isLocked(NodRef)' method which returns 'true' if document
              is locked and current user is not an owner of the lock;
            - new 'VersionableAspectTest' has been added to test the use-case described in the issue and to test
              whether 'VersionableAspect' changes version label of a locked document
      39369: ALF-15583 / ALF-14584 autoVersionOnUpdateProps=true does not increment the version label after checkout/checkin
         - Test failures: A READ_ONLY lock was being set because we are adding a versionable aspect. This resulted in an
           Exception when attempting to update the version. Change made to the isLocked method (now called isLockedOrReadOnly)
           to reflect that a node is locked even for the owner and the lock type is not a WRITE lock.
      39939: ALF-15584 / ALF-15001: Gracefully handle stale NodeRefs in query results in DMDiscoveryServicePort
      - SOLR makes this more likely to occur
      40455: ALF-15585 / ALF-15383: Long-running Feed Cleaner
       - Part 1: Limit problems caused by missing indexes
         - Remove all count calls
         - Remove logic requiring calls to SiteService to list all sites
         - Added in an ID range limit to act as a hard-stop to entry growth (set to 1M)
       - TODO: use JobLockService
      40461: ALF-15585 / ALF-15383: Long running Feed Cleaner 
       - Part 2: Added JobLockService usage to ensure only one instance runs at a time
      40463: ALF-15585 / ALF-15383: Long running Feed Cleaner
       - A bit more trace and debug
      40526: ALF-15586: Fixed ALF-15540: CMIS: Synchronized block in service interceptor
      40574: ALF-15585 / ALF-15383: Long running Feed Cleaner
      - Fix MySQL variant of activities-common-SqlMap
      40579: ALF-15585: Fix fallout from rev 40455: ALF-15383: Long-running Feed Cleaner
       - MySQL dialect was duplicating ALL SQL statements
       - Split 'large' SQL selects into activities-select-SqlMap.xml containing 7 statements that are all overridden for MySQL
       - Fixed split in common file between different types of statements
      40588: ALF-15587 / ALF-15385: Merged V3.4-BUG-FIX to PATCHES/V4.0.2 (Lost revision)
         28830: ALF-7622 Refactored JScriptWorkflowTask. Now when setProperties() is called it properly updates the WorkflowTask properties via the WorflowService.updateTask() method.
   40687: Merged V3.4-BUG-FIX to V4.1-BUG-FIX
      40599: ALF-15567: Merged PATCHES/V3.4.10 to V3.4-BUG-FIX
         40511: ALF-12008: Merged DEV to PATCHES/V3.4.10
            Due to Windows Explorer's URL concatenation behaviour, we must present links as shortcuts to the real URL, rather than direct hrefs.
            This is at least consistent with the way the CIFS server handles links. See org.alfresco.filesys.repo.ContentDiskDriver.openFile().
         40518: ALF-12008: Fixed compilation error


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@40691 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Dave Ward
2012-08-21 16:31:48 +00:00
parent b06f0551f8
commit 6275a2c5e2
20 changed files with 1133 additions and 1060 deletions

View File

@@ -652,6 +652,7 @@
<property name="nodeService"> <property name="nodeService">
<ref bean="nodeService"/> <ref bean="nodeService"/>
</property> </property>
<property name="lockService" ref="lockService" />
<property name="dictionaryDAO"> <property name="dictionaryDAO">
<ref bean="dictionaryDAO"/> <ref bean="dictionaryDAO"/>
</property> </property>

View File

@@ -13,6 +13,7 @@
<mappers> <mappers>
<mapper resource="alfresco/ibatis/#resource.dialect#/activities-common-SqlMap.xml"/> <mapper resource="alfresco/ibatis/#resource.dialect#/activities-common-SqlMap.xml"/>
<mapper resource="alfresco/ibatis/#resource.dialect#/activities-select-SqlMap.xml"/>
<mapper resource="alfresco/ibatis/#resource.dialect#/activities-insert-SqlMap.xml"/> <mapper resource="alfresco/ibatis/#resource.dialect#/activities-insert-SqlMap.xml"/>
</mappers> </mappers>

View File

@@ -78,233 +78,35 @@
values (#{id}, #{status}, #{activityData}, #{userId}, #{postDate}, #{activityType}, #{siteNetwork,jdbcType=VARCHAR}, #{appTool,jdbcType=VARCHAR}, #{jobTaskNode}, #{lastModified}) values (#{id}, #{status}, #{activityData}, #{userId}, #{postDate}, #{activityType}, #{siteNetwork,jdbcType=VARCHAR}, #{appTool,jdbcType=VARCHAR}, #{jobTaskNode}, #{lastModified})
</sql> </sql>
<!-- -->
<!-- Updates -->
<!-- -->
<!-- --> <!-- -->
<!-- Selects --> <!-- Selects -->
<!-- --> <!-- -->
<!-- select feeds for cleaning --> <!-- select maximum ID of feed entries -->
<select id="select_activity_feed_greater_than_max" parameterType="int" resultType="ActivityFeed"> <select id="select_activity_feed_entries_max_id" resultType="Long">
select max(id) from alf_activity_feed
</select>
<!-- select user feeds for cleaning -->
<select id="select_activity_user_feeds_greater_than_max" parameterType="int" resultType="ActivityFeed">
<![CDATA[ <![CDATA[
select site_network as siteNetwork, feed_user_id as feedUserId, activity_format as activitySummaryFormat select feed_user_id as feedUserId, activity_format as activitySummaryFormat
from alf_activity_feed from alf_activity_feed
group by site_network, feed_user_id, activity_format group by feed_user_id, activity_format
having count(*) > #{maxFeedSize} having count(*) > #{maxFeedSize}
]]> ]]>
</select> </select>
<!-- user feed - all sites - everyone --> <!-- select site feeds for cleaning -->
<select id="select_activity_feed_for_feeduser" parameterType="ActivityFeedQuery" resultType="ActivityFeed"> <select id="select_activity_site_feeds_greater_than_max" parameterType="int" resultType="ActivityFeed">
select id as id, activity_type as activityType, activity_format as activitySummaryFormat, activity_summary as activitySummary, feed_user_id as feedUserId, post_user_id as postUserId, site_network as siteNetwork, post_date as postDate
from alf_activity_feed
where feed_user_id = #{feedUserId}
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
order by post_date desc
</select>
<select id="count_activity_feed_for_feeduser" parameterType="ActivityFeedQuery" resultType="long">
select count(1)
from alf_activity_feed
where feed_user_id = #{feedUserId}
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
</select>
<!-- user feed - all sites - others (not me) -->
<select id="select_activity_feed_for_feeduser_others" parameterType="ActivityFeedQuery" resultType="ActivityFeed">
select id as id, activity_type as activityType, activity_format as activitySummaryFormat, activity_summary as activitySummary, feed_user_id as feedUserId, post_user_id as postUserId, site_network as siteNetwork, post_date as postDate
from alf_activity_feed
where feed_user_id = #{feedUserId}
<![CDATA[ and post_user_id <> #{feedUserId} ]]>
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
order by post_date desc
</select>
<select id="count_activity_feed_for_feeduser_others" parameterType="ActivityFeedQuery" resultType="long">
select count(1)
from alf_activity_feed
where feed_user_id = #{feedUserId}
<![CDATA[ and post_user_id <> #{feedUserId} ]]>
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
</select>
<!-- user feed - all sites - me only (not others) -->
<select id="select_activity_feed_for_feeduser_me" parameterType="ActivityFeedQuery" resultType="ActivityFeed">
select id as id, activity_type as activityType, activity_format as activitySummaryFormat, activity_summary as activitySummary, feed_user_id as feedUserId, post_user_id as postUserId, site_network as siteNetwork, post_date as postDate
from alf_activity_feed
where feed_user_id = #{feedUserId}
and post_user_id = #{feedUserId}
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
order by post_date desc
</select>
<select id="count_activity_feed_for_feeduser_me" parameterType="ActivityFeedQuery" resultType="long">
select count(1)
from alf_activity_feed
where feed_user_id = #{feedUserId}
and post_user_id = #{feedUserId}
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
</select>
<!-- user feed - given site - everyone -->
<select id="select_activity_feed_for_feeduser_and_site" parameterType="ActivityFeedQuery" resultType="ActivityFeed">
select id as id, activity_type as activityType, activity_format as activitySummaryFormat, activity_summary as activitySummary, feed_user_id as feedUserId, post_user_id as postUserId, site_network as siteNetwork, post_date as postDate
from alf_activity_feed
where feed_user_id = #{feedUserId}
and site_network = #{siteNetwork}
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
order by post_date desc
</select>
<select id="count_activity_feed_for_feeduser_and_site" parameterType="ActivityFeedQuery" resultType="long">
select count(1)
from alf_activity_feed
where feed_user_id = #{feedUserId}
and site_network = #{siteNetwork}
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
</select>
<!-- user feed - given site - others (not me) -->
<select id="select_activity_feed_for_feeduser_others_and_site" parameterType="ActivityFeedQuery" resultType="ActivityFeed">
select id as id, activity_type as activityType, activity_format as activitySummaryFormat, activity_summary as activitySummary, feed_user_id as feedUserId, post_user_id as postUserId, site_network as siteNetwork, post_date as postDate
from alf_activity_feed
where feed_user_id = #{feedUserId}
<![CDATA[ and post_user_id <> #{feedUserId} ]]>
and site_network = #{siteNetwork}
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
order by post_date desc
</select>
<select id="count_activity_feed_for_feeduser_others_and_site" parameterType="ActivityFeedQuery" resultType="long">
select count(1)
from alf_activity_feed
where feed_user_id = #{feedUserId}
<![CDATA[ and post_user_id <> #{feedUserId} ]]>
and site_network = #{siteNetwork}
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
</select>
<!-- user feed - given site - me only (not others) -->
<select id="select_activity_feed_for_feeduser_me_and_site" parameterType="ActivityFeedQuery" resultType="ActivityFeed">
select id as id, activity_type as activityType, activity_format as activitySummaryFormat, activity_summary as activitySummary, feed_user_id as feedUserId, post_user_id as postUserId, site_network as siteNetwork, post_date as postDate
from alf_activity_feed
where feed_user_id = #{feedUserId}
and post_user_id = #{feedUserId}
and site_network = #{siteNetwork}
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
order by post_date desc
</select>
<select id="count_activity_feed_for_feeduser_me_and_site" parameterType="ActivityFeedQuery" resultType="long">
select count(1)
from alf_activity_feed
where feed_user_id = #{feedUserId}
and post_user_id = #{feedUserId}
and site_network = #{siteNetwork}
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
</select>
<!-- site feed - given site -->
<select id="select_activity_feed_for_site" parameterType="ActivityFeedQuery" resultType="ActivityFeed">
<![CDATA[ <![CDATA[
select id as id, activity_type as activityType, activity_format as activitySummaryFormat, activity_summary as activitySummary, post_user_id as postUserId, site_network as siteNetwork, post_date as postDate select site_network as siteNetwork, activity_format as activitySummaryFormat
from alf_activity_feed from alf_activity_feed
where (feed_user_id = '' or feed_user_id is null) group by site_network, activity_format
and site_network = #{siteNetwork} having count(*) > #{maxFeedSize}
and activity_format = #{activitySummaryFormat}
order by post_date desc
]]> ]]>
</select> </select>
<select id="count_activity_feed_for_site" parameterType="ActivityFeedQuery" resultType="long">
<![CDATA[
select count(1)
from alf_activity_feed
where (feed_user_id = '' or feed_user_id is null)
and site_network = #{siteNetwork}
and activity_format = #{activitySummaryFormat}
]]>
</select>
<!-- -->
<!-- Deletes -->
<!-- -->
<delete id="delete_activity_feed_entries_older_than_date" parameterType="Date">
<![CDATA[
delete from alf_activity_feed where post_date < #{keepdate}
]]>
</delete>
<delete id="delete_activity_feed_for_site_entries_older_than_date" parameterType="ActivityFeed">
<![CDATA[
delete from alf_activity_feed
where post_date < #{postDate}
and site_network = #{siteNetwork}
and activity_format = #{activitySummaryFormat}
]]>
</delete>
<delete id="delete_activity_feed_for_site_entries" parameterType="ActivityFeed">
delete from alf_activity_feed
where site_network = #{siteNetwork}
</delete>
<delete id="delete_activity_feed_for_feeduser_entries_older_than_date" parameterType="ActivityFeed">
<![CDATA[
delete from alf_activity_feed
where post_date < #{postDate}
and feed_user_id = #{feedUserId}
and activity_format = #{activitySummaryFormat}
]]>
</delete>
<delete id="delete_activity_feed_for_feeduser_entries" parameterType="ActivityFeed">
delete from alf_activity_feed
where feed_user_id = #{feedUserId}
</delete>
<select id="select_activity_feedcontrols_for_user" parameterType="FeedControl" resultType="FeedControl">
<![CDATA[
select id as id, feed_user_id as feedUserId, site_network as siteNetwork, app_tool as appTool
from alf_activity_feed_control
where feed_user_id = #{feedUserId}
]]>
</select>
<select id="select_activity_feedcontrol" parameterType="FeedControl" resultType="long">
<![CDATA[
select id as id
from alf_activity_feed_control
where feed_user_id = #{feedUserId}
and ((site_network = #{siteNetwork}) or ((#{siteNetwork} is null) and (site_network is null)))
and ((app_tool = #{appTool}) or ((#{appTool} is null) and (app_tool is null)))
]]>
</select>
<delete id="delete_activity_feedcontrol" parameterType="FeedControl">
<![CDATA[
delete from alf_activity_feed_control
where feed_user_id = #{feedUserId}
and ((site_network = #{siteNetwork}) or ((#{siteNetwork} is null) and (site_network is null)))
and ((app_tool = #{appTool}) or ((#{appTool} is null) and (app_tool is null)))
]]>
</delete>
<select id="select_activity_posts_by_params" parameterType="ActivityPost" resultType="ActivityPost"> <select id="select_activity_posts_by_params" parameterType="ActivityPost" resultType="ActivityPost">
<![CDATA[ <![CDATA[
select select
@@ -364,6 +166,77 @@
where status = 'POSTED' where status = 'POSTED'
</select> </select>
<select id="select_activity_feedcontrol" parameterType="FeedControl" resultType="long">
<![CDATA[
select id as id
from alf_activity_feed_control
where feed_user_id = #{feedUserId}
and ((site_network = #{siteNetwork}) or ((#{siteNetwork} is null) and (site_network is null)))
and ((app_tool = #{appTool}) or ((#{appTool} is null) and (app_tool is null)))
]]>
</select>
<select id="select_activity_feedcontrols_for_user" parameterType="FeedControl" resultType="FeedControl">
<![CDATA[
select id as id, feed_user_id as feedUserId, site_network as siteNetwork, app_tool as appTool
from alf_activity_feed_control
where feed_user_id = #{feedUserId}
]]>
</select>
<!-- -->
<!-- Deletes -->
<!-- -->
<delete id="delete_activity_feed_entries_before_id" parameterType="Long">
<![CDATA[
delete from alf_activity_feed where id < #{id}
]]>
</delete>
<delete id="delete_activity_feed_entries_older_than_date" parameterType="Date">
<![CDATA[
delete from alf_activity_feed where post_date < #{keepdate}
]]>
</delete>
<delete id="delete_activity_feed_for_site_entries_older_than_date" parameterType="ActivityFeed">
<![CDATA[
delete from alf_activity_feed
where post_date < #{postDate}
and site_network = #{siteNetwork}
and activity_format = #{activitySummaryFormat}
]]>
</delete>
<delete id="delete_activity_feed_for_site_entries" parameterType="ActivityFeed">
delete from alf_activity_feed
where site_network = #{siteNetwork}
</delete>
<delete id="delete_activity_feed_for_feeduser_entries_older_than_date" parameterType="ActivityFeed">
<![CDATA[
delete from alf_activity_feed
where post_date < #{postDate}
and feed_user_id = #{feedUserId}
and activity_format = #{activitySummaryFormat}
]]>
</delete>
<delete id="delete_activity_feed_for_feeduser_entries" parameterType="ActivityFeed">
delete from alf_activity_feed
where feed_user_id = #{feedUserId}
</delete>
<delete id="delete_activity_feedcontrol" parameterType="FeedControl">
<![CDATA[
delete from alf_activity_feed_control
where feed_user_id = #{feedUserId}
and ((site_network = #{siteNetwork}) or ((#{siteNetwork} is null) and (site_network is null)))
and ((app_tool = #{appTool}) or ((#{appTool} is null) and (app_tool is null)))
]]>
</delete>
<delete id="delete_activity_posts_older_than_date" parameterType="ActivityPost"> <delete id="delete_activity_posts_older_than_date" parameterType="ActivityPost">
<![CDATA[ <![CDATA[
delete from alf_activity_post delete from alf_activity_post
@@ -372,6 +245,10 @@
]]> ]]>
</delete> </delete>
<!-- -->
<!-- Updates -->
<!-- -->
<update id="update_activity_post_data" parameterType="ActivityPost"> <update id="update_activity_post_data" parameterType="ActivityPost">
<![CDATA[ <![CDATA[
update alf_activity_post set status = #{status}, activity_data=#{activityData}, site_network=#{siteNetwork,jdbcType=VARCHAR}, last_modified=#{lastModified} update alf_activity_post set status = #{status}, activity_data=#{activityData}, site_network=#{siteNetwork,jdbcType=VARCHAR}, last_modified=#{lastModified}

View File

@@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--
Select statements that require proper size limiting on the DB side
Dialect: Generic
-->
<mapper namespace="alfresco.activities.select">
<!-- -->
<!-- Selects -->
<!-- -->
<!-- user feed - all sites - everyone -->
<select id="select_activity_feed_for_feeduser" parameterType="ActivityFeedQuery" resultType="ActivityFeed">
select id as id, activity_type as activityType, activity_format as activitySummaryFormat, activity_summary as activitySummary, feed_user_id as feedUserId, post_user_id as postUserId, site_network as siteNetwork, post_date as postDate
from alf_activity_feed
where feed_user_id = #{feedUserId}
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
order by post_date desc
</select>
<!-- user feed - all sites - others (not me) -->
<select id="select_activity_feed_for_feeduser_others" parameterType="ActivityFeedQuery" resultType="ActivityFeed">
select id as id, activity_type as activityType, activity_format as activitySummaryFormat, activity_summary as activitySummary, feed_user_id as feedUserId, post_user_id as postUserId, site_network as siteNetwork, post_date as postDate
from alf_activity_feed
where feed_user_id = #{feedUserId}
<![CDATA[ and post_user_id <> #{feedUserId} ]]>
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
order by post_date desc
</select>
<!-- user feed - all sites - me only (not others) -->
<select id="select_activity_feed_for_feeduser_me" parameterType="ActivityFeedQuery" resultType="ActivityFeed">
select id as id, activity_type as activityType, activity_format as activitySummaryFormat, activity_summary as activitySummary, feed_user_id as feedUserId, post_user_id as postUserId, site_network as siteNetwork, post_date as postDate
from alf_activity_feed
where feed_user_id = #{feedUserId}
and post_user_id = #{feedUserId}
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
order by post_date desc
</select>
<!-- user feed - given site - everyone -->
<select id="select_activity_feed_for_feeduser_and_site" parameterType="ActivityFeedQuery" resultType="ActivityFeed">
select id as id, activity_type as activityType, activity_format as activitySummaryFormat, activity_summary as activitySummary, feed_user_id as feedUserId, post_user_id as postUserId, site_network as siteNetwork, post_date as postDate
from alf_activity_feed
where feed_user_id = #{feedUserId}
and site_network = #{siteNetwork}
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
order by post_date desc
</select>
<!-- user feed - given site - others (not me) -->
<select id="select_activity_feed_for_feeduser_others_and_site" parameterType="ActivityFeedQuery" resultType="ActivityFeed">
select id as id, activity_type as activityType, activity_format as activitySummaryFormat, activity_summary as activitySummary, feed_user_id as feedUserId, post_user_id as postUserId, site_network as siteNetwork, post_date as postDate
from alf_activity_feed
where feed_user_id = #{feedUserId}
<![CDATA[ and post_user_id <> #{feedUserId} ]]>
and site_network = #{siteNetwork}
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
order by post_date desc
</select>
<!-- user feed - given site - me only (not others) -->
<select id="select_activity_feed_for_feeduser_me_and_site" parameterType="ActivityFeedQuery" resultType="ActivityFeed">
select id as id, activity_type as activityType, activity_format as activitySummaryFormat, activity_summary as activitySummary, feed_user_id as feedUserId, post_user_id as postUserId, site_network as siteNetwork, post_date as postDate
from alf_activity_feed
where feed_user_id = #{feedUserId}
and post_user_id = #{feedUserId}
and site_network = #{siteNetwork}
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
order by post_date desc
</select>
<!-- site feed - given site -->
<select id="select_activity_feed_for_site" parameterType="ActivityFeedQuery" resultType="ActivityFeed">
<![CDATA[
select id as id, activity_type as activityType, activity_format as activitySummaryFormat, activity_summary as activitySummary, post_user_id as postUserId, site_network as siteNetwork, post_date as postDate
from alf_activity_feed
where (feed_user_id = '' or feed_user_id is null)
and site_network = #{siteNetwork}
and activity_format = #{activitySummaryFormat}
order by post_date desc
]]>
</select>
</mapper>

View File

@@ -1,393 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="alfresco.activities">
<!-- NOTE: MyBatis #224 - eg. Oracle -->
<!-- -->
<!-- Result Maps -->
<!-- -->
<!-- Note the MySQL specific fetch size limitation (Integer.MIN_VALUE). fetchSize activates resultset streaming. -->
<resultMap id="ActivityFeedResult" type="ActivityFeed">
<result property="id" column="id" jdbcType="BIGINT" javaType="java.lang.Long"/>
<result property="feedUserId" column="feed_user_id"/>
<result property="postUserId" column="post_user_id"/>
<result property="postDate" column="post_date"/>
<result property="postId" column="post_id"/> <!-- not an explicit FK constraint, can dangle if and when activity post is deleted -->
<result property="siteNetwork" column="site_network"/>
<result property="activityType" column="activity_type"/>
<result property="activitySummary" column="activity_summary"/>
<result property="activitySummaryFormat" column="activity_format"/>
<result property="feedDate" column="feed_date"/>
</resultMap>
<resultMap id="FeedControlResult" type="FeedControl">
<result property="id" column="id" jdbcType="BIGINT" javaType="java.lang.Long"/>
<result property="feedUserId" column="feed_user_id"/>
<result property="siteNetwork" column="site_network"/>
<result property="appTool" column="app_tool"/>
<result property="lastModified" column="last_modified"/>
</resultMap>
<resultMap id="ActivityPostResult" type="ActivityPost">
<result property="id" column="sequence_id" jdbcType="BIGINT" javaType="java.lang.Long"/>
<result property="activityData" column="activity_data"/>
<result property="activityType" column="activity_type"/>
<result property="userId" column="post_user_id"/>
<result property="postDate" column="post_date"/>
<result property="jobTaskNode" column="job_task_node"/>
<result property="siteNetwork" column="site_network"/>
<result property="appTool" column="app_tool"/>
<result property="status" column="status"/>
<result property="lastModified" column="last_modified"/>
</resultMap>
<!-- -->
<!-- SQL Snippets / Inserts -->
<!-- -->
<sql id="insert_ActivityFeedControl_AutoIncrement">
insert into alf_activity_feed_control (feed_user_id, site_network, app_tool, last_modified)
values (#{feedUserId}, #{siteNetwork}, #{appTool}, #{lastModified})
</sql>
<sql id="insert_ActivityFeedControl_Sequence">
insert into alf_activity_feed_control (id, feed_user_id, site_network, app_tool, last_modified)
values (#{id}, #{feedUserId}, #{siteNetwork,jdbcType=VARCHAR}, #{appTool,jdbcType=VARCHAR}, #{lastModified})
</sql>
<sql id="insert_ActivityFeed_AutoIncrement">
insert into alf_activity_feed (activity_type, activity_summary, activity_format, feed_user_id, post_user_id, post_date, post_id, site_network, app_tool, feed_date)
values (#{activityType}, #{activitySummary}, #{activitySummaryFormat}, #{feedUserId}, #{postUserId}, #{postDate}, #{postId}, #{siteNetwork}, #{appTool}, #{feedDate})
</sql>
<sql id="insert_ActivityFeed_Sequence">
insert into alf_activity_feed (id, activity_type, activity_summary, activity_format, feed_user_id, post_user_id, post_date, post_id, site_network, app_tool, feed_date)
values (#{id}, #{activityType}, #{activitySummary,jdbcType=VARCHAR}, #{activitySummaryFormat,jdbcType=VARCHAR}, #{feedUserId,jdbcType=VARCHAR}, #{postUserId}, #{postDate}, #{postId,jdbcType=BIGINT}, #{siteNetwork,jdbcType=VARCHAR}, #{appTool,jdbcType=VARCHAR}, #{feedDate})
</sql>
<sql id="insert_ActivityPost_AutoIncrement">
insert into alf_activity_post (status, activity_data, post_user_id, post_date, activity_type, site_network, app_tool, job_task_node, last_modified)
values (#{status}, #{activityData}, #{userId}, #{postDate}, #{activityType}, #{siteNetwork}, #{appTool}, #{jobTaskNode}, #{lastModified})
</sql>
<sql id="insert_ActivityPost_Sequence">
insert into alf_activity_post (sequence_id, status, activity_data, post_user_id, post_date, activity_type, site_network, app_tool, job_task_node, last_modified)
values (#{id}, #{status}, #{activityData}, #{userId}, #{postDate}, #{activityType}, #{siteNetwork,jdbcType=VARCHAR}, #{appTool,jdbcType=VARCHAR}, #{jobTaskNode}, #{lastModified})
</sql>
<!-- -->
<!-- Updates -->
<!-- -->
<!-- -->
<!-- Selects -->
<!-- -->
<!-- select feeds for cleaning -->
<select id="select_activity_feed_greater_than_max" parameterType="int" resultType="ActivityFeed">
<![CDATA[
select site_network as siteNetwork, feed_user_id as feedUserId, activity_format as activitySummaryFormat
from alf_activity_feed
group by site_network, feed_user_id, activity_format
having count(*) > #{maxFeedSize}
]]>
</select>
<!-- user feed - all sites - everyone -->
<select id="select_activity_feed_for_feeduser" parameterType="ActivityFeedQuery" resultType="ActivityFeed" fetchSize="-2147483648">
select id as id, activity_type as activityType, activity_format as activitySummaryFormat, activity_summary as activitySummary, feed_user_id as feedUserId, post_user_id as postUserId, site_network as siteNetwork, post_date as postDate
from alf_activity_feed
where feed_user_id = #{feedUserId}
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
order by post_date desc
</select>
<select id="count_activity_feed_for_feeduser" parameterType="ActivityFeedQuery" resultType="long">
select count(1)
from alf_activity_feed
where feed_user_id = #{feedUserId}
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
</select>
<!-- user feed - all sites - others (not me) -->
<select id="select_activity_feed_for_feeduser_others" parameterType="ActivityFeedQuery" resultType="ActivityFeed" fetchSize="-2147483648">
select id as id, activity_type as activityType, activity_format as activitySummaryFormat, activity_summary as activitySummary, feed_user_id as feedUserId, post_user_id as postUserId, site_network as siteNetwork, post_date as postDate
from alf_activity_feed
where feed_user_id = #{feedUserId}
<![CDATA[ and post_user_id <> #{feedUserId} ]]>
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
order by post_date desc
</select>
<select id="count_activity_feed_for_feeduser_others" parameterType="ActivityFeedQuery" resultType="long">
select count(1)
from alf_activity_feed
where feed_user_id = #{feedUserId}
<![CDATA[ and post_user_id <> #{feedUserId} ]]>
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
</select>
<!-- user feed - all sites - me only (not others) -->
<select id="select_activity_feed_for_feeduser_me" parameterType="ActivityFeedQuery" resultType="ActivityFeed" fetchSize="-2147483648">
select id as id, activity_type as activityType, activity_format as activitySummaryFormat, activity_summary as activitySummary, feed_user_id as feedUserId, post_user_id as postUserId, site_network as siteNetwork, post_date as postDate
from alf_activity_feed
where feed_user_id = #{feedUserId}
and post_user_id = #{feedUserId}
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
order by post_date desc
</select>
<select id="count_activity_feed_for_feeduser_me" parameterType="ActivityFeedQuery" resultType="long">
select count(1)
from alf_activity_feed
where feed_user_id = #{feedUserId}
and post_user_id = #{feedUserId}
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
</select>
<!-- user feed - given site - everyone -->
<select id="select_activity_feed_for_feeduser_and_site" parameterType="ActivityFeedQuery" resultType="ActivityFeed" fetchSize="-2147483648">
select id as id, activity_type as activityType, activity_format as activitySummaryFormat, activity_summary as activitySummary, feed_user_id as feedUserId, post_user_id as postUserId, site_network as siteNetwork, post_date as postDate
from alf_activity_feed
where feed_user_id = #{feedUserId}
and site_network = #{siteNetwork}
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
order by post_date desc
</select>
<select id="count_activity_feed_for_feeduser_and_site" parameterType="ActivityFeedQuery" resultType="long">
select count(1)
from alf_activity_feed
where feed_user_id = #{feedUserId}
and site_network = #{siteNetwork}
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
</select>
<!-- user feed - given site - others (not me) -->
<select id="select_activity_feed_for_feeduser_others_and_site" parameterType="ActivityFeedQuery" resultType="ActivityFeed" fetchSize="-2147483648">
select id as id, activity_type as activityType, activity_format as activitySummaryFormat, activity_summary as activitySummary, feed_user_id as feedUserId, post_user_id as postUserId, site_network as siteNetwork, post_date as postDate
from alf_activity_feed
where feed_user_id = #{feedUserId}
<![CDATA[ and post_user_id <> #{feedUserId} ]]>
and site_network = #{siteNetwork}
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
order by post_date desc
</select>
<select id="count_activity_feed_for_feeduser_others_and_site" parameterType="ActivityFeedQuery" resultType="long">
select count(1)
from alf_activity_feed
where feed_user_id = #{feedUserId}
<![CDATA[ and post_user_id <> #{feedUserId} ]]>
and site_network = #{siteNetwork}
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
</select>
<!-- user feed - given site - me only (not others) -->
<select id="select_activity_feed_for_feeduser_me_and_site" parameterType="ActivityFeedQuery" resultType="ActivityFeed" fetchSize="-2147483648">
select id as id, activity_type as activityType, activity_format as activitySummaryFormat, activity_summary as activitySummary, feed_user_id as feedUserId, post_user_id as postUserId, site_network as siteNetwork, post_date as postDate
from alf_activity_feed
where feed_user_id = #{feedUserId}
and post_user_id = #{feedUserId}
and site_network = #{siteNetwork}
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
order by post_date desc
</select>
<select id="count_activity_feed_for_feeduser_me_and_site" parameterType="ActivityFeedQuery" resultType="long">
select count(1)
from alf_activity_feed
where feed_user_id = #{feedUserId}
and post_user_id = #{feedUserId}
and site_network = #{siteNetwork}
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
</select>
<!-- site feed - given site -->
<select id="select_activity_feed_for_site" parameterType="ActivityFeedQuery" resultType="ActivityFeed" fetchSize="-2147483648">
<![CDATA[
select id as id, activity_type as activityType, activity_format as activitySummaryFormat, activity_summary as activitySummary, post_user_id as postUserId, site_network as siteNetwork, post_date as postDate
from alf_activity_feed
where (feed_user_id = '' or feed_user_id is null)
and site_network = #{siteNetwork}
and activity_format = #{activitySummaryFormat}
order by post_date desc
]]>
</select>
<select id="count_activity_feed_for_site" parameterType="ActivityFeedQuery" resultType="long">
<![CDATA[
select count(1)
from alf_activity_feed
where (feed_user_id = '' or feed_user_id is null)
and site_network = #{siteNetwork}
and activity_format = #{activitySummaryFormat}
]]>
</select>
<!-- -->
<!-- Deletes -->
<!-- -->
<delete id="delete_activity_feed_entries_older_than_date" parameterType="Date">
<![CDATA[
delete from alf_activity_feed where post_date < #{keepdate}
]]>
</delete>
<delete id="delete_activity_feed_for_site_entries_older_than_date" parameterType="ActivityFeed">
<![CDATA[
delete from alf_activity_feed
where post_date < #{postDate}
and site_network = #{siteNetwork}
and activity_format = #{activitySummaryFormat}
]]>
</delete>
<delete id="delete_activity_feed_for_site_entries" parameterType="ActivityFeed">
delete from alf_activity_feed
where site_network = #{siteNetwork}
</delete>
<delete id="delete_activity_feed_for_feeduser_entries_older_than_date" parameterType="ActivityFeed">
<![CDATA[
delete from alf_activity_feed
where post_date < #{postDate}
and feed_user_id = #{feedUserId}
and activity_format = #{activitySummaryFormat}
]]>
</delete>
<delete id="delete_activity_feed_for_feeduser_entries" parameterType="ActivityFeed">
delete from alf_activity_feed
where feed_user_id = #{feedUserId}
</delete>
<select id="select_activity_feedcontrols_for_user" parameterType="FeedControl" resultType="FeedControl">
<![CDATA[
select id as id, feed_user_id as feedUserId, site_network as siteNetwork, app_tool as appTool
from alf_activity_feed_control
where feed_user_id = #{feedUserId}
]]>
</select>
<select id="select_activity_feedcontrol" parameterType="FeedControl" resultType="long">
<![CDATA[
select id as id
from alf_activity_feed_control
where feed_user_id = #{feedUserId}
and ((site_network = #{siteNetwork}) or ((#{siteNetwork} is null) and (site_network is null)))
and ((app_tool = #{appTool}) or ((#{appTool} is null) and (app_tool is null)))
]]>
</select>
<delete id="delete_activity_feedcontrol" parameterType="FeedControl">
<![CDATA[
delete from alf_activity_feed_control
where feed_user_id = #{feedUserId}
and ((site_network = #{siteNetwork}) or ((#{siteNetwork} is null) and (site_network is null)))
and ((app_tool = #{appTool}) or ((#{appTool} is null) and (app_tool is null)))
]]>
</delete>
<select id="select_activity_posts_by_params" parameterType="ActivityPost" resultType="ActivityPost">
<![CDATA[
select
sequence_id as id,
activity_data as activityData,
activity_type as activityType,
post_user_id as userId,
post_date as postDate,
job_task_node as jobTaskNode,
site_network as siteNetwork,
app_tool as appTool,
status as status
from
alf_activity_post
where
job_task_node = #{jobTaskNode} and
sequence_id >= #{minId} and
sequence_id <= #{maxId} and
status = #{status}
]]>
</select>
<select id="select_activity_posts_by_status" parameterType="ActivityPost" resultType="ActivityPost">
<![CDATA[
select
sequence_id as id,
activity_data as activityData,
activity_type as activityType,
post_user_id as userId,
post_date as postDate,
job_task_node as jobTaskNode,
site_network as siteNetwork,
app_tool as appTool,
status as status
from
alf_activity_post
where
status = #{status}
]]>
</select>
<select id="select_activity_post_max_seq" resultType="long">
select max(sequence_id) as maxId
from alf_activity_post
where status = 'POSTED'
</select>
<select id="select_activity_post_min_seq" resultType="long">
select min(sequence_id) as minId
from alf_activity_post
where status = 'POSTED'
</select>
<select id="select_activity_post_max_jobtasknode" resultType="int">
select max(job_task_node) as maxJobTaskNode
from alf_activity_post
where status = 'POSTED'
</select>
<delete id="delete_activity_posts_older_than_date" parameterType="ActivityPost">
<![CDATA[
delete from alf_activity_post
where post_date < #{postDate}
and status = #{status}
]]>
</delete>
<update id="update_activity_post_data" parameterType="ActivityPost">
<![CDATA[
update alf_activity_post set status = #{status}, activity_data=#{activityData}, site_network=#{siteNetwork,jdbcType=VARCHAR}, last_modified=#{lastModified}
where sequence_id = #{id}
and status <> #{status}
]]>
</update>
<update id="update_activity_post_status" parameterType="ActivityPost">
<![CDATA[
update alf_activity_post set status = #{status}, last_modified=#{lastModified}
where sequence_id = #{id}
and status <> #{status}
]]>
</update>
</mapper>

View File

@@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--
Select statements that require proper size limiting on the DB side
Dialect: MySQL
-->
<mapper namespace="alfresco.activities.select">
<!-- -->
<!-- Selects -->
<!-- -->
<!-- user feed - all sites - everyone -->
<select id="select_activity_feed_for_feeduser" parameterType="ActivityFeedQuery" resultType="ActivityFeed" fetchSize="-2147483648">
select id as id, activity_type as activityType, activity_format as activitySummaryFormat, activity_summary as activitySummary, feed_user_id as feedUserId, post_user_id as postUserId, site_network as siteNetwork, post_date as postDate
from alf_activity_feed
where feed_user_id = #{feedUserId}
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
order by post_date desc
</select>
<!-- user feed - all sites - others (not me) -->
<select id="select_activity_feed_for_feeduser_others" parameterType="ActivityFeedQuery" resultType="ActivityFeed" fetchSize="-2147483648">
select id as id, activity_type as activityType, activity_format as activitySummaryFormat, activity_summary as activitySummary, feed_user_id as feedUserId, post_user_id as postUserId, site_network as siteNetwork, post_date as postDate
from alf_activity_feed
where feed_user_id = #{feedUserId}
<![CDATA[ and post_user_id <> #{feedUserId} ]]>
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
order by post_date desc
</select>
<!-- user feed - all sites - me only (not others) -->
<select id="select_activity_feed_for_feeduser_me" parameterType="ActivityFeedQuery" resultType="ActivityFeed" fetchSize="-2147483648">
select id as id, activity_type as activityType, activity_format as activitySummaryFormat, activity_summary as activitySummary, feed_user_id as feedUserId, post_user_id as postUserId, site_network as siteNetwork, post_date as postDate
from alf_activity_feed
where feed_user_id = #{feedUserId}
and post_user_id = #{feedUserId}
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
order by post_date desc
</select>
<!-- user feed - given site - everyone -->
<select id="select_activity_feed_for_feeduser_and_site" parameterType="ActivityFeedQuery" resultType="ActivityFeed" fetchSize="-2147483648">
select id as id, activity_type as activityType, activity_format as activitySummaryFormat, activity_summary as activitySummary, feed_user_id as feedUserId, post_user_id as postUserId, site_network as siteNetwork, post_date as postDate
from alf_activity_feed
where feed_user_id = #{feedUserId}
and site_network = #{siteNetwork}
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
order by post_date desc
</select>
<!-- user feed - given site - others (not me) -->
<select id="select_activity_feed_for_feeduser_others_and_site" parameterType="ActivityFeedQuery" resultType="ActivityFeed" fetchSize="-2147483648">
select id as id, activity_type as activityType, activity_format as activitySummaryFormat, activity_summary as activitySummary, feed_user_id as feedUserId, post_user_id as postUserId, site_network as siteNetwork, post_date as postDate
from alf_activity_feed
where feed_user_id = #{feedUserId}
<![CDATA[ and post_user_id <> #{feedUserId} ]]>
and site_network = #{siteNetwork}
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
order by post_date desc
</select>
<!-- user feed - given site - me only (not others) -->
<select id="select_activity_feed_for_feeduser_me_and_site" parameterType="ActivityFeedQuery" resultType="ActivityFeed" fetchSize="-2147483648">
select id as id, activity_type as activityType, activity_format as activitySummaryFormat, activity_summary as activitySummary, feed_user_id as feedUserId, post_user_id as postUserId, site_network as siteNetwork, post_date as postDate
from alf_activity_feed
where feed_user_id = #{feedUserId}
and post_user_id = #{feedUserId}
and site_network = #{siteNetwork}
and activity_format = #{activitySummaryFormat}
<if test="minId != null"><![CDATA[ and id >= #{minId} ]]></if>
order by post_date desc
</select>
<!-- site feed - given site -->
<select id="select_activity_feed_for_site" parameterType="ActivityFeedQuery" resultType="ActivityFeed" fetchSize="-2147483648">
<![CDATA[
select id as id, activity_type as activityType, activity_format as activitySummaryFormat, activity_summary as activitySummary, post_user_id as postUserId, site_network as siteNetwork, post_date as postDate
from alf_activity_feed
where (feed_user_id = '' or feed_user_id is null)
and site_network = #{siteNetwork}
and activity_format = #{activitySummaryFormat}
order by post_date desc
]]>
</select>
</mapper>

View File

@@ -774,6 +774,8 @@ imap.attachments.folder.folderPath=Imap Attachments
# Activities Feed - refer to subsystem # Activities Feed - refer to subsystem
# Feed max ID range to limit maximum number of entries
activities.feed.max.idRange=1000000
# Feed max size (number of entries) # Feed max size (number of entries)
activities.feed.max.size=100 activities.feed.max.size=100
# Feed max age (eg. 44640 mins => 31 days) # Feed max age (eg. 44640 mins => 31 days)

View File

@@ -28,10 +28,13 @@
<!-- cleans out-of-date feed entries --> <!-- cleans out-of-date feed entries -->
<bean id="feedCleaner" class="org.alfresco.repo.activities.feed.cleanup.FeedCleaner" init-method="init"> <bean id="feedCleaner" class="org.alfresco.repo.activities.feed.cleanup.FeedCleaner" init-method="init">
<property name="feedDAO" ref="feedDAO"/> <property name="feedDAO" ref="feedDAO"/>
<property name="siteService" ref="SiteService"/> <property name="jobLockService" ref="JobLockService"/>
<property name="nodeService" ref="NodeService"/> <property name="nodeService" ref="NodeService"/>
<property name="policyComponent" ref="policyComponent"/> <property name="policyComponent" ref="policyComponent"/>
<property name="maxIdRange">
<value>${activities.feed.max.idRange}</value> <!-- max ID range between max(id) and min(id). Limits absolute number of entries. -->
</property>
<property name="maxAgeMins"> <property name="maxAgeMins">
<value>${activities.feed.max.ageMins}</value> <!-- max age in mins, eg. 44640 mins = 31 days --> <value>${activities.feed.max.ageMins}</value> <!-- max age in mins, eg. 44640 mins = 31 days -->
</property> </property>

View File

@@ -44,7 +44,7 @@ public class AlfrescoCmisServiceInterceptor implements MethodInterceptor
} }
@Override @Override
public synchronized Object invoke(MethodInvocation invocation) throws Throwable public Object invoke(MethodInvocation invocation) throws Throwable
{ {
// Keep note of whether debug is required // Keep note of whether debug is required
boolean debug = logger.isDebugEnabled(); boolean debug = logger.isDebugEnabled();

View File

@@ -19,28 +19,30 @@
package org.alfresco.repo.activities.feed.cleanup; package org.alfresco.repo.activities.feed.cleanup;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.domain.activities.ActivityFeedDAO; import org.alfresco.repo.domain.activities.ActivityFeedDAO;
import org.alfresco.repo.domain.activities.ActivityFeedEntity; import org.alfresco.repo.domain.activities.ActivityFeedEntity;
import org.alfresco.repo.lock.JobLockService;
import org.alfresco.repo.lock.JobLockService.JobLockRefreshCallback;
import org.alfresco.repo.lock.LockAcquisitionException;
import org.alfresco.repo.node.NodeServicePolicies; import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.node.NodeServicePolicies.BeforeDeleteNodePolicy; import org.alfresco.repo.node.NodeServicePolicies.BeforeDeleteNodePolicy;
import org.alfresco.repo.policy.JavaBehaviour; import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent; import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.site.SiteModel; import org.alfresco.repo.site.SiteModel;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport; import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.repo.transaction.TransactionListenerAdapter; import org.alfresco.repo.transaction.TransactionListenerAdapter;
import org.alfresco.repo.transaction.TransactionalResourceHelper;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.site.SiteService; import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.PropertyCheck; import org.alfresco.util.PropertyCheck;
import org.alfresco.util.VmShutdownListener;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.quartz.JobExecutionException; import org.quartz.JobExecutionException;
@@ -55,15 +57,13 @@ public class FeedCleaner implements NodeServicePolicies.BeforeDeleteNodePolicy
private static String KEY_DELETED_SITE_IDS = "feedCleaner.deletedSites"; private static String KEY_DELETED_SITE_IDS = "feedCleaner.deletedSites";
private static String KEY_DELETED_USER_IDS = "feedCleaner.deletedUsers"; private static String KEY_DELETED_USER_IDS = "feedCleaner.deletedUsers";
private static VmShutdownListener vmShutdownListener = new VmShutdownListener(FeedCleaner.class.getName()); private int maxIdRange = 1000000;
private int maxAgeMins = 0; private int maxAgeMins = 0;
private int maxFeedSize = 100;
private int maxFeedSize = -1; //unlimited
private ActivityFeedDAO feedDAO; private ActivityFeedDAO feedDAO;
private SiteService siteService; private JobLockService jobLockService;
private NodeService nodeService; private NodeService nodeService;
private PolicyComponent policyComponent; private PolicyComponent policyComponent;
@@ -76,9 +76,9 @@ public class FeedCleaner implements NodeServicePolicies.BeforeDeleteNodePolicy
this.feedDAO = feedDAO; this.feedDAO = feedDAO;
} }
public void setSiteService(SiteService siteService) public void setJobLockService(JobLockService jobLockService)
{ {
this.siteService = siteService; this.jobLockService = jobLockService;
} }
public void setNodeService(NodeService nodeService) public void setNodeService(NodeService nodeService)
@@ -91,6 +91,15 @@ public class FeedCleaner implements NodeServicePolicies.BeforeDeleteNodePolicy
this.policyComponent = policyComponent; this.policyComponent = policyComponent;
} }
/**
*
* @param maxIdRange maximum difference between lowest and highest ID
*/
public void setMaxIdRange(int maxIdRange)
{
this.maxIdRange = maxIdRange;
}
public void setMaxAgeMins(int mins) public void setMaxAgeMins(int mins)
{ {
this.maxAgeMins = mins; this.maxAgeMins = mins;
@@ -114,6 +123,9 @@ public class FeedCleaner implements NodeServicePolicies.BeforeDeleteNodePolicy
private void checkProperties() private void checkProperties()
{ {
PropertyCheck.mandatory(this, "feedDAO", feedDAO); PropertyCheck.mandatory(this, "feedDAO", feedDAO);
PropertyCheck.mandatory(this, "policyComponent", policyComponent);
PropertyCheck.mandatory(this, "nodeService", nodeService);
PropertyCheck.mandatory(this, "jobLockService", jobLockService);
// check the max age and max feed size // check the max age and max feed size
if ((maxAgeMins <= 0) && (maxFeedSize <= 0)) if ((maxAgeMins <= 0) && (maxFeedSize <= 0))
@@ -137,16 +149,97 @@ public class FeedCleaner implements NodeServicePolicies.BeforeDeleteNodePolicy
deleteSiteTransactionListener = new FeedCleanerDeleteSiteTransactionListener(); deleteSiteTransactionListener = new FeedCleanerDeleteSiteTransactionListener();
} }
private static final long LOCK_TTL = 60000L; // 1 minute
private static final QName LOCK_QNAME = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "FeedCleaner");
public int execute() throws JobExecutionException public int execute() throws JobExecutionException
{ {
checkProperties(); checkProperties();
final AtomicBoolean keepGoing = new AtomicBoolean(true);
String lockToken = null;
try
{
// Lock
lockToken = jobLockService.getLock(LOCK_QNAME, LOCK_TTL);
// Refresh to get callbacks
JobLockRefreshCallback callback = new JobLockRefreshCallback()
{
@Override
public void lockReleased()
{
keepGoing.set(false);
}
@Override
public boolean isActive()
{
return keepGoing.get();
}
};
jobLockService.refreshLock(lockToken, LOCK_QNAME, LOCK_TTL, callback);
int cleaned = executeWithLock(keepGoing);
if (logger.isDebugEnabled())
{
logger.debug("Cleaned " + cleaned + " feed entries.");
}
}
catch (LockAcquisitionException e)
{
if (logger.isDebugEnabled())
{
logger.debug("Skipping feed cleaning. " + e.getMessage());
}
}
finally
{
keepGoing.set(false); // Notify the refresh callback that we are done
if (lockToken != null)
{
jobLockService.releaseLock(lockToken, LOCK_QNAME);
}
}
return 0;
}
/**
* Does the actual cleanup, expecting the lock to be maintained
*
* @param keepGoing <tt>true</tt> to continue but will switch to <tt>false</tt> to stop
* @return number of entries deleted through whatever means
*/
private int executeWithLock(final AtomicBoolean keepGoing) throws JobExecutionException
{
int maxIdRangeDeletedCount = 0;
int maxAgeDeletedCount = 0; int maxAgeDeletedCount = 0;
int maxSizeDeletedCount = 0; int maxSizeDeletedCount = 0;
try try
{ {
if (maxAgeMins > 0) /*
* ALF-15383 (DH 15/08/2012)
* Previously, we allowed maxFeedSize entries per user per site per format.
* This scaled badly because some users (especially under test conditions)
* were able to perform actions across many thousands of sites. If the size
* limit was 100 and the user belonged to 50K sites, we allowed 5M feed entries
* for that user. This may have been OK but for the fact that the queries
* doing the work are not covered by appropriate indexes to support the where
* and sort by clauses.
* In fact, give the current state of indexes, it is necessary to limit the absolute
* number of feed entries. We can't use count() queries (they are poor) and cannot
* reasonably sort by date and trim by count. Therefore I have introduced an
* absolute ID range trim that runs before everything else.
*/
if (maxIdRange > 0 && keepGoing.get())
{
maxIdRangeDeletedCount = feedDAO.deleteFeedEntries(maxIdRange);
if (logger.isTraceEnabled())
{
logger.trace("Cleaned " + maxIdRangeDeletedCount + " entries to keep ID range of " + maxIdRange + ".");
}
}
if (maxAgeMins > 0 && keepGoing.get())
{ {
// clean old entries based on maxAgeMins // clean old entries based on maxAgeMins
@@ -155,114 +248,73 @@ public class FeedCleaner implements NodeServicePolicies.BeforeDeleteNodePolicy
Date keepDate = new Date(keepTimeOffset); Date keepDate = new Date(keepTimeOffset);
maxAgeDeletedCount = feedDAO.deleteFeedEntries(keepDate); maxAgeDeletedCount = feedDAO.deleteFeedEntries(keepDate);
if (maxAgeDeletedCount > 0)
{
if (logger.isDebugEnabled())
{
logger.debug("Cleaned " + maxAgeDeletedCount + " entries (upto " + keepDate + ", max age " + maxAgeMins + " mins)");
}
}
else
{
if (logger.isTraceEnabled()) if (logger.isTraceEnabled())
{ {
logger.trace("Cleaned " + maxAgeDeletedCount + " entries (upto " + keepDate + ", max age " + maxAgeMins + " mins)"); logger.trace("Cleaned " + maxAgeDeletedCount + " entries (upto " + keepDate + ", max age " + maxAgeMins + " mins)");
} }
} }
// TODO: ALF-15511
if (maxFeedSize > 0 && keepGoing.get())
{
// Get user+format feeds exceeding the required maximum
List<ActivityFeedEntity> userFeedsTooMany = feedDAO.selectUserFeedsToClean(maxFeedSize);
for (ActivityFeedEntity userFeedTooMany : userFeedsTooMany)
{
if (!keepGoing.get())
{
break;
} }
String feedUserId = userFeedTooMany.getFeedUserId();
if (maxFeedSize > 0) String format = userFeedTooMany.getActivitySummaryFormat();
// Rather than filter out the two usernames that indicate site-specific
// feed entries, we can just filter them out now.
if (feedUserId == null || feedUserId.length() == 0)
{ {
// clean old entries based on maxFeedSize continue;
// return candidate feeds to clean - either site+format or user+format
List<ActivityFeedEntity> feeds = feedDAO.selectFeedsToClean(maxFeedSize);
int feedCount = 0;
for (ActivityFeedEntity feed : feeds)
{
String siteId = feed.getSiteNetwork();
final String feedUserId = feed.getFeedUserId();
String format = feed.getActivitySummaryFormat();
List<ActivityFeedEntity> feedToClean;
int feedUserSiteCount = 0;
long numFeeds;
if ((feedUserId == null) || (feedUserId.length() == 0))
{
numFeeds = feedDAO.countSiteFeedEntries(siteId, format, -1);
} }
else // Get the feeds to keep
List<ActivityFeedEntity> feedsToKeep = feedDAO.selectUserFeedEntries(feedUserId, format, null, false, false, -1L, maxFeedSize);
// If the feeds have been removed, then ignore
if (feedsToKeep.size() < maxFeedSize)
{ {
numFeeds = feedDAO.countUserFeedEntries(feedUserId, format, null, false, false, -1L, -1); continue;
if(siteService != null)
{
// note: allow for fact that Share Activities dashlet currently uses userfeed within site context
feedUserSiteCount = AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Integer>()
{
public Integer doWork() throws Exception
{
return siteService.listSites(feedUserId).size();
} }
}, AuthenticationUtil.SYSTEM_USER_NAME); // Get the last one
} Date oldestFeedEntry = feedsToKeep.get(maxFeedSize-1).getPostDate();
} int deletedCount = feedDAO.deleteUserFeedEntries(feedUserId, format, oldestFeedEntry);
if (((feedUserSiteCount == 0) && (numFeeds > maxFeedSize)) ||
((numFeeds > (maxFeedSize * feedUserSiteCount))))
{
if ((feedUserId == null) || (feedUserId.length() == 0))
{
feedToClean = feedDAO.selectSiteFeedEntries(siteId, format, -1);
}
else
{
feedToClean = feedDAO.selectUserFeedEntries(feedUserId, format, null, false, false, -1L, maxFeedSize);
}
Date oldestFeedEntry = feedToClean.get(maxFeedSize-1).getPostDate();
int deletedCount = 0;
if ((feedUserId == null) || (feedUserId.length() == 0))
{
deletedCount = feedDAO.deleteSiteFeedEntries(siteId, format, oldestFeedEntry);
}
else
{
deletedCount = feedDAO.deleteUserFeedEntries(feedUserId, format, oldestFeedEntry);
}
if (deletedCount > 0)
{
maxSizeDeletedCount = maxSizeDeletedCount + deletedCount;
feedCount++;
if (logger.isTraceEnabled()) if (logger.isTraceEnabled())
{ {
logger.trace("Cleaned " + deletedCount + " entries for ["+feed.getSiteNetwork()+", "+feed.getFeedUserId()+", "+feed.getActivitySummaryFormat()+"] (upto " + oldestFeedEntry + ")"); logger.trace("Cleaned " + deletedCount + " entries for user '" + feedUserId + "'.");
}
}
} }
maxSizeDeletedCount += deletedCount;
} }
if (maxSizeDeletedCount > 0) // Get site+format feeds exceeding the required maximum
List<ActivityFeedEntity> siteFeedsTooMany = feedDAO.selectSiteFeedsToClean(maxFeedSize);
for (ActivityFeedEntity siteFeedTooMany : siteFeedsTooMany)
{ {
if (logger.isDebugEnabled()) if (!keepGoing.get())
{ {
logger.debug("Cleaned " + maxSizeDeletedCount + " entries across " + feedCount + " feeds (max feed size "+maxFeedSize+" entries)"); break;
} }
} String siteId = siteFeedTooMany.getSiteNetwork();
else String format = siteFeedTooMany.getActivitySummaryFormat();
// Get the feeds to keep
List<ActivityFeedEntity> feedsToKeep = feedDAO.selectSiteFeedEntries(siteId, format, maxFeedSize);
// If the feeds have been removed, then ignore
if (feedsToKeep.size() < maxFeedSize)
{ {
continue;
}
// Get the last one
Date oldestFeedEntry = feedsToKeep.get(maxFeedSize-1).getPostDate();
int deletedCount = feedDAO.deleteSiteFeedEntries(siteId, format, oldestFeedEntry);
if (logger.isTraceEnabled()) if (logger.isTraceEnabled())
{ {
logger.trace("Cleaned " + maxSizeDeletedCount + " entries across " + feedCount + " feeds (max feed size "+maxFeedSize+" entries)"); logger.trace("Cleaned " + deletedCount + " entries for site '" + siteId + "'.");
} }
maxSizeDeletedCount += deletedCount;
} }
} }
} }
@@ -273,8 +325,8 @@ public class FeedCleaner implements NodeServicePolicies.BeforeDeleteNodePolicy
} }
catch (Throwable e) catch (Throwable e)
{ {
// If the VM is shutting down, then ignore // We were told to stop, which is also what will happen if the VM shuts down
if (vmShutdownListener.isVmShuttingDown()) if (!keepGoing.get())
{ {
// Ignore // Ignore
} }
@@ -284,7 +336,7 @@ public class FeedCleaner implements NodeServicePolicies.BeforeDeleteNodePolicy
} }
} }
return (maxAgeDeletedCount + maxSizeDeletedCount); return (maxIdRangeDeletedCount + maxAgeDeletedCount + maxSizeDeletedCount);
} }
// behaviours // behaviours
@@ -294,35 +346,21 @@ public class FeedCleaner implements NodeServicePolicies.BeforeDeleteNodePolicy
// dummy // dummy
} }
@SuppressWarnings("unchecked")
public void beforeDeleteNodePerson(NodeRef personNodeRef) public void beforeDeleteNodePerson(NodeRef personNodeRef)
{ {
String userId = (String)nodeService.getProperty(personNodeRef, ContentModel.PROP_USERNAME); String userId = (String)nodeService.getProperty(personNodeRef, ContentModel.PROP_USERNAME);
Set<String> deletedUserIds = (Set<String>)AlfrescoTransactionSupport.getResource(KEY_DELETED_USER_IDS); Set<String> deletedUserIds = TransactionalResourceHelper.getSet(KEY_DELETED_USER_IDS);
if (deletedUserIds == null)
{
deletedUserIds = Collections.newSetFromMap(new ConcurrentHashMap()); // Java 6
AlfrescoTransactionSupport.bindResource(KEY_DELETED_USER_IDS, deletedUserIds);
}
deletedUserIds.add(userId); deletedUserIds.add(userId);
AlfrescoTransactionSupport.bindListener(deletePersonTransactionListener); AlfrescoTransactionSupport.bindListener(deletePersonTransactionListener);
} }
@SuppressWarnings("unchecked")
public void beforeDeleteNodeSite(NodeRef siteNodeRef) public void beforeDeleteNodeSite(NodeRef siteNodeRef)
{ {
String siteId = (String)nodeService.getProperty(siteNodeRef, ContentModel.PROP_NAME); String siteId = (String)nodeService.getProperty(siteNodeRef, ContentModel.PROP_NAME);
Set<String> deletedSiteIds = (Set<String>)AlfrescoTransactionSupport.getResource(KEY_DELETED_SITE_IDS); Set<String> deletedSiteIds = TransactionalResourceHelper.getSet(KEY_DELETED_SITE_IDS);
if (deletedSiteIds == null)
{
deletedSiteIds = Collections.newSetFromMap(new ConcurrentHashMap()); // Java 6
AlfrescoTransactionSupport.bindResource(KEY_DELETED_SITE_IDS, deletedSiteIds);
}
deletedSiteIds.add(siteId); deletedSiteIds.add(siteId);
AlfrescoTransactionSupport.bindListener(deleteSiteTransactionListener); AlfrescoTransactionSupport.bindListener(deleteSiteTransactionListener);
@@ -330,13 +368,10 @@ public class FeedCleaner implements NodeServicePolicies.BeforeDeleteNodePolicy
class FeedCleanerDeleteSiteTransactionListener extends TransactionListenerAdapter class FeedCleanerDeleteSiteTransactionListener extends TransactionListenerAdapter
{ {
@SuppressWarnings("unchecked")
@Override @Override
public void afterCommit() public void afterCommit()
{ {
Set<String> deletedSiteIds = (Set<String>)AlfrescoTransactionSupport.getResource(KEY_DELETED_SITE_IDS); Set<String> deletedSiteIds = TransactionalResourceHelper.getSet(KEY_DELETED_SITE_IDS);
if (deletedSiteIds != null)
{
for (String siteId : deletedSiteIds) for (String siteId : deletedSiteIds)
{ {
try try
@@ -351,17 +386,13 @@ public class FeedCleaner implements NodeServicePolicies.BeforeDeleteNodePolicy
} }
} }
} }
}
class FeedCleanerDeletePersonTransactionListener extends TransactionListenerAdapter class FeedCleanerDeletePersonTransactionListener extends TransactionListenerAdapter
{ {
@SuppressWarnings("unchecked")
@Override @Override
public void afterCommit() public void afterCommit()
{ {
Set<String> deletedUserIds = (Set<String>)AlfrescoTransactionSupport.getResource(KEY_DELETED_USER_IDS); Set<String> deletedUserIds = TransactionalResourceHelper.getSet(KEY_DELETED_USER_IDS);
if (deletedUserIds != null)
{
for (String userId : deletedUserIds) for (String userId : deletedUserIds)
{ {
try try
@@ -377,4 +408,3 @@ public class FeedCleaner implements NodeServicePolicies.BeforeDeleteNodePolicy
} }
} }
} }
}

View File

@@ -27,8 +27,11 @@ import junit.framework.TestCase;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.domain.activities.ActivityFeedDAO; import org.alfresco.repo.domain.activities.ActivityFeedDAO;
import org.alfresco.repo.domain.activities.ActivityFeedEntity; import org.alfresco.repo.domain.activities.ActivityFeedEntity;
import org.alfresco.repo.lock.JobLockService;
import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.cmr.site.SiteService; import org.alfresco.service.cmr.site.SiteService;
import org.alfresco.service.cmr.site.SiteVisibility; import org.alfresco.service.cmr.site.SiteVisibility;
@@ -71,6 +74,10 @@ public class FeedCleanerTest extends TestCase
@Override @Override
public void setUp() throws Exception public void setUp() throws Exception
{ {
JobLockService jobLockService = (JobLockService) ctx.getBean("JobLockService");
PolicyComponent policyComponent = (PolicyComponent) ctx.getBean("policyComponent");
NodeService nodeService = (NodeService) ctx.getBean("NodeService");
siteService = (SiteService) ctx.getBean("SiteService"); siteService = (SiteService) ctx.getBean("SiteService");
personService = (PersonService) ctx.getBean("PersonService"); personService = (PersonService) ctx.getBean("PersonService");
feedDAO = (ActivityFeedDAO) ctx.getBean("feedDAO"); feedDAO = (ActivityFeedDAO) ctx.getBean("feedDAO");
@@ -89,6 +96,9 @@ public class FeedCleanerTest extends TestCase
// construct the test cleaner // construct the test cleaner
cleaner = new FeedCleaner(); cleaner = new FeedCleaner();
cleaner.setFeedDAO(feedDAO); cleaner.setFeedDAO(feedDAO);
cleaner.setPolicyComponent(policyComponent);
cleaner.setJobLockService(jobLockService);
cleaner.setNodeService(nodeService);
} }
public void tearDown() throws Exception public void tearDown() throws Exception
@@ -114,6 +124,31 @@ public class FeedCleanerTest extends TestCase
// NOOP // NOOP
} }
public void testMaxIdRange() throws Exception
{
// insert site feed entries for TEST_SITE_4
for (int i = 0; i < 10; i++)
{
ActivityFeedEntity feedEntry = new ActivityFeedEntity();
feedEntry.setPostDate(new Date(System.currentTimeMillis()-(i*60*1000L)));
feedEntry.setActivitySummaryFormat("json");
feedEntry.setSiteNetwork(TEST_SITE_4);
feedEntry.setActivityType("testActivityType");
feedEntry.setPostUserId(TEST_USER_C);
feedEntry.setFeedUserId("");
feedEntry.setFeedDate(new Date());
feedDAO.insertFeedEntry(feedEntry);
}
// Check
assertEquals(10, feedDAO.selectSiteFeedEntries(TEST_SITE_4, "json", -1).size());
// Limit the ID range we will keep
cleaner.setMaxIdRange(5);
cleaner.execute();
// Check
assertEquals(5, feedDAO.selectSiteFeedEntries(TEST_SITE_4, "json", -1).size());
}
public void testMaxAge() throws Exception public void testMaxAge() throws Exception
{ {
cleaner.setMaxFeedSize(0); cleaner.setMaxFeedSize(0);

View File

@@ -36,6 +36,7 @@ public interface ActivityFeedDAO extends ActivitiesDAO
public long insertFeedEntry(ActivityFeedEntity activityFeed) throws SQLException; public long insertFeedEntry(ActivityFeedEntity activityFeed) throws SQLException;
public int deleteFeedEntries(Integer maxIdRange) throws SQLException;
public int deleteFeedEntries(Date keepDate) throws SQLException; public int deleteFeedEntries(Date keepDate) throws SQLException;
public int deleteUserFeedEntries(String feedUserId, String format, Date keepDate) throws SQLException; public int deleteUserFeedEntries(String feedUserId, String format, Date keepDate) throws SQLException;
@@ -46,13 +47,10 @@ public interface ActivityFeedDAO extends ActivitiesDAO
public int deleteSiteFeedEntries(String siteUserId) throws SQLException; public int deleteSiteFeedEntries(String siteUserId) throws SQLException;
public List<ActivityFeedEntity> selectFeedsToClean(int maxFeedSize) throws SQLException; public List<ActivityFeedEntity> selectSiteFeedsToClean(int maxFeedSize) throws SQLException;
public List<ActivityFeedEntity> selectUserFeedsToClean(int maxFeedSize) throws SQLException;
public Long countUserFeedEntries(String feedUserId, String format, String siteId, boolean excludeThisUser, boolean excludeOtherUsers, long minFeedId, int maxFeedItems) throws SQLException;
public List<ActivityFeedEntity> selectUserFeedEntries(String feedUserId, String format, String siteId, boolean excludeThisUser, boolean excludeOtherUsers, long minFeedId, int maxFeedItems) throws SQLException; public List<ActivityFeedEntity> selectUserFeedEntries(String feedUserId, String format, String siteId, boolean excludeThisUser, boolean excludeOtherUsers, long minFeedId, int maxFeedItems) throws SQLException;
public Long countSiteFeedEntries(String siteUserId, String format, int maxFeedItems) throws SQLException;
public List<ActivityFeedEntity> selectSiteFeedEntries(String siteUserId, String format, int maxFeedItems) throws SQLException; public List<ActivityFeedEntity> selectSiteFeedEntries(String siteUserId, String format, int maxFeedItems) throws SQLException;
} }

View File

@@ -31,6 +31,7 @@ import org.apache.ibatis.session.RowBounds;
public class ActivityFeedDAOImpl extends ActivitiesDAOImpl implements ActivityFeedDAO public class ActivityFeedDAOImpl extends ActivitiesDAOImpl implements ActivityFeedDAO
{ {
@Override
public long insertFeedEntry(ActivityFeedEntity activityFeed) throws SQLException public long insertFeedEntry(ActivityFeedEntity activityFeed) throws SQLException
{ {
template.insert("alfresco.activities.insert.insert_activity_feed", activityFeed); template.insert("alfresco.activities.insert.insert_activity_feed", activityFeed);
@@ -38,11 +39,30 @@ public class ActivityFeedDAOImpl extends ActivitiesDAOImpl implements ActivityFe
return (id != null ? id : -1); return (id != null ? id : -1);
} }
@Override
public int deleteFeedEntries(Integer maxIdRange) throws SQLException
{
// Get the largest ID
Long maxId = (Long) template.selectOne("alfresco.activities.select_activity_feed_entries_max_id");
if (maxId == null)
{
return 0; // This happens when there are no entries
}
Long minId = maxId - maxIdRange + 1; // The delete leaves the ID we pass in
if (minId <= 0)
{
return 0;
}
return template.delete("alfresco.activities.delete_activity_feed_entries_before_id", minId);
}
@Override
public int deleteFeedEntries(Date keepDate) throws SQLException public int deleteFeedEntries(Date keepDate) throws SQLException
{ {
return template.delete("alfresco.activities.delete_activity_feed_entries_older_than_date", keepDate); return template.delete("alfresco.activities.delete_activity_feed_entries_older_than_date", keepDate);
} }
@Override
public int deleteSiteFeedEntries(String siteId) throws SQLException public int deleteSiteFeedEntries(String siteId) throws SQLException
{ {
ActivityFeedEntity params = new ActivityFeedEntity(); ActivityFeedEntity params = new ActivityFeedEntity();
@@ -51,6 +71,7 @@ public class ActivityFeedDAOImpl extends ActivitiesDAOImpl implements ActivityFe
return template.delete("alfresco.activities.delete_activity_feed_for_site_entries", params); return template.delete("alfresco.activities.delete_activity_feed_for_site_entries", params);
} }
@Override
public int deleteSiteFeedEntries(String siteId, String format, Date keepDate) throws SQLException public int deleteSiteFeedEntries(String siteId, String format, Date keepDate) throws SQLException
{ {
ActivityFeedEntity params = new ActivityFeedEntity(); ActivityFeedEntity params = new ActivityFeedEntity();
@@ -61,7 +82,7 @@ public class ActivityFeedDAOImpl extends ActivitiesDAOImpl implements ActivityFe
return template.delete("alfresco.activities.delete_activity_feed_for_site_entries_older_than_date", params); return template.delete("alfresco.activities.delete_activity_feed_for_site_entries_older_than_date", params);
} }
@Override
public int deleteUserFeedEntries(String feedUserId, String format, Date keepDate) throws SQLException public int deleteUserFeedEntries(String feedUserId, String format, Date keepDate) throws SQLException
{ {
ActivityFeedEntity params = new ActivityFeedEntity(); ActivityFeedEntity params = new ActivityFeedEntity();
@@ -72,6 +93,7 @@ public class ActivityFeedDAOImpl extends ActivitiesDAOImpl implements ActivityFe
return template.delete("alfresco.activities.delete_activity_feed_for_feeduser_entries_older_than_date", params); return template.delete("alfresco.activities.delete_activity_feed_for_feeduser_entries_older_than_date", params);
} }
@Override
public int deleteUserFeedEntries(String feedUserId) throws SQLException public int deleteUserFeedEntries(String feedUserId) throws SQLException
{ {
ActivityFeedEntity params = new ActivityFeedEntity(); ActivityFeedEntity params = new ActivityFeedEntity();
@@ -81,76 +103,21 @@ public class ActivityFeedDAOImpl extends ActivitiesDAOImpl implements ActivityFe
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public List<ActivityFeedEntity> selectFeedsToClean(int maxFeedSize) throws SQLException @Override
public List<ActivityFeedEntity> selectUserFeedsToClean(int maxFeedSize) throws SQLException
{ {
return (List<ActivityFeedEntity>)template.selectList("alfresco.activities.select_activity_feed_greater_than_max", maxFeedSize); return (List<ActivityFeedEntity>)template.selectList("alfresco.activities.select_activity_user_feeds_greater_than_max", maxFeedSize);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public Long countUserFeedEntries(String feedUserId, String format, String siteId, boolean excludeThisUser, boolean excludeOtherUsers, long minFeedId, int maxFeedSize) throws SQLException @Override
public List<ActivityFeedEntity> selectSiteFeedsToClean(int maxFeedSize) throws SQLException
{ {
ActivityFeedQueryEntity params = new ActivityFeedQueryEntity(); return (List<ActivityFeedEntity>)template.selectList("alfresco.activities.select_activity_site_feeds_greater_than_max", maxFeedSize);
params.setFeedUserId(feedUserId);
params.setActivitySummaryFormat(format);
if (minFeedId > -1)
{
params.setMinId(minFeedId);
}
if (siteId != null)
{
if (excludeThisUser && excludeOtherUsers)
{
return Long.valueOf(0);
}
if ((!excludeThisUser) && (!excludeOtherUsers))
{
// no excludes => everyone => where feed user is me
return (Long)template.selectOne("alfresco.activities.count_activity_feed_for_feeduser_and_site", params);
}
else if ((excludeThisUser) && (!excludeOtherUsers))
{
// exclude feed user => others => where feed user is me and post user is not me
return (Long)template.selectOne("alfresco.activities.count_activity_feed_for_feeduser_others_and_site", params);
}
else if ((excludeOtherUsers) && (!excludeThisUser))
{
// exclude others => me => where feed user is me and post user is me
return (Long)template.selectOne("alfresco.activities.count_activity_feed_for_feeduser_me_and_site", params);
}
}
else
{
// all sites
if (excludeThisUser && excludeOtherUsers)
{
// effectively NOOP - return empty feed
return Long.valueOf(0);
}
if (!excludeThisUser && !excludeOtherUsers)
{
// no excludes => everyone => where feed user is me
return (Long)template.selectOne("alfresco.activities.count_activity_feed_for_feeduser", params);
}
else if (excludeThisUser)
{
// exclude feed user => others => where feed user is me and post user is not me
return (Long)template.selectOne("alfresco.activities.count_activity_feed_for_feeduser_others", params);
}
else if (excludeOtherUsers)
{
// exclude others => me => where feed user is me and post user is me
return (Long)template.selectOne("alfresco.activities.count_activity_feed_for_feeduser_me", params);
}
}
// belts-and-braces
throw new AlfrescoRuntimeException("Unexpected: invalid arguments");
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override
public List<ActivityFeedEntity> selectUserFeedEntries(String feedUserId, String format, String siteId, boolean excludeThisUser, boolean excludeOtherUsers, long minFeedId, int maxFeedSize) throws SQLException public List<ActivityFeedEntity> selectUserFeedEntries(String feedUserId, String format, String siteId, boolean excludeThisUser, boolean excludeOtherUsers, long minFeedId, int maxFeedSize) throws SQLException
{ {
ActivityFeedQueryEntity params = new ActivityFeedQueryEntity(); ActivityFeedQueryEntity params = new ActivityFeedQueryEntity();
@@ -178,17 +145,17 @@ public class ActivityFeedDAOImpl extends ActivitiesDAOImpl implements ActivityFe
if ((!excludeThisUser) && (!excludeOtherUsers)) if ((!excludeThisUser) && (!excludeOtherUsers))
{ {
// no excludes => everyone => where feed user is me // no excludes => everyone => where feed user is me
return (List<ActivityFeedEntity>)template.selectList("alfresco.activities.select_activity_feed_for_feeduser_and_site", params, rowBounds); return (List<ActivityFeedEntity>)template.selectList("alfresco.activities.select.select.select_activity_feed_for_feeduser_and_site", params, rowBounds);
} }
else if ((excludeThisUser) && (!excludeOtherUsers)) else if ((excludeThisUser) && (!excludeOtherUsers))
{ {
// exclude feed user => others => where feed user is me and post user is not me // exclude feed user => others => where feed user is me and post user is not me
return (List<ActivityFeedEntity>)template.selectList("alfresco.activities.select_activity_feed_for_feeduser_others_and_site", params, rowBounds); return (List<ActivityFeedEntity>)template.selectList("alfresco.activities.select.select_activity_feed_for_feeduser_others_and_site", params, rowBounds);
} }
else if ((excludeOtherUsers) && (!excludeThisUser)) else if ((excludeOtherUsers) && (!excludeThisUser))
{ {
// exclude others => me => where feed user is me and post user is me // exclude others => me => where feed user is me and post user is me
return (List<ActivityFeedEntity>)template.selectList("alfresco.activities.select_activity_feed_for_feeduser_me_and_site", params, rowBounds); return (List<ActivityFeedEntity>)template.selectList("alfresco.activities.select.select_activity_feed_for_feeduser_me_and_site", params, rowBounds);
} }
} }
else else
@@ -203,17 +170,17 @@ public class ActivityFeedDAOImpl extends ActivitiesDAOImpl implements ActivityFe
if (!excludeThisUser && !excludeOtherUsers) if (!excludeThisUser && !excludeOtherUsers)
{ {
// no excludes => everyone => where feed user is me // no excludes => everyone => where feed user is me
return (List<ActivityFeedEntity>)template.selectList("alfresco.activities.select_activity_feed_for_feeduser", params, rowBounds); return (List<ActivityFeedEntity>)template.selectList("alfresco.activities.select.select_activity_feed_for_feeduser", params, rowBounds);
} }
else if (excludeThisUser) else if (excludeThisUser)
{ {
// exclude feed user => others => where feed user is me and post user is not me // exclude feed user => others => where feed user is me and post user is not me
return (List<ActivityFeedEntity>)template.selectList("alfresco.activities.select_activity_feed_for_feeduser_others", params, rowBounds); return (List<ActivityFeedEntity>)template.selectList("alfresco.activities.select.select_activity_feed_for_feeduser_others", params, rowBounds);
} }
else if (excludeOtherUsers) else if (excludeOtherUsers)
{ {
// exclude others => me => where feed user is me and post user is me // exclude others => me => where feed user is me and post user is me
return (List<ActivityFeedEntity>)template.selectList("alfresco.activities.select_activity_feed_for_feeduser_me", params, rowBounds); return (List<ActivityFeedEntity>)template.selectList("alfresco.activities.select.select_activity_feed_for_feeduser_me", params, rowBounds);
} }
} }
@@ -222,17 +189,7 @@ public class ActivityFeedDAOImpl extends ActivitiesDAOImpl implements ActivityFe
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public Long countSiteFeedEntries(String siteId, String format, int maxFeedSize) throws SQLException @Override
{
ActivityFeedQueryEntity params = new ActivityFeedQueryEntity();
params.setSiteNetwork(siteId);
params.setActivitySummaryFormat(format);
// for given site
return (Long)template.selectOne("alfresco.activities.count_activity_feed_for_site", params);
}
@SuppressWarnings("unchecked")
public List<ActivityFeedEntity> selectSiteFeedEntries(String siteId, String format, int maxFeedSize) throws SQLException public List<ActivityFeedEntity> selectSiteFeedEntries(String siteId, String format, int maxFeedSize) throws SQLException
{ {
ActivityFeedQueryEntity params = new ActivityFeedQueryEntity(); ActivityFeedQueryEntity params = new ActivityFeedQueryEntity();
@@ -243,6 +200,6 @@ public class ActivityFeedDAOImpl extends ActivitiesDAOImpl implements ActivityFe
RowBounds rowBounds = new RowBounds(RowBounds.NO_ROW_OFFSET, rowLimit); RowBounds rowBounds = new RowBounds(RowBounds.NO_ROW_OFFSET, rowLimit);
// for given site // for given site
return (List<ActivityFeedEntity>)template.selectList("alfresco.activities.select_activity_feed_for_site", params, rowBounds); return (List<ActivityFeedEntity>)template.selectList("alfresco.activities.select.select_activity_feed_for_site", params, rowBounds);
} }
} }

View File

@@ -72,6 +72,7 @@ import org.alfresco.repo.domain.hibernate.dialect.AlfrescoSQLServerDialect;
import org.alfresco.repo.domain.hibernate.dialect.AlfrescoSybaseAnywhereDialect; import org.alfresco.repo.domain.hibernate.dialect.AlfrescoSybaseAnywhereDialect;
import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.descriptor.DescriptorService; import org.alfresco.service.descriptor.DescriptorService;
import org.alfresco.util.DatabaseMetaDataHelper;
import org.alfresco.util.LogUtil; import org.alfresco.util.LogUtil;
import org.alfresco.util.TempFileProvider; import org.alfresco.util.TempFileProvider;
import org.alfresco.util.schemacomp.ExportDb; import org.alfresco.util.schemacomp.ExportDb;
@@ -511,7 +512,7 @@ public class SchemaBootstrap extends AbstractLifecycleBean
*/ */
private int countAppliedPatches(Configuration cfg, Connection connection) throws Exception private int countAppliedPatches(Configuration cfg, Connection connection) throws Exception
{ {
String defaultSchema = cfg.getProperty("hibernate.default_schema"); String defaultSchema = DatabaseMetaDataHelper.getSchema(connection);
if (defaultSchema != null && defaultSchema.length() == 0) if (defaultSchema != null && defaultSchema.length() == 0)
{ {
defaultSchema = null; defaultSchema = null;
@@ -783,8 +784,8 @@ public class SchemaBootstrap extends AbstractLifecycleBean
final Dialect dialect = Dialect.getDialect(cfg.getProperties()); final Dialect dialect = Dialect.getDialect(cfg.getProperties());
String dialectStr = dialect.getClass().getSimpleName(); String dialectStr = dialect.getClass().getSimpleName();
// Initialise Activiti DB, using an unclosable connection. // Initialise Activiti DB, using an unclosable connection
initialiseActivitiDBSchema(new UnclosableConnection(connection), cfg); initialiseActivitiDBSchema(new UnclosableConnection(connection));
if (create) if (create)
{ {
@@ -877,7 +878,7 @@ public class SchemaBootstrap extends AbstractLifecycleBean
* *
* @param connection Connection to use the initialise DB schema * @param connection Connection to use the initialise DB schema
*/ */
private void initialiseActivitiDBSchema(Connection connection, Configuration cfg) private void initialiseActivitiDBSchema(Connection connection)
{ {
// create instance of activiti engine to initialise schema // create instance of activiti engine to initialise schema
ProcessEngine engine = null; ProcessEngine engine = null;
@@ -893,7 +894,7 @@ public class SchemaBootstrap extends AbstractLifecycleBean
buildProcessEngine(); buildProcessEngine();
// create or upgrade the DB schema // create or upgrade the DB schema
engine.getManagementService().databaseSchemaUpgrade(connection, null, cfg.getProperty("hibernate.default_schema")); engine.getManagementService().databaseSchemaUpgrade(connection, null, DatabaseMetaDataHelper.getSchema(connection));
} }
finally finally
{ {

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2005-2011 Alfresco Software Limited. * Copyright (C) 2005-2012 Alfresco Software Limited.
* *
* This file is part of Alfresco * This file is part of Alfresco
* *
@@ -42,6 +42,9 @@ import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport; import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.service.cmr.lock.LockService;
import org.alfresco.service.cmr.lock.LockStatus;
import org.alfresco.service.cmr.lock.LockType;
import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
@@ -87,6 +90,8 @@ public class VersionableAspect implements ContentServicePolicies.OnContentUpdate
/** The node service */ /** The node service */
private NodeService nodeService; private NodeService nodeService;
private LockService lockService;
/** The Version service */ /** The Version service */
private VersionService versionService; private VersionService versionService;
@@ -141,6 +146,16 @@ public class VersionableAspect implements ContentServicePolicies.OnContentUpdate
this.nodeService = nodeService; this.nodeService = nodeService;
} }
/**
* Set the lock service
*
* @param lockService the lock service
*/
public void setLockService(LockService lockService)
{
this.lockService = lockService;
}
/** /**
* Sets the dictionary DAO. * Sets the dictionary DAO.
* *
@@ -437,9 +452,9 @@ public class VersionableAspect implements ContentServicePolicies.OnContentUpdate
Map<QName, Serializable> after) Map<QName, Serializable> after)
{ {
if ((this.nodeService.exists(nodeRef) == true) && if ((this.nodeService.exists(nodeRef) == true) &&
!isLockedOrReadOnly(nodeRef) &&
(this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE) == true) && (this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE) == true) &&
(this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_TEMPORARY) == false) && (this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_TEMPORARY) == false))
(this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_LOCKABLE) == false))
{ {
onUpdatePropertiesBehaviour.disable(); onUpdatePropertiesBehaviour.disable();
try try
@@ -508,6 +523,21 @@ public class VersionableAspect implements ContentServicePolicies.OnContentUpdate
} }
} }
/**
* Indicates if the node is unlocked or the current user has a WRITE_LOCK<p>
*
* Ideally this would be a new method on the lockService, but cannot do this at the moment,
* as this method is being added as part of a hot fix, so a public service cannot change
* as the RM AMP might be installed and it has its own security context which would also need
* to reflect this change.
*/
private boolean isLockedOrReadOnly(NodeRef nodeRef)
{
LockStatus lockStatus = lockService.getLockStatus(nodeRef);
LockType lockType = lockService.getLockType(nodeRef);
return ! (lockStatus == LockStatus.NO_LOCK || (lockStatus == LockStatus.LOCK_OWNER && lockType == LockType.WRITE_LOCK));
}
/** /**
* On create version implementation method * On create version implementation method
* *

View File

@@ -0,0 +1,285 @@
/*
* Copyright (C) 2005-2012 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.version;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import junit.framework.TestCase;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.coci.CheckOutCheckInService;
import org.alfresco.service.cmr.lock.LockService;
import org.alfresco.service.cmr.lock.LockStatus;
import org.alfresco.service.cmr.lock.LockType;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.service.cmr.version.VersionType;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.ApplicationContextHelper;
import org.springframework.context.ApplicationContext;
/**
* @author Dmitry Velichkevich
*/
public class VersionableAspectTest extends TestCase
{
private static final String NAME_AND_EXT_DELIMETER = ".";
private static final String NAME_AND_EXT_DELIMETER_REGEXP = "\\" + NAME_AND_EXT_DELIMETER;
private static final String ADMIN_CREDENTIAL = "admin";
private static final String ROOT_NODE_TERM = "PATH:\"/app\\:company_home\"";
private static final String DOCUMENT_NAME = "ChildDocumentWithVersionLabel-.txt";
private static final String PARENT_FOLDER_NAME = "ParentFolder-" + System.currentTimeMillis();
private static final String TEST_CONTENT_01 = "Test Content version 0.1\n";
private static final String TEST_CONTENT_10 = "Test Content version 1.0\n";
private ApplicationContext applicationContext = ApplicationContextHelper.getApplicationContext();
private NodeService nodeService = (NodeService) applicationContext.getBean("nodeService");
private LockService lockService = (LockService) applicationContext.getBean("lockService");
private SearchService searchService = (SearchService) applicationContext.getBean("searchService");
private ContentService contentService = (ContentService) applicationContext.getBean("contentService");
private TransactionService transactionService = (TransactionService) applicationContext.getBean("transactionService");
private CheckOutCheckInService checkOutCheckInService = (CheckOutCheckInService) applicationContext.getBean("checkOutCheckInService");
private AuthenticationService authenticationService = (AuthenticationService) applicationContext.getBean("authenticationService");
private NodeRef document;
private NodeRef parentFolder;
@Override
protected void setUp() throws Exception
{
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Void>()
{
@Override
public Void execute() throws Throwable
{
authenticationService.authenticate(ADMIN_CREDENTIAL, ADMIN_CREDENTIAL.toCharArray());
ResultSet query = null;
NodeRef rootNode = null;
try
{
query = searchService.query(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, SearchService.LANGUAGE_LUCENE, ROOT_NODE_TERM);
rootNode = query.getNodeRef(0);
}
finally
{
if (null != query)
{
query.close();
}
}
Map<QName, Serializable> properties = new HashMap<QName, Serializable>();
properties.put(ContentModel.PROP_NAME, PARENT_FOLDER_NAME);
parentFolder = nodeService.createNode(rootNode, ContentModel.ASSOC_CONTAINS, QName.createQName(ContentModel.USER_MODEL_URI, PARENT_FOLDER_NAME),
ContentModel.TYPE_FOLDER, properties).getChildRef();
properties.clear();
properties.put(ContentModel.PROP_NAME, DOCUMENT_NAME);
document = nodeService.createNode(parentFolder, ContentModel.ASSOC_CONTAINS, QName.createQName(ContentModel.USER_MODEL_URI, DOCUMENT_NAME),
ContentModel.TYPE_CONTENT, properties).getChildRef();
contentService.getWriter(document, ContentModel.PROP_CONTENT, true).putContent(TEST_CONTENT_01);
if (!nodeService.hasAspect(document, ContentModel.ASPECT_VERSIONABLE))
{
Map<QName, Serializable> versionProperties = new HashMap<QName, Serializable>();
versionProperties.put(ContentModel.PROP_VERSION_LABEL, "0.1");
versionProperties.put(ContentModel.PROP_INITIAL_VERSION, true);
versionProperties.put(ContentModel.PROP_VERSION_TYPE, VersionType.MINOR);
nodeService.addAspect(document, ContentModel.ASPECT_VERSIONABLE, versionProperties);
}
return null;
}
});
}
@Override
protected void tearDown() throws Exception
{
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Void>()
{
@Override
public Void execute() throws Throwable
{
if (null != parentFolder)
{
nodeService.deleteNode(parentFolder);
}
authenticationService.clearCurrentSecurityContext();
return null;
}
});
}
public void testAutoVersionIncrementOnPropertiesUpdateAfterCheckInAlf14584() throws Exception
{
final String name02 = generateDocumentName(DOCUMENT_NAME, "0.2");
final String name11 = generateDocumentName(DOCUMENT_NAME, "1.1");
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Void>()
{
@Override
public Void execute() throws Throwable
{
Map<QName, Serializable> properties = getAndAssertProperties(document, "0.1");
Serializable autoVersionProps = properties.get(ContentModel.PROP_AUTO_VERSION_PROPS);
assertNotNull(("Autoversion property is NULL! NodeRef = '" + document.toString() + "'"), autoVersionProps);
assertTrue(("Autoversion must be TRUE! NodeRef = '" + document.toString() + "'"), (Boolean) autoVersionProps);
nodeService.setProperty(document, ContentModel.PROP_NAME, name02);
return null;
}
});
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Void>()
{
@Override
public Void execute() throws Throwable
{
Map<QName, Serializable> properties = getAndAssertProperties(document, "0.2");
assertEquals(name02, properties.get(ContentModel.PROP_NAME));
NodeRef workingCopy = checkOutCheckInService.checkout(document);
contentService.getWriter(workingCopy, ContentModel.PROP_CONTENT, true).putContent(TEST_CONTENT_10);
Map<String, Serializable> versionProperties = new HashMap<String, Serializable>();
versionProperties.put(VersionModel.PROP_VERSION_TYPE, VersionType.MAJOR);
document = checkOutCheckInService.checkin(workingCopy, versionProperties);
return null;
}
});
assertDocumentVersionAndName("1.0", name02);
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Void>()
{
@Override
public Void execute() throws Throwable
{
nodeService.setProperty(document, ContentModel.PROP_NAME, name11);
return null;
}
});
assertDocumentVersionAndName("1.1", name11);
}
public void testAutoVersionIncrementOnPropertiesUpdateByLockOwnerAlf14584() throws Exception
{
final String name = generateDocumentName(DOCUMENT_NAME, "0.2");
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Void>()
{
@Override
public Void execute() throws Throwable
{
Map<QName, Serializable> properties = getAndAssertProperties(document, "0.1");
Serializable autoVersionProps = properties.get(ContentModel.PROP_AUTO_VERSION_PROPS);
assertNotNull(("Autoversion property is NULL! NodeRef = '" + document.toString() + "'"), autoVersionProps);
assertTrue(("Autoversion must be TRUE! NodeRef = '" + document.toString() + "'"), (Boolean) autoVersionProps);
lockService.lock(document, LockType.WRITE_LOCK);
LockStatus lockStatus = lockService.getLockStatus(document);
assertFalse(
("Node with NodeRef = '" + document.toString() + "' must not be locked for " + AuthenticationUtil.getFullyAuthenticatedUser() + " user! The user is lock owner"),
isLocked(document));
assertEquals(LockStatus.LOCK_OWNER, lockService.getLockStatus(document));
nodeService.setProperty(document, ContentModel.PROP_NAME, name);
return null;
}
});
assertDocumentVersionAndName("0.2", name);
}
// Copy of code from VersionableAspect which really should be in LockService
private boolean isLocked(NodeRef nodeRef)
{
LockStatus lockStatus = lockService.getLockStatus(nodeRef);
return (LockStatus.NO_LOCK != lockStatus) && (LockStatus.LOCK_OWNER != lockStatus);
}
private void assertDocumentVersionAndName(final String versionLabel, final String name)
{
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Void>()
{
@Override
public Void execute() throws Throwable
{
Map<QName, Serializable> properties = getAndAssertProperties(document, versionLabel);
assertEquals(name, properties.get(ContentModel.PROP_NAME));
return null;
}
}, true);
}
private Map<QName, Serializable> getAndAssertProperties(NodeRef nodeRef, String versionLabel)
{
assertNotNull("NodeRef of document is NULL!", nodeRef);
Map<QName, Serializable> properties = nodeService.getProperties(nodeRef);
assertNotNull(("Properties must not be NULL! NodeRef = '" + nodeRef.toString() + "'"), properties);
assertFalse(("Version specific properties can't be found! NodeRef = '" + nodeRef.toString() + "'"), properties.isEmpty());
assertEquals(versionLabel, properties.get(ContentModel.PROP_VERSION_LABEL));
return properties;
}
private String generateDocumentName(String namePattern, String versionLabel)
{
int i = 0;
String[] nameAndExt = namePattern.split(NAME_AND_EXT_DELIMETER_REGEXP);
StringBuilder result = new StringBuilder(nameAndExt[i++]).append(versionLabel).append(NAME_AND_EXT_DELIMETER).append(nameAndExt[i++]);
return result.toString();
}
}

View File

@@ -22,7 +22,7 @@ import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Map;
import org.alfresco.model.ApplicationModel; import org.alfresco.model.ApplicationModel;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
@@ -30,16 +30,19 @@ import org.alfresco.repo.jscript.BaseScopableProcessorExtension;
import org.alfresco.repo.jscript.ScriptNode; import org.alfresco.repo.jscript.ScriptNode;
import org.alfresco.repo.jscript.ScriptableHashMap; import org.alfresco.repo.jscript.ScriptableHashMap;
import org.alfresco.repo.jscript.ScriptableQNameMap; import org.alfresco.repo.jscript.ScriptableQNameMap;
import org.alfresco.repo.workflow.WorkflowModel;
import org.alfresco.service.ServiceRegistry; import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.MutableAuthenticationService;
import org.alfresco.service.cmr.workflow.WorkflowService;
import org.alfresco.service.cmr.workflow.WorkflowTask; import org.alfresco.service.cmr.workflow.WorkflowTask;
import org.alfresco.service.cmr.workflow.WorkflowTaskState;
import org.alfresco.service.cmr.workflow.WorkflowTransition; import org.alfresco.service.cmr.workflow.WorkflowTransition;
import org.alfresco.service.namespace.NamespacePrefixResolver; import org.alfresco.service.namespace.NamespacePrefixResolver;
import org.alfresco.service.namespace.NamespacePrefixResolverProvider; import org.alfresco.service.namespace.NamespacePrefixResolverProvider;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.mozilla.javascript.Context; import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.Scriptable;
@@ -54,154 +57,37 @@ public class JscriptWorkflowTask extends BaseScopableProcessorExtension implemen
{ {
static final long serialVersionUID = -8285971359421912313L; static final long serialVersionUID = -8285971359421912313L;
/** Unique ID for workflow task */
private final String id;
/** Name for workflow task */
private final String name;
/** Title for workflow task */
private final String title;
/** Description of workflow task */
private final String description;
/** Properties (key/value pairs) for this Workflow Task */
private ScriptableQNameMap<String, Serializable> properties;
/** Whether task is complete or not - 'true':complete, 'false':in-progress */
private boolean complete = false;
/** Whether task is pooled or not */
private boolean pooled = false;
/** Service Registry object */ /** Service Registry object */
private ServiceRegistry serviceRegistry; private final ServiceRegistry serviceRegistry;
private final NodeService nodeService;
private final WorkflowService workflowService;
private final DictionaryService dictionaryService;
private MutableAuthenticationService authenticationService;
private final DefaultNamespaceProvider namespaceProvider;
/** Available transitions * */ private WorkflowTask task;
private ScriptableHashMap<String, String> transitions;
/** Package resources * */
private Scriptable packageResources;
/**
* Creates a new instance of a workflow task (instance of a workflow task definition)
*
* @param id
* workflow task ID
* @param name
* workflow task name
* @param title
* workflow task title
* @param description
* workflow task description
* @param serviceRegistry
* Service Registry object
* @param properties
* @param transitions
* @param packageResources
*/
public JscriptWorkflowTask(final String id, final String name, final String title, final String description, final ServiceRegistry serviceRegistry,
final ScriptableQNameMap<String, Serializable> properties, final ScriptableHashMap<String, String> transitions, Scriptable packageResources,
Scriptable scope)
{
this.id = id;
this.name = name;
this.title = title;
this.description = description;
this.serviceRegistry = serviceRegistry;
this.properties = properties;
this.transitions = transitions;
this.packageResources = packageResources;
this.setScope(scope);
}
/** /**
* Creates a new instance of a workflow task from a WorkflowTask from the CMR workflow object model * Creates a new instance of a workflow task from a WorkflowTask from the CMR workflow object model
* *
* @param cmrWorkflowTask * @param task
* an instance of WorkflowTask from CMR workflow object model * an instance of WorkflowTask from CMR workflow object model
* @param serviceRegistry * @param serviceRegistry
* Service Registry object * Service Registry object
*/ */
public JscriptWorkflowTask(final WorkflowTask cmrWorkflowTask, final ServiceRegistry serviceRegistry, Scriptable scope) public JscriptWorkflowTask(WorkflowTask task,
ServiceRegistry serviceRegistry,
Scriptable scope)
{ {
this.id = cmrWorkflowTask.getId();
this.name = cmrWorkflowTask.getName();
this.title = cmrWorkflowTask.getTitle();
this.description = cmrWorkflowTask.getDescription();
this.serviceRegistry = serviceRegistry; this.serviceRegistry = serviceRegistry;
this.namespaceProvider = new DefaultNamespaceProvider(serviceRegistry.getNamespaceService());
this.workflowService = serviceRegistry.getWorkflowService();
this.nodeService = serviceRegistry.getNodeService();
this.dictionaryService = serviceRegistry.getDictionaryService();
this.authenticationService = serviceRegistry.getAuthenticationService();
this.task = task;
this.setScope(scope); this.setScope(scope);
// instantiate ScriptableQNameMap<String, Serializable> properties
// from WorkflowTasks's Map<QName, Serializable> properties
this.properties = new ScriptableQNameMap<String, Serializable>(new NamespacePrefixResolverProvider()
{
private static final long serialVersionUID = 4218645978524914678L;
public NamespacePrefixResolver getNamespacePrefixResolver()
{
return serviceRegistry.getNamespaceService();
}
});
Set<QName> keys = cmrWorkflowTask.getProperties().keySet();
for (QName key : keys)
{
Serializable value = cmrWorkflowTask.getProperties().get(key);
this.properties.put(key.toString(), value);
}
transitions = new ScriptableHashMap<String, String>();
for (WorkflowTransition transition : cmrWorkflowTask.getPath().getNode().getTransitions())
{
transitions.put(transition.getId(), transition.getTitle());
}
// build package context .... should be centralised... YUK
// Needs to match org.alfresco.repo.template.Workflow.WorkflowTaskItem.getPackageResources
List<NodeRef> contents = serviceRegistry.getWorkflowService().getPackageContents(cmrWorkflowTask.getId());
List<NodeRef> resources = new ArrayList<NodeRef>(contents.size());
NodeService nodeService = serviceRegistry.getNodeService();
DictionaryService ddService = serviceRegistry.getDictionaryService();
for (NodeRef nodeRef : contents)
{
if (nodeRef.getStoreRef().getProtocol().equals(StoreRef.PROTOCOL_AVM))
{
resources.add(nodeRef);
}
else
{
if (nodeService.exists(nodeRef))
{
// find it's type so we can see if it's a node we are interested in
QName type = nodeService.getType(nodeRef);
// make sure the type is defined in the data dictionary
if (ddService.getType(type) != null)
{
// look for content nodes or links to content
// NOTE: folders within workflow packages are ignored for now
if (ddService.isSubClass(type, ContentModel.TYPE_CONTENT) || ApplicationModel.TYPE_FILELINK.equals(type))
{
resources.add(nodeRef);
}
}
}
}
}
Object[] answer = new Object[resources.size()];
for (int i = 0; i < resources.size(); i++)
{
// create our Node representation from the NodeRef
answer[i] = new ScriptNode(resources.get(i), serviceRegistry, getScope());
}
packageResources = Context.getCurrentContext().newArray(getScope(), answer);
} }
/** /**
@@ -211,7 +97,7 @@ public class JscriptWorkflowTask extends BaseScopableProcessorExtension implemen
*/ */
public String getId() public String getId()
{ {
return id; return task.getId();
} }
/** /**
@@ -221,7 +107,7 @@ public class JscriptWorkflowTask extends BaseScopableProcessorExtension implemen
*/ */
public String getName() public String getName()
{ {
return name; return task.getName();
} }
/** /**
@@ -231,7 +117,7 @@ public class JscriptWorkflowTask extends BaseScopableProcessorExtension implemen
*/ */
public String getTitle() public String getTitle()
{ {
return title; return task.getTitle();
} }
/** /**
@@ -241,7 +127,7 @@ public class JscriptWorkflowTask extends BaseScopableProcessorExtension implemen
*/ */
public String getDescription() public String getDescription()
{ {
return description; return task.getDescription();
} }
/** /**
@@ -251,18 +137,24 @@ public class JscriptWorkflowTask extends BaseScopableProcessorExtension implemen
*/ */
public Scriptable getProperties() public Scriptable getProperties()
{ {
// instantiate ScriptableQNameMap<String, Serializable> properties
// from WorkflowTasks's Map<QName, Serializable> properties
ScriptableQNameMap<String, Serializable> properties = new ScriptableQNameMap<String, Serializable>(namespaceProvider);
properties.putAll(task.getProperties());
return properties; return properties;
} }
/** /**
* Sets the value of the <code>properties</code> property * Sets the properties on the underlying {@link WorkflowTask}.
* *
* @param properties * @param properties
* the properties to set * the properties to set
*/ */
public void setProperties(ScriptableQNameMap<String, Serializable> properties) public void setProperties(ScriptableQNameMap<String, Serializable> properties)
{ {
this.properties = properties;
Map<QName, Serializable> qNameProps = properties.getMapOfQNames();
this.task = workflowService.updateTask(task.getId(), qNameProps, null, null);
} }
/** /**
@@ -272,7 +164,7 @@ public class JscriptWorkflowTask extends BaseScopableProcessorExtension implemen
*/ */
public boolean isComplete() public boolean isComplete()
{ {
return complete; return task.getState().equals(WorkflowTaskState.COMPLETED);
} }
/** /**
@@ -282,15 +174,13 @@ public class JscriptWorkflowTask extends BaseScopableProcessorExtension implemen
*/ */
public boolean isPooled() public boolean isPooled()
{ {
if(properties != null) { String authority = authenticationService.getCurrentUserName();
Collection<?> actors = (Collection<?>) properties.get(WorkflowModel.ASSOC_POOLED_ACTORS); return workflowService.isTaskClaimable(task, authority);
return actors != null && !actors.isEmpty();
}
return false;
} }
/** /**
* @deprecated pooled state cannot be altered. * @deprecated pooled state cannot be altered.
*
*/ */
@Deprecated @Deprecated
public void setPooled(boolean pooled) public void setPooled(boolean pooled)
@@ -306,7 +196,7 @@ public class JscriptWorkflowTask extends BaseScopableProcessorExtension implemen
*/ */
public void endTask(String transitionId) public void endTask(String transitionId)
{ {
serviceRegistry.getWorkflowService().endTask(this.id, transitionId); workflowService.endTask(task.getId(), transitionId);
} }
/** /**
@@ -316,6 +206,11 @@ public class JscriptWorkflowTask extends BaseScopableProcessorExtension implemen
*/ */
public ScriptableHashMap<String, String> getTransitions() public ScriptableHashMap<String, String> getTransitions()
{ {
ScriptableHashMap<String, String> transitions = new ScriptableHashMap<String, String>();
for (WorkflowTransition transition : task.getPath().getNode().getTransitions())
{
transitions.put(transition.getId(), transition.getTitle());
}
return transitions; return transitions;
} }
@@ -326,7 +221,64 @@ public class JscriptWorkflowTask extends BaseScopableProcessorExtension implemen
*/ */
public Scriptable getPackageResources() public Scriptable getPackageResources()
{ {
return packageResources; List<NodeRef> contents = workflowService.getPackageContents(task.getId());
List<ScriptNode> resources = new ArrayList<ScriptNode>(contents.size());
Collection<QName> allowedTypes = getAllowedPackageResourceTypes();
for (NodeRef node : contents)
{
if (isAvmResource(node, allowedTypes))
{
ScriptNode scriptNode = new ScriptNode(node, serviceRegistry, getScope());
resources.add(scriptNode);
}
}
return Context.getCurrentContext().newArray(getScope(), resources.toArray());
}
private Collection<QName> getAllowedPackageResourceTypes()
{
// look for content nodes or links to content
// NOTE: folders within workflow packages are ignored for now
Collection<QName> allowedTypes = dictionaryService.getSubTypes(ContentModel.TYPE_CONTENT, true);
allowedTypes.addAll(dictionaryService.getSubTypes(ApplicationModel.TYPE_FILELINK, true));
return allowedTypes;
}
private boolean isAvmResource(NodeRef node, Collection<QName> allowedTypes)
{
if(isAvmNode(node))
return true;
if (nodeService.exists(node))
{
//Check if the node is one of the allowedTypes.
return allowedTypes.contains(nodeService.getType(node));
}
return false;
}
private boolean isAvmNode(NodeRef node)
{
return StoreRef.PROTOCOL_AVM.equals(node.getStoreRef().getProtocol());
}
private static class DefaultNamespaceProvider implements NamespacePrefixResolverProvider
{
private static final long serialVersionUID = -7015209142379905617L;
private final NamespaceService namespaceService;
public DefaultNamespaceProvider(NamespaceService namespaceService)
{
this.namespaceService = namespaceService;
}
/**
* {@inheritDoc}
*/
public NamespacePrefixResolver getNamespacePrefixResolver()
{
return namespaceService;
} }
} }
}

View File

@@ -0,0 +1,92 @@
/*
* Copyright (C) 2005-2012 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.util;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Helper class to collect all of our DatabaseMetaData interpretations in one place.
*
* @author sfrensley
*
*/
public class DatabaseMetaDataHelper {
private static Log logger = LogFactory.getLog(DatabaseMetaDataHelper.class);
/**
* Trys to determine the schema name from the DatabaseMetaData obtained from the Connection.
* @param connection A database connection
* @return
*/
public static String getSchema(Connection connection)
{
if (connection == null) {
logger.error("Unable to determine schema due to null connection.");
return null;
}
ResultSet schemas = null;
try
{
final DatabaseMetaData dbmd = connection.getMetaData();
// Assume that if there are schemas, we want the one named after the connection user or the one called "dbo" (MS
// SQL hack)
String schema = null;
schemas = dbmd.getSchemas();
while (schemas.next())
{
final String thisSchema = schemas.getString("TABLE_SCHEM");
if (thisSchema.equals(dbmd.getUserName()) || thisSchema.equalsIgnoreCase("dbo"))
{
schema = thisSchema;
break;
}
}
return schema;
}
catch (Exception e)
{
logger.error("Unable to determine current schema.",e);
}
finally
{
if (schemas != null)
{
try
{
schemas.close();
}
catch (Exception e)
{
//noop
}
}
}
return null;
}
}

View File

@@ -55,7 +55,7 @@ public class OpenOfficeCommandLine extends AbstractMap<String, List<String>>
if (variant.isLibreOffice3Dot5(officeHome)) if (variant.isLibreOffice3Dot5(officeHome))
{ {
command.add("--accept=" + acceptValue); command.add("--accept=" + acceptValue);
if (variant.isMac()) if (variant.isMac() && !variant.isLibreOffice3Dot6(officeHome))
{ {
command.add("--env:UserInstallation=" + userInstallation); command.add("--env:UserInstallation=" + userInstallation);
} }
@@ -70,7 +70,9 @@ public class OpenOfficeCommandLine extends AbstractMap<String, List<String>>
//command.add("--nolockcheck"); included by JOD //command.add("--nolockcheck"); included by JOD
command.add("--nologo"); command.add("--nologo");
command.add("--norestore"); command.add("--norestore");
logger.info("Using GNU based LibreOffice command"+(variant.isMac() ? " on Mac" : "")+": "+command); logger.info("Using GNU based LibreOffice "+
(variant.isLibreOffice3Dot6(officeHome) ? "3.6" : "3.5")+" command"+
(variant.isMac() ? " on Mac" : "")+": "+command);
} }
else else
{ {

View File

@@ -108,20 +108,32 @@ public class OpenOfficeVariant
} }
public boolean isLibreOffice3Dot5(File officeHome) public boolean isLibreOffice3Dot5(File officeHome)
{
if (logger.isDebugEnabled())
{ {
logger.debug("System.getProperty(\"os.name\")="+System.getProperty("os.name")); logger.debug("System.getProperty(\"os.name\")="+System.getProperty("os.name"));
logger.debug("officeHome="+(officeHome == null ? null : "'"+officeHome.getAbsolutePath()+"'")); logger.debug("officeHome="+(officeHome == null ? null : "'"+officeHome.getAbsolutePath()+"'"));
logger.debug("basis-link:"+new File(officeHome, "basis-link").isFile()); logger.debug("basis-link:"+new File(officeHome, "basis-link").isFile());
logger.debug(" ure-link:"+new File(officeHome, "ure-link").isFile());
logger.debug("basis-link:"+new File(officeHome, "basis-link").isDirectory()); logger.debug("basis-link:"+new File(officeHome, "basis-link").isDirectory());
logger.debug(" ure-link:"+new File(officeHome, "ure-link").isFile());
logger.debug(" ure-link:"+new File(officeHome, "ure-link").isDirectory()); logger.debug(" ure-link:"+new File(officeHome, "ure-link").isDirectory());
logger.debug(" NOTICE:"+new File(officeHome, "NOTICE").isFile());
}
return return
officeHome != null && officeHome != null &&
!new File(officeHome, "basis-link").isFile() && !new File(officeHome, "basis-link").isFile() &&
(new File(officeHome, "ure-link").isFile() || new File(officeHome, "ure-link").isDirectory()); (new File(officeHome, "ure-link").isFile() || new File(officeHome, "ure-link").isDirectory());
} }
public boolean isLibreOffice3Dot6(File officeHome)
{
if (logger.isDebugEnabled())
{
logger.debug(" NOTICE:"+new File(officeHome, "NOTICE").isFile());
}
return isLibreOffice3Dot5(officeHome) && new File(officeHome, "NOTICE").isFile();
}
public boolean isLinux() public boolean isLinux()
{ {
return OS_NAME.startsWith("linux"); return OS_NAME.startsWith("linux");