mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-07 18:25:23 +00:00
24662: 3.4.1 bug fix branch 24718: Merged V3.3 to V3.4-BUG-FIX 24717: Fix ALF-5555: It is impossible to edit review date from record's details page 24719: Fix for ALF-6106: Error on Check In operation with % symbol (SPP) 24733: Better fix for ALF-6106: Error on Check In operation with % symbol 24734: Fix for ALF-6089: Incorrect order of fields at 'Create Series', 'Create Category' and 'Create Folder' forms The name, title and description fields are now placed in their own group on the server, all other non custom rm fields are put in an 'other' group, the client side config then declares a set for each group and orders them appropriately. 24752: Merged V3.4 to V3.4-BUG-FIX 24751: Merged V3.3-BUG-FIX to V3.4 (RECORD ONLY) Restored V3.3-BUG-FIX mergeinfo, somehow truncated in revision 24274 24753: Merged V3.3-BUG-FIX to V3.4-BUG-FIX 23870: Merge Dev to V3.3_BUG_FIX ALF-4243: F5 load-balancer sending regular HTTP requests to Alfresco server causing Faces Servlet to throw java.lang.NullPointerException (MyFaces upgrade to from 1.1.5 to 1.1.7) 23897: Additional fixes and tweaks since introduction of MyFaces 1.1.7 library. 23919: More JSF component id related fixes. 23945: More MyFaces1.1.7 JSF page fix ups 23959: Another MyFaces 1.1.7 dup id issue fixed. 24008: ALF-4243 - Upgraded MyFaces from 1.1.7 to 1.1.8 to fix a bug seen in 1.1.7 - Added handling for the fact that valuebound properties that result in null now cause an exception where-as they were perfectly valid in 1.1.5. 24419: Merge from V3.3 to V3.3-BUG-FIX r.24418 Fix for ALF-6075. Running out of /tmp space on the server is causing uploads to fail. 24768: Fixes ALF-6295: Allows MySQL to not be installed via unattended installer invocation 24771: Merged BRANCHES/V3.4 to BRANCHES/DEV/V3.4-BUG-FIX: 24767: Merged BRANCHES/V3.3 to BRANCHES/V3.4: 24765: ALF-6547: fix intermittent test failure (AssetServiceImplTest renameFile/renameFolder) - fallout from ALF-1948 24779: Merge V3.3 to V3.4-BUG-FIX 24497 : ALF-3092 - deployment service - catch Throwable from Begin. 24684 : Merge DEV/BELARUS/V3.3-BUG-FIX-2010_10_04 to V3.3 23498 : ALF-5498 In Windows XP, placing a Folder with a Name that already Exists Removes all Content of the Existing Folder 24749 : ALF-6174 - Transfer Service fails with double peer assoc custom content type 24766 : ALF-5603 - It is impossible to assign workflow from workflow console to non-admin user 24802: Merged BRANCHES/V3.4 to BRANCHES/DEV/V3.4-BUG-FIX: 24801: Fix for ALF-3055: "SecurityTestSuite hangs when run in DOD5015 context - failed authentication audit hangs on DB connection" - do failed audits in a separate thread (from a thread pool) 24812: Fix ALF-6316: A new "spoof" multivalue text property (cm:tagScopeSummary) is now made available for TagScope nodes when accessed via the getProperty or getProperties operations on the standard node service. The values of this property take the form "<tagname>=<tagcount>". A new interceptor has been added to the node service to do this (TagScopePropertyMethodInterceptor). WQS has been tweaked to make use of this new property, and the now defunct behaviour has been removed. 24820: Work in progress refactoring transaction handling of transfer unit tests. 24822: Merged BRANCHES/V3.4 to BRANCHES/DEV/V3.4-BUG-FIX: 24821: Fix for ALF-3055: "SecurityTestSuite hangs when run in DOD5015 context - failed authentication audit hangs on DB connection" - fix up unit tests 24834: ALF-6468 - Update the scheduled actions folder bootstrap to use localisable names and descriptions, following the normal pattern 24836: Added system property 'system.cache.disableImmutableSharedCaches' (false by default) - Equivalent to disabling Hibernate L2 cache for *immutable* entities - Allows distinction between mutable and immutable cache entries 24850: Fix ALF-6562: Moved property that is used to label the WQS dashlet on the "configure site dashboard" page out of the Slingshot project and into the WQS Share Module project. Corrected its value to "Web Quick Start" rather than "WCM Quick Start". 24857: Merged V3.4 to V3.4-BUG-FIX 24853: Merged V3.3 to V3.4 24852: Fixed ALF-6573 "Incorrect name of subgroups on "Groups" page" 24870: Removed svn:mergeinfo from root 24873: Merged V3.3 to V3.4-BUG-FIX (RECORD ONLY) 21789: ALF-4333: Fix - Updated RepoPrimaryManifestProcessorImpl so it can handle deletions that are reported by either pre-delete noderef or archived noderef (previously only handled the latter). - Updated TransferManifestNodeFactory so that it handles the case where the status of the node to transfer is "deleted". - Updated UnitTestTransferManifestNodeFactory so that it handles the change to TransferManifestNodeFactory above. - Added new tests for deletion cases. 23259: Merged HEAD to V3.3 23256: Fix ALF-4573: Start Workflow action is absent for edited document and working copy in Share 23346: Brought WebQS module in (including build process but not installer elements yet) 23371: "Simply" added wcmqs to installer 23391: ALF-5367: Copy dlls into tomcat/bin as appropriate. 23485: Merged V3.4 to V3.3 (fix backported for V3.3.x lines) 23472: Fixed ALF-5408: SQL Server missing ON DELETE CASCADE declarations 23515: Merged PATCHES/V3.2.0 to V3.3 23514: ALF-5554: Merged HEAD to V3.2.0 23153: When updating tag scopes following system shutdown/restore, be smarter about quickly skipping tag scopes that another (new) thread is currently working on 23283: More debugging level logging for tagging updates, to help identify the problem with periodic multi-threaded test failures on bamboo 23535: Merged V3.4 to V3.3 (complements 23517: ALF-5552) 23508: Fixed ALF-5559: Permission interceptors can fail if Lucene returns invalid NodeRefs 23564: ALF-5600: Merged V3.4 to V3.3 23424: Fixes: ALF-2989 - Incorrect sideId reference in URL for event in Site Calendar Dashlet Adds support for displaying events that start in the past but finish in the future (previously only events that start in the future were shown) 23586: MERGED V3.4 to V3.3 22864: Fix for ALF-5005: "Create and edit functions on AWE become "confused"" 23042: Fix ALF-5127: Impossible to create an article/blog (WCMQS) [Must clear panel hideEvent handler if manually hiding a YUI panel] 23561: Fixes: ALF-4569 - Removes universal override of input width box and switches the editor form panel to adjust it's width based on content rather than window size. Fixes: ALF-4570 - Adds an override for the CSS 'top' property of the form dialogue to ensure it's always below the ribbon. (Was being set automatically by the YUI widget.panel call) 23569: Fixes: ALF-5606 - Ribbon wasn't resizing correctly after the form events. 23630: Backport of installer 23631: Added 64-bit & deployment installers 23664: Fixes ALF-5691: TransferService: Multi-byte characters are not encoded correctly 23681: Fixes ALF-5699: TransferService: Snapshot file from source repo never contains complete MLText properties 23695: Fixed bug exposed after fixing ALF-5699. Parsing of MLText properties out of the transfer snapshot file was incorrect, and that was causing multi-lingual property values to be duplicated 23709: ALF-5699: Fix NPE in ManifestIntegrationTest 23734: Merged V3.4 to V3.3 23731: Fixes for ALF-3098 and ALF-3097 - Share - Security check on Personal Dashboard - only the owning user can view a user dashboard page - Share - Security issue on Customize Site Dashboard - private and moderated site dashboard pages no longer visible to non-members, customise site and dashboard pages only accessible to SiteManager 23747: ALF-5696: Merged V3.4 to V3.3 23585: Fixed ALF-5372 "JavaScript error on Groups management dialog with IE8 : document.getElementById is null" 23790: Fixed ALF-3823 "Share: RSS feed can't be read: http://cds-srv.sun.com:8700/rss/update/public/sunalert_update.xml - ok with other RSS client." 23883: Fixes ALF-5759: WQS: Attempt to copy a website section fails 23907: Merged DEV/BELARUS/V3.3-BUG-FIX-2010_09_20 to V33 22750: ALF-4846: Update rules are firing on inbound actions 23931: Undid rev 23907 (Reverse-merged /alfresco/BRANCHES/DEV/BELARUS/V3.3-BUG-FIX-2010_09_20:r22750) 23961: Fixed ALF-5686 "Incorrect behaviour of "All" filter in "My Tasks" dashlet" - Variables assigned in a <#macro> shall always be assigned using <#local> (using <#assign> makes them globally available which might cause naming collisions) 24132: Disable intermittent failing unit test 24148: ALF-6007: Merged HEAD to V3.3 23049: Fixed ALF-5099: Error when trying to go back in Create Web Content Wizard (only with certain XSDs) 24263: Merged from V3.3-BUG-FIX to V3.3 24264: V3.3-BUG-FIX to V3.3 24262: Stress test code for ALF-5025: Support background processing of archiving 24287: Added missing import 24336: Merged V3.4 to V3.3 23205: Fix for ALF-2111 - Download URLS are different on different pages, authentication fails when URL sent 24353: Merged V3.4 to V3.3 24352: Fix SQL fallout from ALF-6078 24510: Merged V3.4 to V3.3 21960: First round of date refactoring: Document Library pages now expect XML dates (ISO8601) from Share data webscripts 21961: Share client-side I18N utility now emulates sever-side handling of doubled-up single quotes. 24526: Merged V3.4 to V3.3 24402: Fix for performance degredation related to ALF-3823. RSS feed processing in JavaScript relies on Rhino impl of regex - this is extreemly slow as Rhino regex is by far the slowest component of the library. Switched code to use the Java Regex libraries to improve performance and reduce memory usage. 24587: Merged V3.4 to V3.3 24564: Fix for ALF-3727: Custom permissions aren't visible in Explorer UI 24604: Merged V3.4 to V3.3 24602: Build fix for RM permission model loading - collateral damage for R 24564 24774: Merged BRANCHES/V3.4 to BRANCHES/V3.3: 23492: Fixed ALF-5550: DB2: Unable to insert values into alf_string_value 24813: Merged BRANCHES/V3.4 to BRANCHES/V3.3: 24750: Limit installer builds to 2 threads 24874: Merged V3.4 to V3.4-BUG-FIX 24667: Resolve ALF-6202 - MT: fix offline edit (Share) 24672: Fixes from Gloria for: ALF-6339 and ALF-6337 24673: Merge V3.3 to V3.4 24668 : Upgrade of large repository to latest 3.3 fails on excession of mysql table lock size 24674: Fixes ALF-6294: Remove illegal CLI option 24675: Fix ALF-6099: CLONE - IE6: Sometimes errors occur on almost actions in Office Add-ins. Removed linebreaks from JSON response template & prevented "undefined" entries in URL. 24680: ALF-6120 : Version notes are lost for versioned items migrated from 2.2 to 3.4.0 24681: Merged BRANCHES/DEV/BELARUS/V3.4-2010_12_14 to BRANCHES/V3.4: 24609: MT - ALF-3563 24640: MT - ALF-3563 (merged w/ minor improvement) 24685: Fixes ALF-6403: Change installer window height on Linux 24688: Fix ALF-6029 (part II) - MT: cannot "Show Folders" for "Data Dictionary" in Afresco Share - part II adds patch and removes workaround 24689: Fixes: ALF-6219 - Incorrectly formatted variable in translation 24691: MT: ALF-3263 - Explorer login now fails with consistent error message ("Unable to login - unknown username/password.") if tenant does not exist or is disabled 24692: Fixes: ALF-6370 and ALF-6225 among others - sweep of FR and DE resource bundles for quote escaping. 24694: Fixes ALF-6424. Erased erroneous equals sign 24695: Fixes: ALF-6320 - removed the country specific portion of the language pack suffixes for French, German and Spanish. This enables speakers of those languages outside of those countries to benefit from the language packs. 24696: Fix for ALF-6299: XSS attack on editing blog post with XSS data in IE6&IE7 24700: Swaps _it_IT for _it to make Italian language pack available to Italian speakers outside of Italy. 24703: Avoid DB2 query failure if someone passes in a made-up UUID - Test RunningActionRestApiTest was making up a long node UUID - DB2 fails to set the parameter with SQLSTATE=22001 24706: Merged V3.4-BUG-FIX to V3.4 24705: Fix for ALF-6365, ALF-6335 24708: Fix ALF-6386: View Details and Edit Metadata icons are incorrect for folder 24709: Missing first/last name handling. 24711: Merged V3.3 to V3.4 24710: ALF-5535 - Fix to correctly format json number values (not as numeric human readable strings) 24713: Fix ALF-5404: It is now possible to configure who receives notifications of "Contact Us" requests by setting a configuration property on the WQS website node, such as "feedbackAssignee.Contact Request=brian" Also added missing Spring MVC source to 3rd Party. 24715: Fix for ALF-6412. OOoDirect always tries to connect to port 8100. Formerly the ooo.port property did not exist for the OOoDirect connector. It was added in r.23182 for the soffice process, but not for the connector bean. Now added for the connector too. 24721: Fix for ALF-6351 - Simple search breaks if override config is used and does not contain new 'repository-search' element 24728: Fixes: ALF-5685 - Incorrect encoding of Japanese Characters 24732: Fixes ALF-6381 and others - calendar strings appearing incorrectly. Problem was an unicode encoded comma preventing the property string being broken up into different days of the weeks or months. 24739: Fix ALF-6545: DB2: SQLCODE=-302, SQLSTATE=22001 (testCreateMultiLingualCategoryRoots) - Shortened Japanese name to 14 characters 24740: Fixes: ALF-6413 (with some translations still pending). 24742: Update readmes. 24744: Merged HEAD to BRANCHES/V3.4: 24137: Fixes: ALF-5642, ALF-3892, ALF-5043 & Brings Add Event dialog in line with other forms in share by disabling the popup validation error box. 24746: Build/test fix: PostgreSQL -AssetServiceImplTest.renameFolder 24755: Merged V3.3 to V3.4 (RECORD ONLY) 21789: ALF-4333: Fix - Updated RepoPrimaryManifestProcessorImpl so it can handle deletions that are reported by either pre-delete noderef or archived noderef (previously only handled the latter). - Updated TransferManifestNodeFactory so that it handles the case where the status of the node to transfer is "deleted". - Updated UnitTestTransferManifestNodeFactory so that it handles the change to TransferManifestNodeFactory above. - Added new tests for deletion cases. 23259: Merged HEAD to V3.3 23256: Fix ALF-4573: Start Workflow action is absent for edited document and working copy in Share 23346: Brought WebQS module in (including build process but not installer elements yet) 23371: "Simply" added wcmqs to installer 23391: ALF-5367: Copy dlls into tomcat/bin as appropriate. 23485: Merged V3.4 to V3.3 (fix backported for V3.3.x lines) 23472: Fixed ALF-5408: SQL Server missing ON DELETE CASCADE declarations 23515: Merged PATCHES/V3.2.0 to V3.3 23514: ALF-5554: Merged HEAD to V3.2.0 23153: When updating tag scopes following system shutdown/restore, be smarter about quickly skipping tag scopes that another (new) thread is currently working on 23283: More debugging level logging for tagging updates, to help identify the problem with periodic multi-threaded test failures on bamboo 23535: Merged V3.4 to V3.3 (complements 23517: ALF-5552) 23508: Fixed ALF-5559: Permission interceptors can fail if Lucene returns invalid NodeRefs 23564: ALF-5600: Merged V3.4 to V3.3 23424: Fixes: ALF-2989 - Incorrect sideId reference in URL for event in Site Calendar Dashlet Adds support for displaying events that start in the past but finish in the future (previously only events that start in the future were shown) 23586: MERGED V3.4 to V3.3 22864: Fix for ALF-5005: "Create and edit functions on AWE become "confused"" 23042: Fix ALF-5127: Impossible to create an article/blog (WCMQS) [Must clear panel hideEvent handler if manually hiding a YUI panel] 23561: Fixes: ALF-4569 - Removes universal override of input width box and switches the editor form panel to adjust it's width based on content rather than window size. Fixes: ALF-4570 - Adds an override for the CSS 'top' property of the form dialogue to ensure it's always below the ribbon. (Was being set automatically by the YUI widget.panel call) 23569: Fixes: ALF-5606 - Ribbon wasn't resizing correctly after the form events. 23630: Backport of installer 23631: Added 64-bit & deployment installers 23664: Fixes ALF-5691: TransferService: Multi-byte characters are not encoded correctly 23681: Fixes ALF-5699: TransferService: Snapshot file from source repo never contains complete MLText properties 23695: Fixed bug exposed after fixing ALF-5699. Parsing of MLText properties out of the transfer snapshot file was incorrect, and that was causing multi-lingual property values to be duplicated 23709: ALF-5699: Fix NPE in ManifestIntegrationTest 23734: Merged V3.4 to V3.3 23731: Fixes for ALF-3098 and ALF-3097 - Share - Security check on Personal Dashboard - only the owning user can view a user dashboard page - Share - Security issue on Customize Site Dashboard - private and moderated site dashboard pages no longer visible to non-members, customise site and dashboard pages only accessible to SiteManager 23747: ALF-5696: Merged V3.4 to V3.3 23585: Fixed ALF-5372 "JavaScript error on Groups management dialog with IE8 : document.getElementById is null" 23790: Fixed ALF-3823 "Share: RSS feed can't be read: http://cds-srv.sun.com:8700/rss/update/public/sunalert_update.xml - ok with other RSS client." 23883: Fixes ALF-5759: WQS: Attempt to copy a website section fails 23907: Merged DEV/BELARUS/V3.3-BUG-FIX-2010_09_20 to V33 - 22750: ALF-4846: Update rules are firing on inbound actions 23931: Undid rev 23907 (Reverse-merged /alfresco/BRANCHES/DEV/BELARUS/V3.3-BUG-FIX-2010_09_20:r22750) 23961: Fixed ALF-5686 "Incorrect behaviour of "All" filter in "My Tasks" dashlet" - Variables assigned in a <#macro> shall always be assigned using <#local> (using <#assign> makes them globally available which might cause naming collisions) 24132: Disable intermittent failing unit test 24148: ALF-6007: Merged HEAD to V3.3 23049: Fixed ALF-5099: Error when trying to go back in Create Web Content Wizard (only with certain XSDs) 24263: Merged from V3.3-BUG-FIX to V3.3 24264: Merged V3.3-BUG-FIX to V3.3 24262: Stress test code for ALF-5025: Support background processing of archiving 24287: Added missing import 24336: Merged V3.4 to V3.3 23205: Fix for ALF-2111 - Download URLS are different on different pages, authentication fails when URL sent 24353: Merged V3.4 to V3.3 24352: Fix SQL fallout from ALF-6078 24510: Merged V3.4 to V3.3 21960: First round of date refactoring: Document Library pages now expect XML dates (ISO8601) from Share data webscripts 21961: Share client-side I18N utility now emulates sever-side handling of doubled-up single quotes. 24526: Merged V3.4 to V3.3 24402: Fix for performance degredation related to ALF-3823. RSS feed processing in JavaScript relies on Rhino impl of regex - this is extreemly slow as Rhino regex is by far the slowest component of the library. Switched code to use the Java Regex libraries to improve performance and reduce memory usage. 24587: Merged V3.4 to V3.3 24564: Fix for ALF-3727: Custom permissions aren't visible in Explorer UI 24604: Merged V3.4 to V3.3 24602: Build fix for RM permission model loading - collateral damage for R 24564 24775: Merged BRANCHES/V3.3 to BRANCHES/V3.4: (RECORD-ONLY) - already in V3.4 24774: (RECORD-ONLY) Merged BRANCHES/V3.4 to BRANCHES/V3.3: 23492: Fixed ALF-5550: DB2: Unable to insert values into alf_string_value 24788: Add evaluation use message for OSX installer 24790: Removed svn:mergeinfo on root 24791: Fixed ALF-6560: MIME type not detected (set to application/octet-stream) when content written via FileFolderService - First access of content on a new file (FileFolderService.getWriter) guesses a mimetype - The initial mimetype guess *was* done during create, but that was expensive. - Added unit test to cover regression 24803: Merged BRANCHES/DEV/dwebster/ to BRANCHES/V3.4: 24773: DE bug fixes received from translators 10th Jan. 24776: ES files received from translators 10th Jan 24793: FR files received from translators 10th Jan 24792: IT files received from translators 10th Jan 24804: Temporarily removing Japanese language bundle 24856: Merged BRANCHES/DEV/dwebster/ to BRANCHES/V3.4: 24848: Latest Language updates from Translators 24863: ALF-6029 (MT Share - repo' view after upg) 24880: Merged V3.3 to V3.4-BUG-FIX 24463: Fixed ALF-4398 "Path to rule set is not displayed" ($html alias was missing from a merge) 24465: Merge V3.3 to V3.4 (RECORD ONLY) 24463: Fixed ALF-4398 "Path to rule set is not displayed" ($html alias was missing from a merge) 24493: Fix for Mac OS X CIFS logon problem, change UID to start at one as zero has special meaning, plus other minor fixes. JLAN-112. 24569: Fix for ALF-5333: Webdav - Online editing of files in a folder with German umlauts does not report correct characters 24611: Fix broken build due to merge #fail (r24460 / ALF-4015) 24668: ALF-4557 - Upgrade of large repository to latest 3.3 fails on excession of mysql table lock size 24707: Fix for handling of null first/last name in wiki page list 24710: ALF-5535 - Fix to correctly format json number values (not as numeric human readable strings) 24794: Fix for ALF-4984 - Outdated custom-slingshot-application-context.xml.sample file for share 24798: Fix for ALF-5806: Lucene query does not return expected result. - Alfresco FTS now supports the prefixes ~ and = for phrase queries 24814: Build fix after r24798: Fix for ALF-5806: Lucene query does not return expected result. 24823: Synchronization improvements to RemoteClient and http proxy hosts 24825: Fixed #3 of ALF-6308 "Share data issues" - Share falls back to use "html uploader" (in all browsers except IE) when "JSESSIONID" cookie is unreachable from javascript (like when "HttpOnly cookies" is activated on the server. 24835: Fixed ALF-5484: Check-in does not update association - Copy code when copying over an existing target node was NOT processing associations - Fallout from refactor and subsequent fixes related to ALF-958 (Target associations aren't copied) - Some commented-out unit tests reintroduced 24842: Fix for ALF-6308 item #4 - validate the redirect URL to ensure it is a relative url 24845: Merged DEV/DAVEW/SAP to V3.3 23874: ALF-5822: Correct Lucene throttling mechanism to prevent build up of excessive committed deltas - Also correct BatchProcessor's mechanism for single-threading batches with cross dependencies - Single-threaded batches must be sequenced in order 23876: ALF-5822: Default lucene.indexer.mergerTargetOverlaysBlockingFactor to 2 for better write performance under load 24022: ALF-5822: Refinement of fix - Don't block a thread that has already entered the prepare phase with another indexer (e.g. a cross-store commit). Otherwise it could block indefinitely and never enter the commit phase - Also added extra debug diagnostics and handle all Throwables on failure 24023: ALF-5822: Minor correction to debug log message 24421: ALF-6134: Do not export org.hibernate.jmx.StatisticsService through JMX to avoid excessive blocking under load 24422: ALF-6135: Remove lock contention from concurrent Lucene searches - Added a RW Lock and Thread local-based solution to org.apache.lucene.store.FSDirectory.FSIndexInput.readInternal() to avoid contention during multiple parallel Lucene searches. This is already recognized as a bottleneck by the Lucene developers, who offer NIOFSDirectory as an alternative, which unfortunately doesn't work on Windows. - Added RW lock to org.apache.lucene.index.TermInfosReader.ensureIndexIsRead() - Threads no longer hanging in lucene searches during load tests. Woohoo! 24423: ALF-6136: Don't call through to org.apache.log4j.NDC unless debug is enabled as it's heavily synchronized. Also avoid dynamic method invocation by using a delegate. 24426: ALF-6138 (SURF - PARTIAL): 'Warm' the java.beans.Introspector cache for key Freemarker accessible bean classes on loading in static initializers 24428: ALF-6139 (SURF - PARTIAL): First log in to Share is expensive due to 'lazy' dashboard creation and excessive synchronization - Added AVMRemoteStore.createDocuments() for creating multiple XML documents at once, all embedded within the same master XML document in the request body - Added corresponding saveDocuments() methods to Store, RemoteStore, Model, ModelObjectManager and ModelObjectPersister on the Surf side - Used this in PresetsManager - Removed excessive synchronization from StoreModelObjectPersister 24429: ALF-6140 (SURF - PARTIAL): Surf tweaks to allow concurrent execution of web scripts - Use StrongCacheStorage instead of MruCacheStorage in RepositoryTemplateProcessor to avoid use of a synchronized cache - Tweak cache sizes in FreeMarkerProcessor - Use thread local object wrapper delegates in QNameAwareObjectWrapper and PresentationTemplateProcessor to work around synchronization in DefaultObjectWrapper - Swap in the same object wrapper to WrappingTemplateModel - Use a concurrent HashMap in ModelObjectCache and ModelHelper and remove excessive synchronization - Use RW locks rather than synchronized blocks in AbstractWebScript 24431: ALF-6141: Improvements to IBatis DAO performance under load - Use lazyLoadingEnabled="false", enhancementEnabled="false" to avoid unnecessary blocking and generation of CGI proxies in IBATIS DAOs - Use useTransactionAwareDataSource="false" to prevent Spring from agressively unwrapping DBCP connections and bypassing the prepared statement cache 24432: ALF-6142: Remove dependency between RepositoryAuthenticationDAO and Lucene - Reworked RepositoryAuthenticationDAO to use a node service lookup by child association QName - This required adding a patch to 'upgrade' the qnames of existing authentication nodes, which previously all had the same QName 24433: ALF-6143: Remove net.sf.ehcache.use.classic.lru setting from EhCacheManagerFactoryBean and InternalEhCacheManagerFactoryBean to prevent serialization of accesses to shared caches by multiple executing threads 24434: ALF-6144: DirtySessionMethodInterceptor was causing contention between multiple threads calling the same DAO. - Unfortunately method.getAnnotation() is a synchronized call, and thus causes concurrent calls to the same method to contended with each other. - Added a non-blocking cache so that DAOs can be accessed in multiple threads without contending. 24435: ALF-6145: Use RW Locks in Subsystem Framework - The operations relied on by the dynamic proxies wrapping subsystems were synchronized and thus caused contention when multiple threads were calling in to the same subsystem - Replaced synchronized blocks with use of read write locks, thus allowing multiple concurrent readers 24436: ALF-6146: Regulate PermissionModel accesses with RW locks, rather than synchronized blocks and an excessive number of concurrent hashmaps. 24438: ALF-6136: Fix build classpath 24439: ALF-6142: Fixed seeding of admin user password 24444: ALF-6142: Fix unit test fallout - InviteServiceTest needs a transaction - RepositoryAuthenticationDao must listen for Person username changes and update authentication node qname accordingly - Correction to MT handling in RepositoryAuthenticationDao - Repository Authentication Component must 'normalize' the username before passing it through the DAO 24445: ALF-6145: Correction to lock handling when propagating destroy() events 24446: ALF-6142: Add new dependencies to unit test 24448: ALF-6142: Further fix ups 24461: ALF-6142: Fix unit test 24664: ALF-6408: Prevent possible deadlock during reindexing - waitForHeadOfQueue() now only called in beforeCommit() phase rather than afterCommit() to prevent deadlocking with Lucene throttler - indexes are also flushed beforehand in beforeCommit() so that indexing work can still be parallelized - also prevent potential deadlock caused by clearing of IndexInfo.thisThreadPreparing in a nested transaction 24810: ALF-6653: Use read write lock in Hibernate ReadWriteCache to avoid needless contention on L2 cache reads 24817: ALF-4725: Avoid excessive lock contention in dbcp by upgrading to 1.4 - also upgraded commons pool 24818: ALF-6658: Remove synchronization from LockService - transaction local collections used anyway 24844: ALF-6681: Don't let the PostLookup job stack up in multiple threads - Now only executes in one thread at a time and skips scheduled slots where it is already running 24864: Fix for ALF-5904: Explorer - Space model rights not duplicated when creating a space based on a template - copy service no longer uses hasPermission - added tests for permission copy scenarios with assorted rights - this fix assumed there is nothing special about templates - ie that they should always carry permissions and is the "default" copy behaviour to copy permissions if possible 24865: ALF-6145: Fix failing unit test 24878: ALF-6146: Correction to write lock around requiredPermissionsCache 24881: Increment version revision git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@26792 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
1848 lines
66 KiB
Java
1848 lines
66 KiB
Java
/*
|
|
* Copyright (C) 2005-2010 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.domain.permissions;
|
|
|
|
import java.io.Serializable;
|
|
import java.util.ArrayList;
|
|
import java.util.Collections;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
|
|
import org.alfresco.error.AlfrescoRuntimeException;
|
|
import org.alfresco.repo.cache.SimpleCache;
|
|
import org.alfresco.repo.domain.node.NodeDAO;
|
|
import org.alfresco.repo.domain.qname.QNameDAO;
|
|
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
|
import org.alfresco.repo.security.permissions.ACEType;
|
|
import org.alfresco.repo.security.permissions.ACLCopyMode;
|
|
import org.alfresco.repo.security.permissions.ACLType;
|
|
import org.alfresco.repo.security.permissions.AccessControlEntry;
|
|
import org.alfresco.repo.security.permissions.AccessControlList;
|
|
import org.alfresco.repo.security.permissions.AccessControlListProperties;
|
|
import org.alfresco.repo.security.permissions.SimpleAccessControlEntry;
|
|
import org.alfresco.repo.security.permissions.SimpleAccessControlList;
|
|
import org.alfresco.repo.security.permissions.SimpleAccessControlListProperties;
|
|
import org.alfresco.repo.security.permissions.impl.AclChange;
|
|
import org.alfresco.repo.security.permissions.impl.SimplePermissionReference;
|
|
import org.alfresco.repo.tenant.TenantService;
|
|
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
|
|
import org.alfresco.service.cmr.repository.NodeRef;
|
|
import org.alfresco.service.cmr.repository.StoreRef;
|
|
import org.alfresco.service.cmr.security.AccessStatus;
|
|
import org.alfresco.service.cmr.security.AuthorityType;
|
|
import org.alfresco.service.namespace.QName;
|
|
import org.alfresco.util.GUID;
|
|
import org.alfresco.util.Pair;
|
|
import org.alfresco.util.ParameterCheck;
|
|
import org.apache.commons.logging.Log;
|
|
import org.apache.commons.logging.LogFactory;
|
|
|
|
/**
|
|
* DAO to manage ACL persistence
|
|
*
|
|
* Note: based on earlier AclDaoComponentImpl
|
|
*
|
|
* @author Andy Hind, janv
|
|
* @since 3.4
|
|
*/
|
|
public class AclDAOImpl implements AclDAO
|
|
{
|
|
private static Log logger = LogFactory.getLog(AclDAOImpl.class);
|
|
|
|
/** Access to QName entities */
|
|
private QNameDAO qnameDAO;
|
|
|
|
/** Access to ACL entities */
|
|
private AclCrudDAO aclCrudDAO;
|
|
|
|
/** Access to Nodes entities */
|
|
private NodeDAO nodeDAO;
|
|
|
|
private TenantService tenantService;
|
|
|
|
/** a transactionally-safe cache to be injected */
|
|
private SimpleCache<Long, AccessControlList> aclCache;
|
|
|
|
private SimpleCache<Serializable, Set<String>> readersCache;
|
|
|
|
private enum WriteMode
|
|
{
|
|
/**
|
|
* Remove inherited ACEs after that set
|
|
*/
|
|
TRUNCATE_INHERITED,
|
|
/**
|
|
* Add inherited ACEs
|
|
*/
|
|
ADD_INHERITED,
|
|
/**
|
|
* The source of inherited ACEs is changing
|
|
*/
|
|
CHANGE_INHERITED,
|
|
/**
|
|
* Remove all inherited ACEs
|
|
*/
|
|
REMOVE_INHERITED,
|
|
/**
|
|
* Insert inherited ACEs
|
|
*/
|
|
INSERT_INHERITED,
|
|
/**
|
|
* Copy ACLs and update ACEs and inheritance
|
|
*/
|
|
COPY_UPDATE_AND_INHERIT,
|
|
/**
|
|
* Simple copy
|
|
*/
|
|
COPY_ONLY, CREATE_AND_INHERIT;
|
|
}
|
|
|
|
public void setQnameDAO(QNameDAO qnameDAO)
|
|
{
|
|
this.qnameDAO = qnameDAO;
|
|
}
|
|
|
|
public void setTenantService(TenantService tenantService)
|
|
{
|
|
this.tenantService = tenantService;
|
|
}
|
|
|
|
public void setAclCrudDAO(AclCrudDAO aclCrudDAO)
|
|
{
|
|
this.aclCrudDAO = aclCrudDAO;
|
|
}
|
|
|
|
public void setNodeDAO(NodeDAO nodeDAO)
|
|
{
|
|
this.nodeDAO = nodeDAO;
|
|
}
|
|
|
|
/**
|
|
* Set the ACL cache
|
|
*
|
|
* @param aclCache
|
|
*/
|
|
public void setAclCache(SimpleCache<Long, AccessControlList> aclCache)
|
|
{
|
|
this.aclCache = aclCache;
|
|
}
|
|
|
|
/**
|
|
* @param readersCache the readersCache to set
|
|
*/
|
|
public void setReadersCache(SimpleCache<Serializable, Set<String>> readersCache)
|
|
{
|
|
this.readersCache = readersCache;
|
|
}
|
|
|
|
/* (non-Javadoc)
|
|
* @see org.alfresco.repo.domain.permissions.AclDAO#createAccessControlList()
|
|
*/
|
|
public Long createAccessControlList()
|
|
{
|
|
return createAccessControlList(getDefaultProperties()).getId();
|
|
}
|
|
|
|
/* (non-Javadoc)
|
|
* @see org.alfresco.repo.domain.permissions.AclDAO#getDefaultProperties()
|
|
*/
|
|
public AccessControlListProperties getDefaultProperties()
|
|
{
|
|
SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties();
|
|
properties.setAclType(ACLType.DEFINING);
|
|
properties.setInherits(true);
|
|
properties.setVersioned(false);
|
|
return properties;
|
|
}
|
|
|
|
/* (non-Javadoc)
|
|
* @see org.alfresco.repo.domain.permissions.AclDAO#createAcl(org.alfresco.repo.security.permissions.AccessControlListProperties)
|
|
*/
|
|
public Acl createAccessControlList(AccessControlListProperties properties)
|
|
{
|
|
if (properties == null)
|
|
{
|
|
throw new IllegalArgumentException("Properties cannot be null");
|
|
}
|
|
|
|
if (properties.getAclType() == null)
|
|
{
|
|
throw new IllegalArgumentException("ACL Type must be defined");
|
|
}
|
|
switch (properties.getAclType())
|
|
{
|
|
case OLD:
|
|
if (properties.isVersioned() == Boolean.TRUE)
|
|
{
|
|
throw new IllegalArgumentException("Old acls can not be versioned");
|
|
}
|
|
break;
|
|
case SHARED:
|
|
throw new IllegalArgumentException("Can not create shared acls direct - use get inherited");
|
|
case DEFINING:
|
|
case LAYERED:
|
|
break;
|
|
case FIXED:
|
|
if (properties.getInherits() == Boolean.TRUE)
|
|
{
|
|
throw new IllegalArgumentException("Fixed ACLs can not inherit");
|
|
}
|
|
case GLOBAL:
|
|
if (properties.getInherits() == Boolean.TRUE)
|
|
{
|
|
throw new IllegalArgumentException("Fixed ACLs can not inherit");
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
return createAccessControlList(properties, null, null);
|
|
}
|
|
|
|
/* (non-Javadoc)
|
|
* @see org.alfresco.repo.domain.permissions.AclDAO#createAcl(org.alfresco.repo.security.permissions.AccessControlListProperties, java.util.List, java.lang.Long)
|
|
*/
|
|
public Acl createAccessControlList(AccessControlListProperties properties, List<AccessControlEntry> aces, Long inherited)
|
|
{
|
|
if (properties == null)
|
|
{
|
|
throw new IllegalArgumentException("Properties cannot be null");
|
|
}
|
|
|
|
AclEntity acl = new AclEntity();
|
|
if (properties.getAclId() != null)
|
|
{
|
|
acl.setAclId(properties.getAclId());
|
|
}
|
|
else
|
|
{
|
|
acl.setAclId(GUID.generate());
|
|
}
|
|
acl.setAclType(properties.getAclType());
|
|
acl.setAclVersion(Long.valueOf(1l));
|
|
|
|
switch (properties.getAclType())
|
|
{
|
|
case FIXED:
|
|
case GLOBAL:
|
|
acl.setInherits(Boolean.FALSE);
|
|
case OLD:
|
|
case SHARED:
|
|
case DEFINING:
|
|
case LAYERED:
|
|
default:
|
|
if (properties.getInherits() != null)
|
|
{
|
|
acl.setInherits(properties.getInherits());
|
|
}
|
|
else
|
|
{
|
|
acl.setInherits(Boolean.TRUE);
|
|
}
|
|
break;
|
|
}
|
|
acl.setLatest(Boolean.TRUE);
|
|
|
|
switch (properties.getAclType())
|
|
{
|
|
case OLD:
|
|
acl.setVersioned(Boolean.FALSE);
|
|
break;
|
|
case LAYERED:
|
|
if (properties.isVersioned() != null)
|
|
{
|
|
acl.setVersioned(properties.isVersioned());
|
|
}
|
|
else
|
|
{
|
|
acl.setVersioned(Boolean.TRUE);
|
|
}
|
|
break;
|
|
case FIXED:
|
|
case GLOBAL:
|
|
case SHARED:
|
|
case DEFINING:
|
|
default:
|
|
if (properties.isVersioned() != null)
|
|
{
|
|
acl.setVersioned(properties.isVersioned());
|
|
}
|
|
else
|
|
{
|
|
acl.setVersioned(Boolean.FALSE);
|
|
}
|
|
break;
|
|
}
|
|
|
|
acl.setAclChangeSetId(getCurrentChangeSetId());
|
|
acl.setRequiresVersion(false);
|
|
|
|
Acl createdAcl = (AclEntity)aclCrudDAO.createAcl(acl);
|
|
long created = createdAcl.getId();
|
|
|
|
if ((aces != null) && aces.size() > 0)
|
|
{
|
|
List<AclChange> changes = new ArrayList<AclChange>();
|
|
|
|
List<Ace> toAdd = new ArrayList<Ace>(aces.size());
|
|
List<AccessControlEntry> excluded = new ArrayList<AccessControlEntry>(aces.size());
|
|
for (AccessControlEntry ace : aces)
|
|
{
|
|
if ((ace.getPosition() != null) && (ace.getPosition() != 0))
|
|
{
|
|
throw new IllegalArgumentException("Invalid position");
|
|
}
|
|
|
|
// Find authority
|
|
Authority authority = aclCrudDAO.getOrCreateAuthority(ace.getAuthority());
|
|
Permission permission = aclCrudDAO.getOrCreatePermission(ace.getPermission());
|
|
|
|
// Find context
|
|
if (ace.getContext() != null)
|
|
{
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
|
|
// Find ACE
|
|
Ace entry = aclCrudDAO.getOrCreateAce(permission, authority, ace.getAceType(), ace.getAccessStatus());
|
|
|
|
// Wire up
|
|
// COW and remove any existing matches
|
|
|
|
SimpleAccessControlEntry exclude = new SimpleAccessControlEntry();
|
|
// match any access status
|
|
exclude.setAceType(ace.getAceType());
|
|
exclude.setAuthority(ace.getAuthority());
|
|
exclude.setPermission(ace.getPermission());
|
|
exclude.setPosition(0);
|
|
|
|
toAdd.add(entry);
|
|
excluded.add(exclude);
|
|
// Will remove from the cache
|
|
}
|
|
Long toInherit = null;
|
|
if (inherited != null)
|
|
{
|
|
toInherit = getInheritedAccessControlList(inherited);
|
|
}
|
|
getWritable(created, toInherit, excluded, toAdd, toInherit, false, changes, WriteMode.CREATE_AND_INHERIT);
|
|
}
|
|
|
|
return createdAcl;
|
|
}
|
|
|
|
private void getWritable(final Long id, final Long parent, List<? extends AccessControlEntry> exclude, List<Ace> toAdd, Long inheritsFrom, boolean cascade,
|
|
List<AclChange> changes, WriteMode mode)
|
|
{
|
|
List<Ace> inherited = null;
|
|
List<Integer> positions = null;
|
|
|
|
if ((mode == WriteMode.ADD_INHERITED) || (mode == WriteMode.INSERT_INHERITED) || (mode == WriteMode.CHANGE_INHERITED))
|
|
{
|
|
inherited = new ArrayList<Ace>();
|
|
positions = new ArrayList<Integer>();
|
|
|
|
// get aces for acl (via acl member)
|
|
List<AclMember> members = aclCrudDAO.getAclMembersByAcl(parent);
|
|
|
|
for (AclMember member : members)
|
|
{
|
|
Ace aceEntity = aclCrudDAO.getAce(member.getAceId());
|
|
|
|
if ((mode == WriteMode.INSERT_INHERITED) && (member.getPos() == 0))
|
|
{
|
|
inherited.add(aceEntity);
|
|
positions.add(member.getPos());
|
|
}
|
|
else
|
|
{
|
|
inherited.add(aceEntity);
|
|
positions.add(member.getPos());
|
|
}
|
|
}
|
|
}
|
|
|
|
getWritable(id, parent, exclude, toAdd, inheritsFrom, inherited, positions, cascade, 0, changes, mode, false);
|
|
}
|
|
|
|
/**
|
|
* Make a whole tree of ACLs copy on write if required Includes adding and removing ACEs which can be optimised
|
|
* slightly for copy on write (no need to add and then remove)
|
|
*
|
|
* @param id
|
|
* @param parent
|
|
* @param exclude
|
|
* @param toAdd
|
|
* @param inheritsFrom
|
|
* @param cascade
|
|
* @param depth
|
|
* @param changes
|
|
*/
|
|
private void getWritable(final Long id, final Long parent, List<? extends AccessControlEntry> exclude, List<Ace> toAdd, Long inheritsFrom,
|
|
List<Ace> inherited, List<Integer> positions, boolean cascade, int depth, List<AclChange> changes, WriteMode mode, boolean requiresVersion)
|
|
{
|
|
AclChange current = getWritable(id, parent, exclude, toAdd, inheritsFrom, inherited, positions, depth, mode, requiresVersion);
|
|
changes.add(current);
|
|
|
|
boolean cascadeVersion = requiresVersion;
|
|
if (!cascadeVersion)
|
|
{
|
|
cascadeVersion = !current.getBefore().equals(current.getAfter());
|
|
}
|
|
|
|
if (cascade)
|
|
{
|
|
List<Long> inheritors = aclCrudDAO.getAclsThatInheritFromAcl(id);
|
|
for (Long nextId : inheritors)
|
|
{
|
|
// Check for those that inherit themselves to other nodes ...
|
|
if (nextId != id)
|
|
{
|
|
getWritable(nextId, current.getAfter(), exclude, toAdd, current.getAfter(), inherited, positions, cascade, depth + 1, changes, mode, cascadeVersion);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* COW for an individual ACL
|
|
*
|
|
* @param id
|
|
* @param parent
|
|
* @param exclude
|
|
* @param toAdd
|
|
* @param inheritsFrom
|
|
* @param depth
|
|
* @return - an AclChange
|
|
*/
|
|
private AclChange getWritable(final Long id, final Long parent, List<? extends AccessControlEntry> exclude, List<Ace> acesToAdd, Long inheritsFrom,
|
|
List<Ace> inherited, List<Integer> positions, int depth, WriteMode mode, boolean requiresVersion)
|
|
{
|
|
AclUpdateEntity acl = aclCrudDAO.getAclForUpdate(id);
|
|
if (!acl.isLatest())
|
|
{
|
|
aclCache.remove(id);
|
|
readersCache.remove(id);
|
|
return new AclChangeImpl(id, id, acl.getAclType(), acl.getAclType());
|
|
}
|
|
|
|
List<Long> toAdd = new ArrayList<Long>(0);
|
|
if (acesToAdd != null)
|
|
{
|
|
for (Ace ace : acesToAdd)
|
|
{
|
|
toAdd.add(ace.getId());
|
|
}
|
|
}
|
|
|
|
if (!acl.isVersioned())
|
|
{
|
|
switch (mode)
|
|
{
|
|
case COPY_UPDATE_AND_INHERIT:
|
|
removeAcesFromAcl(id, exclude, depth);
|
|
aclCrudDAO.addAclMembersToAcl(acl.getId(), toAdd, depth);
|
|
break;
|
|
case CHANGE_INHERITED:
|
|
replaceInherited(id, acl, inherited, positions, depth);
|
|
break;
|
|
case ADD_INHERITED:
|
|
addInherited(acl, inherited, positions, depth);
|
|
break;
|
|
case TRUNCATE_INHERITED:
|
|
truncateInherited(id, depth);
|
|
break;
|
|
case INSERT_INHERITED:
|
|
insertInherited(id, acl, inherited, positions, depth);
|
|
break;
|
|
case REMOVE_INHERITED:
|
|
removeInherited(id, depth);
|
|
break;
|
|
case CREATE_AND_INHERIT:
|
|
aclCrudDAO.addAclMembersToAcl(acl.getId(), toAdd, depth);
|
|
addInherited(acl, inherited, positions, depth);
|
|
case COPY_ONLY:
|
|
default:
|
|
break;
|
|
}
|
|
if (inheritsFrom != null)
|
|
{
|
|
acl.setInheritsFrom(inheritsFrom);
|
|
aclCrudDAO.updateAcl(acl);
|
|
}
|
|
aclCache.remove(id);
|
|
readersCache.remove(id);
|
|
return new AclChangeImpl(id, id, acl.getAclType(), acl.getAclType());
|
|
}
|
|
else if ((acl.getAclChangeSetId() == getCurrentChangeSetId()) && (!requiresVersion) && (!acl.getRequiresVersion()))
|
|
{
|
|
switch (mode)
|
|
{
|
|
case COPY_UPDATE_AND_INHERIT:
|
|
removeAcesFromAcl(id, exclude, depth);
|
|
aclCrudDAO.addAclMembersToAcl(acl.getId(), toAdd, depth);
|
|
break;
|
|
case CHANGE_INHERITED:
|
|
replaceInherited(id, acl, inherited, positions, depth);
|
|
break;
|
|
case ADD_INHERITED:
|
|
addInherited(acl, inherited, positions, depth);
|
|
break;
|
|
case TRUNCATE_INHERITED:
|
|
truncateInherited(id, depth);
|
|
break;
|
|
case INSERT_INHERITED:
|
|
insertInherited(id, acl, inherited, positions, depth);
|
|
break;
|
|
case REMOVE_INHERITED:
|
|
removeInherited(id, depth);
|
|
break;
|
|
case CREATE_AND_INHERIT:
|
|
aclCrudDAO.addAclMembersToAcl(acl.getId(), toAdd, depth);
|
|
addInherited(acl, inherited, positions, depth);
|
|
case COPY_ONLY:
|
|
default:
|
|
break;
|
|
}
|
|
if (inheritsFrom != null)
|
|
{
|
|
acl.setInheritsFrom(inheritsFrom);
|
|
aclCrudDAO.updateAcl(acl);
|
|
}
|
|
aclCache.remove(id);
|
|
readersCache.remove(id);
|
|
return new AclChangeImpl(id, id, acl.getAclType(), acl.getAclType());
|
|
}
|
|
else
|
|
{
|
|
AclEntity newAcl = new AclEntity();
|
|
newAcl.setAclChangeSetId(getCurrentChangeSetId());
|
|
newAcl.setAclId(acl.getAclId());
|
|
newAcl.setAclType(acl.getAclType());
|
|
newAcl.setAclVersion(acl.getAclVersion() + 1);
|
|
newAcl.setInheritedAcl(-1l);
|
|
newAcl.setInherits(acl.getInherits());
|
|
newAcl.setInheritsFrom((inheritsFrom != null) ? inheritsFrom : acl.getInheritsFrom());
|
|
newAcl.setLatest(Boolean.TRUE);
|
|
newAcl.setVersioned(Boolean.TRUE);
|
|
newAcl.setRequiresVersion(Boolean.FALSE);
|
|
|
|
AclEntity createdAcl = (AclEntity)aclCrudDAO.createAcl(newAcl);
|
|
long created = createdAcl.getId();
|
|
|
|
// Create new membership entries - excluding those in the given pattern
|
|
|
|
// AcePatternMatcher excluder = new AcePatternMatcher(exclude);
|
|
|
|
// get aces for acl (via acl member)
|
|
List<AclMember> members = aclCrudDAO.getAclMembersByAcl(id);
|
|
|
|
if (members.size() > 0)
|
|
{
|
|
List<Pair<Long,Integer>> aceIdsWithDepths = new ArrayList<Pair<Long,Integer>>(members.size());
|
|
|
|
for (AclMember member : members)
|
|
{
|
|
aceIdsWithDepths.add(new Pair<Long, Integer>(member.getAceId(), member.getPos()));
|
|
}
|
|
|
|
// copy acl members to new acl
|
|
aclCrudDAO.addAclMembersToAcl(newAcl.getId(), aceIdsWithDepths);
|
|
}
|
|
|
|
// add new
|
|
|
|
switch (mode)
|
|
{
|
|
case COPY_UPDATE_AND_INHERIT:
|
|
// Done above
|
|
removeAcesFromAcl(newAcl.getId(), exclude, depth);
|
|
aclCrudDAO.addAclMembersToAcl(newAcl.getId(), toAdd, depth);
|
|
break;
|
|
case CHANGE_INHERITED:
|
|
replaceInherited(newAcl.getId(), newAcl, inherited, positions, depth);
|
|
break;
|
|
case ADD_INHERITED:
|
|
addInherited(newAcl, inherited, positions, depth);
|
|
break;
|
|
case TRUNCATE_INHERITED:
|
|
truncateInherited(newAcl.getId(), depth);
|
|
break;
|
|
case INSERT_INHERITED:
|
|
insertInherited(newAcl.getId(), newAcl, inherited, positions, depth);
|
|
break;
|
|
case REMOVE_INHERITED:
|
|
removeInherited(newAcl.getId(), depth);
|
|
break;
|
|
case CREATE_AND_INHERIT:
|
|
aclCrudDAO.addAclMembersToAcl(acl.getId(), toAdd, depth);
|
|
addInherited(acl, inherited, positions, depth);
|
|
case COPY_ONLY:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// Fix up inherited ACL if required
|
|
if (newAcl.getAclType() == ACLType.SHARED)
|
|
{
|
|
if (parent != null)
|
|
{
|
|
Long writableParentAcl = getWritable(parent, null, null, null, null, null, null, 0, WriteMode.COPY_ONLY, false).getAfter();
|
|
AclUpdateEntity parentAcl = aclCrudDAO.getAclForUpdate(writableParentAcl);
|
|
parentAcl.setInheritedAcl(created);
|
|
aclCrudDAO.updateAcl(parentAcl);
|
|
}
|
|
}
|
|
|
|
// fix up old version
|
|
acl.setLatest(Boolean.FALSE);
|
|
acl.setRequiresVersion(Boolean.FALSE);
|
|
aclCrudDAO.updateAcl(acl);
|
|
aclCache.remove(id);
|
|
readersCache.remove(id);
|
|
return new AclChangeImpl(id, created, acl.getAclType(), newAcl.getAclType());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Helper to remove ACEs from an ACL
|
|
*
|
|
* @param id
|
|
* @param exclude
|
|
* @param depth
|
|
*/
|
|
private void removeAcesFromAcl(final Long id, final List<? extends AccessControlEntry> exclude, final int depth)
|
|
{
|
|
if (exclude == null)
|
|
{
|
|
// cascade delete all acl members - no exclusion
|
|
aclCrudDAO.deleteAclMembersByAcl(id);
|
|
}
|
|
else
|
|
{
|
|
AcePatternMatcher excluder = new AcePatternMatcher(exclude);
|
|
|
|
List<Map<String, Object>> results = aclCrudDAO.getAcesAndAuthoritiesByAcl(id);
|
|
List<Long> memberIds = new ArrayList<Long>(results.size());
|
|
|
|
for (Map<String, Object> result : results)
|
|
{
|
|
Long result_aclmemId = (Long) result.get("aclmemId");
|
|
|
|
if ((exclude != null) && excluder.matches(aclCrudDAO, result, depth))
|
|
{
|
|
memberIds.add(result_aclmemId);
|
|
}
|
|
}
|
|
|
|
// delete list of acl members
|
|
aclCrudDAO.deleteAclMembers(memberIds);
|
|
}
|
|
}
|
|
|
|
private void replaceInherited(Long id, Acl acl, List<Ace> inherited, List<Integer> positions, int depth)
|
|
{
|
|
truncateInherited(id, depth);
|
|
addInherited(acl, inherited, positions, depth);
|
|
}
|
|
|
|
private void truncateInherited(final Long id, int depth)
|
|
{
|
|
List<AclMember> members = aclCrudDAO.getAclMembersByAcl(id);
|
|
|
|
List<Long> membersToDelete = new ArrayList<Long>(members.size());
|
|
for (AclMember member : members)
|
|
{
|
|
if (member.getPos() > depth)
|
|
{
|
|
membersToDelete.add(member.getId());
|
|
}
|
|
}
|
|
|
|
if (membersToDelete.size() > 0)
|
|
{
|
|
// delete list of acl members
|
|
aclCrudDAO.deleteAclMembers(membersToDelete);
|
|
}
|
|
}
|
|
|
|
private void removeInherited(final Long id, int depth)
|
|
{
|
|
List<AclMemberEntity> members = aclCrudDAO.getAclMembersByAclForUpdate(id);
|
|
|
|
List<Long> membersToDelete = new ArrayList<Long>(members.size());
|
|
for (AclMemberEntity member : members)
|
|
{
|
|
if (member.getPos() == depth + 1)
|
|
{
|
|
membersToDelete.add(member.getId());
|
|
}
|
|
else if (member.getPos() > (depth + 1))
|
|
{
|
|
member.setPos(member.getPos() - 1);
|
|
aclCrudDAO.updateAclMember(member);
|
|
}
|
|
}
|
|
|
|
if (membersToDelete.size() > 0)
|
|
{
|
|
// delete list of acl members
|
|
aclCrudDAO.deleteAclMembers(membersToDelete);
|
|
}
|
|
}
|
|
|
|
private void addInherited(Acl acl, List<Ace> inherited, List<Integer> positions, int depth)
|
|
{
|
|
if ((inherited != null) && (inherited.size() > 0))
|
|
{
|
|
List<Pair<Long,Integer>> aceIdsWithDepths = new ArrayList<Pair<Long,Integer>>(inherited.size());
|
|
for (int i = 0; i < inherited.size(); i++)
|
|
{
|
|
Ace add = inherited.get(i);
|
|
Integer position = positions.get(i);
|
|
aceIdsWithDepths.add(new Pair<Long, Integer>(add.getId(), position.intValue() + depth + 1));
|
|
}
|
|
aclCrudDAO.addAclMembersToAcl(acl.getId(), aceIdsWithDepths);
|
|
}
|
|
}
|
|
|
|
private void insertInherited(final Long id, AclEntity acl, List<Ace> inherited, List<Integer> positions, int depth)
|
|
{
|
|
// get aces for acl (via acl member)
|
|
List<AclMemberEntity> members = aclCrudDAO.getAclMembersByAclForUpdate(id);
|
|
|
|
for (AclMemberEntity member : members)
|
|
{
|
|
if (member.getPos() > depth)
|
|
{
|
|
member.setPos(member.getPos() + 1);
|
|
aclCrudDAO.updateAclMember(member);
|
|
}
|
|
}
|
|
|
|
addInherited(acl, inherited, positions, depth);
|
|
}
|
|
|
|
/* (non-Javadoc)
|
|
* @see org.alfresco.repo.domain.permissions.AclDAO#deleteAccessControlEntries(java.lang.String)
|
|
*/
|
|
public List<AclChange> deleteAccessControlEntries(final String authority)
|
|
{
|
|
List<AclChange> acls = new ArrayList<AclChange>();
|
|
|
|
// get authority
|
|
Authority authEntity = aclCrudDAO.getAuthority(authority);
|
|
if (authEntity == null)
|
|
{
|
|
return acls;
|
|
}
|
|
|
|
List<Long> aces = new ArrayList<Long>();
|
|
|
|
List<AclMember> members = aclCrudDAO.getAclMembersByAuthority(authority);
|
|
|
|
boolean leaveAuthority = false;
|
|
if (members.size() > 0)
|
|
{
|
|
List<Long> membersToDelete = new ArrayList<Long>(members.size());
|
|
|
|
// fix up members and extract acls and aces
|
|
for (AclMember member : members)
|
|
{
|
|
// Delete acl entry
|
|
Long aclMemberId = member.getId();
|
|
Long aclId = member.getAclId();
|
|
Long aceId = member.getAceId();
|
|
|
|
boolean hasAnotherTenantNodes = false;
|
|
if (AuthenticationUtil.isMtEnabled())
|
|
{
|
|
// ALF-3563
|
|
|
|
// Retrieve dependent nodes
|
|
List<Long> nodeIds = aclCrudDAO.getADMNodesByAcl(aclId, -1);
|
|
nodeIds.addAll(aclCrudDAO.getAVMNodesByAcl(aclId, -1));
|
|
|
|
if (nodeIds.size() > 0)
|
|
{
|
|
for (Long nodeId : nodeIds)
|
|
{
|
|
Pair<Long, NodeRef> nodePair = nodeDAO.getNodePair(nodeId);
|
|
if (nodePair == null)
|
|
{
|
|
logger.warn("Node does not exist: " + nodeId);
|
|
}
|
|
NodeRef nodeRef = nodePair.getSecond();
|
|
|
|
try
|
|
{
|
|
// Throws AlfrescoRuntimeException in case of domain mismatch
|
|
tenantService.checkDomain(nodeRef.getStoreRef().getIdentifier());
|
|
}
|
|
catch (AlfrescoRuntimeException e)
|
|
{
|
|
hasAnotherTenantNodes = true;
|
|
leaveAuthority = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!hasAnotherTenantNodes)
|
|
{
|
|
aclCache.remove(aclId);
|
|
readersCache.remove(aclId);
|
|
|
|
Acl list = aclCrudDAO.getAcl(aclId);
|
|
acls.add(new AclChangeImpl(aclId, aclId, list.getAclType(), list.getAclType()));
|
|
membersToDelete.add(aclMemberId);
|
|
aces.add((Long)aceId);
|
|
}
|
|
}
|
|
|
|
// delete list of acl members
|
|
aclCrudDAO.deleteAclMembers(membersToDelete);
|
|
}
|
|
|
|
if (!leaveAuthority)
|
|
{
|
|
// remove ACEs
|
|
aclCrudDAO.deleteAces(aces);
|
|
|
|
// Tidy up any unreferenced ACEs
|
|
|
|
// get aces by authority
|
|
List<Ace> unreferenced = aclCrudDAO.getAcesByAuthority(authEntity.getId());
|
|
|
|
if (unreferenced.size() > 0)
|
|
{
|
|
List<Long> unrefencedAcesToDelete = new ArrayList<Long>(unreferenced.size());
|
|
for (Ace ace : unreferenced)
|
|
{
|
|
unrefencedAcesToDelete.add(ace.getId());
|
|
}
|
|
aclCrudDAO.deleteAces(unrefencedAcesToDelete);
|
|
}
|
|
|
|
// remove authority
|
|
if (authEntity != null)
|
|
{
|
|
aclCrudDAO.deleteAuthority(authEntity.getId());
|
|
}
|
|
}
|
|
|
|
return acls;
|
|
}
|
|
|
|
/* (non-Javadoc)
|
|
* @see org.alfresco.repo.domain.permissions.AclDAO#deleteAclForNode(long, boolean)
|
|
*/
|
|
public void deleteAclForNode(long aclId, boolean isAVMNode)
|
|
{
|
|
Acl dbAcl = getAcl(aclId);
|
|
if (dbAcl.getAclType() == ACLType.DEFINING)
|
|
{
|
|
// delete acl members & acl
|
|
aclCrudDAO.deleteAclMembersByAcl(aclId);
|
|
aclCrudDAO.deleteAcl(aclId);
|
|
|
|
aclCache.remove(aclId);
|
|
readersCache.remove(aclId);
|
|
}
|
|
if (dbAcl.getAclType() == ACLType.SHARED)
|
|
{
|
|
// check unused
|
|
Long defining = dbAcl.getInheritsFrom();
|
|
if (aclCrudDAO.getAcl(defining) == null)
|
|
{
|
|
if (! isAVMNode)
|
|
{
|
|
// ADM
|
|
if (getADMNodesByAcl(aclId, 1).size() == 0)
|
|
{
|
|
// delete acl members & acl
|
|
aclCrudDAO.deleteAclMembersByAcl(aclId);
|
|
aclCrudDAO.deleteAcl(aclId);
|
|
|
|
aclCache.remove(aclId);
|
|
readersCache.remove(aclId);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// TODO: AVM
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* (non-Javadoc)
|
|
* @see org.alfresco.repo.domain.permissions.AclDAO#deleteAccessControlList(java.lang.Long)
|
|
*/
|
|
public List<AclChange> deleteAccessControlList(final Long id)
|
|
{
|
|
if (logger.isDebugEnabled())
|
|
{
|
|
// debug only
|
|
int maxForDebug = 11;
|
|
List<Long> nodeIds = getADMNodesByAcl(id, maxForDebug);
|
|
|
|
for (Long nodeId : nodeIds)
|
|
{
|
|
logger.debug("deleteAccessControlList: Found nodeId=" + nodeId + ", aclId=" + id);
|
|
}
|
|
}
|
|
|
|
List<AclChange> acls = new ArrayList<AclChange>();
|
|
|
|
final AclUpdateEntity acl = aclCrudDAO.getAclForUpdate(id);
|
|
if (!acl.isLatest())
|
|
{
|
|
throw new UnsupportedOperationException("Old ACL versions can not be updated");
|
|
}
|
|
if (acl.getAclType() == ACLType.SHARED)
|
|
{
|
|
throw new UnsupportedOperationException("Delete is not supported for shared acls - they are deleted with the defining acl");
|
|
}
|
|
|
|
if ((acl.getAclType() == ACLType.DEFINING) || (acl.getAclType() == ACLType.LAYERED))
|
|
{
|
|
if ((acl.getInheritedAcl() != null) && (acl.getInheritedAcl() != -1))
|
|
{
|
|
final Acl inherited = aclCrudDAO.getAcl(acl.getInheritedAcl());
|
|
|
|
// Will remove from the cache
|
|
getWritable(inherited.getId(), acl.getInheritsFrom(), null, null, null, true, acls, WriteMode.REMOVE_INHERITED);
|
|
Acl unusedInherited = null;
|
|
for (AclChange change : acls)
|
|
{
|
|
if (change.getBefore() == inherited.getId())
|
|
{
|
|
unusedInherited = aclCrudDAO.getAcl(change.getAfter());
|
|
}
|
|
}
|
|
|
|
final Long newId = unusedInherited.getId();
|
|
List<Long> inheritors = aclCrudDAO.getAclsThatInheritFromAcl(newId);
|
|
for (Long nextId : inheritors)
|
|
{
|
|
// Will remove from the cache
|
|
getWritable(nextId, acl.getInheritsFrom(), null, null, acl.getInheritsFrom(), true, acls, WriteMode.REMOVE_INHERITED);
|
|
}
|
|
|
|
// delete acl members
|
|
aclCrudDAO.deleteAclMembersByAcl(newId);
|
|
|
|
// delete 'unusedInherited' acl
|
|
aclCrudDAO.deleteAcl(unusedInherited.getId());
|
|
|
|
if (inherited.isVersioned())
|
|
{
|
|
AclUpdateEntity inheritedForUpdate = aclCrudDAO.getAclForUpdate(inherited.getId());
|
|
if (inheritedForUpdate != null)
|
|
{
|
|
inheritedForUpdate.setLatest(Boolean.FALSE);
|
|
aclCrudDAO.updateAcl(inheritedForUpdate);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// delete 'inherited' acl
|
|
aclCrudDAO.deleteAcl(inherited.getId());
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
List<Long> inheritors = aclCrudDAO.getAclsThatInheritFromAcl(id);
|
|
for (Long nextId : inheritors)
|
|
{
|
|
// Will remove from the cache
|
|
getWritable(nextId, acl.getInheritsFrom(), null, null, null, true, acls, WriteMode.REMOVE_INHERITED);
|
|
}
|
|
}
|
|
|
|
// delete
|
|
if (acl.isVersioned())
|
|
{
|
|
acl.setLatest(Boolean.FALSE);
|
|
aclCrudDAO.updateAcl(acl);
|
|
}
|
|
else
|
|
{
|
|
// delete acl members & acl
|
|
aclCrudDAO.deleteAclMembersByAcl(id);
|
|
aclCrudDAO.deleteAcl(acl.getId());
|
|
}
|
|
|
|
// remove the deleted acl from the cache
|
|
aclCache.remove(id);
|
|
readersCache.remove(id);
|
|
acls.add(new AclChangeImpl(id, null, acl.getAclType(), null));
|
|
return acls;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
public List<AclChange> deleteLocalAccessControlEntries(Long id)
|
|
{
|
|
List<AclChange> changes = new ArrayList<AclChange>();
|
|
SimpleAccessControlEntry pattern = new SimpleAccessControlEntry();
|
|
pattern.setPosition(Integer.valueOf(0));
|
|
// Will remove from the cache
|
|
getWritable(id, null, Collections.singletonList(pattern), null, null, true, changes, WriteMode.COPY_UPDATE_AND_INHERIT);
|
|
return changes;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
public List<AclChange> deleteInheritedAccessControlEntries(Long id)
|
|
{
|
|
List<AclChange> changes = new ArrayList<AclChange>();
|
|
SimpleAccessControlEntry pattern = new SimpleAccessControlEntry();
|
|
pattern.setPosition(Integer.valueOf(-1));
|
|
// Will remove from the cache
|
|
getWritable(id, null, Collections.singletonList(pattern), null, null, true, changes, WriteMode.COPY_UPDATE_AND_INHERIT);
|
|
return changes;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
public List<AclChange> deleteAccessControlEntries(Long id, AccessControlEntry pattern)
|
|
{
|
|
List<AclChange> changes = new ArrayList<AclChange>();
|
|
// Will remove from the cache
|
|
getWritable(id, null, Collections.singletonList(pattern), null, null, true, changes, WriteMode.COPY_UPDATE_AND_INHERIT);
|
|
return changes;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
public Acl getAcl(Long id)
|
|
{
|
|
return aclCrudDAO.getAcl(id);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
public AccessControlListProperties getAccessControlListProperties(Long id)
|
|
{
|
|
ParameterCheck.mandatory("id", id); // Prevent unboxing failures
|
|
return aclCrudDAO.getAcl(id);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
public AccessControlList getAccessControlList(Long id)
|
|
{
|
|
AccessControlList acl = aclCache.get(id);
|
|
if (acl == null)
|
|
{
|
|
acl = getAccessControlListImpl(id);
|
|
aclCache.put(id, acl);
|
|
}
|
|
else
|
|
{
|
|
// System.out.println("Used cache for "+id);
|
|
}
|
|
return acl;
|
|
}
|
|
|
|
/**
|
|
* @return the access control list
|
|
*/
|
|
private AccessControlList getAccessControlListImpl(final Long id)
|
|
{
|
|
SimpleAccessControlList acl = new SimpleAccessControlList();
|
|
AccessControlListProperties properties = getAccessControlListProperties(id);
|
|
if (properties == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
acl.setProperties(properties);
|
|
|
|
List<Map<String, Object>> results = aclCrudDAO.getAcesAndAuthoritiesByAcl(id);
|
|
|
|
List<AccessControlEntry> entries = new ArrayList<AccessControlEntry>(results.size());
|
|
for (Map<String, Object> result : results)
|
|
// for (AclMemberEntity member : members)
|
|
{
|
|
Boolean aceIsAllowed = (Boolean) result.get("allowed");
|
|
Integer aceType = (Integer) result.get("applies");
|
|
String authority = (String) result.get("authority");
|
|
Long permissionId = (Long) result.get("permissionId");
|
|
Integer position = (Integer) result.get("pos");
|
|
//Long result_aclmemId = (Long) result.get("aclmemId"); // not used here
|
|
|
|
SimpleAccessControlEntry sacEntry = new SimpleAccessControlEntry();
|
|
sacEntry.setAccessStatus(aceIsAllowed ? AccessStatus.ALLOWED : AccessStatus.DENIED);
|
|
sacEntry.setAceType(ACEType.getACETypeFromId(aceType));
|
|
sacEntry.setAuthority(authority);
|
|
// if (entry.getContext() != null)
|
|
// {
|
|
// SimpleAccessControlEntryContext context = new SimpleAccessControlEntryContext();
|
|
// context.setClassContext(entry.getContext().getClassContext());
|
|
// context.setKVPContext(entry.getContext().getKvpContext());
|
|
// context.setPropertyContext(entry.getContext().getPropertyContext());
|
|
// sacEntry.setContext(context);
|
|
// }
|
|
Permission perm = aclCrudDAO.getPermission(permissionId);
|
|
QName permTypeQName = qnameDAO.getQName(perm.getTypeQNameId()).getSecond(); // Has an ID so must exist
|
|
SimplePermissionReference permissionRefernce = SimplePermissionReference.getPermissionReference(permTypeQName, perm.getName());
|
|
sacEntry.setPermission(permissionRefernce);
|
|
sacEntry.setPosition(position);
|
|
entries.add(sacEntry);
|
|
}
|
|
|
|
Collections.sort(entries);
|
|
acl.setEntries(entries);
|
|
|
|
return acl;
|
|
}
|
|
|
|
/* (non-Javadoc)
|
|
* @see org.alfresco.repo.domain.permissions.AclDAO#getInheritedAccessControlList(java.lang.Long)
|
|
*/
|
|
public Long getInheritedAccessControlList(Long id)
|
|
{
|
|
AclUpdateEntity acl = aclCrudDAO.getAclForUpdate(id);
|
|
if (acl.getAclType() == ACLType.OLD)
|
|
{
|
|
return null;
|
|
}
|
|
if ((acl.getInheritedAcl() != null) && (acl.getInheritedAcl() != -1))
|
|
{
|
|
return acl.getInheritedAcl();
|
|
}
|
|
|
|
Long inheritedAclId = null;
|
|
|
|
if ((acl.getAclType() == ACLType.DEFINING) || (acl.getAclType() == ACLType.LAYERED))
|
|
{
|
|
List<AclChange> changes = new ArrayList<AclChange>();
|
|
// created shared acl
|
|
SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties();
|
|
properties.setAclType(ACLType.SHARED);
|
|
properties.setInherits(Boolean.TRUE);
|
|
properties.setVersioned(acl.isVersioned());
|
|
Long sharedId = createAccessControlList(properties, null, null).getId();
|
|
getWritable(sharedId, id, null, null, id, true, changes, WriteMode.ADD_INHERITED);
|
|
acl.setInheritedAcl(sharedId);
|
|
inheritedAclId = sharedId;
|
|
}
|
|
else
|
|
{
|
|
acl.setInheritedAcl(acl.getId());
|
|
inheritedAclId = acl.getId();
|
|
}
|
|
|
|
aclCrudDAO.updateAcl(acl);
|
|
return inheritedAclId;
|
|
}
|
|
|
|
/* (non-Javadoc)
|
|
* @see org.alfresco.repo.domain.permissions.AclDAO#mergeInheritedAccessControlList(java.lang.Long, java.lang.Long)
|
|
*/
|
|
public List<AclChange> mergeInheritedAccessControlList(Long inherited, Long target)
|
|
{
|
|
// TODO: For now we do a replace - we could do an insert if both inherit from the same acl
|
|
|
|
List<AclChange> changes = new ArrayList<AclChange>();
|
|
|
|
Acl targetAcl = aclCrudDAO.getAcl(target);
|
|
|
|
Acl inheritedAcl = null;
|
|
if (inherited != null)
|
|
{
|
|
inheritedAcl = aclCrudDAO.getAcl(inherited);
|
|
}
|
|
else
|
|
{
|
|
// Assume we are just resetting it to inherit as before
|
|
if (targetAcl.getInheritsFrom() != null)
|
|
{
|
|
inheritedAcl = aclCrudDAO.getAcl(targetAcl.getInheritsFrom());
|
|
if (inheritedAcl == null)
|
|
{
|
|
// TODO: Try previous versions
|
|
throw new IllegalStateException("No old inheritance definition to use");
|
|
}
|
|
else
|
|
{
|
|
// find the latest version of the acl
|
|
if (!inheritedAcl.isLatest())
|
|
{
|
|
final String searchAclId = inheritedAcl.getAclId();
|
|
|
|
Long actualInheritor = (Long)aclCrudDAO.getLatestAclByGuid(searchAclId);
|
|
|
|
inheritedAcl = aclCrudDAO.getAcl(actualInheritor);
|
|
if (inheritedAcl == null)
|
|
{
|
|
// TODO: Try previous versions
|
|
throw new IllegalStateException("No ACL found");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// There is no inheritance to set
|
|
return changes;
|
|
}
|
|
}
|
|
|
|
// recursion test
|
|
// if inherited already inherits from the target
|
|
|
|
Acl test = inheritedAcl;
|
|
while (test != null)
|
|
{
|
|
if (test.getId() == target)
|
|
{
|
|
throw new IllegalStateException("Cyclical ACL detected");
|
|
}
|
|
Long parent = test.getInheritsFrom();
|
|
if ((parent == null) || (parent == -1l))
|
|
{
|
|
test = null;
|
|
}
|
|
else
|
|
{
|
|
test = aclCrudDAO.getAcl(test.getInheritsFrom());
|
|
}
|
|
}
|
|
|
|
if ((targetAcl.getAclType() != ACLType.DEFINING) && (targetAcl.getAclType() != ACLType.LAYERED))
|
|
{
|
|
throw new IllegalArgumentException("Only defining ACLs can have their inheritance set");
|
|
}
|
|
|
|
if (!targetAcl.getInherits())
|
|
{
|
|
return changes;
|
|
}
|
|
|
|
Long actualInheritedId = inheritedAcl.getId();
|
|
|
|
if ((inheritedAcl.getAclType() == ACLType.DEFINING) || (inheritedAcl.getAclType() == ACLType.LAYERED))
|
|
{
|
|
actualInheritedId = getInheritedAccessControlList(actualInheritedId);
|
|
}
|
|
// Will remove from the cache
|
|
getWritable(target, actualInheritedId, null, null, actualInheritedId, true, changes, WriteMode.CHANGE_INHERITED);
|
|
|
|
return changes;
|
|
}
|
|
|
|
/* (non-Javadoc)
|
|
* @see org.alfresco.repo.domain.permissions.AclDAO#setAccessControlEntry(java.lang.Long, org.alfresco.repo.security.permissions.AccessControlEntry)
|
|
*/
|
|
public List<AclChange> setAccessControlEntry(final Long id, final AccessControlEntry ace)
|
|
{
|
|
Acl target = aclCrudDAO.getAcl(id);
|
|
if (target.getAclType() == ACLType.SHARED)
|
|
{
|
|
throw new IllegalArgumentException("Shared ACLs are immutable");
|
|
}
|
|
|
|
List<AclChange> changes = new ArrayList<AclChange>();
|
|
|
|
if ((ace.getPosition() != null) && (ace.getPosition() != 0))
|
|
{
|
|
throw new IllegalArgumentException("Invalid position");
|
|
}
|
|
|
|
// Find authority
|
|
Authority authority = aclCrudDAO.getOrCreateAuthority(ace.getAuthority());
|
|
Permission permission = aclCrudDAO.getOrCreatePermission(ace.getPermission());
|
|
|
|
// Find context
|
|
if (ace.getContext() != null)
|
|
{
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
|
|
// Find ACE
|
|
Ace entry = aclCrudDAO.getOrCreateAce(permission, authority, ace.getAceType(), ace.getAccessStatus());
|
|
|
|
// Wire up
|
|
// COW and remove any existing matches
|
|
|
|
SimpleAccessControlEntry exclude = new SimpleAccessControlEntry();
|
|
// match any access status
|
|
exclude.setAceType(ace.getAceType());
|
|
exclude.setAuthority(ace.getAuthority());
|
|
exclude.setPermission(ace.getPermission());
|
|
exclude.setPosition(0);
|
|
List<Ace> toAdd = new ArrayList<Ace>(1);
|
|
toAdd.add(entry);
|
|
// Will remove from the cache
|
|
getWritable(id, null, Collections.singletonList(exclude), toAdd, null, true, changes, WriteMode.COPY_UPDATE_AND_INHERIT);
|
|
|
|
return changes;
|
|
}
|
|
|
|
/* (non-Javadoc)
|
|
* @see org.alfresco.repo.domain.permissions.AclDAO#enableInheritance(java.lang.Long, java.lang.Long)
|
|
*/
|
|
public List<AclChange> enableInheritance(Long id, Long parent)
|
|
{
|
|
List<AclChange> changes = new ArrayList<AclChange>();
|
|
|
|
AclUpdateEntity acl = aclCrudDAO.getAclForUpdate(id);
|
|
|
|
switch (acl.getAclType())
|
|
{
|
|
case FIXED:
|
|
case GLOBAL:
|
|
throw new IllegalArgumentException("Fixed and global permissions can not inherit");
|
|
case OLD:
|
|
acl.setInherits(Boolean.TRUE);
|
|
aclCrudDAO.updateAcl(acl);
|
|
aclCache.remove(id);
|
|
readersCache.remove(id);
|
|
changes.add(new AclChangeImpl(id, id, acl.getAclType(), acl.getAclType()));
|
|
return changes;
|
|
case SHARED:
|
|
// TODO support a list of children and casacade if given
|
|
throw new IllegalArgumentException(
|
|
"Shared acls should be replace by creating a definig ACL, wiring it up for inhertitance, and then applying inheritance to any children. It can not be done by magic ");
|
|
case DEFINING:
|
|
case LAYERED:
|
|
default:
|
|
if (!acl.getInherits())
|
|
{
|
|
// Will remove from the cache
|
|
getWritable(id, null, null, null, null, false, changes, WriteMode.COPY_ONLY);
|
|
acl = aclCrudDAO.getAclForUpdate(changes.get(0).getAfter());
|
|
acl.setInherits(Boolean.TRUE);
|
|
aclCrudDAO.updateAcl(acl);
|
|
}
|
|
else
|
|
{
|
|
// Will remove from the cache
|
|
getWritable(id, null, null, null, null, false, changes, WriteMode.COPY_ONLY);
|
|
}
|
|
|
|
List<AclChange> merged = mergeInheritedAccessControlList(parent, changes.get(0).getAfter());
|
|
changes.addAll(merged);
|
|
return changes;
|
|
}
|
|
}
|
|
|
|
/* (non-Javadoc)
|
|
* @see org.alfresco.repo.domain.permissions.AclDAO#disableInheritance(java.lang.Long, boolean)
|
|
*/
|
|
public List<AclChange> disableInheritance(Long id, boolean setInheritedOnAcl)
|
|
{
|
|
AclUpdateEntity acl = aclCrudDAO.getAclForUpdate(id);
|
|
List<AclChange> changes = new ArrayList<AclChange>(1);
|
|
switch (acl.getAclType())
|
|
{
|
|
case FIXED:
|
|
case GLOBAL:
|
|
return Collections.<AclChange> singletonList(new AclChangeImpl(id, id, acl.getAclType(), acl.getAclType()));
|
|
case OLD:
|
|
acl.setInherits(Boolean.FALSE);
|
|
aclCrudDAO.updateAcl(acl);
|
|
aclCache.remove(id);
|
|
readersCache.remove(id);
|
|
changes.add(new AclChangeImpl(id, id, acl.getAclType(), acl.getAclType()));
|
|
return changes;
|
|
case SHARED:
|
|
// TODO support a list of children and casacade if given
|
|
throw new IllegalArgumentException("Shared ACL must inherit");
|
|
case DEFINING:
|
|
case LAYERED:
|
|
default:
|
|
return disableInheritanceImpl(id, setInheritedOnAcl, acl);
|
|
}
|
|
}
|
|
|
|
private Long getCopy(Long toCopy, Long toInheritFrom, ACLCopyMode mode)
|
|
{
|
|
AclUpdateEntity aclToCopy;
|
|
Long inheritedId;
|
|
Acl aclToInheritFrom;
|
|
switch (mode)
|
|
{
|
|
case INHERIT:
|
|
if (toCopy.equals(toInheritFrom))
|
|
{
|
|
return getInheritedAccessControlList(toCopy);
|
|
}
|
|
else
|
|
{
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
case COW:
|
|
aclToCopy = aclCrudDAO.getAclForUpdate(toCopy);
|
|
aclToCopy.setRequiresVersion(true);
|
|
aclCrudDAO.updateAcl(aclToCopy);
|
|
aclCache.remove(toCopy);
|
|
readersCache.remove(toCopy);
|
|
inheritedId = getInheritedAccessControlList(toCopy);
|
|
if ((inheritedId != null) && (!inheritedId.equals(toCopy)))
|
|
{
|
|
AclUpdateEntity inheritedAcl = aclCrudDAO.getAclForUpdate(inheritedId);
|
|
inheritedAcl.setRequiresVersion(true);
|
|
aclCrudDAO.updateAcl(inheritedAcl);
|
|
aclCache.remove(inheritedId);
|
|
readersCache.remove(inheritedId);
|
|
}
|
|
return toCopy;
|
|
case REDIRECT:
|
|
if ((toInheritFrom != null) && (toInheritFrom == toCopy))
|
|
{
|
|
return getInheritedAccessControlList(toInheritFrom);
|
|
}
|
|
aclToCopy = aclCrudDAO.getAclForUpdate(toCopy);
|
|
aclToInheritFrom = null;
|
|
if (toInheritFrom != null)
|
|
{
|
|
aclToInheritFrom = aclCrudDAO.getAcl(toInheritFrom);
|
|
}
|
|
|
|
switch (aclToCopy.getAclType())
|
|
{
|
|
case DEFINING:
|
|
// This is not called on the redirecting node as only LAYERED change permissions when redirected
|
|
// So this needs to make a copy in the same way layered does
|
|
case LAYERED:
|
|
if (toInheritFrom == null)
|
|
{
|
|
return toCopy;
|
|
}
|
|
// manages cache clearing beneath
|
|
List<AclChange> changes = mergeInheritedAccessControlList(toInheritFrom, toCopy);
|
|
for (AclChange change : changes)
|
|
{
|
|
if (change.getBefore().equals(toCopy))
|
|
{
|
|
return change.getAfter();
|
|
}
|
|
}
|
|
throw new UnsupportedOperationException();
|
|
case SHARED:
|
|
if (aclToInheritFrom != null)
|
|
{
|
|
return getInheritedAccessControlList(toInheritFrom);
|
|
}
|
|
else
|
|
{
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
case FIXED:
|
|
case GLOBAL:
|
|
case OLD:
|
|
return toCopy;
|
|
default:
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
case COPY:
|
|
aclToCopy = aclCrudDAO.getAclForUpdate(toCopy);
|
|
aclToInheritFrom = null;
|
|
if (toInheritFrom != null)
|
|
{
|
|
aclToInheritFrom = aclCrudDAO.getAcl(toInheritFrom);
|
|
}
|
|
|
|
switch (aclToCopy.getAclType())
|
|
{
|
|
case DEFINING:
|
|
SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties();
|
|
properties.setAclType(ACLType.DEFINING);
|
|
properties.setInherits(aclToCopy.getInherits());
|
|
properties.setVersioned(true);
|
|
|
|
Long id = createAccessControlList(properties).getId();
|
|
|
|
AccessControlList indirectAcl = getAccessControlList(toCopy);
|
|
for (AccessControlEntry entry : indirectAcl.getEntries())
|
|
{
|
|
if (entry.getPosition() == 0)
|
|
{
|
|
setAccessControlEntry(id, entry);
|
|
}
|
|
}
|
|
if (aclToInheritFrom != null)
|
|
{
|
|
mergeInheritedAccessControlList(toInheritFrom, id);
|
|
}
|
|
return id;
|
|
case SHARED:
|
|
if (aclToInheritFrom != null)
|
|
{
|
|
return getInheritedAccessControlList(toInheritFrom);
|
|
}
|
|
else
|
|
{
|
|
return null;
|
|
}
|
|
case FIXED:
|
|
case GLOBAL:
|
|
case LAYERED:
|
|
case OLD:
|
|
return toCopy;
|
|
default:
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
default:
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
}
|
|
|
|
/* (non-Javadoc)
|
|
* @see org.alfresco.repo.domain.permissions.AclDAO#getDbAccessControlListCopy(java.lang.Long, java.lang.Long, org.alfresco.repo.security.permissions.ACLCopyMode)
|
|
*/
|
|
public Acl getAclCopy(Long toCopy, Long toInheritFrom, ACLCopyMode mode)
|
|
{
|
|
return getAclEntityCopy(toCopy, toInheritFrom, mode);
|
|
}
|
|
|
|
private Acl getAclEntityCopy(Long toCopy, Long toInheritFrom, ACLCopyMode mode)
|
|
{
|
|
Long id = getCopy(toCopy, toInheritFrom, mode);
|
|
if (id == null)
|
|
{
|
|
return null;
|
|
}
|
|
return aclCrudDAO.getAcl(id);
|
|
}
|
|
|
|
public List<Long> getAVMNodesByAcl(long aclEntityId, int maxResults)
|
|
{
|
|
return aclCrudDAO.getAVMNodesByAcl(aclEntityId, maxResults);
|
|
}
|
|
|
|
public List<Long> getADMNodesByAcl(long aclEntityId, int maxResults)
|
|
{
|
|
return aclCrudDAO.getADMNodesByAcl(aclEntityId, maxResults);
|
|
}
|
|
|
|
public Acl createLayeredAcl(Long indirectedAcl)
|
|
{
|
|
SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties();
|
|
properties.setAclType(ACLType.LAYERED);
|
|
|
|
Acl acl = createAccessControlList(properties);
|
|
long id = acl.getId();
|
|
|
|
if (indirectedAcl != null)
|
|
{
|
|
mergeInheritedAccessControlList(indirectedAcl, id);
|
|
}
|
|
return acl;
|
|
}
|
|
|
|
private List<AclChange> disableInheritanceImpl(Long id, boolean setInheritedOnAcl, AclEntity aclIn)
|
|
{
|
|
List<AclChange> changes = new ArrayList<AclChange>();
|
|
|
|
if (!aclIn.getInherits())
|
|
{
|
|
return Collections.<AclChange> emptyList();
|
|
}
|
|
|
|
// Manages caching
|
|
getWritable(id, null, null, null, null, false, changes, WriteMode.COPY_ONLY);
|
|
AclUpdateEntity acl = aclCrudDAO.getAclForUpdate(changes.get(0).getAfter());
|
|
final Long inheritsFrom = acl.getInheritsFrom();
|
|
acl.setInherits(Boolean.FALSE);
|
|
aclCrudDAO.updateAcl(acl);
|
|
|
|
// Keep inherits from so we can reinstate if required
|
|
// acl.setInheritsFrom(-1l);
|
|
|
|
// Manages caching
|
|
getWritable(acl.getId(), null, null, null, null, true, changes, WriteMode.TRUNCATE_INHERITED);
|
|
|
|
// set Inherited - TODO: UNTESTED
|
|
|
|
if ((inheritsFrom != null) && (inheritsFrom != -1) && setInheritedOnAcl)
|
|
{
|
|
// get aces for acl (via acl member)
|
|
List<AclMember> members = aclCrudDAO.getAclMembersByAcl(inheritsFrom);
|
|
|
|
for (AclMember member : members)
|
|
{
|
|
// TODO optimise
|
|
Ace ace = aclCrudDAO.getAce(member.getAceId());
|
|
Authority authority = aclCrudDAO.getAuthority(ace.getAuthorityId());
|
|
|
|
SimpleAccessControlEntry entry = new SimpleAccessControlEntry();
|
|
entry.setAccessStatus(ace.isAllowed() ? AccessStatus.ALLOWED : AccessStatus.DENIED);
|
|
entry.setAceType(ace.getAceType());
|
|
entry.setAuthority(authority.getAuthority());
|
|
|
|
/* NOTE: currently unused - intended for possible future enhancement
|
|
if (ace.getContextId() != null)
|
|
{
|
|
AceContext aceContext = aclCrudDAO.getAceContext(ace.getContextId());
|
|
|
|
SimpleAccessControlEntryContext context = new SimpleAccessControlEntryContext();
|
|
context.setClassContext(aceContext.getClassContext());
|
|
context.setKVPContext(aceContext.getKvpContext());
|
|
context.setPropertyContext(aceContext.getPropertyContext());
|
|
entry.setContext(context);
|
|
}
|
|
*/
|
|
|
|
Permission perm = aclCrudDAO.getPermission(ace.getPermissionId());
|
|
QName permTypeQName = qnameDAO.getQName(perm.getTypeQNameId()).getSecond(); // Has an ID so must exist
|
|
SimplePermissionReference permissionRefernce = SimplePermissionReference.getPermissionReference(permTypeQName, perm.getName());
|
|
entry.setPermission(permissionRefernce);
|
|
entry.setPosition(Integer.valueOf(0));
|
|
|
|
setAccessControlEntry(id, entry);
|
|
}
|
|
}
|
|
return changes;
|
|
}
|
|
|
|
private static final String RESOURCE_KEY_ACL_CHANGE_SET_ID = "acl.change.set.id";
|
|
|
|
/**
|
|
* Support to get the current ACL change set and bind this to the transaction. So we only make one new version of an
|
|
* ACL per change set. If something is in the current change set we can update it.
|
|
*/
|
|
private long getCurrentChangeSetId()
|
|
{
|
|
Long changeSetId = (Long)AlfrescoTransactionSupport.getResource(RESOURCE_KEY_ACL_CHANGE_SET_ID);
|
|
if (changeSetId == null)
|
|
{
|
|
changeSetId = aclCrudDAO.createAclChangeSet();
|
|
|
|
// bind the id
|
|
AlfrescoTransactionSupport.bindResource(RESOURCE_KEY_ACL_CHANGE_SET_ID, changeSetId);
|
|
if (logger.isDebugEnabled())
|
|
{
|
|
logger.debug("New change set = " + changeSetId);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
AclChangeSetEntity changeSet = aclCrudDAO.getAclChangeSet((Long)changeSetId);
|
|
if (changeSet == null)
|
|
{
|
|
throw new AlfrescoRuntimeException("Unexpected: missing change set "+changeSetId);
|
|
}
|
|
|
|
if (logger.isDebugEnabled())
|
|
{
|
|
logger.debug("Existing change set = " + changeSetId);
|
|
}
|
|
*/
|
|
}
|
|
return changeSetId;
|
|
}
|
|
|
|
private static class AcePatternMatcher
|
|
{
|
|
private List<? extends AccessControlEntry> patterns;
|
|
|
|
AcePatternMatcher(List<? extends AccessControlEntry> patterns)
|
|
{
|
|
this.patterns = patterns;
|
|
}
|
|
|
|
boolean matches(AclCrudDAO aclCrudDAO, Map<String, Object> result, int position)
|
|
{
|
|
if (patterns == null)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
for (AccessControlEntry pattern : patterns)
|
|
{
|
|
if (checkPattern(aclCrudDAO, result, position, pattern))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private boolean checkPattern(AclCrudDAO aclCrudDAO, Map<String, Object> result, int position, AccessControlEntry pattern)
|
|
{
|
|
Boolean result_aceIsAllowed = (Boolean) result.get("allowed");
|
|
Integer result_aceType = (Integer) result.get("applies");
|
|
String result_authority = (String) result.get("authority");
|
|
Long result_permissionId = (Long) result.get("permissionId");
|
|
Integer result_position = (Integer) result.get("pos");
|
|
//Long result_aclmemId = (Long) result.get("aclmemId"); // not used
|
|
|
|
if (pattern.getAccessStatus() != null)
|
|
{
|
|
if (pattern.getAccessStatus() != (result_aceIsAllowed ? AccessStatus.ALLOWED : AccessStatus.DENIED))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (pattern.getAceType() != null)
|
|
{
|
|
if (pattern.getAceType() != ACEType.getACETypeFromId(result_aceType))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (pattern.getAuthority() != null)
|
|
{
|
|
if ((pattern.getAuthorityType() != AuthorityType.WILDCARD) && !pattern.getAuthority().equals(result_authority))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (pattern.getContext() != null)
|
|
{
|
|
throw new IllegalArgumentException("Context not yet supported");
|
|
}
|
|
|
|
if (pattern.getPermission() != null)
|
|
{
|
|
Long permId = aclCrudDAO.getPermission(pattern.getPermission()).getId();
|
|
if (!permId.equals(result_permissionId))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (pattern.getPosition() != null)
|
|
{
|
|
if (pattern.getPosition().intValue() >= 0)
|
|
{
|
|
if (result_position != position)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else if (pattern.getPosition().intValue() == -1)
|
|
{
|
|
if (result_position <= position)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
static class AclChangeImpl implements AclChange
|
|
{
|
|
private Long before;
|
|
private Long after;
|
|
private ACLType typeBefore;
|
|
private ACLType typeAfter;
|
|
|
|
public AclChangeImpl(Long before, Long after, ACLType typeBefore, ACLType typeAfter)
|
|
{
|
|
this.before = before;
|
|
this.after = after;
|
|
this.typeAfter = typeAfter;
|
|
this.typeBefore = typeBefore;
|
|
}
|
|
|
|
public Long getAfter()
|
|
{
|
|
return after;
|
|
}
|
|
|
|
public Long getBefore()
|
|
{
|
|
return before;
|
|
}
|
|
|
|
/**
|
|
* @param after
|
|
*/
|
|
public void setAfter(Long after)
|
|
{
|
|
this.after = after;
|
|
}
|
|
|
|
/**
|
|
* @param before
|
|
*/
|
|
public void setBefore(Long before)
|
|
{
|
|
this.before = before;
|
|
}
|
|
|
|
public ACLType getTypeAfter()
|
|
{
|
|
return typeAfter;
|
|
}
|
|
|
|
/**
|
|
* @param typeAfter
|
|
*/
|
|
public void setTypeAfter(ACLType typeAfter)
|
|
{
|
|
this.typeAfter = typeAfter;
|
|
}
|
|
|
|
public ACLType getTypeBefore()
|
|
{
|
|
return typeBefore;
|
|
}
|
|
|
|
/**
|
|
* @param typeBefore
|
|
*/
|
|
public void setTypeBefore(ACLType typeBefore)
|
|
{
|
|
this.typeBefore = typeBefore;
|
|
}
|
|
|
|
@Override
|
|
public String toString()
|
|
{
|
|
StringBuilder builder = new StringBuilder();
|
|
builder.append("(").append(getBefore()).append(",").append(getTypeBefore()).append(")");
|
|
builder.append(" - > ");
|
|
builder.append("(").append(getAfter()).append(",").append(getTypeAfter()).append(")");
|
|
return builder.toString();
|
|
}
|
|
}
|
|
|
|
/* (non-Javadoc)
|
|
* @see org.alfresco.repo.domain.permissions.AclDAO#renameAuthority(java.lang.String, java.lang.String)
|
|
*/
|
|
public void renameAuthority(String before, String after)
|
|
{
|
|
aclCrudDAO.renameAuthority(before, after);
|
|
aclCache.clear();
|
|
}
|
|
}
|