mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-06-30 18:15:39 +00:00
48730: Record only merge from 4-1.BUG-FIX (4.1.5) to HEAD-BUG-FIX (4.2) 48447: Performance problem with Eclipse can be fixed by excluding the web-client build directory from the searchable resources. Done for 58 other projects (generally include in the 4.1 code line) 48726: Reverse Merge (did not work after an Eclipse Clean) - already done on HEAD 48447: Performance problem with Eclipse can be fixed by excluding the web-client build directory from the searchable resources. Done for 58 other projects (generally include in the 4.1 code line) 48929: Synced up with HEAD r48903 48957: Merged PATCHES/V4.1.4 to HEAD-BUG-FIX 47847: Merged V4.1-BUG-FIX to PATCHES/V4.1.4 47625: Fixed ALF-18063 - AlfrescoUtil's getPages method now parses json using jsonUtils.toObject to force strict json - CSRFFilter got new throwError action meaning the filter now can stop certain resources form being reached directly from the browser - /remoteadm/* webscripts can no longer be accessed directly from the browser - Modified regexps to be easier to read - Added config samples 47879: Merged V4.1-BUG-FIX to PATCHES/V4.1.4 47878: Final part of fix for ALF-14086 - Sort order of folders including hyphens ( - ) are different in folder-tree and view on folders (in Share) - People Finder 47912: Merged BRANCHES/DEV/V4.1-BUG-FIX to PATCHES/V4.1.4: 47909: ALF-18257: partial fix - adds back in missing TinyMCE files. 47928: Merged V4.1-BUG-FIX to PATCHES/V4.1.4 47913: Final part of fix for ALF-18257 - AWE panel is not displayed 47932: ALF-14587: Created article or publication cant be viewed on WQS site - Fix by Dmitry Vaserin - Same fix was done to style1.get.html.ftl in ALF-17117 47956: ALF-10243: workflow shows wrong date - Missing WQS date field configuration 47983: ALF-15803: CH, NL, RU: There are no Chinese, Russian, Dutch templates for IMAP messages and Chinese, Russian templates for Email messages - Email templates from Gloria 48026: ALF-15803: CH, NL, RU: There are no Chinese, Russian, Dutch templates for IMAP messages and Chinese, Russian templates for Email messages - Email templates from Gloria 48027: Merged V4.1-BUG-FIX to PATCHES/V4.1.4 48020: Fix for ALF-18220 - Cancel checkout in 'View Original Document' view fails and causes document stuck in checkedout state. 48048: Merged BRANCHES/DEV/DWEBSTER/HEAD_AWE to PATCHES/V4.1.4: 48047: Fixes: ALF-14758. Adds z-index as a work around to an overlapping menu bug that occurs if they are created in a particular order and viewed on a large enough resolution monitor. 48086: Merged BRANCHES/DEV/V4.1-BUG-FIX to PATCHES/V4.1.4: 48083: Fixes ALF-14931 48121: Merged BRANCHES/DEV/V4.1-BUG-FIX to PATCHES/V4.1.4: 48116: Fixes build failure caused by 'fix' for ALF-14931 48153: Merged V4.1-BUG-FIX to PATCHES/V4.1.4 48102: Fix for ALF-18354 - SPP-Meeting workspace event can be edited and deleted on Agenda tab 48124: Fixes ALF-18349: Slideshare and YouTube channels can now be created. 48151: Fix for ALF-15475 - Liferay Portal: IE9: Layout of portlets is broken when document details page is opened 48156: Improved fix (removed useless media queries) for ALF-18196 - Document Preview - Flash Movie Sized to a Thin Horizontal Bar at 1024x768 Resolution 48185: Another go at a solution for ALF-16413 - Share asks for Basic-Auth while not needed trying to access RSS feeds (thus breaking SSO). 48189: ALF-17818 - Strikethrough formatting is not preserved in Wiki 48208: ALF-18385: Alfresco Explorer: Localization is not applied after login. - Fixes regression caused by ALF-17189 48261: Fix for ALF-18352 - Manager can not update permissions more than once for the folder/content created by other user 48264: Merged DEV to PATCHES/V4.1.4 48258: ALF-18325 : Can't delete wcmqs if it was published to live We should also check for site is not being deleted before creating site container. 48283: Correction to fix for ALF-18196 48284: Fix for ALF-18328 - Share dependencies containing dependencies breaks Hazelcast clustering 48352: Fix for MNT-6390 - Incorrect type for Group and Review workflow after task approved by all users 48354: Fix for MNT-3196 - No information is displayed in My Activities and Site Activities dashlets for content creation 48390: MNT-6292: Created article or publication cant be viewed on WQS site - Fix researched by Dmity Vaserin - More handling of empty lists - It seems that WCMQS requires renditions to be indexed (in order for them to be returned by CMIS queries) so we must remove the ASPECT_INDEX_CONTROL aspect from them in RenditionHelper 48424: Fixed MNT-7521 "Document Library" instead "File Plan" displayed in the site navigation bar 48430: MNT-7522: Users with "read only" or "read and file" permissions don't have access to RM folders - In ScriptNode.childByNamePath() check for PermissionService.READ permission rather than PermissionService.READ_PROPERTIES permission, which apparently isn't compatible with RM! 48434: MNT-7522: Users with "read only" or "read and file" permissions don't have access to RM folders - Corrected fix with help from Andy Hind 48500: Fixed MNT-6311 "Activities with Google Docs are not displayed in My Site Activities and Site Activities dashlets" 48548: MNT-7528 My Tasks to Do and My Pooled Tasks dashlets do not show the correct description of a workflow 48635: MNT-8482 Enterprise 4.1.4: Backwards compatibility breaking change in public Java API class org.alfresco.service.cmr.dictionary.ClassDefinition - Added back in missing methods and using StaticMessageLookup so will still have the issue identified by MNT-413. The new methods still exist and don't have this issue. 48645: MNT-8484: Oracle: An unexpected difference is present after comparison of database schema with reference schema (post-upgrade) 48729: MNT-8498 Could not transform .psd file 48745: MNT-8527: Activity Feed Cleaner broken on Oracle - Due to ibatis weirdnesses, the select_activity_user_feeds_greater_than_max query has to exclude results with null user_ids (non user feeds) as this maps to a null row on Oracle and results in an NPE! - Also fixed all comparisons with feed_user_id to be NULL safe 48751: Fixed MNT-8504 "Script error occurs when clicking Edit Tags action from document/folder details page" - Removed js_string encoding of nodeRef and made sure nodeRef is taken from the repo instead of the page url 48752: MNT-8467: Cannot authorize to Share Kerberos automatically - Reversed r44754 performance fix causing this (Sorry Kev) 48755: MNT-8514: Incorrect workflow status is displayed on My Tasks dashlet - Fix by Viachaslau reviewed by Frederik 48756: MNT-8531: Merged PATCHES/V4.1.3 to PATCHES/V4.1.4 48683: MNT-8494: Lucene index recovery fails to reindex an orphaned node whose parent is deleted - Added unit test for this and fixed regression over MNT-6545 fix 48717: MNT-8494: Lucene index recovery fails to reindex an orphaned node whose parent is deleted - Strengthened unit test to check for deleted nodes with parents and strengthened handling of these as a result - Hopefully fixes unit test failures 48798: Fixed MNT-7646 "CLONE - [Pentest] Internet Explorer <= v8 XSS" - Share now inspects text/xml content from the webscript content, if it finds a <!DOCTYPE svg> it will change the mimetype to text/plain. 48810: Upgrade Surf version in POM files to 1.2.0-M4 (r1217) 48819: Fixed MNT-8504 "Script error occurs when clicking Edit Tags action from document/folder details page" part 2 - Fix on folders page 48820: Make SchemaReferenceFileTest actually output its reason for failing - I can't track down the temp files! 48822: MNT-8508: Fixing description-property in LazyActivitiWorkflowTask which is not the same as WorklfowTask.description 48823: BDE-130: fail the build when yuicompressor minimization fails 48890: Fixed MNT-8554 "FF: Download button on Document Details page is not working" - Note also fixes the "Comment" widget in the header not working (in any browser) 48933: MNT-8560: It's impossible to find the user by any property except the username Modify People.getSortedPeopleObjects() method to create ArrayList based on provided List<NodeRef> and use it for sort, because provided List<NodeRef> can be unmodifiable list. 48964: MNT-6494: Fixed merge issue (already fixed in HEAD-BUG-FIX) 49033: Merged PATCHES/V4.1.4 to HEAD-BUG-FIX-QA 48996: MNT-8564 : CLONE - Incorrect saving process when editing event Fix event.put.json.ftl to produce valid json 49006: MNT-8555: Reverse Merge MNT-6419 (ALF-17089) 45245: ALF-17089 (Displaying Url Name instead of site Name in Select form) 47089: ALF-17089 (Displaying Url Name instead of site Name in Select form) 49039: Merged HEAD to HEAD-BUG-FIX-QA 48931: Fixed CLOUD-1511 "My Documents dashlet is crashing when inspecting the syncmode value" 48955: Fix name of wdr-deployment jar in mvninstall task 48979: ALF-18573: fix sharepoint module context name. This is a change that was appropriate for cloud but had crept in to HEAD during the megamerge. 48988: Fix integration with CLOUD2 + compile and package remote-api test classes separately 48995: CLOUD-1460 "CloudConv: Re-implement header customizations" - #1. Re-add link so network admin can access admin console Added in widget ids that could be referenced to add and remove widgets in the user & app items menu 49008: Fix public api tests 49014: Fix public api tests 49136: Fix public api tests 49141: Merged HEAD-BUG-FIX to HEAD-QA (thus completing 4.1.4 -> HEAD-QA merge) 49139: Merged PATCHES/V4.1.4 to BRANCHES/DEV/HEAD-BUG-FIX (mergeinfo committed earlier) 48735: Fixed MNT-8506 & MNT-8507 * MNT-8506 "A server error has occurred when press Follow/Unfollow button from User Profile" * MNT-8507 "A server error occurs when set "Private" checkbox on My Profile" * Instead of using Alfresco.util.Ajax.request and creating XHR requests forms were being submitted meaning the Alfresco-CSRFToken never got added. * Now refactored to use Alfresco.util.Ajax.request and post directly to the proxy, meaning the Share "services" now can be removed. 48812: MNT-8506 / MNT-8507: Fix up by Vasily to avoid YUI compression error 48813: Fixed MNT-8507 "A server error occurs when set "Private" checkbox on My Profile" part 2 - variable used keyword "private", now refactored to "isPrivate" 49154: Merged BRANCHES/DEV/CLOUD1 to BRANCHES/DEV/HEAD-QA: 48470: Merged BRANCHES/DEV/FEATURES/CLOUD1-PUBLICAPI3 to BRANCHES/DEV/CLOUD1: 48041: Merged BRANCHES/DEV/FEATURES/CLOUD1-PUBLICAP2 to BRANCHES/DEV/FEATURES/CLOUD1-PUBLICAPI3: 47129: Merged BRANCHES/DEV/FEATURES/CLOUD1-PUBLICAPI1 to BRANCHES/DEV/FEATURES/CLOUD1-PUBLICAP2: 45439: PUBLICAPI-39: "Favourites API" wip 45681: PUBLICAPI-39: "Favourites API" wip 45897: Test a fix for issue found during bm testing - CMIS: null entries in property list values 45965: Public api performance investigation: test node bulk loading change 45978: PUBLICAPI-39/40: wip, changes from review. 46019: PUBLICAPI-39: "Favourites API" wip 46056: Re-instate opencmis config that was mistakenly changed 46156: Public api performance investigation: test node bulk loading change 46193: PUBLICAPI-39: "Favourites API" wip 46200: PUBLICAPI-39: "Favourites API" wip 46247: Upgrade to OpenCMIS 0.8 46248: PUBLICAPI-72: "Add users role to Site entity" 46249: PUBLICAPI-72: "Add users role to Site entity" 46250: PUBLICAPI-40: "Site membership API" - modifiedAt timestamp + some tidy up 46251: PUBLICAPI-40: "Site membership API" - bug fixes 46253: public api tests refactoring (split tests into separate classes by functional area), site membership api tests 46273: public api tests refactoring (split tests into separate classes by functional area), site membership api tests 46298: Cloud OpenCMIS browser binding support through the OpenCMIS Alfresco webscript (currently disabled) 46299: Cloud OpenCMIS browser binding support through the OpenCMIS Alfresco webscript (currently disabled) 46300: Cloud OpenCMIS browser binding support through the OpenCMIS Alfresco webscript (currently disabled) 46311: Cloud OpenCMIS browser binding support through the OpenCMIS Alfresco webscript (currently disabled) 46337: PUBLICAPI-79: "GET a Favorite" 46338: PUBLICAPI-79: "GET a Favorite" 46339: public api tests: some refactoring 46340: Cloud OpenCMIS browser binding support through the OpenCMIS Alfresco webscript (currently disabled) 46345: Added name parameter to the @uniqueId annotation. e.g. @UniqueId(name="targetGuid") 46346: PUBLICAPI-39: "Favourites API" - tests 46359: PUBLICAPI-40: "Site membership API" - PUT requests and bug fixes 46380: PUBLICAPI-40: "Site membership API" - PUT requests and bug fixes 46381: PUBLICAPI-40: "Site membership API" - PUT requests and bug fixes 46397: PUBLICAPI-40: "Site membership API" - add missing file 46411: public api tests: re-instate tests (accidentally commented out) 46427: Cloud OpenCMIS browser binding support through the OpenCMIS Alfresco webscript (currently disabled) 46442: Cloud OpenCMIS browser binding support through the OpenCMIS Alfresco webscript (currently disabled) 46467: PUBLICAPI-80: "GET on a deleted Favorite answers a 500" 46476: Upgrade to OpenCMIS 0.8 46514: Initial implementation of WHERE clause functionality. (Likely to change a lot). 46518: PUBLICAPI-75: "Use a 'where' parameter to specify criteria for favorite result set content " 49157: Merged BRANCHES/DEV/CLOUD1 to BRANCHES/DEV/HEAD-QA: 48552: Merged BRANCHES/DEV/V4.1-BUG-FIX to BRANCHES/DEV/CLOUD1 48551: Fix for DEVOPS-2976 P1 - Solr nodes crash with tracking enabled + configuration fixes 48796: Merged BRANCHES/DEV/FEATURES/ACCOUNT_TYPES to BRANCHES/DEV/CLOUD1: 48092: Resolve CLOUD-1303: Add 2 new Account Types to Cloud 48325: Translations from Gloria 48445: Japanese: translation update from Gloria 48698: JA: Translation update from Gloria. 49130: Merged BRANCHES/DEV/CLOUD1-HOTFIX to BRANCHES/DEV/CLOUD1: 49120: Merged BRANCHES/DEV/FEATURES/CLOUD1-PUBLICAPI3 to BRANCHES/DEV/CLOUD1-HOTFIX: 49093: CLOUD-1518: "Favourite sites are not displayed correctly" 49110: CLOUD-1518: "Favourite sites are not displayed correctly": fix up PreferencesService to return correct site preference keys 49116: CLOUD-1518: "Favourite sites are not displayed correctly": favourite sites uses the favourites service rather thanpreferences service directly, making it and favourites consistent 49159: fixup pesky solrcore.properties 49197: Fix for Cloud AccountUsageQuotaTest - make action-executor node service mt aware (fallout from previous commit that now does a node existence check in action executor that needs to be mt aware) 49199: Fix tests 49241: CLOUD-1527 "Logo in Share footer is broken" - Added /res to make logo getting displayed when running in multi tenancy mode 49250: CLOUD-1527 "Logo in Share footer is broken" - Removed image dimensions to make image replaceable 49267: Fix tests: remove incorrect OpenCMIS jars 49272: Use newer patched version of chemistry-opencmis-server-bindings 49273: Removed extraneous chemistry library dependency 49293: CLOUD-1512 "SAML integration needs to override "CSRFPolicy" config" - Adding new (overridable) getPath() method in CSRFFilter 49315: Merged PATCHES/V4.1.4 to HEAD-QA 49236: Fixed MNT-8615 "Browser page is not reloaded after deleting folder/file or after creation content in Repository" 49301: Fixed MNT-8615 "Browser page is not reloaded after deleting folder/file or after creation content in Repository" part 2 49316: Merged PATCHES/V4.1.4 to HEAD-QA (RECORD ONLY) 48735: Fixed MNT-8506 & MNT-8507 * MNT-8506 "A server error has occurred when press Follow/Unfollow button from User Profile" * MNT-8507 "A server error occurs when set "Private" checkbox on My Profile" * Instead of using Alfresco.util.Ajax.request and creating XHR requests forms were being submitted meaning the Alfresco-CSRFToken never got added. * Now refactored to use Alfresco.util.Ajax.request and post directly to the proxy, meaning the Share "services" now can be removed. 48812: MNT-8506 / MNT-8507: Fix up by Vasily to avoid YUI compression error 48813: Fixed MNT-8507 "A server error occurs when set "Private" checkbox on My Profile" part 2 - variable used keyword "private", now refactored to "isPrivate" 49328: Fix up People script class so that it deals with access denied exceptions (this will hopefully fix failing PeopleRestApiTest in Cloud2) 49346: Fixed CLOUD-1532 "Test email signup page is brokebn due to new header" 49364: Fixed CLOUD-1524 "Unable to retrieve Google Docs subsystem status from Alfresco (re: googleEditable not defined ?)" 49373: CONV: Fix CLOUD-1524 / CLOUD-446 - disable GoogleDocsV1 subsystem and prevent deferred start (and associated error) when Share later calls explicit "status" webscript (to see that it is disabled) - revert 49364 and replace with alternative fix - see also similar IMAP status issue (CLOUD-1507) 49375: CONV: Fix CLOUD-1507 -fix IMAP subsystem to prevent deferred start (and associated error) when Share later calls explicit "status" webscript (to see that it is disabled) - see also similar GDocsV1 status issue (CLOUD-1524 / CLOUD-446) 49416: Merged BRANCHES/DEV/CLOUD1 to BRANCHES/DEV/HEAD-QA: 49303: CLOUD-1518: "Favourite sites are not displayed correctly": fix fallout 49418: CONV: Fix ALF-18698 - Core MT: "create tenant" ignores the tenant-specific root contentstore dir path (if specified) 49433: Fix for failing Cloud2 test https://bamboo.alfresco.com/bamboo/browse/THOR-CLOUD2HEADQA-JOB1-38/test/case/12496544 49491: CLOUD-1552 "The invite link icon in the new header's site title "area" points to the "on premise" invite page (which has been admin secured) instead of the invite dialog" - Improving extensibility by adding further widgets ids for header menu 49590: CLOUD-1556 "CloudConv: CLOUD2 does not start on DP: "Possible CSRF attack"" part 1 - Not a bug in the CSRFFIlter but an improvement that introduces a <properties> elements which may hold variables used by the CSRFPolicy config to avoid repetition and the possibility to only override the <properties> section in different environemnts, i.e. set different referer proxies in test & prod. 49758: Fix for CLOUD-1542, Google Docs action was missing from the action list in the document library. An action is still listed in the document-browse action group that has no definition, this was causing the web tier webscript to abort processing of any actions defined after it i.e. any custom actions. 49789: Merged BRANCHES/DEV/HEAD-BUG-FIX to BRANCHES/DEV/HEAD-QA: 49788: L10N update from Gloria, based on EN r48822 49801: Move CLOUD2 to HEAD-QA, as part of Alfresco One project 49806: Bring POM file back from CLOUD2 49807: Fix order of from/set/to lines in rules, to match schema validation. 49829: Merged BRANCHES/DEV/HEAD-BUG-FIX to BRANCHES/DEV/HEAD-QA: 49808: CLOUD-1615: CloudConv - Regression: CLONE: the info panel isn't wide enough to display the share link without a line break - Increased panel and image widths 49830: Merged BRANCHES/DEV/HEAD-BUG-FIX to BRANCHES/DEV/HEAD-QA: 49823: CLOUD-1609: CloudConv - Regression: DAM: Item header was moved (also incorrect color is using) for folders and files. - Added overrides and changes to gallery view to accomodate changed CSS in detail and simple view 49831: Merged BRANCHES/DEV/HEAD-BUG-FIX to BRANCHES/DEV/HEAD-QA: 49827: CLOUD-1610: CloudConv - Regression: DAM: More menu does not disappear after first opening more link - Fixed el passed in for onEventUnhighlightRow in fnHideDetailPanel - Also added hiding of more actions on mouseleave of more actions 49834: SVN ignore patterns - "test" folder. 49835: Merged BRANCHES/DEV/HEAD-BUG-FIX to BRANCHES/DEV/HEAD-QA 49800: Fix to build.properties that got munged in rev 49209. Fix to share-header that was horribly merged to pull in code with dependencies that aren't present yet. Fix to login dialog width that hasn't made it over to this branch for some reason. 49872: Added name to logging of transformer registration 49885: CLOUD-1626: CloudConv - Regression: Networks are not displayed via WebDav. Reinstated code that was originally part of THOR1_SPRINTS (r34168) but was lost as part of convergence work. 49889: CLOUD-1669: upgrade jibx from 1.2.3 to 1.2.5 to allow full JDK7 support 49906: Merged BRANCHES/DEV/BELARUS/HEAD-QA-2013_04_22 to BRANCHES/DEV/HEAD-QA: 49794: ALF-18797 : SPP: Check out action doesn't work for Document Workspace Merged but with minor bug fix. 49908: CLOUD-1649: Added the missing network menu for the public users. 49916: Fix to User Factory bean setter to avoid: WARN [springframework.beans.GenericTypeAwarePropertyDescriptor] [main] Invalid JavaBean property 'userFactory' being accessed! Ambiguous write methods found next to actually used 49917: Merged SHOULDERS to HEAD-QA 48984: Minor UI fixes: - fix height of user status text-area to be consistent across browsers - fix hover style and font size of user status text-area - fix login dialog width since Cloud merge 49918: Fix for CLOUD-1571 - CloudConv - Regression: My Sites dashet isn't loaded 49919: Fix for CLOUD-1648 - CloudConv - regression: cloud2headqa is not localized in any language - code for the login language drop-down refactored to fit within login component rather than global function javascript - fixed to work since code convergence also 49920: Fix for CLOUD-1584 - CloudConv - Regression: Some dashlets should be absent on User/Site Dashboard - Disabled new dashlets (Site Search, Saved Search, My Discussions) because they are too exciting for the Cloud. 49921: CLOUD-1669 Switch -source and -target compilation parameters to 1.7 49923: Fix to 404 error on login page (visible in firebug etc.) Correct list of image dependencies. 49924: Fix for CLOUD-1629 - CloudConv - Regression: It's impossible to remove the Welcome Widget on Site Dashboard - encoding of preference values must handle "." dot character or it ends up as nested preference! 49927: Fix for CLOUD-1577 - CloudConv - regression:Incorrect display of status message 49928: Fix for CLOUD-1586 - CloudConv - regression:The user is redirected to login page after clicking 'Invite' button from Site members page - Button should be disabled on Cloud (redirect is because on-premise Invite page is admin only!) - but pattern to do so has changed since merge with 4.2. 49931: WebDAV: exclusive lock could be obtained when shared lock already in place. In addition, the invalid lock state that was produced then led to a stack overflow due to infinite loop. 49933: Added svn:ignore entires for build/pom.xml and root/privatemodules/thor/config/log4j.properties 49936: CLOUD-1600: CloudConv - regression: Cannot add a tag through inline edit option - Removed mandatory validator 49938: Merge V4.1-BUG-FIX to HEAD-QA 48904: BDE-109: generate coverage statistics from JaCoCo when running tests 48925: 3rd party classpath refers to available mysql-connector-java-5.1.13-bin.jar 49065: Limit coverage to org.alfresco classes, otherwise overhead is too big and tests too slow 49474: MNT-8668 Remove Maven declared dependency on addressing-1.0.mar 49655: BDE-109 new Ant task to generate JaCoCo report for test coverage 49941: CLOUD-1668: CloudConv - Regression: Incorrect displaying of default avatar on task section on document's details page - Fixed avatar link 49943: CLOUD-1661: CloudConv - Regression: progress bar is absent in Storage section on Account Summary page - Brought theme-bg-3, theme-bg-4, and theme-border-5 CSS over from greyTheme to lightTheme 49958: SpringSurf libs upgrade to r1257 Updated Cloud share config overrides to remove values that are now the default in Surf (e.g. reconnect-timeout etc.) 49965: Fix for CLOUD-1588 - CloudConv - Regression: "Download as Zip" option should be absent - remove the lovely new Download as Zip feature from Cloud as it is Officially Too Exciting. 49975: Fix for CLOUD-1663 - CloudConv - Regression: Search query containing wildcards is partially cut off on the results page (encoding is not being applied) 49977: CLOUD-1640: Fixed external user site member visibility issue. 50007: Fix to disallow change of own user role or removal in Site Member for the current user. 50011: Activiti schema reference files ignore table column ordering (testing CLOUD-1675) 50012: Reorganize repository database bootstrap beans to register scripts and patches with SchemaBootstrap (CLOUD-1675) - New Spring config file: alfresco/dbscripts/db-schema-context.xml - Split Repo, JPBM, AVM and Activiti scripts 50013: Update module properties to reflect latest Alfresco stack requirement and set version to 2.0 50014: Fixed CLOUD-1675: Upgrade failed from CLOUD1-BUG-FIX3 to HEAD-QA - Use module-friendly registration of create scripts - Note: Schema validation will report errors due to 2 Cloud-specific tables in the 'alf' schema namespace 50018: CLOUD-1568: CloudConv - regression:created/modified time is not displayed in Properties section - Added unit test for combining default controls where a new data type is added, which was failing - Fixed DefaultControlsConfigElement.combine method 50023: Fix for CLOUD-1578 - CloudConv - regression: Unable to join a site Fix for CLOUD-1579 - CloudConv - Regression: It's impossible to perform "Leave Site" action by Site Member from Site Dashboard 50027: BDE-150 Create RPMs for Cloud deployment 50028: ALF-18908: WebDAV litmus tests failing on HEAD-QA/CLOUD2 50032: CLOUD-1624: CloudConv - regression: Login button is missing on Quick Share page - Moved CSS loading to quickshare/header.get.html.ftl 50039: CLOUD-1626: networks not displayed via WebDAV (fix for PROPFIND) 50040: CLOUD-1637 / MNT-8462 "Post" button works incorrectly - Added check for response type of string to userStatusUpdateSuccess and userStatusUpdateFailure since it's already coming back as a JSON object 50047: Add missing dependency on java-property-utils-1.6 50048: BDE-150: fix RPMs 50051: Fix for CLOUD-1664 - CloudConv - Regression: New logo is not applied Fix for CLOUD-1580 - CloudConv - Regression: It's impossible to change the application theme - Fix to correctly handle "network admin" concept - manually allow the network admin to perform admin actions where appropriate - AFAIK this can never have worked correctly... remove nonsense runas=admin webscripts overrides that don't work anyway. - Clean up of related scripts. 50055: CLOUD-1607: filter sent-invites-min.js coming from Enterprise build, so that it gets overridden by the non-minimised cloud one 50070: Temporarily adding exploded Ant build for cloud2 environment. This now means the same steps for building a cloud1 environment can be used to build a cloud2 environment. NOTE: There is one outstanding licence issue to resolve that will be fixed in a subsequent commit. 50088: Remove unused or duplicate MyBatis config (CLOUD-1672) 50090: CLOUD-1672: CloudConv: MyBatis error when downloadCleanerJob is run - Cloud was duplicating the MyBatis configuration - Created Cloud-specific SQL templates - Tested using sign ups and general use but full account and tenant usage needs to be tested 50092: CLOUD-1591: CloudConv - Regression: Incorrect layout of "Link to Rule Set" page - Made the more specific rules-picker treeview width override lightTheme's overriding treeview width 50094: Fixes for exploded Ant build. 50097: Added ignore of projects/web-client/source/web/images/logo/alfresco_enterprise.gif which is apparently moved from elsewhere during some build step 50099: CLOUD-1614: CloudConv - Regression: Incorrect label "Start workflow" displays instead of "Create Task" - Added page.startWorkflow.title to cloud localization files 50101: BDE-154: upgrade urlrewritefilter to 4.0.4, avoiding compilation warning 50102: CLOUD-1602: CloudConv - Regression - Chrome specific: Close (X) button doesn't work on "Alfresco Cloud information" window - Removed committed minified about-share-min.js and ant touch command which kept it in place 50107: Merged HEAD-BUG-FIX to HEAD-QA (4.2) for CLOUD-1466: stop relying on a patched version of wss4j 49973: Merged DEV to HEAD-BUG-FIX (4.2) 49648: MNT-8652 Treat PasswordText as default for CMIS Web Service authentication (using patched version of wss4j) Execute PasswordTypeInterceptor before WSS4JInInterceptor to add PasswordText type as default if Password element misses it. Add system test for case. 50076: Follow-up on MNT-8652: rename CXFAuthenticationTest into CXFAuthenticationSystemTest, so that it is not executed in web-service-client tests, but only in system-build-test 50109: Fix to issue where application logo was resized and broke aspect ratio of uploaded image. Also changed size to valid for new header. 50113: Fix for CLOUD-1576 - CloudConv - Regression: Incorrect notification is displayed when Site Admin performs "Leave Site" action 50114: Fix for CLOUD-1662 - CloudConv - Regression: Incorrect behavior when searching with empty field - trim searchbox text before event publication 50116: Cleanup of copy/pasted files... 50117: Merged BRANCHES/DEV/V4.1-BUG-FIX to BRANCHES/DEV/HEAD-QA 47811: ALF-18245 - BM-0013: Soak: Run 06: Search population of ScriptNode is expensive: Refactor Share search UI and REST API to provide server-side paging. 50122: MNT-8480 - cloud sync and revert 50126: BDE-150 Add build number as RPM release property 50150: Merged V4.1-BUG-FIX (4.1.5) to HEAD-QA (4.2) << MNT-8721 Security fix from 4.1.4.2 >> << Merge direct from V4.1-BUG-FIX rather than HEAD-BUG-FIX as r49633 was merged with a block of other changes >> 49633: Merged DEV to V4.1-BUG-FIX (4.1.5) 49574: MNT-8473: Share's workflow-details page exposes all workflow instances to everyone Introduce WorkflowPermissionInterceptor that check if current user allowed to perform operation. 49752: MNT-8473: Share's workflow-details page exposes all workflow instances to everyone Fix errors that were found during unit testing. 50153: ALF-18708: Merged V4.1-BUG-FIX to HEAD-QA << Security fix from 4.1.4.4 >> 50151: MNT-8866: Merge V4.1.4 (4.1.4.4) to V4.1-BUG-FIX (4.1.5) 49802: MNT-8725: CLONE - Security context for Alfresco Explorer is not being cleaned up after processing a request JSF phase listener, which cleans up security context for Alfresco Explorer requests. It is necessary for avoiding sharing of security context between Alfresco Explorer and CMIS services, based on OpenCMIS libraries 49803: MNT-8725: CLONE - Security context for Alfresco Explorer is not being cleaned up after processing a request Configuration part of the fix has been reversed 49804: MNT-8725: CLONE - Security context for Alfresco Explorer is not being cleaned up after processing a request JSF phase listener, which cleans up security context for Alfresco Explorer requests. It is necessary for avoiding sharing of security context between Alfresco Explorer and CMIS services, based on OpenCMIS libraries 50164: Merged V4.1-BUG-FIX to HEAD-QA << Priority for transformer.remote.alfresco. Includes JMX controls for the Transformers subsystem >> 49038: MNT-7158 Merge DEV to HEAD-BUF-FIX (4.2) - Addition of TransformerConfigMBeam (JMX bean) to control transformers dynamically - Transformer level config limits are now a default for mimetype specific values. Possible now that we don't have these in the Spring config. previously had been 'combined' which was not too clear. Also added system wide mimetype defaults. - All transformers are now 'known' to the content transformer registry - not just the ones that may be selected. i.e it knows about the component transformers. - TransformerSelector now round robins all equal priority transformers until they reach their thresholds, rather than doing so for each one in turn. 49135: MNT-7158 Investigating adding priorities to transformers - Changes to make it possible to check debugTransformer.txt output in 4.1.5 against 4.2 49190: MNT-7158 fix build failure testGetMaxSourceSizeKBytesPageSupports 49207: MNT-7158 Investigating adding priorities to transformers - Modified priorities so that it is now deterministic Try as sourceMimetype of 00 in JMX op getTransformationsByExtension to double check - Changed default priorities 5 and 10 to 50 and 100 for EXPLICIT and DEFAULT to give more room in the future - Combined transformer.complex.AdobeIllustrator.Image with transformer.complex.PDF.Image as they were the same except for the transformer settings - TransformerDebug now uses [---] as the priority for compound transformers - TransformerDebug now includes Component in the type of compound transformers e.g. fred<<ComplexCompound>> 49947: MNT-7158 Investigating adding priorities to transformers - Added limits based on use. So a limit may be set for "index", "doclib", "webpreview", "syncRule", "asyncRule" ... 49985: MNT-7158 Investigating adding priorities to transformers - Allow <tomcat>/shared/classes/alfresco-global.properties to be used in transformers. 50002: MNT-7158 Investigating adding priorities to transformers - Missing file 50061: MNT-7158 Investigating adding priorities to transformers - Set up remote transformations BinaryPassThrough.priority=20 remote.alfresco.priority=30 remoteServer.priority=40 50143: MNT-7158 Investigating adding priorities to transformers - Show default values in getProperties, comment out values set to defaults and add under line transformer name 50166: Merged V4.1-BUG-FIX to HEAD-QA << Two 4.1.4.4 hot fixes >> 50165: Merged V4.1-BUG-FIX (4.1.5) to HEAD-BUG-FIX (4.2) 50110: MNT-8844 - CSRFFilter disables https login 50158: MNT-8870: Merge V4.1.4 (4.1.4.4) to V4.1-BUG-FIX (4.1.5) 50120: MNT-8858: AJAX Servlet does not clean up security context after processing a request Modification for cleaning up security context after processing an AJAX request to 'org.alfresco.web.app.servlet.ajax.AjaxServlet' 50169: CLOUD-1641: Made people-finder to use CannedQuery rather than Solr. 50173: Fix for CLOUD-1587 - CloudConv - Regression: Advanced Search link should be unavailable. 50174: Fix for CLOUD-1608 - CloudConv - Regression: Changing roles of site members is displayed only after page refresh Fix for ALF-18534 - Changing roles of site members is displayed only after page refresh 50176: Fix for CLOUD-1592 - CloudConv - Regression: Content I'm Editing dashlet contains redundant info (about blogs, wiki, forum) 50177: CLOUD-1689: CloudConv - Regression:Networks are not displayed via SPP 50182: ALF-18702 : Tenant isn't able to log in Share once another tenant has logged in before. Fix for clearing tenant user domain and authentication context after the Repository webscript is executed. Copied the TenantLeakLogger from CLOUD to HEAD into org.alfresco.web.app.servlet package. 50183: CLOUD-1606, CLOUD-1459: Fixed the permissions issue for the get preferences in the MailActionExecuter. 50184: Changed default Cloud Share Hazelcast config to empty IP list rather than promiscuous multicast - which was much too saucy! 50185: XSS attack hardening - incorrect use of ?js_string for safe HTML element IDs - should be ?html 50197: Code tidy 50200: ALF-18957: SchemaReferenceFileTest failing on Oracle Updated ACT schema-reference file for Oracle. 50203: Fix for CLOUD-1613 - CloudConv - Regression: CLONE: Under selected Item menu the manage permission should be hidden 50208: Fix CLOUD-1660 - CloudConv - Regression: Incorrect layout of tag icon on Search result page 50211: Fix to (unreported?) issue where Colleagues dashlet would not show the user status relative time - showed empty value in brackets () 50215: DEVOPS-3172, CLOUD-1701: cloud2/HEAD-QA unable to startup in DP environment. 50227: CLOUD-1612: CloudConv - Regression: Incorrect location of help icon for "Message" field on "Create Task" page - Moved rendering of help element - Added CSS for desired positioning 50245: Merged BRANCHES/DEV/HEAD-BUG-FIX to BRANCHES/DEV/HEAD-QA: 50240: Merged BRANCHES/DEV/V4.1-BUG-FIX to BRANCHES/DEV/HEAD-BUG-FIX: 50221: Merged DEV to V4.1-BUG-FIX (4.1.5) 50030: Attempt a workaround for MNT-8704: WebDAV:Content does not disappear after being deleted - Deprecate various methods related to the existing WebDAV use of sys:hidden - Put in a timer task on use of the sys:hidden aspect in WebDAV DeleteMethod 50093: MNT-8704: WebDAV:Content does not disappear after being deleted - "if (!fileFolderService.isHidden(nodeRef))" block was moved to deleteHackRunAs.doWork(). 50187: MNT-8704: added node existence check; unhiding node prior to deletion. As per Derek's comment: https://issues.alfresco.com/jira/browse/MNT-8704?focusedCommentId=227689&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-227689 50251: CLOUD-1702: Fixed NPE in WorkflowPermissionInterceptor, also fixed the issue that when the invitee tries to click on the link in the invitation email, 'org.alfresco.service.cmr.security.NoSuchPersonException' is thrown. 50298: Fixed the failing unit tests as a result of the newly added WorkflowPermissionInterceptor. 50306: Fix to merge causing ALF-18979 - Activiti servlet references on by default in web.xml Removed duplicated class now that the LoggerFilter is part of code webclient code 50311: MNT-8890: Commented the newly added method in TenantRepositoryContainer in order to fix the failing unit tests. 50318: Generate a jar of tests for alfresco-cloud, for consumption by QA tests later 50322: Fix for CLOUD-1657 - CloudConv - Regression: Admin section in the Header should be located in the user's menu having name "Account settings" 50335: ALF-18702 : Tenant isn't able to log in Share once another tenant has logged in before. Fixed failing JUnit tests. Reverted 50311 revision. 50337: CLOUD-1699: Cloud example content thumbnails - some have the wrong width and look rubbish in doclib/search results - Added new versions of doclib for Data Sheets to sampleContent.acp - Added doclib and imgpreview for all content in sampleContent.acp except 'Alfresco Cloud Intro.mp4' 50345: ALF-18702 : Tenant isn't able to log in Share once another tenant has logged in before. Fixed failing JUnit tests. 50352: Fix for CLOUD-1691 - Incorrect notification when leaving name field empty through inline edit - fixes the issues where; length validator not fired, order of validators wrong for cm:name inline editor, fixes issue where previously validation would still be shown on reedit of field after Cancel << hat tip to Mr Draper for validation solution 50353: Fix for CLOUD-1604 - CloudConv - regression: Links on "Oops page" should be highlited. - also removed duplicate messages and cleaned up message text from the late 90's. 50356: Fixed CLOUD-1697: URL rewrite filter upgrade causes additional logging 50357: Fixed the failing unit tests which were failing as a result of rev: 50335 commit. 50374: Revert r50182 and the subsequent changes made to fix the fallout: r50311, r50335, r50345, and r50357 50379: CLOUD-1669: update Eclipse JibX launchers with the upgraded JibX 1.2.5 jars 50390: Revert the part of r50306 that updated enterprise-web-scripts-application-context.xml and deleted TenantLeakLogger.java. This was necessary following the reverts that took place at r50374. 50396: Corrected name of content transform test class file. 50397: Added new "transform" folder (which should have been there before) 50398: Move content transform test class file into the new "transform" folder. 50401: - Added two Eclipse projects: one for the thor private module ("Alfresco Cloud") and one for its dependencies ("Cloud Dependencies"). - Turned the JiBX builder on by default in the data-model project. 50410: MNT-8890: split classpath when executing JUnit tests in Ant, so that repository tests do not get classes of upstream projects 50411: MNT-8890 follow-up - make enterprise repository tests run with a reduced classpath too, otherwise EntRepoCacheStopTest fails - add wdrdeployment classes to reduced classpath, otherwise enterprise tests cannot find alfresco/bootstrap/deployedSpace.xml 50416: Removed unused component (no longer required in 4.2 so the override isn't required) 50417: Dialog styling tweaks 50422: Merged BRANCHES/DEV/FEATURES/CLOUD1-SECURITY to BRANCHES/DEV/HEAD-QA 50409: Fix for CLOUD-1721 50473: CLOUD-1726 CLOUD-1732: move tests CMISChangeLogServiceTest and SubsystemsTest from repository to remote-api, because they depend on resources in remote-api (follow-up of MNT-8890) 50474: CLOUD-1736 Shouldn't have tweaked the classpath of system-build-test, since it already has its own (follow-up of MNT-8890) 50479: ALF-18927: SPP: Incorrect information is displayed on Event Information window for yearly recurrect event BYMONTHDAY shouldn't be deleted for YEARLY recurrence. Also setting interval was not accurate. 50480: ALF-18927: SPP: Incorrect information is displayed on Event Information window for yearly recurrect event Additional check in. 50485: Fixes ALF-18702: Corrected the logic for how tenant switching is achieved so that both Enterprise and Cloud scenarios are catered for. 50495: Fix for ALF-18981 - Non-ASCII characters are not displayed in Share interface correctly - Fix to deal with issue where a valid JSON result string is not always valid JavaScript text e.g. some unicode characters etc. 50498: svn ignore patterns 50499: files should not be in svn 50500: remove eclipse folder settings from svn 50505: Fix to (unreported?) search results paging issue - merge error meant that only the first page of results would ever be returned no matter what page was selected, but who goes past the first page anyway eh? 50516: CLOUD-1718: "CloudConv - Regression:"Imap Attachments" and "IMAP Home" folders are displayed via CMIS Workbench client" 50517: CLOUD-1727: CloudConv - Regression - WebDav: The mapped network drive could not be created on Windows This was broken by MNT-2823. 50524: CLOUD-1665: New accounts are not available for CLOUD2 Manually merged revision 48796 as it was mistakenly marked as merged. 50525: Merged BRANCHES/DEV/CLOUD1 to BRANCHES/DEV/HEAD-QA: 50033: (RECORD ONLY) Merge HEAD-QA to CLOUD1 (for BDE-109: generate coverage on unit tests) Merge V4.1-BUG-FIX to HEAD-QA 48904: BDE-109: generate coverage statistics from JaCoCo when running tests 48925: 3rd party classpath refers to available mysql-connector-java-5.1.13-bin.jar 49065: Limit coverage to org.alfresco classes, otherwise overhead is too big and tests too slow 49474: MNT-8668 Remove Maven declared dependency on addressing-1.0.mar 49655: BDE-109 new Ant task to generate JaCoCo report for test coverage 50582: Removed and ignored .classpath and .project 50614: CLOUD-1713 append the Cloud build number after the Enterprise build number, as in: r50345-b65-c129 Upgrade a few Maven plugins 50649: Merged BRANCHES/DEV/CLOUD1 to BRANCHES/DEV/HEAD-QA: 50083: Merged BRANCHES/DEV/FEATURES/CLOUD1-BUG-FIX3 to BRANCHES/DEV/CLOUD1: 49357: New Cloud Bug Fix Branch 49363: Merged BRANCHES/DEV/FEATURES/CLOUD1-BUG-FIX2 to BRANCHES/DEV/FEATURES/CLOUD1-BUG-FIX3: 46487: Fixes CLOUD-1293: "Other" included in total activities count. Refactor activity groupings. 46488: Fixes: CLOUD-1310: Adds "no-wrap" to last element to that the second link all appears on the same line. 46493: Fixes: CLOUD-1229: Removes max-width CSS constraint so that table cells can expand to find room for long transltions. 46535: PUBLICAPI-63: "Unable to list comments associated to a document : Malformated comment object ?": fix + tests 46555: PUBLICAPI-90: "You can not remove yourself from a site using the -me- identifier" 46826: Fix for CLOUD-1368 - Tomcat thread blocking during concurrent user testing causing service to become unresponsive. 47249: Merged BRANCHES/DEV/V4.1-BUG-FIX to BRANCHES/DEV/FEATURES/CLOUD1-BUG-FIX2 47243: Fix for ALF-18194 - Bad performance with multiple contentstores browsing files on the slower stores 47681: Merged HEAD to CLOUD1-BUG-FIX2 47448,47484,47504,47518,47552 47865: GERMAN: Latest translation updates, based on EN r46485 & including fixes from check report. 47866: FRENCH: Latest translation updates, based on EN r46485 & including fixes from check report. 47867: SPANISH: Latest translation updates, based on EN r46485 & including fixes from check report. 47868: ITALIAN: Latest translation updates, based on EN r46485 & including fixes from check report. 47869: JAPANESE: Latest translation updates, based on EN r46485 & including fixes from check report. 47885: ALL LANG: Minor update to translations to bring them in line with EN r47485 48355: CLOUD-1458: Added MailActionExecuterTest to ActionTestSuite. 48402: CLOUD-1458: Remove inadvertently added test class 48561: CLOUD-1458, CLOUD-1459, CLOUD-1479, CLOUD-1485 - Fix MailActionExecuter to correctly resolve primary domain for sender and recipients. 47249: Merged BRANCHES/DEV/V4.1-BUG-FIX to BRANCHES/DEV/FEATURES/CLOUD1-BUG-FIX2 47243: Fix for ALF-18194 - Bad performance with multiple contentstores browsing files on the slower stores 47681: Merged HEAD to CLOUD1-BUG-FIX2 47448,47484,47504,47518,47552 47865: GERMAN: Latest translation updates, based on EN r46485 & including fixes from check report. 47866: FRENCH: Latest translation updates, based on EN r46485 & including fixes from check report. 47867: SPANISH: Latest translation updates, based on EN r46485 & including fixes from check report. 47868: ITALIAN: Latest translation updates, based on EN r46485 & including fixes from check report. 47869: JAPANESE: Latest translation updates, based on EN r46485 & including fixes from check report. 47885: ALL LANG: Minor update to translations to bring them in line with EN r47485 48355: CLOUD-1458: Added MailActionExecuterTest to ActionTestSuite. 48402: CLOUD-1458: Remove inadvertently added test class 48561: CLOUD-1458, CLOUD-1459, CLOUD-1479, CLOUD-1485 - Fix MailActionExecuter to correctly resolve primary domain for sender and recipients. 49371: PUBLICAPI-166: "Unable to upload large file on Cloud (> 5MB)" 49389: Merged BRANCHES/DEV/FEATURES/CLOUD1_SAML1 to BRANCHES/DEV/FEATURES/CLOUD1-BUG-FIX3: 49295: CLOUD-1529: Made SessionIndex optional in the SSO response. Also commented out 'autoProvisionEnabled' and 'alfrescoLoginCredentialEnabled' from the SAMLConfigSettings as they are not implemented yet. 49406: CLOUD-1488: Merged BRANCHES/DEV/V4.1-BUG-FIX to BRANCHES/DEV/FEATURES/CLOUD1-BUG-FIX3 (Also added the missing elements from the merge): ALF-16480: Merged PATCHES/V4.1.1 to V4.1-BUG-FIX 43252: MNT-166: Document lock not removed after the lock expiry date has been reached - Changed evaluator "evaluator.doclib.metadata.isLocked" to use "evaluator.doclib.indicator.nodeLocked" and "evaluator.doclib.indicator.lockOwner" evaluator. 43253: MNT-165: "Cancel Editing" does not completely remove lock from document - Added documentLibrary cancel editing action for locked documents. 43300: MNT-171: Merged V4.1-BUG-FIX to PATCHES/V4.1.1 (modified) 43096: Fix for ALF-16283 - When document is checked out, 'Edit Online' and 'Upload New Version' options should not be visible on the original document. 43311: MNT-165: "Cancel Editing" does not completely remove lock from document - Fix for page refresh problem when cancel editing on details page 43421: MNT-186: 4.1.1.7 HF: Webscipt error on doclib page, containing locked by other users files - Change evaluator.doclib.metadata.isLocked to break circular dependency 43755: MNT-202: Upload New Version not available for a document that has been edited offline - Upload New Version is now available if editable by user (respecting locks, type of checkout, etc). 49463: CLOUD-1510 - Cache remote transformation calls to isTransformable - Make TransformationOptions serializable - Expose ehcache statistics and configuration, via JMX 49492: CLOUD-1510 - Fix broken unit test 49631: CLOUD-1455: "Hide activity in a site from the activity feed" 49662: CLOUD-1455: "Hide activity in a site from the activity feed": fix broken unit test 49759: Merged BRANCHES/DEV/HEAD-QA to BRANCHES/DEV/FEATURES/CLOUD1-BUG-FIX3: 49758: Fix for CLOUD-1542, Google Docs action was missing from the action list in the document library. 49814: CLOUD-1455: "Hide activity in a site from the activity feed" 49866: CLOUD-1597: Added the missing evaluators. 49948: Merged BRANCHES/DEV/FEATURES/CLOUD1_GOOGLEDOCS to BRANCHES/DEV/FEATURES/CLOUD1-BUG-FIX3: 49880: Update Google Docs integration from 2.0.2 to 2.0.3. 50045: Merged BRANCHES/DEV/FEATURES/CLOUD1_GOOGLEDOCS to BRANCHES/DEV/FEATURES/CLOUD1-BUG-FIX3: 50043: Update 2.0.3 AMPs 50686: GERMAN: Latest translations and updates based on EN rev49789. Jira fixes: MNT-7526, ALF-18650, ALF-18523, ALF-18521, ALF-18255, ALF-18069 50689: SPANISH: Latest translations and updates based on EN rev49789. Jira fixes: ALF-18650, ALF-18523, ALF-18521, ALF-18255 50691: FRENCH: Latest translations and updates based on EN rev49789. Jira fixes: ALF-18650, ALF-18523, ALF-18521, ALF-18255 50693: ITALIAN: Latest translations and updates based on EN rev49789. Jira fixes: ALF-18650, ALF-18523, ALF-18521, ALF-18255 50694: JAPANESE: Latest translations and updates based on EN rev49789. Jira fixes: ALF-18650, ALF-18523, ALF-18521, ALF-18255 50695: DUTCH: Latest translations and updates based on EN rev49789. Jira fixes: ALF-18650, ALF-18523, ALF-18521, ALF-18255 50696: RUSSIAN: Latest translations and updates based on EN rev49789. Jira fixes: ALF-18650, ALF-18523, ALF-18521, ALF-18255, ALF-18504, ALF-18503, ALF-18502, ALF-17793 50699: CHINESE: Latest translations and updates based on EN rev49789. Jira fixes: ALF-18650, ALF-18523, ALF-18521, ALF-18255, MNT-8874, MNT-8874, MNT-8874 50709: CLOUD-1699: Cloud example content thumbnails - some have the wrong width and look rubbish in doclib/search results - Fixed imgpreview for Alfresco Mobile.pdf 50711: Merged DEV to HEAD-QA (4.2.0) 50482: ALF-18996 : Upgrade from 3.4.12 to 4.2.0 fails: ERROR [domain.schema.SchemaBootstrap] [localhost-startStop-1] Statement execution failed: SQL: ALTER TABLE ACT_RU_TASK MODIFY ASSIGNEE_ VARCHAR(255) Error: Table 'alfupg.ACT_RU_TASK' doesn't exist - Correctly handle activiti tables creation/upgrade when performing upgrade from 3.4.x. 50728: CLOUD-1754 do not fail the build as soon as tests fail: we are now quarantining tests in Bamboo, so installers need to be built regardless 50755: Merged HEAD-BUG-FIX to HEAD-QA 50754: Merged V4.1-BUG-FIX (4.1.6) to HEAD-BUG-FIX 50753: Merged DEV to V4.1-BUG-FIX (4.1.6) 50727: MNT-3368: BM-0013: Soak: Run 08: OnPremiseSyncPullJob runs without a transaction - Add transactions. 50750: MNT-3368: BM-0013: Soak: Run 08: OnPremiseSyncPullJob runs without a transaction - Correction for 'readOnly' parameter. 50759: Merged BRANCHES/DEV/JAMAL/Fast_Test into HEAD-QA (CLOUD-1680: Make thor tests run blazingly fast) 50635: CLOUD-1680: Make thor tests run blazingly fast. 50684: CLOUD-1680: Regouped a few of the public api tests. 50688: CLOUD-1680: Regouped a few of the public api tests. 50706: CLOUD-1680: Moved the excludedGroups from the parent pom to thor. Also grouped the webdav tests. 50710: CLOUD-1680: Deleted the un-necessary junit category. 50773: Fixing up the tests to separate out the cloud tests. MailActionExecuter should now get the locale correctly. 50779: Redundant file 50780: Redundant File 50782: Redundant File 50783: Fixed missing double quote 50784: Missed strings included 50785: Missed key included 50795: ALF-19035 - MT Cloud Policies run with inconsistent "short" base and "full" node refs. 50823: ALF-17548: Disable Google Docs v1 integration * MBean controlling the subsystem has been removed (commented out) from bootstrap-context.xml * Admin console web script org/alfresco/components/console/repository/google-docs.get has been removed * Admin console form config has been deleted from share-form-config.xml * No changes have been made to the installer, as I could find no evidence that the configuration of the v1 subsystem was being changed by it * Note: The subsystem property 'googledocs.googleeditable.enabled' was already set to false. 50825: ALF-17548: Fix status web script which assumed the presence of the Google Docs v1 MBean removed in r50823. Now the web script returns enabled: false if the bean is not present. 50827: CLOUD-1600: CloudConv - regression: Cannot add a tag through inline edit option - Added ignoreEmpty argument to accommodate changes in r50352 50831: CLOUD-1770: Redundant Perform Action ("Embed properties as metadata in content") is displayed for Content Rules - Moved embedder action to sample file since we don't supply any embedders out-of-the-box 50833: CLOUD-1770: Redundant Perform Action ("Embed properties as metadata in content") is displayed for Content Rules - Programmatically created executer rather than loading from context 50838: Cloud: Patch overrides - Moved live patches to 'module-schema-context.xml' ('patch.redeployProcessesWithReminders2' and 'patch.redeployProcessesWithReminders3') - No Sample Web Site in Cloud: (CLOUD-1480) Created no-op patch for 'patch.siteLoadPatch.swsdp' - IMAP is disabled in Cloud: (CLOUD-1743): Created no-op patch for 'patch.imapFolders' 50839: ALF-18702: Tenant isn't able to log in Share once another tenant has logged in before Following review, added logic in AuthenticationServiceImpl.authenticate that is similar to AuthenticationServiceImpl.validate in order to handle case where the tenant is determined by the requested URI 50851: First part of fix for ALF-19052. 50853: ALF-18096: Integrate document security AMP files from the Alfresco Mobile iOS 1.5 project * New aspect dp:restrictable * Form configuration for properties provided by this aspect * Note: As detailed on the ticket the source files have been copied into the repository and slingshot project and mofified there. 50864: Fix for CLOUD-1769 CloudConv - Admin section in header menu instead of Account Settings are available for free account user 50879: ALF-18914 : SPP: It's possible to create meeting with empty subject field linking to an existing workspace Added a check for an empty subject when creating a meeting from iCal. 50922: Revert r50853 mistakenly adding Mobile project dp:restricted aspect to HEAD-QA 50925: CLOUD-1759: Fixed most of the Sonar ‘Critical’ violations. 50937: CloudConv - Regression - CLONE - No notification is displayed when performing "Leave Site" action 50938: Added Cloud override to remove MyFiles and Shared links from toolbar 50941: Fix for CLOUD-1768 CloudConv - Regression - CLONE: It's impossible to find the user by any property except the username and CLOUD-1778 CloudConv:in people search first name and last name people search always return zero results 50942: Fix for CLOUD-1741 - CloudConv: User should be redirected to Alfresco Cloud Documentation instead of Alfresco Community 4.2 Documentation. Comical spelling error in config. 50945: GERMAN: Latest Cloud translations and updates based on EN rev50920. Jira fixes: CLOUD-1729 50946: FRENCH: Latest Cloud translations and updates based on EN rev50920. Jira fixes: CLOUD-1729 and CLOUD-1763 50947: SPANISH: Latest Cloud translations and updates based on EN rev50920. Jira fixes: CLOUD-1729 and CLOUD-1763 50948: ITALIAN: Latest Cloud translations and updates based on EN rev50920. Jira fixes: CLOUD-1729 and CLOUD-1763 50949: JAPANESE: Latest Cloud translations and updates based on EN rev50920. Jira fixes: CLOUD-1729 and CLOUD-1763 50957: Fix for CLOUD-1623 Unfriendly warning appears when user try to create private site with the same URL 50960: CLOUD-1772: Configuration files have been localized - Removed all pointlessly translated configuration files 50961: MNT-8480 : New web script for delete audit entry. 50968: Merged BRANCHES/DEV/CLOUD1 to BRANCHES/DEV/HEAD-QA: 50624: (RECORD ONLY) Delete generation of installers in continuous, to allow 'amber' builds 50973: Merged BRANCHES/DEV/CLOUD1 to BRANCHES/DEV/HEAD-QA: 50568: Merged BRANCHES/DEV/FEATURES/CLOUD1-SECURITY to BRANCHES/DEV/CLOUD1 50423: Merged PATCHES/V4.1.1 to BRANCHES/DEV/FEATURES/CLOUD1-SECURITY 44129: MNT-223: Unbound SOLR result set (from Explorer trashcan query) consumes heap 44130: MNT-223: Unbound SOLR result set (from Explorer trashcan query) consumes heap 44129: MNT-223: Unbound SOLR result set (from Explorer trashcan query) consumes heap Merged PATCHES/V4.1.4 to BRANCHES/DEV/FEATURES/CLOUD1-SECURITY 45951: Fix for ALF-17687 BM-0013: Soak: Run 02: SolrJSONResultSet must preload nodes 50622: Fix for CLOUD-1751 Users searching in their home tenant (or other person related operations) should not be subject to visibility checks 50664: Fix for CLOUD-1751 Users searching in their home tenant (or other person related operations) should not be subject to visibility checks 50976: CLOUD-1634: CloudConv - regression: Upload form is not closed automatically after upload limit error occurs - Added Javascript to hide upload status and show upload control again 50992: Changing the modifiers for the "addAuthorityNameIfMatches" methods from "private" to "protected" to allow the RM module do RM specific changes without copying a lot of the existing code. 50993: Fix for ALF-18850 - Incorrect label "page.ruleEdit.title" on New Rule page from Repository Browser 51031: CLOUD-1761: Activity is not generated when deleting document via SPP/WebDAV - fix part 1 This is the first part of a fix: activities were not being raised due to MNT-181 fix. This is now fixed. However, the posts are not being processed properly, which also needs fixing. 51083: Fixed the failing test (testHasSite) 51085: First part of fix for CLOUD-1787 51091: CLOUD-446: Remove 'overridden' googledocs subsystem bean from Cloud override context, which was causing the subsystem to start up still 51092: Fix to URLRewrite config rule to correct escape UTF-8 characters either side of the detected '@' character when rewriting URLs where browsers have not correctly dealt with the @ character. 51097: Updated BG for ludicrous screen resolution CLOUD-1795 51098: Fix for CLOUD-1795 - Login dialog centre on window resize 51103: Fix for CLOUD-1796 CloudConv:-Search pagination to other pages no results are shown 51105: Merged BRANCHES/DEV/HEAD-BUG-FIX to BRANCHES/DEV/HEAD-QA: 51104: Merged BRANCHES/DEV/V4.1-BUG-FIX to BRANCHES/DEV/HEAD-BUG-FIX: 51101: MNT-8704: node was not being unhidden (thread local client marker needed setting) 51107: Improvements to search result list handling - only populate node result structures for the items that are going to be returned. 51140: Minor tweaks to search processing hand merged from 4.1.N 51163: JAPANESE: Fix for CLOUD-1799 51170: ALF-18074 add a new flag to enable clustering. 51184: Make cloud tests depend on repository test resources, to be able to reuse them 51234: CLOUD-1800: Made the Rules to be executed asynchronously in the cloud by overriding “rule-edit.js”. 51245: Merged BRANCHES/DEV/HEAD42-MERGE to BRANCHES/DEV/HEAD-QA 51230: Addition of a modified YUI Compressor ANT task to speed up the minimize-slingshot-deployed-javascript build step - from around 3 mins on most machines down to 3 secs. w00t AND THIS IS THE RESULT: ant clean incremental-webclient-tomcat-exploded incremental-slingshot-tomcat-exploded ... BUILD SUCCESSFUL Total time: 1 minute 18 seconds 51248: Merged HEAD-BUG-FIX to HEAD-QA 51247: Merged V4.1-BUG-FIX to HEAD-BUG-FIX (RECORD ONLY) 51246 (RECORD ONLY): Merged PATCHES/V4.1.5 to V4.1-BUG-FIX 51233: MNT-8129: NPE - Servlet.service() - getGlobalConfig for "webClientConfigService" Missing JGroups messages receiver has been added to handle cluster messages correctly. Port range default value has been increased to add some slack around required ports 50999 (PARTIAL RECORD ONLY): Better logging for AsynchronouslyRefreshedCache (MNT-8129) 51273: Partial fix for CLOUD-1806. This checkin fixes serialisation of TransformationSourceOptions objects. A subsequent check-in will fix deserialisation. 51275: Fixed CLOUD-1804 51279: Allow calls to NodeDAO.getParentAssocs to succeed for deleted nodes - The error message reported is incorrect. Previously, no calls were made to the DAO to retrieve details for deleted nodes. There was therefore an assumption that the node had been internally referenced and that this represented an error. This is no longer the case (nor has it been for a some time). - In this case, the SOLR tracking attempts to get the parent associations for all nodes, regardless of their state of deletion. - CLOUD-1807: CloudConv: I get the following error in the solr nodes "Detected stale node entry: NodeVersionKey" - MNT-9072: SOLR tracking can be delayed by node deletion 51291: JobLockService.releaseLock is not optimistic - AcquireLockException is no longer thrown if the lock token is invalid - releaseLock returns a boolean to indicate whether the lock was removed or whether it was already gone - Prevents unnecessary retrying withing JobLockService implementation (ALF-19098) 51292: Fix thread safety in PostLookup w.r.t. job lock state; general logging improvements (ALF-19098) 51293: Fix build after rev 51291 (ALF-19098): JobLockService.releaseLock is now optimistic 51305: Remainder of fix for CLOUD-1806. RemoteAlfrescoTransformer is unable to serialize transformation options as JSON. This check-in just changes Jackson configuration to handle the new TransformationSourceOptions which are now part of TransformationOptions. As this field needs to be JSON serialised along with its containing TransformationOptions instance - and particularly because TransformationSourceOptions is not a concrete type - we need extra Jackson config in order to correctly marshall and unmarshall the actual concrete types of any instances of TransformationSourceOptions. 51307: Slight tidy-up of fix for CLOUD-1806. I had specified some Jackson config in 3 subclasses and didn't need it as it was already configured on a base type. 51315: Fix on HEAD-QA only for ALF-19101, which I believe may affect CLOUD-1806. A typo in a TransformationSourceOptions method breaks the JavaBeans contract and imperils the JSON serialisation needed for CLOUD-1806. I think the method with the typo has been published (in 4.1?) so rather than rename it, I've deprecated it and added a new one with the correct spelling. 51350: Preparatory work for fixing CLOUD-1754. MailActionExecuterTest failing. It has been very difficult to get reliable test feedback on dealing with the MailActionExecuter. This is largely because of the difference in the way mail actions are handled in cloud and on enterprise. Therefore I have refactored and extended our test code to support fixing the MailActionExecuter. Part 1: Refactor the JUnit Rules AlfrescoPeople, AlfrescoPerson, AlfrescoTenant so that when a test is run in Community, Enterprise or Cloud the test 'does the right thing' when creating/tearing down test users. i.e. On Community/Enterprise, create the user/auth and the person on the single tenant. In Cloud create the user in system tenant, create the person in their home tenant, precreating the tenant if necessary and tear the whole thing down again. I achieved this by having the cm:person-related rules delegate to a spring bean responsible for dealing with test users. Then I've got a mechanism to let Enterprise override Community and Cloud override Enterprise. So the Community 'TestUserComponent' just creates/deletes users. Enterprise 'inherits' this behaviour. The Cloud TestUserComponent deals with the tenant sideshow. It's all started in the global-integration-test-context.xml. 51351: Adding the JIRA number for BDE-173 into this file. 51353: Fixing some test fallout from pervious commit (51350) which was part of preparatory work for fixing CLOUD-1754. Looks like the SyncAudit tests were using ApplicationContextHelper's getApplicationContext method having already started a custom app context? 51371: Merged BRANCHES/DEV/HEAD42-MERGE to BRANCHES/DEV/HEAD-QA 51277: Fix for ALF-18948 - Share Hazelcast cluster configuration change required in 4.2 51313: Minor css improvements to search box 51367: Fixed order of button styles for lightTheme overrides 51368: Fix to broken css file - erroneous end comment marker 51370: Fix for CLOUD-1795 - Login screen isn't resizing to display window 51406: CLOUD-1573: CloudConv - regression:Preview is not displayed for locked document - Added check for presence of container element before attempting setup of document versions data table 51407: Fix for CLOUD-1754. MailActionExecuterTest test failing. The code in MailActionExecuter needs some refactoring. As it was, validation of the mail recipients (are they usernames? email addresses? do the users exist? etc) are not the same for the to-many parameter as they are for the 'to' parameter. There are various other inconsistencies in the code also. I have tried to fix the cases where the inconsistencies are obvious and I've tried to imporove the test coverage too. This code has now become a little too complex and a future JIRA will lead to simplification. Currently the priority is to complete code convergence. 51410: Fix for CLOUD-1641 CloudConv - Regression: User from other domain cannot be found - cloud queries for people use all a users domains (OK until we partition by tenant) Fix for CLOUD-1768 CloudConv - Regression - CLONE: It's impossible to find the user by any property except the username 51422: Partial revert of r51410 where accountService was apparently added to the wrong bean definition 51424: Correct wire up for R 51410 related to Fix for CLOUD-1641 CloudConv - Regression: User from other domain cannot be found - cloud queries for people use all a users domains (OK until we partition by tenant) Fix for CLOUD-1768 CloudConv - Regression - CLONE: It's impossible to find the user by any property except the username 51429: CLOUD-1641: User from other domain cannot be found Removing previous fix for CLOUD-1641, the back-end should decide the best route to go depending on the parameters provided. Forcing the query to use a canned query has caused CLOUD-1768. 51444: Fix for CLOUD-1641 CloudConv - Regression: User from other domain cannot be found Fix for CLOUD-1768 CloudConv - Regression - CLONE: It's impossible to find the user by any property - ignore tenant filter for cloud people query and rely on post query visibility filtering (to see people from other tenants invited in) 51466: Fix for CLOUD-1641 CloudConv - Regression: User from other domain cannot be found Fix for CLOUD-1768 CloudConv - Regression - CLONE: It's impossible to find the user by any property - exclude permission evaluation when searching for people in the cloud (covered by the visibility stuff) 51553: CLOUD-1780: CloudConv :- follow button is visible for external user as well - Refactored customizations for new dependency loading to fix order of loading - Refactored widget userHomeTenant option addition for new instantiation pattern - Refactored override of widget's _renderFollowingActions method with new CloudPeopleFinder object that extends PeopleFinder 51571: Merged HEAD-BUG-FIX to HEAD-QA 51473: Moved CacheTest back into Repository Note for Cluster features: This change no longer relies on any distributed caches and therefore the new files should just stay as they are and the old ones removed. 51583: Merged HEAD-BUG-FIX to HEAD-QA 51477 Merged V4.1-BUG-FIX to HEAD-BUG-FIX 50995: Support for locking and unlocking of values in the TransactionalCache - Infrastructure for MNT-8997: Support definitive writes for TransactionalCache - Allows a definitive write (put or remove) call to be made to the TransactionalCache 51584: Merged HEAD-BUG-FIX to HEAD-QA 51478: Merged V4.1-BUG-FIX to HEAD-BUG-FIX 50997: Make use of TransactionalCache's locking ability - MNT-8997: Support definitive writes for TransactionalCache - PersonServiceImpl and AuthorityDaoImpl both do cache modificiations in 'beforeXYZ' callbacks, which leaves room for further attempted cache updates by other callbacks. Reapplied the fixes using TransactionalCache locks 51327: Fix CLOUD-1698 Intermittent invite test failures - Uses MNT-8997: Support transactional locking for Authentication Cache removal 51635: CLOUD-1812 Fix invalid license issue: modify version.properties to have version.label=Cloud and version.edition=Enterprise 51739: Merged HEAD-BUG-FIX (4.2) to HEAD-QA << Low risk change to avoid NPE found testing remote alfresco transformation nodes in DP env >> 51738: Merged V4.1-BUG-FIX (4.1.6) to HEAD-BUG-FIX (4.2) 51731: Avoid NPE in ContentServiceImpl.debugActiveTransformers(). Relates to MNT-7158 Investigating adding priorities to transformers 51752: CLOUD-1812 Fix version.label to simply add a '-Cloud' suffix. 51753: CLOUD-1822 Change RPM installation folder from tomcat6 to tomcat7 51760: CLOUD-1385: "Sending a PUT request without a Content-Type header resets the contents mimetype to application/octet-stream" - CMIS was not correctly parsing the mime type header 51779: Depend on Spring Surf 1.2.0-M6 (r1265) rather than a SNAPSHOT version 51780: Depend on Spring Surf 1.2.0-M6 (r1265) rather than a SNAPSHOT version 51783: Merged HEAD to BRANCHES/DEV/HEAD-QA (RECORD ONLY) 49055: ALF-15191: Saving files (new or existing) to Alfresco via CIFS using iWork Pages or Numbers results in invisible files Modify HiddenAspect to hide node with explicit='false' by default. 49062: ALF-15191: Saving files (new or existing) to Alfresco via CIFS using iWork Pages or Numbers results in invisible files Revert changes that were mistakenly committed. Rolled back to r49054 49075: Merged BRANCHES/DEV/HEAD-QA to HEAD: 49074: ALF-18573: exclude module-context.xml from alfresco-spp-config.jar 49245: Merged HEAD-QA to HEAD (RECORD ONLY) 49244: Switch version of mvninstall to 4.2.0-QA-SNAPSHOT 49442: CLOUD-1541: "CloudConv: REGRESS - can't connect to cmisatom on HEAD (works on HEAD-QA)": spurious chemistry library appeared 49599: CLOUD-1541: "CloudConv: REGRESS - can't connect to cmisatom on HEAD (works on HEAD-QA)": spurious chemistry library appeared 49980: Merged BRANCHES/DEV/HEAD-QA to HEAD: 49458: Merged BRANCHES/DEV/HEAD-BUG-FIX to BRANCHES/DEV/HEAD-QA: 49117: Merged BRANCHES/DEV/CONV_V413 to BRANCHES/DEV/HEAD-BUG-FIX: 49111: - Revert of r47645 - Change of imgpreview thumbnailDefinition to mimetype and size expected for HEAD - Relates to ALF-5051 and MNT-8599 / ALF-18726 49118: Restored high resolution placeholder icons for imgpreview, relates to ALF-13984 49979: ALF-18726: Alfresco could not start with WCMQS applied - Updated RenditionServiceIntegrationTest with new imgpreview values 51793: Increase size of in-transaction "nodeOwnerCache" to 40K items. 51819: CLOUD-1385: "Sending a PUT request without a Content-Type header resets the contents mimetype to application/octet-stream" - add further tests not covered by original fix 51836: TenantUtil now gives a bit more information when exceptions pass through (CLOUD-1685) 51837: Merged BRANCHES/DEV/CLOUD1 to BRANCHES/DEV/HEAD-QA: 51502: Merged BRANCHES/DEV/FEATURES/CLOUD1-SECURITY to BRANCHES/DEV/CLOUD1: 50389: Created branch for Cloud1 Security Release 50395: Merged BRANCHES/DEV/FEATURES/CLOUD1-BUG-FIXSF to BRANCHES/DEV/FEATURES/CLOUD1-SECURITY: 49713: Branch for SalesForce bug fix merges 49718: Fix for CLOUD-1590 - Session fixation on Cloud specific login page 49721: CLOUD-1589 Protect Login-page against XSS Cross-Site Scripting attacks 50320: CLOUD-1653: Improve password strength * Password length constraint previously contained in client-side files has now been removed and is now loaded from the 'Users' scoped config * Minimum password length is increased to 8 characters from 6 previously * The length requirement has been augmented with restrictions on the content, contained in a <password-content> element - A minimum number of uppercase, lowercase, numeric and special characters can be specified - The system-wide default is zero for these new restrictions (i.e. no restrictions) * Alongside the existing <users> element, <network-users> allows the password length or content policies to be tightened for specific networks - Example config is provided in cloud-config.xml showing showing how to do this * Cleaned up existing validation messages and added a custom message based on the content restrictions, where this is configured - Due to ALF-18975 the message appears with raw HTML visible for now * IMPORTANT NOTE: No checking of submitted password values takes place (as before). Users can by-pass the length and content checks by mimiking the web browser themselves. - It is not feasible to add this as part of this work unit, since there are multiple form targets in use, some of which are in the repository. There are no password policies defined in the repository, so these would need adding. 50358: CLOUD-1707: Regress: Copyright logo is incorrectly encoded on Login and My Dashboard pages for French locale 50408: CLOUD-1468: Red bar in Tasks "error loading items". 50409: Fix for CLOUD-1721 50413: Merge of rev 50185 - XSS attack hardening - incorrect use of ?js_string for safe HTML element IDs - should be ?html 50576: Merged alfresco/BRANCHES/DEV/FEATURES/CLOUD1-BUG-FIXSF to alfresco/BRANCHES/DEV/FEATURES/CLOUD1-SECURITY: 50518: ALF-19012: Form validation messages shown in Bubble widgets are not consistent with the input title attribute value 50574: ALF-18975: HTML in forms validation messages appears as raw HTML in the UI * HTML messages added via Alfresco.forms.Form.addValidation() method no longer escape HTML entities in validation messages presented to the user * The 'message' parameter in addValidation() can now be an object with separate 'html' and 'text' properties. Not all methods of displaying messages to the user support HTML. - If no separate HTML and text values are supplied, the message is assumed to be HTML and is converted to text by removing HTML elements via a regexp 50575: CLOUD-1653: Supply separate HTML and text validation messages for password content validation failures, since HTML cannot always be displayed 50577: CLOUD-1653: Use separate HTML and text validation messages for Reset Password and Account Completion pages 50731: CLOUD-1722: Apply config for Aetna specific password policy. 50745: Merged BRANCHES/DEV/CLOUD1 to BRANCHES/DEV/FEATURES/CLOUD1-SECURITY: 50622: Fix for CLOUD-1751 Users searching in their home tenant (or other person related operations) should not be subject to visibility checks 50664: Fix for CLOUD-1751 Users searching in their home tenant (or other person related operations) should not be subject to visibility checks 50748: Merged BRANCHES/DEV/CLOUD1 to BRANCHES/DEV/FEATURES/CLOUD1-SECURITY: 50568: (RECORD ONLY) Merged BRANCHES/DEV/FEATURES/CLOUD1-SECURITY to BRANCHES/DEV/CLOUD1 50423: Merged PATCHES/V4.1.1 to BRANCHES/DEV/FEATURES/CLOUD1-SECURITY 44129: MNT-223: Unbound SOLR result set (from Explorer trashcan query) consumes heap 44130: MNT-223: Unbound SOLR result set (from Explorer trashcan query) consumes heap 44129: MNT-223: Unbound SOLR result set (from Explorer trashcan query) consumes heap Merged PATCHES/V4.1.4 to BRANCHES/DEV/FEATURES/CLOUD1-SECURITY 45951: Fix for ALF-17687 BM-0013: Soak: Run 02: SolrJSONResultSet must preload nodes 50624: (RECORD ONLY) Delete generation of installers in continuous, to allow 'amber' builds 50869: CLOUD-1773: Cloud1Security branch build8. User cannot create site 50872: CLOUD-1653: Ensure password policy is always loaded based on home network, rather than the current context, which could be different. 51156: CLOUD-1653: Add global flag to regexps to ensure that the number of digits and symbols is correctly counted 51175: CLOUD-1682: "Hidden File Rename is Broken": fix and make sure the hidden aspect tests run as part of the build 51183: CLOUD-1682: "Hidden File Rename is Broken": fix up test suite 51187: CLOUD-1682: "Hidden File Rename is Broken": try again 51349: CLOUD-1682: "Hidden File Rename is Broken": further tests, deal with hidden aspect manipulation by clients during rename 51383: CLOUD-1682: "Hidden File Rename is Broken": deal properly with all client controlled hidden aspect cases 51843: CLOUD-1815: OPTIONS request for force.com not returning 200 Removed comment around publicapi URL pattern for CORS filter. 51845: Fixed ALF-19128: Artifact alfresco-repository-*-config.jar contains test files and configuration - Move test files into test-resources 51853: ALF-9096 - CLOUD-1825: Fixed issue with ordering of TransactionSynchronizationAdapter when Activiti job fails 51859: Merged PATCHES/V4.1.4 to HEAD-QA (REMERGE) 47738: ALF-18301 (now MNT-6342): ... NPE ... when debug logging for '...AbstractAsynchronouslyRefreshedCache' Merge note: The fix was not present even though it went to HEAD on 8 March (rev 47807) 51889: Upgrade Spring Surf to 1.2.0-M7 (r1274) 51893: Removed old Activiti libraries that were conflicting with new ones and causing compilation failure. 51895: Merge HEAD-BUG-FIX to HEAD-QA (4.2) 50984: BDE-103: Switch joda-time dependency to core 51896: Upgrade activiti to 5.11-alf-20130627 in POM for Cloud git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@51909 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
2088 lines
84 KiB
Java
2088 lines
84 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.avm;
|
|
|
|
import java.io.IOException;
|
|
import java.io.OutputStream;
|
|
import java.io.Serializable;
|
|
import java.util.ArrayList;
|
|
import java.util.Collection;
|
|
import java.util.Collections;
|
|
import java.util.Date;
|
|
import java.util.HashMap;
|
|
import java.util.HashSet;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
import java.util.SortedMap;
|
|
|
|
import org.alfresco.model.ContentModel;
|
|
import org.alfresco.model.WCMModel;
|
|
import org.alfresco.repo.avm.util.AVMUtil;
|
|
import org.alfresco.repo.domain.PropertyValue;
|
|
import org.alfresco.repo.node.AbstractNodeServiceImpl;
|
|
import org.alfresco.service.cmr.avm.AVMException;
|
|
import org.alfresco.service.cmr.avm.AVMExistsException;
|
|
import org.alfresco.service.cmr.avm.AVMNodeDescriptor;
|
|
import org.alfresco.service.cmr.avm.AVMNotFoundException;
|
|
import org.alfresco.service.cmr.avm.AVMService;
|
|
import org.alfresco.service.cmr.avm.AVMStoreDescriptor;
|
|
import org.alfresco.service.cmr.avm.AVMWrongTypeException;
|
|
import org.alfresco.service.cmr.dictionary.AspectDefinition;
|
|
import org.alfresco.service.cmr.dictionary.ClassDefinition;
|
|
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
|
import org.alfresco.service.cmr.dictionary.DictionaryException;
|
|
import org.alfresco.service.cmr.dictionary.InvalidAspectException;
|
|
import org.alfresco.service.cmr.dictionary.InvalidTypeException;
|
|
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
|
|
import org.alfresco.service.cmr.dictionary.TypeDefinition;
|
|
import org.alfresco.service.cmr.repository.AssociationExistsException;
|
|
import org.alfresco.service.cmr.repository.AssociationRef;
|
|
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
|
import org.alfresco.service.cmr.repository.ContentData;
|
|
import org.alfresco.service.cmr.repository.CyclicChildRelationshipException;
|
|
import org.alfresco.service.cmr.repository.InvalidChildAssociationRefException;
|
|
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
|
|
import org.alfresco.service.cmr.repository.InvalidStoreRefException;
|
|
import org.alfresco.service.cmr.repository.NodeRef;
|
|
import org.alfresco.service.cmr.repository.NodeService;
|
|
import org.alfresco.service.cmr.repository.Path;
|
|
import org.alfresco.service.cmr.repository.StoreExistsException;
|
|
import org.alfresco.service.cmr.repository.StoreRef;
|
|
import org.alfresco.service.cmr.repository.datatype.TypeConversionException;
|
|
import org.alfresco.service.namespace.NamespaceService;
|
|
import org.alfresco.service.namespace.QName;
|
|
import org.alfresco.service.namespace.QNamePattern;
|
|
import org.alfresco.util.Pair;
|
|
import org.apache.commons.logging.Log;
|
|
import org.apache.commons.logging.LogFactory;
|
|
|
|
/**
|
|
* NodeService implementing facade over AVMService.
|
|
* @author britt
|
|
*/
|
|
public class AVMNodeService extends AbstractNodeServiceImpl implements NodeService
|
|
{
|
|
private static Log logger = LogFactory.getLog(AVMNodeService.class);
|
|
|
|
/**
|
|
* Flag for whether policy callbacks are made.
|
|
*/
|
|
private boolean fInvokePolicies = false;
|
|
|
|
/**
|
|
* Reference to AVMService.
|
|
*/
|
|
private AVMService fAVMService;
|
|
|
|
/**
|
|
* Set the AVMService. For Spring.
|
|
* @param service The AVMService instance.
|
|
*/
|
|
public void setAvmService(AVMService service)
|
|
{
|
|
fAVMService = service;
|
|
}
|
|
|
|
/**
|
|
* Default constructor.
|
|
*/
|
|
public AVMNodeService()
|
|
{
|
|
}
|
|
|
|
public void setInvokePolicies(boolean invoke)
|
|
{
|
|
fInvokePolicies = invoke;
|
|
}
|
|
|
|
/**
|
|
* Helper method to convert the <code>Serializable</code> value into a full,
|
|
* persistable {@link PropertyValue}.
|
|
* <p>
|
|
* Where the property definition is null, the value will take on the
|
|
* {@link DataTypeDefinition#ANY generic ANY} value.
|
|
* <p>
|
|
* Where the property definition specifies a multi-valued property but the
|
|
* value provided is not a collection, the value will be wrapped in a collection.
|
|
*
|
|
* @param propertyDef the property dictionary definition, may be null
|
|
* @param value the value, which will be converted according to the definition -
|
|
* may be null
|
|
* @return Returns the persistable property value
|
|
*/
|
|
protected PropertyValue makePropertyValue(PropertyDefinition propertyDef, Serializable value)
|
|
{
|
|
// get property attributes
|
|
QName propertyTypeQName = null;
|
|
if (propertyDef == null) // property not recognised
|
|
{
|
|
// allow it for now - persisting excess properties can be useful sometimes
|
|
propertyTypeQName = DataTypeDefinition.ANY;
|
|
}
|
|
else
|
|
{
|
|
propertyTypeQName = propertyDef.getDataType().getName();
|
|
// check that multi-valued properties are allowed
|
|
boolean isMultiValued = propertyDef.isMultiValued();
|
|
if (isMultiValued && !(value instanceof Collection<?>))
|
|
{
|
|
if (value != null)
|
|
{
|
|
// put the value into a collection
|
|
// the implementation gives back a Serializable list
|
|
value = (Serializable) Collections.singletonList(value);
|
|
}
|
|
}
|
|
else if (!isMultiValued && (value instanceof Collection<?>))
|
|
{
|
|
// we only allow this case if the property type is ANY
|
|
if (!propertyTypeQName.equals(DataTypeDefinition.ANY))
|
|
{
|
|
throw new DictionaryException(
|
|
"A single-valued property of this type may not be a collection: \n" +
|
|
" Property: " + propertyDef + "\n" +
|
|
" Type: " + propertyTypeQName + "\n" +
|
|
" Value: " + value);
|
|
}
|
|
}
|
|
}
|
|
try
|
|
{
|
|
PropertyValue propertyValue = new PropertyValue(propertyTypeQName, value);
|
|
// done
|
|
return propertyValue;
|
|
}
|
|
catch (TypeConversionException e)
|
|
{
|
|
throw new TypeConversionException(
|
|
"The property value is not compatible with the type defined for the property: \n" +
|
|
" property: " + (propertyDef == null ? "unknown" : propertyDef) + "\n" +
|
|
" value: " + value + "\n" +
|
|
" value type: " + value.getClass(),
|
|
e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Extracts the externally-visible property from the {@link PropertyValue propertyValue}.
|
|
*
|
|
* @param propertyDef the model property definition - may be <tt>null</tt>
|
|
* @param propertyValue the persisted property
|
|
* @return Returns the value of the property in the format dictated by the property
|
|
* definition, or null if the property value is null
|
|
*/
|
|
protected Serializable makeSerializableValue(PropertyDefinition propertyDef, PropertyValue propertyValue)
|
|
{
|
|
if (propertyValue == null)
|
|
{
|
|
return null;
|
|
}
|
|
// get property attributes
|
|
QName propertyTypeQName = null;
|
|
if (propertyDef == null)
|
|
{
|
|
// allow this for now
|
|
propertyTypeQName = DataTypeDefinition.ANY;
|
|
}
|
|
else
|
|
{
|
|
propertyTypeQName = propertyDef.getDataType().getName();
|
|
}
|
|
try
|
|
{
|
|
Serializable value = propertyValue.getValue(propertyTypeQName);
|
|
// done
|
|
return value;
|
|
}
|
|
catch (TypeConversionException e)
|
|
{
|
|
throw new TypeConversionException(
|
|
"The property value is not compatible with the type defined for the property: \n" +
|
|
" property: " + (propertyDef == null ? "unknown" : propertyDef) + "\n" +
|
|
" property value: " + propertyValue,
|
|
e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets a list of all available node store references
|
|
*
|
|
* @return Returns a list of store references
|
|
*/
|
|
public List<StoreRef> getStores()
|
|
{
|
|
// For AVM stores we fake up StoreRefs.
|
|
List<AVMStoreDescriptor> stores = fAVMService.getStores();
|
|
List<StoreRef> result = new ArrayList<StoreRef>();
|
|
for (AVMStoreDescriptor desc : stores)
|
|
{
|
|
String name = desc.getName();
|
|
result.add(new StoreRef(StoreRef.PROTOCOL_AVM, name));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Create a new AVM store.
|
|
* @param protocol the implementation protocol
|
|
* @param identifier the protocol-specific identifier
|
|
* @return Returns a reference to the store
|
|
* @throws StoreExistsException
|
|
*/
|
|
public StoreRef createStore(String protocol, String identifier) throws StoreExistsException
|
|
{
|
|
StoreRef result = new StoreRef(StoreRef.PROTOCOL_AVM, identifier);
|
|
// invokeBeforeCreateStore(ContentModel.TYPE_STOREROOT, result);
|
|
try
|
|
{
|
|
fAVMService.createStore(identifier);
|
|
NodeRef rootRef = getRootNode(result);
|
|
addAspect(rootRef, ContentModel.ASPECT_ROOT,
|
|
Collections.<QName, Serializable>emptyMap());
|
|
// invokeOnCreateStore(rootRef);
|
|
return result;
|
|
}
|
|
catch (AVMExistsException e)
|
|
{
|
|
throw new StoreExistsException(result, e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @throws UnsupportedOperationException Always
|
|
*/
|
|
public void deleteStore(StoreRef storeRef) throws InvalidStoreRefException
|
|
{
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
|
|
/**
|
|
* Does the indicated store exist?
|
|
* @param storeRef a reference to the store to look for
|
|
* @return Returns true if the store exists, otherwise false
|
|
*/
|
|
public boolean exists(StoreRef storeRef)
|
|
{
|
|
return fAVMService.getStore(storeRef.getIdentifier()) != null;
|
|
}
|
|
|
|
/**
|
|
* @param nodeRef a reference to the node to look for
|
|
* @return Returns true if the node exists, otherwise false
|
|
*/
|
|
public boolean exists(NodeRef nodeRef)
|
|
{
|
|
Pair<Integer, String> avmInfo = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
int version = avmInfo.getFirst();
|
|
String avmPath = avmInfo.getSecond();
|
|
return fAVMService.lookup(version, avmPath) != null;
|
|
}
|
|
|
|
/**
|
|
* Gets the ID of the last transaction that caused the node to change. This includes
|
|
* deletions, so it is possible that the node being referenced no longer exists.
|
|
* If the node never existed, then null is returned.
|
|
*
|
|
* @param nodeRef a reference to a current or previously existing node
|
|
* @return Returns the status of the node, or null if the node never existed
|
|
*/
|
|
public NodeRef.Status getNodeStatus(NodeRef nodeRef)
|
|
{
|
|
// TODO Need to find out if this is important and if so
|
|
// need to capture Transaction IDs.
|
|
return new NodeRef.Status(null, nodeRef, "Unknown", null, !exists(nodeRef));
|
|
}
|
|
|
|
/**
|
|
* @throws UnsupportedOperationException always
|
|
*/
|
|
@Override
|
|
public NodeRef getNodeRef(Long nodeId)
|
|
{
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
|
|
/**
|
|
* @param storeRef a reference to an existing store
|
|
* @return Returns a reference to the root node of the store
|
|
* @throws InvalidStoreRefException if the store could not be found
|
|
*/
|
|
public NodeRef getRootNode(StoreRef storeRef) throws InvalidStoreRefException
|
|
{
|
|
String storeName = storeRef.getIdentifier();
|
|
if (fAVMService.getStore(storeName) != null)
|
|
{
|
|
return AVMNodeConverter.ToNodeRef(-1, storeName + ":/");
|
|
}
|
|
else
|
|
{
|
|
throw new InvalidStoreRefException(storeName +":/" + " not found.", storeRef);
|
|
}
|
|
}
|
|
|
|
public Set<NodeRef> getAllRootNodes(StoreRef storeRef)
|
|
{
|
|
return Collections.singleton(getRootNode(storeRef));
|
|
}
|
|
|
|
/**
|
|
* @see #createNode(NodeRef, QName, QName, QName, Map)
|
|
*/
|
|
public ChildAssociationRef createNode(
|
|
NodeRef parentRef,
|
|
QName assocTypeQName,
|
|
QName assocQName,
|
|
QName nodeTypeQName)
|
|
throws InvalidNodeRefException, InvalidTypeException
|
|
{
|
|
return createNode(parentRef,
|
|
assocTypeQName,
|
|
assocQName,
|
|
nodeTypeQName,
|
|
new HashMap<QName, Serializable>());
|
|
}
|
|
|
|
/**
|
|
* Creates a new, non-abstract, real node as a primary child of the given parent node.
|
|
*
|
|
* @param parentRef the parent node
|
|
* @param assocTypeQName the type of the association to create. This is used
|
|
* for verification against the data dictionary.
|
|
* @param assocQName the qualified name of the association
|
|
* @param nodeTypeQName a reference to the node type
|
|
* @param properties optional map of properties to keyed by their qualified names
|
|
* @return Returns a reference to the newly created child association
|
|
* @throws InvalidNodeRefException if the parent reference is invalid
|
|
* @throws InvalidTypeException if the node type reference is not recognised
|
|
*
|
|
* @see org.alfresco.service.cmr.dictionary.DictionaryService
|
|
*/
|
|
@SuppressWarnings("deprecation")
|
|
public ChildAssociationRef createNode(
|
|
NodeRef parentRef,
|
|
QName assocTypeQName,
|
|
QName assocQName,
|
|
QName nodeTypeQName,
|
|
Map<QName, Serializable> properties)
|
|
throws InvalidNodeRefException, InvalidTypeException
|
|
{
|
|
// AVM stores only allow simple child associations.
|
|
if (!assocTypeQName.equals(ContentModel.ASSOC_CONTAINS))
|
|
{
|
|
throw new InvalidTypeException(assocTypeQName);
|
|
}
|
|
String nodeName = assocQName.getLocalName();
|
|
Pair<Integer, String> avmVersionPath = AVMNodeConverter.ToAVMVersionPath(parentRef);
|
|
int version = avmVersionPath.getFirst();
|
|
if (version >= 0)
|
|
{
|
|
throw new InvalidNodeRefException("Read only store.", parentRef);
|
|
}
|
|
String avmPath = avmVersionPath.getSecond();
|
|
// Invoke policy behavior.
|
|
// invokeBeforeUpdateNode(parentRef);
|
|
// invokeBeforeCreateNode(parentRef, assocTypeQName, assocQName, nodeTypeQName);
|
|
// Look up the type definition in the dictionary.
|
|
TypeDefinition nodeTypeDef = dictionaryService.getType(nodeTypeQName);
|
|
// Do the creates for supported types, or error out.
|
|
try
|
|
{
|
|
if (nodeTypeQName.equals(WCMModel.TYPE_AVM_PLAIN_FOLDER) ||
|
|
nodeTypeQName.equals(ContentModel.TYPE_FOLDER))
|
|
{
|
|
fAVMService.createDirectory(avmPath, nodeName);
|
|
}
|
|
else if (nodeTypeQName.equals(WCMModel.TYPE_AVM_PLAIN_CONTENT) ||
|
|
nodeTypeQName.equals(ContentModel.TYPE_CONTENT))
|
|
{
|
|
OutputStream os = fAVMService.createFile(avmPath, nodeName);
|
|
try
|
|
{
|
|
if (os != null) { os.close(); }
|
|
}
|
|
catch (IOException ioe)
|
|
{
|
|
logger.warn("Failed to close output stream when creating file '"+AVMUtil.extendAVMPath(avmPath, nodeName)+"'"+ioe.getMessage());
|
|
}
|
|
}
|
|
else if (nodeTypeQName.equals(WCMModel.TYPE_AVM_LAYERED_CONTENT))
|
|
{
|
|
NodeRef indirection = (NodeRef)properties.get(WCMModel.PROP_AVM_FILE_INDIRECTION);
|
|
if (indirection == null)
|
|
{
|
|
throw new InvalidTypeException("No Indirection Property", nodeTypeQName);
|
|
}
|
|
Pair<Integer, String> indVersionPath = AVMNodeConverter.ToAVMVersionPath(indirection);
|
|
fAVMService.createLayeredFile(indVersionPath.getSecond(), avmPath, nodeName);
|
|
}
|
|
else if (nodeTypeQName.equals(WCMModel.TYPE_AVM_LAYERED_FOLDER))
|
|
{
|
|
NodeRef indirection = (NodeRef)properties.get(WCMModel.PROP_AVM_DIR_INDIRECTION);
|
|
if (indirection == null)
|
|
{
|
|
throw new InvalidTypeException("No Indirection Property.", nodeTypeQName);
|
|
}
|
|
Pair<Integer, String> indVersionPath = AVMNodeConverter.ToAVMVersionPath(indirection);
|
|
fAVMService.createLayeredDirectory(indVersionPath.getSecond(), avmPath, nodeName);
|
|
}
|
|
else
|
|
{
|
|
throw new InvalidTypeException("Invalid node type for AVM.", nodeTypeQName);
|
|
}
|
|
properties.putAll(getDefaultProperties(nodeTypeDef));
|
|
addDefaultAspects(nodeTypeDef, avmPath, properties);
|
|
}
|
|
catch (AVMNotFoundException e)
|
|
{
|
|
throw new InvalidNodeRefException(avmPath + " not found.", parentRef);
|
|
}
|
|
catch (AVMExistsException e)
|
|
{
|
|
throw new InvalidNodeRefException("Child " + nodeName + " exists", parentRef);
|
|
}
|
|
String newAVMPath = AVMNodeConverter.ExtendAVMPath(avmPath, nodeName);
|
|
NodeRef childRef = AVMNodeConverter.ToNodeRef(-1, newAVMPath);
|
|
properties.putAll(getDefaultProperties(nodeTypeDef));
|
|
addDefaultAspects(nodeTypeDef, newAVMPath, properties);
|
|
Map<QName, PropertyValue> props = new HashMap<QName, PropertyValue>();
|
|
for (Map.Entry<QName, Serializable> entry : properties.entrySet())
|
|
{
|
|
QName propertyQName = entry.getKey();
|
|
if (isBuiltInProperty(propertyQName))
|
|
{
|
|
continue;
|
|
}
|
|
Serializable value = entry.getValue();
|
|
PropertyDefinition propertyDef = dictionaryService.getProperty(propertyQName);
|
|
PropertyValue propertyValue = makePropertyValue(propertyDef, value);
|
|
props.put(propertyQName, propertyValue);
|
|
}
|
|
fAVMService.setNodeProperties(newAVMPath, props);
|
|
ChildAssociationRef ref =
|
|
new ChildAssociationRef(assocTypeQName,
|
|
parentRef,
|
|
assocQName,
|
|
childRef,
|
|
true,
|
|
-1);
|
|
// invokeOnCreateNode(ref);
|
|
// invokeOnUpdateNode(parentRef);
|
|
// if (properties.size() != 0)
|
|
// {
|
|
// invokeOnUpdateProperties(childRef, new HashMap<QName, Serializable>(), properties);
|
|
// }
|
|
return ref;
|
|
}
|
|
|
|
/**
|
|
* Moves the primary location of the given node.
|
|
* <p>
|
|
* This involves changing the node's primary parent and possibly the name of the
|
|
* association referencing it.
|
|
* <p>
|
|
* If the new parent is in a different store from the original, then the entire
|
|
* node hierarchy is moved to the new store. Inter-store associations are not
|
|
* affected.
|
|
*
|
|
* @param nodeToMoveRef the node to move
|
|
* @param newParentRef the new parent of the moved node
|
|
* @param assocTypeQName the type of the association to create. This is used
|
|
* for verification against the data dictionary.
|
|
* @param assocQName the qualified name of the new child association
|
|
* @return Returns a reference to the newly created child association
|
|
* @throws InvalidNodeRefException if either the parent node or move node reference is invalid
|
|
* @throws CyclicChildRelationshipException if the child partakes in a cyclic relationship after the add
|
|
*
|
|
* @see #getPrimaryParent(NodeRef)
|
|
*/
|
|
public ChildAssociationRef moveNode(
|
|
NodeRef nodeToMoveRef,
|
|
NodeRef newParentRef,
|
|
QName assocTypeQName,
|
|
QName assocQName)
|
|
throws InvalidNodeRefException
|
|
{
|
|
// AVM stores only allow simple child associations.
|
|
if (!assocTypeQName.equals(ContentModel.ASSOC_CONTAINS))
|
|
{
|
|
throw new InvalidTypeException(assocTypeQName);
|
|
}
|
|
// Extract the parts from the source.
|
|
Pair<Integer, String> src = AVMNodeConverter.ToAVMVersionPath(nodeToMoveRef);
|
|
int srcVersion = src.getFirst();
|
|
if (srcVersion >= 0)
|
|
{
|
|
throw new InvalidNodeRefException("Read Only Store.", nodeToMoveRef);
|
|
}
|
|
String srcPath = src.getSecond();
|
|
String [] splitSrc = null;
|
|
try
|
|
{
|
|
splitSrc = AVMNodeConverter.SplitBase(srcPath);
|
|
}
|
|
catch (AVMException e)
|
|
{
|
|
throw new InvalidNodeRefException("Invalid src path.", nodeToMoveRef);
|
|
}
|
|
String srcParent = splitSrc[0];
|
|
if (srcParent == null)
|
|
{
|
|
throw new InvalidNodeRefException("Cannot rename root node.", nodeToMoveRef);
|
|
}
|
|
String srcName = splitSrc[1];
|
|
// Extract and setup the parts of the destination.
|
|
Pair<Integer, String> dst = AVMNodeConverter.ToAVMVersionPath(newParentRef);
|
|
if (dst.getFirst() >= 0)
|
|
{
|
|
throw new InvalidNodeRefException("Read Only Store.", newParentRef);
|
|
}
|
|
String dstParent = dst.getSecond();
|
|
String dstName = assocQName.getLocalName();
|
|
// TODO Invoke policy behavior. Not quite sure how to translate this.
|
|
NodeRef oldParentRef = AVMNodeConverter.ToNodeRef(-1, srcParent);
|
|
ChildAssociationRef oldAssocRef =
|
|
new ChildAssociationRef(assocTypeQName,
|
|
oldParentRef,
|
|
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, srcName),
|
|
nodeToMoveRef,
|
|
true,
|
|
-1);
|
|
// invokeBeforeDeleteChildAssociation(oldAssocRef);
|
|
String dstPath = AVMNodeConverter.ExtendAVMPath(dstParent, dstName);
|
|
NodeRef newChildRef = AVMNodeConverter.ToNodeRef(-1, dstPath);
|
|
// invokeBeforeUpdateNode(oldParentRef);
|
|
// invokeBeforeUpdateNode(newParentRef);
|
|
// Actually perform the rename and return a pseudo
|
|
// ChildAssociationRef.
|
|
try
|
|
{
|
|
fAVMService.rename(srcParent, srcName, dstParent, dstName);
|
|
ChildAssociationRef newAssocRef =
|
|
new ChildAssociationRef(assocTypeQName,
|
|
newParentRef,
|
|
assocQName,
|
|
newChildRef,
|
|
true,
|
|
-1);
|
|
invokeOnMoveNode(oldAssocRef, newAssocRef);
|
|
// invokeOnCreateChildAssociation(newAssocRef);
|
|
// invokeOnDeleteChildAssociation(oldAssocRef);
|
|
// invokeOnUpdateNode(oldParentRef);
|
|
// invokeOnUpdateNode(newParentRef);
|
|
return newAssocRef;
|
|
}
|
|
catch (AVMNotFoundException e)
|
|
{
|
|
throw new InvalidNodeRefException("Non existent node.", nodeToMoveRef);
|
|
}
|
|
catch (AVMExistsException e)
|
|
{
|
|
throw new InvalidNodeRefException("Target already exists.", newParentRef);
|
|
}
|
|
catch (AVMException e)
|
|
{
|
|
throw new InvalidNodeRefException("Illegal move.", nodeToMoveRef);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set the ordering index of the child association. This affects the ordering of
|
|
* of the return values of methods that return a set of children or child
|
|
* associations.
|
|
*
|
|
* @param childAssocRef the child association that must be moved in the order
|
|
* @param index an arbitrary index that will affect the return order
|
|
*
|
|
* @see #getChildAssocs(NodeRef)
|
|
* @see #getChildAssocs(NodeRef, QNamePattern, QNamePattern)
|
|
* @see ChildAssociationRef#getNthSibling()
|
|
*/
|
|
public void setChildAssociationIndex(
|
|
ChildAssociationRef childAssocRef,
|
|
int index)
|
|
throws InvalidChildAssociationRefException
|
|
{
|
|
// TODO We'll keep this a no-op unless there's a
|
|
// compelling reason to implement this capability
|
|
// for the AVM repository.
|
|
}
|
|
|
|
/**
|
|
* @param nodeRef
|
|
* @return Returns the type name
|
|
* @throws InvalidNodeRefException if the node could not be found
|
|
*
|
|
* @see org.alfresco.service.cmr.dictionary.DictionaryService
|
|
*/
|
|
public QName getType(NodeRef nodeRef) throws InvalidNodeRefException
|
|
{
|
|
Pair<Integer, String> avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
AVMNodeDescriptor desc = fAVMService.lookup(avmVersionPath.getFirst(),
|
|
avmVersionPath.getSecond());
|
|
if (desc == null)
|
|
{
|
|
throw new InvalidNodeRefException(avmVersionPath.getSecond() + " not found.", nodeRef);
|
|
}
|
|
if (desc.isPlainDirectory())
|
|
{
|
|
return WCMModel.TYPE_AVM_PLAIN_FOLDER;
|
|
}
|
|
else if (desc.isPlainFile())
|
|
{
|
|
return WCMModel.TYPE_AVM_PLAIN_CONTENT;
|
|
}
|
|
else if (desc.isLayeredDirectory())
|
|
{
|
|
return WCMModel.TYPE_AVM_LAYERED_FOLDER;
|
|
}
|
|
else
|
|
{
|
|
return WCMModel.TYPE_AVM_LAYERED_CONTENT;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Re-sets the type of the node. Can be called in order specialise a node to a sub-type.
|
|
*
|
|
* This should be used with caution since calling it changes the type of the node and thus
|
|
* implies a different set of aspects, properties and associations. It is the calling codes
|
|
* responsibility to ensure that the node is in a approriate state after changing the type.
|
|
*
|
|
* @param nodeRef the node reference
|
|
* @param typeQName the type QName
|
|
*
|
|
* @since 1.1
|
|
*/
|
|
public void setType(NodeRef nodeRef, QName typeQName) throws InvalidNodeRefException
|
|
{
|
|
throw new UnsupportedOperationException("AVM Types are immutable.");
|
|
}
|
|
|
|
/**
|
|
* Applies an aspect to the given node. After this method has been called,
|
|
* the node with have all the aspect-related properties present
|
|
*
|
|
* @param nodeRef
|
|
* @param aspectTypeQName the aspect to apply to the node
|
|
* @param aspectProperties a minimum of the mandatory properties required for
|
|
* the aspect
|
|
* @throws InvalidNodeRefException
|
|
* @throws InvalidAspectException if the class reference is not to a valid aspect
|
|
*
|
|
* @see org.alfresco.service.cmr.dictionary.DictionaryService#getAspect(QName)
|
|
* @see org.alfresco.service.cmr.dictionary.ClassDefinition#getProperties()
|
|
*/
|
|
public void addAspect(
|
|
NodeRef nodeRef,
|
|
QName aspectTypeQName,
|
|
Map<QName, Serializable> aspectProperties)
|
|
throws InvalidNodeRefException, InvalidAspectException
|
|
{
|
|
// Check that the aspect exists.
|
|
AspectDefinition aspectDef = this.dictionaryService.getAspect(aspectTypeQName);
|
|
if (aspectDef == null)
|
|
{
|
|
throw new InvalidAspectException("The aspect is invalid: " + aspectTypeQName,
|
|
aspectTypeQName);
|
|
}
|
|
// Invoke policy behaviors.
|
|
// invokeBeforeUpdateNode(nodeRef);
|
|
// invokeBeforeAddAspect(nodeRef, aspectTypeQName);
|
|
// Crack the nodeRef.
|
|
Pair<Integer, String> avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
int version = avmVersionPath.getFirst();
|
|
if (version >= 0)
|
|
{
|
|
throw new InvalidNodeRefException("Read Only node.", nodeRef);
|
|
}
|
|
String avmPath = avmVersionPath.getSecond();
|
|
// Accumulate properties.
|
|
Map<QName, Serializable> properties = new HashMap<QName, Serializable>();
|
|
// Add the supplied properties.
|
|
if (aspectProperties != null)
|
|
{
|
|
properties.putAll(aspectProperties);
|
|
}
|
|
// Now set any unspecified default properties for the aspect.
|
|
Map<QName, Serializable> defaultProperties = getDefaultProperties(aspectDef);
|
|
properties.putAll(defaultProperties);
|
|
// Now add any cascading aspects.
|
|
addDefaultAspects(aspectDef, avmPath, properties);
|
|
// Set the property values on the AVM Node.
|
|
if (properties.size() != 0)
|
|
{
|
|
Map<QName, PropertyValue> props = new HashMap<QName, PropertyValue>();
|
|
for (Map.Entry<QName, Serializable> entry : properties.entrySet())
|
|
{
|
|
QName propertyQName = entry.getKey();
|
|
if (isBuiltInProperty(propertyQName))
|
|
{
|
|
continue;
|
|
}
|
|
Serializable value = entry.getValue();
|
|
PropertyDefinition propertyDef = dictionaryService.getProperty(propertyQName);
|
|
PropertyValue propertyValue = makePropertyValue(propertyDef, value);
|
|
props.put(propertyQName, propertyValue);
|
|
}
|
|
if (props.size() != 0)
|
|
{
|
|
fAVMService.setNodeProperties(avmPath, props);
|
|
}
|
|
}
|
|
if (isBuiltinAspect(aspectTypeQName))
|
|
{
|
|
// No more work to do in this case.
|
|
return;
|
|
}
|
|
try
|
|
{
|
|
fAVMService.addAspect(avmPath, aspectTypeQName);
|
|
// Invoke policy behaviors.
|
|
// invokeOnUpdateNode(nodeRef);
|
|
// invokeOnAddAspect(nodeRef, aspectTypeQName);
|
|
}
|
|
catch (AVMNotFoundException e)
|
|
{
|
|
throw new InvalidNodeRefException(nodeRef);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add any aspects that are mandatory for the ClassDefinition.
|
|
* @param classDef The ClassDefinition.
|
|
* @param path The path to the AVMNode.
|
|
* @param properties The in/out map of accumulated properties.
|
|
*/
|
|
private void addDefaultAspects(ClassDefinition classDef, String path,
|
|
Map<QName, Serializable> properties)
|
|
{
|
|
NodeRef nodeRef = AVMNodeConverter.ToNodeRef(-1, path);
|
|
// Get mandatory aspects.
|
|
List<AspectDefinition> defaultAspectDefs = classDef.getDefaultAspects();
|
|
// add all the aspects (and there dependent aspects recursively).
|
|
for (AspectDefinition def : defaultAspectDefs)
|
|
{
|
|
// invokeBeforeAddAspect(nodeRef, def.getName());
|
|
addAspect(nodeRef, def.getName(), Collections.<QName, Serializable>emptyMap());
|
|
properties.putAll(getDefaultProperties(def));
|
|
// invokeOnAddAspect(nodeRef, def.getName());
|
|
// recurse
|
|
addDefaultAspects(def, path, properties);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove an aspect and all related properties from a node
|
|
*
|
|
* @param nodeRef
|
|
* @param aspectTypeQName the type of aspect to remove
|
|
* @throws InvalidNodeRefException if the node could not be found
|
|
* @throws InvalidAspectException if the the aspect is unknown or if the
|
|
* aspect is mandatory for the <b>class</b> of the <b>node</b>
|
|
*/
|
|
public void removeAspect(NodeRef nodeRef, QName aspectTypeQName)
|
|
throws InvalidNodeRefException, InvalidAspectException
|
|
{
|
|
// Invoke policy behaviors.
|
|
// invokeBeforeUpdateNode(nodeRef);
|
|
// invokeBeforeRemoveAspect(nodeRef, aspectTypeQName);
|
|
AspectDefinition def = dictionaryService.getAspect(aspectTypeQName);
|
|
if (def == null)
|
|
{
|
|
throw new InvalidAspectException(aspectTypeQName);
|
|
}
|
|
if (isBuiltinAspect(aspectTypeQName))
|
|
{
|
|
// TODO shouldn't we be throwing some kind of exception here.
|
|
return;
|
|
}
|
|
Pair<Integer, String> avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
int version = avmVersionPath.getFirst();
|
|
if (version >= 0)
|
|
{
|
|
throw new InvalidNodeRefException("Read Only Node.", nodeRef);
|
|
}
|
|
String path = avmVersionPath.getSecond();
|
|
try
|
|
{
|
|
if (fAVMService.hasAspect(-1, path, aspectTypeQName))
|
|
{
|
|
fAVMService.removeAspect(path, aspectTypeQName);
|
|
Map<QName, PropertyDefinition> propDefs = def.getProperties();
|
|
for (QName propertyName : propDefs.keySet())
|
|
{
|
|
fAVMService.deleteNodeProperty(path, propertyName);
|
|
}
|
|
}
|
|
// Invoke policy behaviors.
|
|
// invokeOnUpdateNode(nodeRef);
|
|
// invokeOnRemoveAspect(nodeRef, aspectTypeQName);
|
|
}
|
|
catch (AVMNotFoundException e)
|
|
{
|
|
throw new InvalidNodeRefException(nodeRef);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Determines if a given aspect is present on a node. Aspects may only be
|
|
* removed if they are <b>NOT</b> mandatory.
|
|
*
|
|
* @param nodeRef
|
|
* @param aspectTypeQName
|
|
* @return Returns true if the aspect has been applied to the given node,
|
|
* otherwise false
|
|
* @throws InvalidNodeRefException if the node could not be found
|
|
* @throws InvalidAspectException if the aspect reference is invalid
|
|
*/
|
|
public boolean hasAspect(NodeRef nodeRef, QName aspectTypeQName)
|
|
throws InvalidNodeRefException, InvalidAspectException
|
|
{
|
|
Pair<Integer, String> avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
int version = avmVersionPath.getFirst();
|
|
String path = avmVersionPath.getSecond();
|
|
if (isBuiltinAspect(aspectTypeQName))
|
|
{
|
|
return true;
|
|
}
|
|
return fAVMService.hasAspect(version, path, aspectTypeQName);
|
|
}
|
|
|
|
private static QName [] fgBuiltinAspects = new QName[] { ContentModel.ASPECT_AUDITABLE,
|
|
ContentModel.ASPECT_REFERENCEABLE };
|
|
|
|
private boolean isBuiltinAspect(QName aspectQName)
|
|
{
|
|
for (QName builtin : fgBuiltinAspects)
|
|
{
|
|
if (builtin.equals(aspectQName))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @param nodeRef
|
|
* @return Returns a set of all aspects applied to the node, including mandatory
|
|
* aspects
|
|
* @throws InvalidNodeRefException if the node could not be found
|
|
*/
|
|
public Set<QName> getAspects(NodeRef nodeRef) throws InvalidNodeRefException
|
|
{
|
|
Pair<Integer, String> avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
int version = avmVersionPath.getFirst();
|
|
String path = avmVersionPath.getSecond();
|
|
Set<QName> result = new HashSet<QName>();
|
|
// Add the builtin ones.
|
|
for (QName name : fgBuiltinAspects)
|
|
{
|
|
result.add(name);
|
|
}
|
|
try
|
|
{
|
|
for (QName name : fAVMService.getAspects(version, path))
|
|
{
|
|
result.add(name);
|
|
}
|
|
return result;
|
|
}
|
|
catch (AVMNotFoundException e)
|
|
{
|
|
throw new InvalidNodeRefException(nodeRef);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Deletes the given node.
|
|
* <p>
|
|
* All associations (both children and regular node associations)
|
|
* will be deleted, and where the given node is the primary parent,
|
|
* the children will also be cascade deleted.
|
|
*
|
|
* @param nodeRef reference to a node within a store
|
|
* @throws InvalidNodeRefException if the reference given is invalid
|
|
*/
|
|
public void deleteNode(NodeRef nodeRef) throws InvalidNodeRefException
|
|
{
|
|
// Invoke policy behaviors.
|
|
// invokeBeforeDeleteNode(nodeRef);
|
|
Pair<Integer, String> avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
if (avmVersionPath.getFirst() != -1)
|
|
{
|
|
throw new InvalidNodeRefException("Read only store.", nodeRef);
|
|
}
|
|
String [] avmPathBase = AVMNodeConverter.SplitBase(avmVersionPath.getSecond());
|
|
if (avmPathBase[0] == null)
|
|
{
|
|
throw new InvalidNodeRefException("Cannot delete root node.", nodeRef);
|
|
}
|
|
try
|
|
{
|
|
// QName nodeTypeQName = getType(nodeRef);
|
|
// Set<QName> aspects = getAspects(nodeRef);
|
|
fAVMService.removeNode(avmPathBase[0], avmPathBase[1]);
|
|
// ChildAssociationRef childAssocRef =
|
|
// new ChildAssociationRef(ContentModel.ASSOC_CHILDREN,
|
|
// AVMNodeConverter.ToNodeRef(-1, avmPathBase[0]),
|
|
// QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI,
|
|
// avmPathBase[1]),
|
|
// nodeRef);
|
|
// invokeOnDeleteNode(childAssocRef, nodeTypeQName, aspects, false);
|
|
}
|
|
catch (AVMNotFoundException e)
|
|
{
|
|
throw new InvalidNodeRefException(avmVersionPath.getSecond() +" not found.", nodeRef);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Makes a parent-child association between the given nodes. Both nodes must belong to the same store.
|
|
* <p>
|
|
*
|
|
* @param parentRef
|
|
* @param childRef
|
|
* @param assocTypeQName the qualified name of the association type as defined in the datadictionary
|
|
* @param qname the qualified name of the association
|
|
* @return Returns a reference to the newly created child association
|
|
* @throws InvalidNodeRefException if the parent or child nodes could not be found
|
|
* @throws CyclicChildRelationshipException if the child partakes in a cyclic relationship after the add
|
|
*/
|
|
public ChildAssociationRef addChild(
|
|
NodeRef parentRef,
|
|
NodeRef childRef,
|
|
QName assocTypeQName,
|
|
QName qname) throws InvalidNodeRefException
|
|
{
|
|
return addChild(Collections.singletonList(parentRef), childRef, assocTypeQName, qname).get(0);
|
|
}
|
|
|
|
/**
|
|
* Associates a given child node with a given collection of parents. All nodes must belong to the same store.
|
|
* <p>
|
|
*
|
|
*
|
|
* @param parentRefs
|
|
* @param childRef
|
|
* @param assocTypeQName the qualified name of the association type as defined in the datadictionary
|
|
* @param qname the qualified name of the association
|
|
* @return Returns a reference to the newly created child association
|
|
* @throws InvalidNodeRefException if the parent or child nodes could not be found
|
|
* @throws CyclicChildRelationshipException if the child partakes in a cyclic relationship after the add
|
|
*/
|
|
public List<ChildAssociationRef> addChild(
|
|
Collection<NodeRef> parentRefs,
|
|
NodeRef childRef,
|
|
QName assocTypeQName,
|
|
QName qname) throws InvalidNodeRefException
|
|
{
|
|
Pair<Integer, String> childVersionPath = AVMNodeConverter.ToAVMVersionPath(childRef);
|
|
AVMNodeDescriptor child = fAVMService.lookup(childVersionPath.getFirst(),
|
|
childVersionPath.getSecond());
|
|
if (child == null)
|
|
{
|
|
throw new InvalidNodeRefException(childVersionPath.getSecond() + " not found.", childRef);
|
|
}
|
|
|
|
List<ChildAssociationRef> childAssociationRefs = new ArrayList<ChildAssociationRef>(parentRefs.size());
|
|
for (NodeRef parentRef : parentRefs)
|
|
{
|
|
Pair<Integer, String> parentVersionPath = AVMNodeConverter.ToAVMVersionPath(parentRef);
|
|
if (parentVersionPath.getFirst() >= 0)
|
|
{
|
|
throw new InvalidNodeRefException("Read Only.", parentRef);
|
|
}
|
|
try
|
|
{
|
|
fAVMService.link(parentVersionPath.getSecond(), qname.getLocalName(), child);
|
|
ChildAssociationRef newChild = new ChildAssociationRef(assocTypeQName, parentRef, qname,
|
|
AVMNodeConverter.ToNodeRef(-1, AVMNodeConverter.ExtendAVMPath(parentVersionPath.getSecond(),
|
|
qname.getLocalName())));
|
|
childAssociationRefs.add(newChild);
|
|
}
|
|
catch (AVMException e)
|
|
{
|
|
throw new InvalidNodeRefException("Could not link.", childRef);
|
|
}
|
|
}
|
|
return childAssociationRefs;
|
|
}
|
|
|
|
/**
|
|
* Severs all parent-child relationships between two nodes.
|
|
* <p>
|
|
* The child node will be cascade deleted if one of the associations was the
|
|
* primary association, i.e. the one with which the child node was created.
|
|
*
|
|
* @param parentRef the parent end of the association
|
|
* @param childRef the child end of the association
|
|
* @throws InvalidNodeRefException if the parent or child nodes could not be found
|
|
*/
|
|
public void removeChild(NodeRef parentRef, NodeRef childRef) throws InvalidNodeRefException
|
|
{
|
|
Pair<Integer, String> parentVersionPath = AVMNodeConverter.ToAVMVersionPath(parentRef);
|
|
if (parentVersionPath.getFirst() >= 0)
|
|
{
|
|
throw new InvalidNodeRefException("Read only store.", parentRef);
|
|
}
|
|
Pair<Integer, String> childVersionPath = AVMNodeConverter.ToAVMVersionPath(childRef);
|
|
if (childVersionPath.getFirst() >= 0)
|
|
{
|
|
throw new InvalidNodeRefException("Read only store.", childRef);
|
|
}
|
|
String parentPath = parentVersionPath.getSecond();
|
|
String childPath = childVersionPath.getSecond();
|
|
String [] childPathBase = AVMNodeConverter.SplitBase(childPath);
|
|
if (childPathBase[0] == null || !childPathBase[0].equals(parentPath))
|
|
{
|
|
throw new InvalidNodeRefException(childPath + " not a child of " + parentPath, childRef);
|
|
}
|
|
try
|
|
{
|
|
// ChildAssociationRef assocRef =
|
|
// new ChildAssociationRef(ContentModel.ASSOC_CHILDREN,
|
|
// AVMNodeConverter.ToNodeRef(-1, parentPath),
|
|
// QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI,
|
|
// childPathBase[1]),
|
|
// AVMNodeConverter.ToNodeRef(-1, childPath));
|
|
// invokeBeforeDeleteChildAssociation(assocRef);
|
|
fAVMService.removeNode(childPathBase[0], childPathBase[1]);
|
|
// invokeOnDeleteChildAssociation(assocRef);
|
|
// invokeOnUpdateNode(AVMNodeConverter.ToNodeRef(-1, parentPath));
|
|
}
|
|
catch (AVMNotFoundException e)
|
|
{
|
|
throw new InvalidNodeRefException(childPathBase[1] + " not found in " + childPathBase[0],
|
|
childRef);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* TODO: Check implementation
|
|
*/
|
|
public boolean removeChildAssociation(ChildAssociationRef childAssocRef)
|
|
{
|
|
NodeRef parentRef = childAssocRef.getParentRef();
|
|
NodeRef childRef = childAssocRef.getChildRef();
|
|
Pair<Integer, String> parentVersionPath = AVMNodeConverter.ToAVMVersionPath(parentRef);
|
|
if (parentVersionPath.getFirst() >= 0)
|
|
{
|
|
throw new InvalidNodeRefException("Read only store.", parentRef);
|
|
}
|
|
Pair<Integer, String> childVersionPath = AVMNodeConverter.ToAVMVersionPath(childRef);
|
|
if (childVersionPath.getFirst() >= 0)
|
|
{
|
|
throw new InvalidNodeRefException("Read only store.", childRef);
|
|
}
|
|
String parentPath = parentVersionPath.getSecond();
|
|
String childPath = childVersionPath.getSecond();
|
|
String [] childPathBase = AVMNodeConverter.SplitBase(childPath);
|
|
if (childPathBase[0] == null || !childPathBase[0].equals(parentPath))
|
|
{
|
|
return false;
|
|
}
|
|
try
|
|
{
|
|
fAVMService.removeNode(childPathBase[0], childPathBase[1]);
|
|
return true;
|
|
}
|
|
catch (AVMNotFoundException e)
|
|
{
|
|
throw new InvalidNodeRefException("Not found.", childRef);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* TODO: Implement
|
|
*/
|
|
public boolean removeSecondaryChildAssociation(ChildAssociationRef childAssocRef)
|
|
{
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
|
|
/**
|
|
* @param nodeRef
|
|
* @return Returns all properties keyed by their qualified name
|
|
* @throws InvalidNodeRefException if the node could not be found
|
|
*/
|
|
public Map<QName, Serializable> getProperties(NodeRef nodeRef) throws InvalidNodeRefException
|
|
{
|
|
Pair<Integer, String> avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
Map<QName, PropertyValue> props = null;
|
|
AVMNodeDescriptor desc = fAVMService.lookup(avmVersionPath.getFirst(),
|
|
avmVersionPath.getSecond());
|
|
try
|
|
{
|
|
props = fAVMService.getNodeProperties(avmVersionPath.getFirst(),
|
|
avmVersionPath.getSecond());
|
|
}
|
|
catch (AVMNotFoundException e)
|
|
{
|
|
throw new InvalidNodeRefException(avmVersionPath.getSecond() + " not found.", nodeRef);
|
|
}
|
|
Map<QName, Serializable> result = new HashMap<QName, Serializable>();
|
|
for (QName qName : props.keySet())
|
|
{
|
|
PropertyValue value = props.get(qName);
|
|
PropertyDefinition def = dictionaryService.getProperty(qName);
|
|
result.put(qName, makeSerializableValue(def, value));
|
|
}
|
|
// Now spoof properties that are built in.
|
|
result.put(ContentModel.PROP_CREATED, new Date(desc.getCreateDate()));
|
|
result.put(ContentModel.PROP_CREATOR, desc.getCreator());
|
|
result.put(ContentModel.PROP_MODIFIED, new Date(desc.getModDate()));
|
|
result.put(ContentModel.PROP_MODIFIER, desc.getLastModifier());
|
|
result.put(ContentModel.PROP_OWNER, desc.getOwner());
|
|
result.put(ContentModel.PROP_NAME, desc.getName());
|
|
result.put(ContentModel.PROP_NODE_UUID, "UNKNOWN");
|
|
result.put(ContentModel.PROP_NODE_DBID, new Long(desc.getId()));
|
|
result.put(ContentModel.PROP_STORE_PROTOCOL, "avm");
|
|
result.put(ContentModel.PROP_STORE_IDENTIFIER, nodeRef.getStoreRef().getIdentifier());
|
|
if (desc.isLayeredDirectory())
|
|
{
|
|
result.put(WCMModel.PROP_AVM_DIR_INDIRECTION,
|
|
AVMNodeConverter.ToNodeRef(-1, desc.getIndirection()));
|
|
}
|
|
if (desc.isLayeredFile())
|
|
{
|
|
result.put(WCMModel.PROP_AVM_FILE_INDIRECTION,
|
|
AVMNodeConverter.ToNodeRef(-1, desc.getIndirection()));
|
|
}
|
|
if (desc.isFile())
|
|
{
|
|
try
|
|
{
|
|
ContentData contentData = fAVMService.getContentDataForRead(avmVersionPath.getFirst(),
|
|
avmVersionPath.getSecond());
|
|
result.put(ContentModel.PROP_CONTENT, contentData);
|
|
}
|
|
catch (AVMException e)
|
|
{
|
|
// TODO For now ignore.
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* @param nodeRef
|
|
* @param qname the qualified name of the property
|
|
* @return Returns the value of the property, or null if not yet set
|
|
* @throws InvalidNodeRefException if the node could not be found
|
|
*/
|
|
public Serializable getProperty(NodeRef nodeRef, QName qname) throws InvalidNodeRefException
|
|
{
|
|
Pair<Integer, String> avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
if (isBuiltInProperty(qname))
|
|
{
|
|
return getBuiltInProperty(avmVersionPath, qname, nodeRef);
|
|
}
|
|
try
|
|
{
|
|
PropertyValue value = fAVMService.getNodeProperty(avmVersionPath.getFirst(),
|
|
avmVersionPath.getSecond(),
|
|
qname);
|
|
if (value == null)
|
|
{
|
|
return null;
|
|
}
|
|
PropertyDefinition def = this.dictionaryService.getProperty(qname);
|
|
return makeSerializableValue(def, value);
|
|
}
|
|
catch (AVMNotFoundException e)
|
|
{
|
|
throw new InvalidNodeRefException(avmVersionPath.getSecond() + " not found.", nodeRef);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
public void removeProperty(NodeRef nodeRef, QName qname) throws InvalidNodeRefException
|
|
{
|
|
Pair<Integer, String> avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
if (isBuiltInProperty(qname))
|
|
{
|
|
// Ignore
|
|
return;
|
|
}
|
|
try
|
|
{
|
|
fAVMService.deleteNodeProperty(avmVersionPath.getSecond(), qname);
|
|
}
|
|
catch (AVMNotFoundException e)
|
|
{
|
|
throw new InvalidNodeRefException(avmVersionPath.getSecond() + " not found.", nodeRef);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A Helper to spoof built in properties.
|
|
* @param avmVersionPath The broken out version and path from a NodeRef.
|
|
* @param qName The name of the property to retrieve.
|
|
* @param nodeRef The original NodeRef (for error reporting).
|
|
* @return The property value.
|
|
*/
|
|
private Serializable getBuiltInProperty(Pair<Integer, String> avmVersionPath,
|
|
QName qName,
|
|
NodeRef nodeRef)
|
|
{
|
|
if (qName.equals(ContentModel.PROP_CONTENT))
|
|
{
|
|
try
|
|
{
|
|
ContentData contentData =
|
|
fAVMService.getContentDataForRead(avmVersionPath.getFirst(),
|
|
avmVersionPath.getSecond());
|
|
return contentData;
|
|
}
|
|
catch (AVMException e)
|
|
{
|
|
// TODO This seems very wrong. Do something better
|
|
// sooner rather than later.
|
|
return null;
|
|
}
|
|
}
|
|
AVMNodeDescriptor desc = fAVMService.lookup(avmVersionPath.getFirst(),
|
|
avmVersionPath.getSecond());
|
|
if (desc == null)
|
|
{
|
|
throw new InvalidNodeRefException(avmVersionPath.getSecond() + " not found.", nodeRef);
|
|
}
|
|
if (qName.equals(ContentModel.PROP_CREATED))
|
|
{
|
|
return new Date(desc.getCreateDate());
|
|
}
|
|
else if (qName.equals(ContentModel.PROP_CREATOR))
|
|
{
|
|
return desc.getCreator();
|
|
}
|
|
else if (qName.equals(ContentModel.PROP_MODIFIED))
|
|
{
|
|
return new Date(desc.getModDate());
|
|
}
|
|
else if (qName.equals(ContentModel.PROP_MODIFIER))
|
|
{
|
|
return desc.getLastModifier();
|
|
}
|
|
else if (qName.equals(ContentModel.PROP_OWNER))
|
|
{
|
|
return desc.getOwner();
|
|
}
|
|
else if (qName.equals(ContentModel.PROP_NAME))
|
|
{
|
|
return desc.getName();
|
|
}
|
|
else if (qName.equals(ContentModel.PROP_NODE_UUID))
|
|
{
|
|
return "UNKNOWN";
|
|
}
|
|
else if (qName.equals(ContentModel.PROP_NODE_DBID))
|
|
{
|
|
return new Long(desc.getId());
|
|
}
|
|
else if (qName.equals(ContentModel.PROP_STORE_PROTOCOL))
|
|
{
|
|
return "avm";
|
|
}
|
|
else if (qName.equals(ContentModel.PROP_STORE_IDENTIFIER))
|
|
{
|
|
return nodeRef.getStoreRef().getIdentifier();
|
|
}
|
|
else if (qName.equals(WCMModel.PROP_AVM_DIR_INDIRECTION))
|
|
{
|
|
if (desc.isLayeredDirectory())
|
|
{
|
|
return AVMNodeConverter.ToNodeRef(-1, desc.getIndirection());
|
|
}
|
|
return null;
|
|
}
|
|
else if (qName.equals(WCMModel.PROP_AVM_FILE_INDIRECTION))
|
|
{
|
|
if (desc.isLayeredFile())
|
|
{
|
|
return AVMNodeConverter.ToNodeRef(-1, desc.getIndirection());
|
|
}
|
|
return null;
|
|
}
|
|
else
|
|
{
|
|
logger.error("Invalid Built In Property: " + qName);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set the values of all properties to be an <code>Serializable</code> instances.
|
|
* The properties given must still fulfill the requirements of the class and
|
|
* aspects relevant to the node.
|
|
* <p>
|
|
* <b>NOTE:</b> Null values <u>are</u> allowed.
|
|
*
|
|
* @param nodeRef
|
|
* @param properties all the properties of the node keyed by their qualified names
|
|
* @throws InvalidNodeRefException if the node could not be found
|
|
*/
|
|
public void setProperties(NodeRef nodeRef, Map<QName, Serializable> properties) throws InvalidNodeRefException
|
|
{
|
|
Pair<Integer, String> avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
if (avmVersionPath.getFirst() >= 0)
|
|
{
|
|
throw new InvalidNodeRefException("Read only store.", nodeRef);
|
|
}
|
|
// TODO Not sure this try block is necessary.
|
|
try
|
|
{
|
|
// Prepare fr policy invocation.
|
|
Map<QName, Serializable> propsBefore = null;
|
|
if (fInvokePolicies)
|
|
{
|
|
propsBefore = getProperties(nodeRef);
|
|
}
|
|
// Remove all properties
|
|
fAVMService.deleteNodeProperties(avmVersionPath.getSecond());
|
|
// Rebuild node properties
|
|
Map<QName, PropertyValue> values = new HashMap<QName, PropertyValue>();
|
|
for (Map.Entry<QName, Serializable> entry : properties.entrySet())
|
|
{
|
|
QName propertyQName = entry.getKey();
|
|
Serializable value = entry.getValue();
|
|
// For AVM nodes is in place.
|
|
if (isBuiltInProperty(propertyQName))
|
|
{
|
|
if (propertyQName.equals(ContentModel.PROP_CONTENT))
|
|
{
|
|
AVMNodeDescriptor desc = fAVMService.lookup(-1, avmVersionPath.getSecond());
|
|
if (desc == null)
|
|
{
|
|
throw new InvalidNodeRefException(avmVersionPath.getSecond() + " not found.", nodeRef);
|
|
}
|
|
if (desc.isPlainFile())
|
|
{
|
|
fAVMService.setContentData(avmVersionPath.getSecond(),
|
|
(ContentData)properties.get(propertyQName));
|
|
}
|
|
}
|
|
}
|
|
PropertyDefinition propertyDef = dictionaryService.getProperty(propertyQName);
|
|
PropertyValue propertyValue = makePropertyValue(propertyDef, value);
|
|
values.put(propertyQName, propertyValue);
|
|
}
|
|
// Finally set node properties
|
|
fAVMService.setNodeProperties(avmVersionPath.getSecond(), values);
|
|
// Invoke policies
|
|
if (fInvokePolicies)
|
|
{
|
|
Map<QName, Serializable> propsAfter = properties;
|
|
invokeOnUpdateProperties(nodeRef, propsBefore, propsAfter);
|
|
}
|
|
// Invoke policy behaviors.
|
|
// invokeOnUpdateNode(nodeRef);
|
|
// invokeOnUpdateProperties(nodeRef, oldProps, properties);
|
|
}
|
|
catch (AVMNotFoundException e)
|
|
{
|
|
throw new InvalidNodeRefException(avmVersionPath.getSecond() + " not found.", nodeRef);
|
|
}
|
|
}
|
|
|
|
public void addProperties(NodeRef nodeRef, Map<QName, Serializable> properties)
|
|
{
|
|
// Overwrite the current properties
|
|
Map<QName, Serializable> currentProperties = getProperties(nodeRef);
|
|
currentProperties.putAll(properties);
|
|
setProperties(nodeRef, currentProperties);
|
|
}
|
|
|
|
static QName [] fgBuiltinProperties = new QName []
|
|
{
|
|
ContentModel.PROP_CREATED,
|
|
ContentModel.PROP_CREATOR,
|
|
ContentModel.PROP_MODIFIED,
|
|
ContentModel.PROP_MODIFIER,
|
|
ContentModel.PROP_OWNER,
|
|
ContentModel.PROP_CONTENT,
|
|
ContentModel.PROP_NAME,
|
|
ContentModel.PROP_NODE_UUID,
|
|
ContentModel.PROP_NODE_DBID,
|
|
ContentModel.PROP_STORE_PROTOCOL,
|
|
ContentModel.PROP_STORE_IDENTIFIER,
|
|
WCMModel.PROP_AVM_FILE_INDIRECTION,
|
|
WCMModel.PROP_AVM_DIR_INDIRECTION
|
|
};
|
|
|
|
/**
|
|
* Helper to distinguish built-in from generic properties.
|
|
* @param qName The name of the property to check.
|
|
* @return Whether <code>qName</code> is a built-in propety.
|
|
*/
|
|
private boolean isBuiltInProperty(QName qName)
|
|
{
|
|
for (QName name : fgBuiltinProperties)
|
|
{
|
|
if (name.equals(qName))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Sets the value of a property to be any <code>Serializable</code> instance.
|
|
* To remove a property value, use {@link #getProperties(NodeRef)}, remove the
|
|
* value and call {@link #setProperties(NodeRef, Map)}.
|
|
* <p>
|
|
* <b>NOTE:</b> Null values <u>are</u> allowed.
|
|
*
|
|
* @param nodeRef
|
|
* @param qname the fully qualified name of the property
|
|
* @param propertyValue the value of the property - never null
|
|
* @throws InvalidNodeRefException if the node could not be found
|
|
*/
|
|
public void setProperty(NodeRef nodeRef, QName qname, Serializable value) throws InvalidNodeRefException
|
|
{
|
|
// Invoke policy behaviors.
|
|
// invokeBeforeUpdateNode(nodeRef);
|
|
Pair<Integer, String> avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
if (avmVersionPath.getFirst() >= 0)
|
|
{
|
|
throw new InvalidNodeRefException("Read only store.", nodeRef);
|
|
}
|
|
|
|
Map<QName, Serializable> propsBefore = null;
|
|
if (fInvokePolicies)
|
|
{
|
|
propsBefore = getProperties(nodeRef);
|
|
}
|
|
|
|
if (isBuiltInProperty(qname))
|
|
{
|
|
if (qname.equals(ContentModel.PROP_CONTENT))
|
|
{
|
|
try
|
|
{
|
|
fAVMService.setContentData(avmVersionPath.getSecond(), (ContentData)value);
|
|
if (fInvokePolicies)
|
|
{
|
|
Map<QName, Serializable> propsAfter = new HashMap<QName, Serializable>(propsBefore);
|
|
propsAfter.put(ContentModel.PROP_CONTENT, value);
|
|
invokeOnUpdateProperties(nodeRef, propsBefore, propsAfter);
|
|
}
|
|
}
|
|
catch (ClassCastException e)
|
|
{
|
|
throw new AVMException("Invalid ContentData.", e);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
try
|
|
{
|
|
|
|
PropertyDefinition propertyDef = dictionaryService.getProperty(qname);
|
|
PropertyValue propertyValue = makePropertyValue(propertyDef, value);
|
|
fAVMService.setNodeProperty(avmVersionPath.getSecond(), qname, propertyValue);
|
|
if (fInvokePolicies)
|
|
{
|
|
Map<QName, Serializable> propsAfter = new HashMap<QName, Serializable>(propsBefore);
|
|
propsAfter.put(qname, value);
|
|
invokeOnUpdateProperties(nodeRef, propsBefore, propsAfter);
|
|
}
|
|
// Map<QName, Serializable> propsAfter = getProperties(nodeRef);
|
|
// Invoke policy behaviors.
|
|
// invokeOnUpdateNode(nodeRef);
|
|
// invokeOnUpdateProperties(nodeRef, propsBefore, propsAfter);
|
|
}
|
|
catch (AVMNotFoundException e)
|
|
{
|
|
throw new InvalidNodeRefException(avmVersionPath.getSecond() + " not found.", nodeRef);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param nodeRef the child node
|
|
* @return Returns a list of all parent-child associations that exist where the given
|
|
* node is the child
|
|
* @throws InvalidNodeRefException if the node could not be found
|
|
*
|
|
* @see #getParentAssocs(NodeRef, QNamePattern, QNamePattern)
|
|
*/
|
|
public List<ChildAssociationRef> getParentAssocs(NodeRef nodeRef) throws InvalidNodeRefException
|
|
{
|
|
// TODO OK, for now we'll simply return the single parent that corresponds
|
|
// to the path stuffed in the NodeRef.
|
|
Pair<Integer, String> avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
String path = avmVersionPath.getSecond();
|
|
List<ChildAssociationRef> result = new ArrayList<ChildAssociationRef>();
|
|
String [] splitPath = AVMNodeConverter.SplitBase(path);
|
|
if (splitPath[0] == null)
|
|
{
|
|
return result;
|
|
}
|
|
result.add(new ChildAssociationRef(ContentModel.ASSOC_CONTAINS,
|
|
AVMNodeConverter.ToNodeRef(avmVersionPath.getFirst(),
|
|
splitPath[0]),
|
|
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI,
|
|
splitPath[1]),
|
|
nodeRef,
|
|
true,
|
|
-1));
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Gets all parent associations where the pattern of the association qualified
|
|
* name is a match
|
|
* <p>
|
|
* The resultant list is ordered by (a) explicit index and (b) association creation time.
|
|
*
|
|
* @param nodeRef the child node
|
|
* @param typeQNamePattern the pattern that the type qualified name of the association must match
|
|
* @param qnamePattern the pattern that the qnames of the assocs must match
|
|
* @return Returns a list of all parent-child associations that exist where the given
|
|
* node is the child
|
|
* @throws InvalidNodeRefException if the node could not be found
|
|
*
|
|
* @see ChildAssociationRef#getNthSibling()
|
|
* @see #setChildAssociationIndex(ChildAssociationRef, int)
|
|
* @see QName
|
|
* @see org.alfresco.service.namespace.RegexQNamePattern#MATCH_ALL
|
|
*/
|
|
public List<ChildAssociationRef> getParentAssocs(NodeRef nodeRef, QNamePattern typeQNamePattern, QNamePattern qnamePattern)
|
|
throws InvalidNodeRefException
|
|
{
|
|
if (!typeQNamePattern.isMatch(ContentModel.ASSOC_CONTAINS))
|
|
{
|
|
return new ArrayList<ChildAssociationRef>();
|
|
}
|
|
List<ChildAssociationRef> result = getParentAssocs(nodeRef);
|
|
if (result.size() == 0)
|
|
{
|
|
return result;
|
|
}
|
|
if (qnamePattern.isMatch(result.get(0).getQName()))
|
|
{
|
|
return result;
|
|
}
|
|
return new ArrayList<ChildAssociationRef>();
|
|
}
|
|
|
|
/**
|
|
* Get all child associations of the given node.
|
|
* <p>
|
|
* The resultant list is ordered by (a) explicit index and (b) association creation time.
|
|
*
|
|
* @param nodeRef the parent node - usually a <b>container</b>
|
|
* @return Returns a collection of <code>ChildAssocRef</code> instances. If the
|
|
* node is not a <b>container</b> then the result will be empty.
|
|
* @throws InvalidNodeRefException if the node could not be found
|
|
*
|
|
* @see #getChildAssocs(NodeRef, QNamePattern, QNamePattern)
|
|
* @see #setChildAssociationIndex(ChildAssociationRef, int)
|
|
* @see ChildAssociationRef#getNthSibling()
|
|
*/
|
|
public List<ChildAssociationRef> getChildAssocs(NodeRef nodeRef) throws InvalidNodeRefException
|
|
{
|
|
|
|
Pair<Integer, String> avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
int version = avmVersionPath.getFirst();
|
|
String path = avmVersionPath.getSecond();
|
|
List<ChildAssociationRef> result = new ArrayList<ChildAssociationRef>();
|
|
SortedMap<String, AVMNodeDescriptor> children = null;
|
|
try
|
|
{
|
|
children =
|
|
fAVMService.getDirectoryListing(version,
|
|
path);
|
|
}
|
|
catch (AVMNotFoundException e)
|
|
{
|
|
return result;
|
|
}
|
|
for (String name : children.keySet())
|
|
{
|
|
result.add(new ChildAssociationRef(ContentModel.ASSOC_CONTAINS,
|
|
nodeRef,
|
|
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI,
|
|
name),
|
|
AVMNodeConverter.ToNodeRef(
|
|
version,
|
|
AVMNodeConverter.ExtendAVMPath(path, name)),
|
|
true,
|
|
-1));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Gets all child associations where the pattern of the association qualified
|
|
* name is a match.
|
|
*
|
|
* @param nodeRef the parent node - usually a <b>container</b>
|
|
* @param typeQNamePattern the pattern that the type qualified name of the association must match
|
|
* @param qnamePattern the pattern that the qnames of the assocs must match
|
|
* @return Returns a list of <code>ChildAssocRef</code> instances. If the
|
|
* node is not a <b>container</b> then the result will be empty.
|
|
* @throws InvalidNodeRefException if the node could not be found
|
|
*
|
|
* @see QName
|
|
* @see org.alfresco.service.namespace.RegexQNamePattern#MATCH_ALL
|
|
*/
|
|
public List<ChildAssociationRef> getChildAssocs(
|
|
NodeRef nodeRef,
|
|
QNamePattern typeQNamePattern,
|
|
QNamePattern qnamePattern)
|
|
throws InvalidNodeRefException
|
|
{
|
|
List<ChildAssociationRef> result = new ArrayList<ChildAssociationRef>();
|
|
if (!typeQNamePattern.isMatch(ContentModel.ASSOC_CONTAINS))
|
|
{
|
|
return result;
|
|
}
|
|
// First check if we are matching on all
|
|
if (qnamePattern == null || !(qnamePattern instanceof QName))
|
|
{
|
|
// Either null (always match) or we have to match on each, individually
|
|
List<ChildAssociationRef> all = getChildAssocs(nodeRef);
|
|
for (ChildAssociationRef child : all)
|
|
{
|
|
if (qnamePattern == null || !qnamePattern.isMatch(child.getQName()))
|
|
{
|
|
continue;
|
|
}
|
|
result.add(child);
|
|
}
|
|
return result;
|
|
}
|
|
else
|
|
{
|
|
// We have a specific QName and therefore an exact path
|
|
QName qname = (QName) qnamePattern;
|
|
String name = qname.getLocalName();
|
|
|
|
// Resolve the container
|
|
Pair<Integer, String> containerVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
int containerVersion = containerVersionPath.getFirst();
|
|
String containerPath = containerVersionPath.getSecond();
|
|
try
|
|
{
|
|
// Get the descriptor for the container
|
|
AVMNodeDescriptor containerDescriptor = fAVMService.lookup(containerVersion, containerPath);
|
|
@SuppressWarnings("unused") // Might succeed or fail
|
|
AVMNodeDescriptor childDescriptor = fAVMService.lookup(containerDescriptor, name);
|
|
result.add(
|
|
new ChildAssociationRef(
|
|
ContentModel.ASSOC_CONTAINS,
|
|
nodeRef,
|
|
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, name),
|
|
AVMNodeConverter.ToNodeRef(
|
|
containerVersion,
|
|
AVMNodeConverter.ExtendAVMPath(containerPath, name)),
|
|
true,
|
|
-1));
|
|
}
|
|
catch (AVMNotFoundException e)
|
|
{
|
|
return result;
|
|
}
|
|
catch (AVMWrongTypeException e)
|
|
{
|
|
return result;
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public List<ChildAssociationRef> getChildAssocs(NodeRef nodeRef, QName typeQName, QName qname, int maxResults,
|
|
boolean preload) throws InvalidNodeRefException
|
|
{
|
|
List<ChildAssociationRef> result = getChildAssocs(nodeRef, typeQName, qname);
|
|
if (result.size() > maxResults)
|
|
{
|
|
return result.subList(0, maxResults);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public List<ChildAssociationRef> getChildAssocs(NodeRef nodeRef, QNamePattern typeQNamePattern,
|
|
QNamePattern qnamePattern, boolean preload) throws InvalidNodeRefException
|
|
{
|
|
return getChildAssocs(nodeRef, typeQNamePattern, qnamePattern);
|
|
}
|
|
|
|
public List<ChildAssociationRef> getChildAssocs(NodeRef nodeRef, Set<QName> childNodeTypes)
|
|
{
|
|
/*
|
|
* ETWOTWO-961 forced an implementation, but this is just a workaround.
|
|
* We do a listing and then keep files or folders looking specifically
|
|
* for cm:folder and cm:content types from childNodeTypes.
|
|
*/
|
|
Pair<Integer, String> avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
int version = avmVersionPath.getFirst();
|
|
String path = avmVersionPath.getSecond();
|
|
List<ChildAssociationRef> result = new ArrayList<ChildAssociationRef>();
|
|
SortedMap<String, AVMNodeDescriptor> children = null;
|
|
try
|
|
{
|
|
children =
|
|
fAVMService.getDirectoryListing(version,
|
|
path);
|
|
}
|
|
catch (AVMNotFoundException e)
|
|
{
|
|
return result;
|
|
}
|
|
for (Map.Entry<String, AVMNodeDescriptor> entry : children.entrySet())
|
|
{
|
|
String name = entry.getKey();
|
|
AVMNodeDescriptor descriptor = entry.getValue();
|
|
if (descriptor.isFile())
|
|
{
|
|
if (!childNodeTypes.contains(ContentModel.TYPE_CONTENT))
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
else if (descriptor.isDirectory())
|
|
{
|
|
if (!childNodeTypes.contains(ContentModel.TYPE_FOLDER))
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Not a file or directory???
|
|
continue;
|
|
}
|
|
result.add(new ChildAssociationRef(ContentModel.ASSOC_CONTAINS,
|
|
nodeRef,
|
|
QName.createQName(
|
|
NamespaceService.CONTENT_MODEL_1_0_URI,
|
|
name),
|
|
AVMNodeConverter.ToNodeRef(
|
|
version,
|
|
AVMNodeConverter.ExtendAVMPath(path, name)),
|
|
true,
|
|
-1));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* getChildrenByName
|
|
*/
|
|
public List<ChildAssociationRef> getChildrenByName(NodeRef nodeRef, QName assocTypeQName, Collection<String> childNames)
|
|
{
|
|
final List<ChildAssociationRef> results = new ArrayList<ChildAssociationRef>(100);
|
|
|
|
if (!assocTypeQName.equals(ContentModel.ASSOC_CONTAINS))
|
|
{
|
|
throw new UnsupportedOperationException("AVM getChildrenByName only supports ASSOCS_CONTAINS.");
|
|
}
|
|
|
|
Pair<Integer, String> avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
try
|
|
{
|
|
for(String childName : childNames)
|
|
{
|
|
AVMNodeDescriptor child = fAVMService.lookup(avmVersionPath.getFirst(),
|
|
AVMUtil.extendAVMPath(avmVersionPath.getSecond(), childName));
|
|
|
|
if (child != null)
|
|
{
|
|
NodeRef childRef = AVMNodeConverter.ToNodeRef(avmVersionPath.getFirst(),
|
|
child.getPath());
|
|
QName childQName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI,
|
|
childName);
|
|
ChildAssociationRef ref = new ChildAssociationRef(assocTypeQName, nodeRef, childQName, childRef);
|
|
|
|
if(logger.isDebugEnabled())
|
|
{
|
|
logger.debug("got a child node :" + ref);
|
|
}
|
|
results.add(ref);
|
|
}
|
|
}
|
|
return results;
|
|
}
|
|
catch (AVMException e)
|
|
{
|
|
logger.debug("exception in getChildrenByName ", e);
|
|
return results;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Get a child NodeRef by name.
|
|
* @param nodeRef The parent node.
|
|
* @param assocTypeQName The type of the Child Association.
|
|
* @param childName The name of the child to get.
|
|
*/
|
|
public NodeRef getChildByName(NodeRef nodeRef, QName assocTypeQName, String childName)
|
|
{
|
|
if (!assocTypeQName.equals(ContentModel.ASSOC_CONTAINS))
|
|
{
|
|
return null;
|
|
}
|
|
Pair<Integer, String> avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
try
|
|
{
|
|
AVMNodeDescriptor child = fAVMService.lookup(avmVersionPath.getFirst(),
|
|
AVMUtil.extendAVMPath(avmVersionPath.getSecond(), childName));
|
|
if (child == null)
|
|
{
|
|
return null;
|
|
}
|
|
return AVMNodeConverter.ToNodeRef(avmVersionPath.getFirst(),
|
|
child.getPath());
|
|
}
|
|
catch (AVMException e)
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fetches the primary parent-child relationship.
|
|
* <p>
|
|
* For a root node, the parent node reference will be null.
|
|
*
|
|
* @param nodeRef
|
|
* @return Returns the primary parent-child association of the node
|
|
* @throws InvalidNodeRefException if the node could not be found
|
|
*/
|
|
public ChildAssociationRef getPrimaryParent(NodeRef nodeRef) throws InvalidNodeRefException
|
|
{
|
|
List<ChildAssociationRef> parents = getParentAssocs(nodeRef);
|
|
if (parents.size() == 0)
|
|
{
|
|
return new ChildAssociationRef(null, null, null, nodeRef);
|
|
}
|
|
return parents.get(0);
|
|
}
|
|
|
|
/**
|
|
* @throws UnsupportedOperationException always
|
|
*/
|
|
@Override
|
|
public AssociationRef createAssociation(NodeRef sourceRef, NodeRef targetRef, QName assocTypeQName)
|
|
throws InvalidNodeRefException, AssociationExistsException
|
|
{
|
|
throw new UnsupportedOperationException("AVM does not support arbitrary associations.");
|
|
}
|
|
|
|
/**
|
|
* @throws UnsupportedOperationException always
|
|
*/
|
|
@Override
|
|
public void setAssociations(NodeRef sourceRef, QName assocTypeQName, List<NodeRef> targetRefs)
|
|
{
|
|
throw new UnsupportedOperationException("AVM does not support arbitrary associations.");
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param sourceRef the associaton source node
|
|
* @param targetRef the association target node
|
|
* @param assocTypeQName the qualified name of the association type
|
|
* @throws InvalidNodeRefException if either of the nodes could not be found
|
|
*/
|
|
public void removeAssociation(NodeRef sourceRef, NodeRef targetRef, QName assocTypeQName)
|
|
throws InvalidNodeRefException
|
|
{
|
|
throw new UnsupportedOperationException("AVM does not support arbitrary associations.");
|
|
}
|
|
|
|
/**
|
|
* Gets an association by ID.
|
|
*
|
|
* @param assocId
|
|
* the association id
|
|
* @return the association, or <code>null</code> if it does not exist
|
|
*/
|
|
public AssociationRef getAssoc(Long id)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Fetches all associations <i>from</i> the given source where the associations'
|
|
* qualified names match the pattern provided.
|
|
*
|
|
* @param sourceRef the association source
|
|
* @param qnamePattern the association qname pattern to match against
|
|
* @return Returns a list of <code>NodeAssocRef</code> instances for which the
|
|
* given node is a source
|
|
* @throws InvalidNodeRefException if the source node could not be found
|
|
*
|
|
* @see QName
|
|
* @see org.alfresco.service.namespace.RegexQNamePattern#MATCH_ALL
|
|
*/
|
|
public List<AssociationRef> getTargetAssocs(NodeRef sourceRef, QNamePattern qnamePattern)
|
|
throws InvalidNodeRefException
|
|
{
|
|
return new ArrayList<AssociationRef>();
|
|
}
|
|
|
|
/**
|
|
* Fetches all associations <i>to</i> the given target where the associations'
|
|
* qualified names match the pattern provided.
|
|
*
|
|
* @param targetRef the association target
|
|
* @param qnamePattern the association qname pattern to match against
|
|
* @return Returns a list of <code>NodeAssocRef</code> instances for which the
|
|
* given node is a target
|
|
* @throws InvalidNodeRefException
|
|
*
|
|
* @see QName
|
|
* @see org.alfresco.service.namespace.RegexQNamePattern#MATCH_ALL
|
|
*/
|
|
public List<AssociationRef> getSourceAssocs(NodeRef targetRef, QNamePattern qnamePattern)
|
|
throws InvalidNodeRefException
|
|
{
|
|
return new ArrayList<AssociationRef>();
|
|
}
|
|
|
|
/**
|
|
* The root node has an entry in the path(s) returned. For this reason, there
|
|
* will always be <b>at least one</b> path element in the returned path(s).
|
|
* The first element will have a null parent reference and qname.
|
|
*
|
|
* @param nodeRef
|
|
* @return Returns the path to the node along the primary node path
|
|
* @throws InvalidNodeRefException if the node could not be found
|
|
*
|
|
* @see #getPaths(NodeRef, boolean)
|
|
*/
|
|
public Path getPath(NodeRef nodeRef) throws InvalidNodeRefException
|
|
{
|
|
// TODO Review later. This may be wrong.
|
|
Path path = new Path();
|
|
Pair<Integer, String> avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
|
|
int version = avmVersionPath.getFirst();
|
|
String currPath = avmVersionPath.getSecond();
|
|
while (!currPath.endsWith("/"))
|
|
{
|
|
String [] splitPath = AVMNodeConverter.SplitBase(currPath);
|
|
String parentPath = splitPath[0];
|
|
String name = splitPath[1];
|
|
ChildAssociationRef caRef =
|
|
new ChildAssociationRef(ContentModel.ASSOC_CONTAINS,
|
|
AVMNodeConverter.ToNodeRef(version, parentPath),
|
|
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI,
|
|
name),
|
|
AVMNodeConverter.ToNodeRef(version, currPath),
|
|
true,
|
|
-1);
|
|
path.prepend(new Path.ChildAssocElement(caRef));
|
|
currPath = parentPath;
|
|
}
|
|
ChildAssociationRef caRef = new ChildAssociationRef(null, null, null,
|
|
AVMNodeConverter.ToNodeRef(version,
|
|
currPath));
|
|
path.prepend(new Path.ChildAssocElement(caRef));
|
|
return path;
|
|
}
|
|
|
|
/**
|
|
* The root node has an entry in the path(s) returned. For this reason, there
|
|
* will always be <b>at least one</b> path element in the returned path(s).
|
|
* The first element will have a null parent reference and qname.
|
|
*
|
|
* @param nodeRef
|
|
* @param primaryOnly true if only the primary path must be retrieved. If true, the
|
|
* result will have exactly one entry.
|
|
* @return Returns a List of all possible paths to the given node
|
|
* @throws InvalidNodeRefException if the node could not be found
|
|
*/
|
|
public List<Path> getPaths(NodeRef nodeRef, boolean primaryOnly) throws InvalidNodeRefException
|
|
{
|
|
List<Path> result = new ArrayList<Path>();
|
|
result.add(getPath(nodeRef));
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Get the node where archived items will have gone when deleted from the given store.
|
|
*
|
|
* @param storeRef the store that items were deleted from
|
|
* @return Returns the archive node parent
|
|
*/
|
|
public NodeRef getStoreArchiveNode(StoreRef storeRef)
|
|
{
|
|
throw new UnsupportedOperationException("AVM does not support this operation.");
|
|
}
|
|
|
|
/**
|
|
* Restore an individual node (along with its sub-tree nodes) to the target location.
|
|
* The archived node must have the {@link org.alfresco.model.ContentModel#ASPECT_ARCHIVED archived aspect}
|
|
* set against it.
|
|
*
|
|
* @param archivedNodeRef the archived node
|
|
* @param destinationParentNodeRef the parent to move the node into
|
|
* or <tt>null</tt> to use the original
|
|
* @param assocTypeQName the primary association type name to use in the new location
|
|
* or <tt>null</tt> to use the original
|
|
* @param assocQName the primary association name to use in the new location
|
|
* or <tt>null</tt> to use the original
|
|
* @return Returns the reference to the newly created node
|
|
*/
|
|
public NodeRef restoreNode(
|
|
NodeRef archivedNodeRef,
|
|
NodeRef destinationParentNodeRef,
|
|
QName assocTypeQName,
|
|
QName assocQName)
|
|
{
|
|
throw new UnsupportedOperationException("AVM does not support this operation.");
|
|
}
|
|
|
|
/* (non-Javadoc)
|
|
* @see org.alfresco.service.cmr.repository.NodeService#getChildAssocsWithoutParentAssocsOfType(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName)
|
|
*/
|
|
public Collection<ChildAssociationRef> getChildAssocsWithoutParentAssocsOfType(NodeRef parent, QName assocTypeQName)
|
|
{
|
|
throw new UnsupportedOperationException("AVM does not support this operation.");
|
|
}
|
|
|
|
public Long getNodeAclId(NodeRef nodeRef) throws InvalidNodeRefException
|
|
{
|
|
throw new UnsupportedOperationException("getNodeAclId is unsupported for AVMNodeService");
|
|
}
|
|
|
|
@Override
|
|
public List<ChildAssociationRef> getChildAssocsByPropertyValue(
|
|
NodeRef nodeRef, QName propertyQName, Serializable value)
|
|
{
|
|
throw new UnsupportedOperationException("AVM does not support this operation.");
|
|
}
|
|
|
|
@Override
|
|
public int countChildAssocs(NodeRef nodeRef, boolean isPrimary) throws InvalidNodeRefException
|
|
{
|
|
throw new UnsupportedOperationException("AVM does not support this operation.");
|
|
}
|
|
|
|
}
|