Dave Ward 419ecfb9e7 Merged V3.4-TEAM to HEAD
24882: Branch for Team
   24883: Version Edition label
   24906: Partial implementation of ALF-6566. Replace gears image...
     This check-in adds support for the feature as described in JIRA. However we do not yet have
     the icon graphics files. I have therefore used some temporary icons in order to flush out
     implementation issues and to enable browser-based testing.
     A future check-in will add the correct placeholder icons and if they follow the naming
     convention, no change in code should be necessary.
   
     Also added and modified some test cases.
   24909: ALF-6606: Configurable sorting for Share Document Library. Also change Show/Hide Folder button to icon. (Placeholder icons)
   24914: ALF-6564: Initial cut of JMXFormProcessor, will show all attributes of a given MBean and has the ability to persist an attribute value.
   24916: Initial Alfresco Team project structure and build targets
   24917: First tranche of thumbnail icons for ALF-6566. Replace gears icon.
     Have added icons for some basic mime types and removed some temporary icons.
     I had to do a clean repo build to flush out the temporary docx and jpeg icons.
   24919: svn ignore patterns
   24922: Missed files for team build targets
   24932: Add a simple AVM to Zip exporter service, initially for use by the site exporter
   24935: Start on a java backed webscript to export a site, including all the details (ALF-6567)
   24945: Removed two unnecessary TODOs from the RatingService code.
   24949: Improved documentation for RatingService webscripts.
   Added sample JSON responses for two webscripts.
   24956: Implementation of ALF-6792. RatingSchemes should allow self-rating.
     Formerly, the cm:creator of a node could never apply a rating to it. An unchecked RatingServiceException would be thrown if they attempted to do so.
     With this check-in ratingScheme beans have a new property: selfRatingAllowed. The exception will now only be thrown if a cm:creator attempts to rate their own content in a scheme where this property is false.
     The property is true by default and in particular, is true for "likesRatingScheme".
   24958: ALF-6599: First pass DND file upload - FireFox4/Chrome support for single/multifile DND upload with basic progress
   24961: Added additional data to the response coming from rating.post.
   I have added averageRating, ratingsTotal and ratingsCount to that response.
   24963: ALF-6625: Balloon Popup Framework. Initial checking. More work maybe required when we start using it, or when designs are complete.
   24964: ALF-6598 "Configure Site page refactor"
   - page.lib.js - Freemarker lib to sort out used pages and which links and labels to use
   - Drag n drop
     * now supports horisontal lists
     * improved tabfocus and keynavigations
     * callbacks can be attached on dnd events: delete-clicks, enter-clicks, element-moved, element-duplicated
   - Alfresco.util.isVisible - Checks if the element and all its parents are visible and displayed in the ui.
   - Alfresco.util.PopupManager.getUserInput now accepts a "input" parameter that can be set to "text" ("textarea" is default)
   - Automatic click listeners can be defined as: 
     <a href="#onRenameClick" class="${el}" rel="${page.pageId?js_string}">${msg("link.rename")}</a>
     which will call:
     onRenameClick: function(pageId, anchor) {}
   24965: Changing date format of appliedAt JSON property to xmldate.
   24971: ALF-6600: Event handling performance improvements for DND file upload
   24976: Added team.war to continuous assemble-tomcat
   24977: ALF-6600: Initial pass at DND upload highlighting
   24979: Add method AuthorityService.getAuthorityNodeRef, and unit tests for it
   24980: UI label change for Team install
   24981: Set security permission on the new AuthorityService.getAuthorityNodeRef method, in line with the other get methods
   24987: ALF-6607 - Likes, favourite and comment actions. Also DocLib panel redesign. Updates to Rating Service to better match Team use cases.
   24989: ALF-6601: Added JavaScript multipart data constructor for FireFox 3.6 support
   24990: Fix "Access Denied" error when navigating into a "Liked" folder.
   25000: Merged V3.4 to V3.4-TEAM
      24999: ALF-6764 - Updated copyright year to 2011
   25004: ALF-6601: Set file size limit, HTTP status code error handling
   25007: Add user, group and person ACP exports to the Site Export webscript.
   (The user export is provisional, pending a service level way to access the user NodeRef)
   25008: ALF-6788: Update dashboard template to provide full width component and presets updates to reflect new default layouts.
   25017: Initial check-in for ALF-6809. A service to managed deleted items.
   This check in adds a basic REST API for GETting and DELETEing deleted items from the archive store.
   JUnit tests of the REST API are included but are not yet complete.
   
   25018: Trivial fix for failing test case related to ALF-6809
   25019: A previous check-in (25017) accidentally included an extra Java file that wasn't ready.
   File is related to ALF-6809 and will be implemented today.
   This check-in removes the internals of the class to allow it to compile.
   The class is not injected into the spring application context and is essentially dead code pending its implementation later.
   25027: Adding nodeType to the archivednodes.get webscript response.
     Requested by UI as part of ALF-6809.
   25035: ALF-6789: Personal dashboard welcome (with wireframe styling)
   25036: ALF-6782 - Undelete administration console page (WIP)
   ALF-6784, ALF-6786, ALF-6787
   25037: ALF-6564: Added operations to default form, all parameter-less operations are displayed as a button on the form. Clicking a button executes the operation after saving all attribute values.
   25038: Added a node filter to the archivednodes.get webscript. Currently excluding cm:thumbnails.
     A new bean on the script's controller class that allows injection of nodetypes to be excluded.
     Should be trivial to exclude other node types later and easy to exclude based on other criteria.
   25039: Part of ALF-6809. Deleted items were returned from archivednodes.get in the wrong order.
   They are now sorted by archive datetime most recent first. (Was previously sorted with most recent last.)
   Also switched the test case, which was backwards too!
   25040: Changing some copyright headers from 2010 to 2011.
   25041: ALF-6564: JMX forms can now be configured with selective attributes and the set of operations. Also includes an example form configuration for the outbound email almost matching Linton's wireframes.
   25042: ALF-6788: Fix rendering of old (V3.4) user dashboards stored in AVM with new Team layout
   25044: Part of ALF-6809. Added displayPath value to archivednodes.get.
   25047: Part of ALF-6809. Reconfiguration of cm:thumbnail archive behaviour.
   Formerly, we were archiving cm:thumbnails on deletion and filtering them from the archivednodes.get webscript which was not ideal as they remained in the archive.
   This check in removes the filter on the GET webscript and prevents cm:thumbnails from being archived in the first place.
   25049: ALF-6782
    - added Trashcan to admin tools menu
    - cleaned up list, show display path
   25050: ALF-6782 - css tweaks
   25052: Added check for multiple calls to onHistoryManagerReady() as workaround for issue with multiple History Manager objects when using Alfresco.util.DataTable.
   25053: Test case refactoring as part of ALF-6809
   25055: ALF-6803: First drop of aggregate file upload progress information.
   25056: Part of ALF-6809. A preliminary PUT webscript that is used to restore nodes from the archive to their original loaction.
   Currently only works on a single node per call (which is what the JIRA requires).
   Test code currently incomplete. I'm checking in now to give UI something to work with.
   25057: Fix for failing test case, which was part of ALF-6566.
   25058: ALF-6567 - AVM importer, which can load a zip file's contents into a specified AVM filesystem. Includes a bootstrap wrapper around the main importer.
   25068: Part ALF-6893: RTEAM 03: Expose restrictions using RepoAdminService
     - Subtask of ALF-6832: AT17: License restriction reporting
     - Added RepoAdminService.getRestrictions in Java and Webscripts APIs
     - Currently nulls returned indication 'no restrictions'
     - Cleaned up unused AdminService
   25069: ALF-6625 - adds a switch to control what calendar views are enabled and switches off Day, Week and Month views in Team.
   25073: Test case overhaul and minor tidying of code. Part of ALF-6809.
   25074: ALF-6803: Style updates to upload progress info
   25075: ALF-6601: Updated in-memory file upload check so that failure is based on total (not individual) file size.
   25081: Merged V3.4 to V3.4-TEAM
      25051: Build Fix: ALF-6865 CopyServiceImplTest.testCopyToNewNodeWithPermissions failing on permission copying
   25082: Part ALF-6893: RTEAM 03: Expose restrictions using RepoAdminService
     - Subtask of ALF-6832: AT17: License restriction reporting
     - Added RepoAdminService.getUsage in Java and Webscripts APIs
   25084: Improve how the Site Exporter gets at the users for a site, and have the user authentication details export skipped if a non-repository based authenticator is enabled
   25085: Final part of ALF-6809. Support for paging the results from archivednodes.get.
   Follows the standard maxItems, skipCount convention and enables paging in the trashcan view automatically thanks to Kev's use of the convention.
   25088: Final, final part of ALF-6809. Throwing 4xx, 5xx exceptions for nodeArchiveService-level failures to restore nodes
   25090: ALF-6601: Updated in-memory upload limit to be configurable
   25096: ALF-6601: Updates to DND highlighting and behaviour, set correct upload limit in bytes, NLS updates
   25101: Fixing failing test cases. Fallout from recent changes to the JSON response formats in these webscripts.
   25103: ALF-6613 - SpringSurf improvements to allow easier refactoring of Document Details page
    - latest SpringSurf libs with RequestCachingConnector improvements
    - removed manual request level caching of remote calls responses in web-tier components - now completely automatic
   25104: ALF-6803: DND upload dialog styling
   25106: ALF-6802: Added feature detection to disable drag'n'drop events (disables for IE6, IE7 & IE8)
   25108: ALF-6564: Added a check to the JMXFormProcessor to ensure the current user is an administrator. Also relaxed the rules in the checkbox control so it can be used for string values not just boolean values.
   25113: ALF-6789: Updated CSS to support IE6/IE7
   25116: Prevent server-side exception when navigating trashcan; related to paging. (ALF-6809)
   25117: ALF-6824 - Only show "Like" and "Comment" actions if a user has the correct permissions. Additional fixes for IE7.
   25118: Fix incorrect category aspect name. Missing file from r25117
   25119: ALF-6645 - Share and Team branding updates
   25121: Removed erroneous comment block
   25123: Merged HEAD to BRANCHES/V3.4-TEAM:
      25115: Fixes: ALF-6336 - resolved incorrectly translated date formatting strings.
   25124: Add a new bootstrap component for bootstrapping Sites. Handles the contents, AVM and authentication, people and their group membership to follow. 
   (Uses singleton spring beans in line with the patch service's use, to ensure that when loaded from a bootstrap extension things still occur in the correct order)
   25128: Merged V3.4 to V3.4-TEAM
      25127: Merged V3.3 to V3.4
         25126: ALF-6903 - Share theme feature does not work. Also fixes issue with MultiThreadedHttpConnectionManager in SpringSurf.
   25130: Continue with the site bootstrapper - finish supporting the loading of the site contents ACP
   25132: Work on ALF-6832:TR25: License restriction reporting
    - ALF-6893: RTEAM 03: Expose restrictions using RepoAdminService
    - ALF-6911: RTEAM 02: Record and expose system attributes
    - Added RepoUsageComponent
      - Unit test incl. testLicenseUse
      - Persists and retrieves usage data using AttributeService
   25133: ALF-6789: Added "Close" link to dynamic-welcome dashlet and associated webscript
   25135: ALF-6789: Add missing localization
   25136: ALF-6601: Defensively code against missing config
   25137: Fix up of transfer test.
   25138: Flattening of user preferences remote calls - ensures /preferences hits the RequestCachingConnector - reduces no. of remote calls by 3 for the doclib and by 4 for a site dashboard.
   25139: ALF-6804: Disable drop outside of document list
   25140: ALF-6887 - for sending HTML emails
   - prelim support - either text explicitly starts with "<html" and/or is passed via new HTML param
   25141: Updated version to 3.5.0 for Team
   25142: ALF-6834 - activities feed email notification (1st cut)
   - for sprint 1 demo (ALF-6928, ALF-6929, ALF-6931, ALF-6932)
   - note: to demo ... manually copy "activities-email.ftl" into repo (/Company Home/Data Dictionary/Email Templates/activities) and configure your own email address (for one or more users)
   25145: ALF-6602: Added first time instructions for DND upload
   25147: Merged HEAD to BRANCHES/V3.4-TEAM:
      25100: Fix for build issue Steve was encountering on new build boxes using Ant 1.8.x
   25151: ALF-6790: Updated CSS and images to match latest mockups
   25161: Basic support for canned queries
    - ALF-6910: RTEAM 01: Query support for system-wide attributes (ALF-6832)
    - At this stage it only has support for count-style queries
    - General-purpose change that will be needed for main Enterprise branches
   25162: Temporarily disables the balloon framework while I fix a bug in it.
   25163: Basic support for canned queries: extended tests
    - ALF-6910: RTEAM 01: Query support for system-wide attributes (ALF-6832)
    - General-purpose change that will be needed for main Enterprise branches
   25164: Further Site Export/Bootstrap work - support importing People (profiles for users), and placing them into the correct groups
   25165: ALF-6905 - RTEAM 04: Add restrictions to trial license
   25166: ALF-6644 - Theme per site.
    - Theme selection for a site and its child pages can be made in the Customise Site page
    - Framework now allows theme per application, site or page.
   25167: ALF-6790: First pass at new site dashboards welcome dashlets
   25168: ALF-6832 - RTEAM 19: Update DescriptorService
   25169: ALF-6906 - RTEAM 18: Report Team or Enterprise in startup log
   25171: ALF-6998 - activities feed email - reuse Share messages (including L10N)
   25172: ALF-6910: RTEAM 01: Query support for system-wide attributes
    - Added and call canned queries for users and documents
    - ALF-6832 TR25: License restriction reporting
   25175: ALF-6998 - activities feed email - fix build copy of activity-list*.properties
   25176: ALF-6962 - activities feed email - use configured share url (from sysAdminParams)
   => share.protocol, share.host, share.port, share.context (note: you may need to override for dev/demo env)
   25178: ALF-6564: TR12: Implement JMX Form Processor. Added tests, fixed a couple of bugs in form processor and added all Mike's form config for MBeans we're provisionally exposing.
   25187: ALF-6998 - activities feed email 
   - quick fix if running within repo-only context (eg. via Eclipse)
   25188: Prevented NPE with Enterprise edition built as community.
   25189: Expose getAllowWrite on the TransactionService API
    - This is a user-independent flag as opposed to isReadOnly, which makes allowance for the 'System' user
   25190: Work on ALF-6832:TR25: License restriction reporting
    - ALF-6893: RTEAM 03: Expose restrictions using RepoAdminService
    - Use TransactionService as the source of 'isReadOnly'
   25191: Fix to issue where null could be passed as URI Tokens
    - fixes issue where pages failed to render on first display since rev 25166
   25192: CSS tweak
   25194: I18N'd system startup message
   25195: Restrictions now sets current time and readOnly property.
   25196: ALF-6790: Added user prefs to enable site welcome dashlet visibility
   25198: ALF-6790: Fix user close welcome dashlet persistence. Added site welcome dashlet close reload.
   25200: ALF-6803: Update upload dialog title to display (encoded) folder name (not entire path)
   25203: ALF-6834 - TR15: Activities feed email notifications
   - ALF-6931 - RTEAM 23: update activity feed DAO to filter by min id and/or max items
   - ALF-6929 - RTEAM 21: now uses last feed id for each user
   - minor cleanup (eg. tweak template to deal with null message)
   25204: ALF-6790: Fixed broken site preference logic
   25206: Checkpoint ALF-6608 - Inline property editing - name field. Also paves the way for ALF-6611 - Inline property editing - any meta field. Currently does not constrain input values, nor handle repository errors (e.g. duplicate name).
   25212: ALF-6602: Updates to reflect latest designs
   25213: ALF-6564: More MBean form config
   25248: A new schema version range for 3.5
   25249: ALF-7049 - RTEAM 12: Disable Alfresco Explorer
   25252: ALF-7050 - RTEAM 09: Disable MT
   25263: Fix trailing comma for IE browsers
   25268: Implementation of ALF-6829 Popularity of a node (RatingService).
   
   This check-in is actually a fairly generic support for rolled up property values within rating schemes.
   Popularity is currently the only concrete rollup in the system, but it should be possible to add more without too
   much difficulty.
   
   Given the published API for the rating service, we have added rollups for "ratingCount" and "ratingTotal" for the built-in rating schemes (likes). Therefore searching/sorting on either cm:likesRatingSchemeCount or cm:likesRatingSchemeTotal, both of which are defined in an aspect cm:likesRatingSchemeRollups should give popularity for the likes rating scheme.
   
   
   Additions to the content model.
     I have added aspects, properties for the built-in rollups, namely count and total.
   
   Spring changes
     The rating scheme(s) now have rollups injected into them. These rollups are algorithm classes that know how to calculate the rolled up props.
     Naming conventions are used to determine the output property and are captured in RatingRollupNamingConventionsUtil.java.
   
   API changes
     New methods: RatingService.getRatingRollup(NodeRef, String, String)
     & RatingScheme.getPropertyRollups()
   
   Changes to the RatingService implementation and JUnit test code.
   
   To roll your own rating rollups:
     To add your own rating rollup, you need to reuse one of the existing AbstractRatingRollupAlgorithm subclasses or create a new one.
     That class will produce the value of the rolled up property by iterating the ratings in the given rating scheme for a given node.
     You need to inject your rollup algorithm into the rating scheme bean in rating-services-context.xml
     On applyRating() and removeRating() the RatingService will check the rating scheme for any registered rollup algorithms and will have them recalculated.
     It will then use the naming conventions described in the JIRA and in RatingRollupNamingConventionsUtil to get aspect/property names for each of the rollups.
     It will then add the property value in the normal way.
     Therefore, you need to extend the content model to include the expected aspect and property values. Follow likesRatingScheme for a sample.
   25273: Fix failing unit test.
   25274: DocLib sorting support for "popularity" (Likes rating scheme)
   25277: ALF-6602: Updated instructions to reflect new design. Info shown now dynamically based on site ownership/access rights/browser feature support
   25278: Merged BRANCHES/V3.4 to BRANCHES/V3.4-TEAM:
      25267: ALF-1070 - if site/user is deleted then immediately clean associated site/user feed
   25279: ALF-6601: Updated to handle 0 byte dropped files (or folders)
   25280: ALF-7009 WIP checkpoint
    - Also removed some code that is obsolete since ConsoleTool class extends Alfresco.component.Base
   25286: ALF-6599: Changed folder DND target back to image (not row)
   25298: ALF-7009 - Upload and replace Share logo
   25311: ALF-7080 / ALF-7002 - ActivitiesFeed subsystem (+ option to enable/disable job triggers)
   - moved ActivitiesFeed into subsystem for dynamic mgmt via JMX
   - FeedNotifier repeat interval can be dynamically changed
   - also added "enabled" property to AbstractTriggerBean => FeedNotifier job can be disabled / re-enabled
   25312: ROLLBACK (Partial) 25249 ALF-7049 Disable Alfresco Explorer.
   25313: ROLLBACK 25252 : ALF-7050 - RTEAM 09: Disable MT
   25317: ALF-6930 - bootstrap / patch activities email template
   25331: ALF-6890 - RTEAM 16: License-based restrictions: Number of users
   25333: Merged BRANCHES/V3.4 to BRANCHES/V3.4-TEAM:
      25319: Build/test fix (fallout from ALF-1070)
      25322: Build/test fix (fallout from ALF-1070)
   25356: ALF-6930 - bootstrap / patch activities email template
   - missed file, sorry !
   25358: ALF-6834 - Activities email: tweaks
   - pass through repeatInterval (to template model)
   - add exclude email list (eg. for default admin)
   25360: RTEAM 28: License restriction reporting: Force refresh
    - Added API for selective updates of usage data based on an enumeration: USAGE_USERS, USAGE_DOCUMENTS or USAGE_ALL
    - When people are added, for instance, usage will be updated and then retrieved for checking.
   25363: ALF-6639 - Default collaboration dashboard
    - NOTE: may need Team overlay version on merge if this change is *not* the default for Swift
   25364: Modified usage/restriction admin webscripts to use a common FTL lib for the json output and added some missing quotes around the license mode value.
   25365: ALF-6597: Added DashletTitleBarActions widget and applied to WebView dashlet
   25367: ALF-7082 - Remove Network Dashlet
    - Removed network dashlet from codeline
    - Support in WebScripts to allow hook for override of exception handling from webscripts for specific use cases
    - Surf LocalWebScriptRuntime overrides error handling looking for specific case of SC_NOT_FOUND - and silent ignores missing webscript components
    - Improved Share handling of missing webscript components that have already been bound into a dashboard (i.e. not a missing "slot" but an existing component binding that points to a missing webscript URL) - this will also allow for easier removal of other existing dashlets in the future without requiring repo-side patches or similar.
   25369: ALF-7042 (ALF-6832) RTEAM 28: License restriction reporting: Force refresh
    - Added unit test for update WebScript
   25375: Implementation of ALF-7024. Document versions service/webscript needs to return avatar url.
   The avatar url has been added to the JSON response as requested.
   If there is no avatar, a JSON null is returned as requested.
   25377: Add maxDocs, maxUsers and license mode to License JMX bean
   25378: Adding additional property to version.get webscript: a correctly-formatted ISO8601 date.
   This has been added as requested in the comments of ALF-7024.
   25381: Refactor of LicenseComponent and related to produce LicenseMode in descriptor (ALF-6907 RTEAM 19)
    - Need actual enum to do later usage updates according to mode
   25382: ALF-7053 - RTEAM 07: Disable Transfer
   25387: ALF-6564: Finished JMXFormProcessor (again). There is now a configurable list of operations to ignore, revert is ignored by default. The labels for the buttons are also localisable now.
   25390: Fixed up License MBean after changing the descriptor API
   25391: ALF-6911: RTEAM 02: Record and expose system attributes
    - Added job locking around individual usage queries
    - It is possible to concurrently update user and document counts
    - Exposed true/false return value on updates and added this to usages webscripts
   25392: Switched version edition back to Community
    - If we distribute Team using a community build, then we should know about it.
    - Team functionality is triggered by an Enterprise build or TEAM license.
   25393: Undid rev 25392
   25394: Work on ALF-6832:TR25: License restriction reporting
    - ALF-6893: RTEAM 03: Expose restrictions using RepoAdminService
    - ALF-6911: RTEAM 02: Record and expose system attributes
    - Added RepoUsageMonitor
      - Self-starting schedule
      - Only checks for restrictions that are in place
      - Issues warnings and errors; puts system into read-only mode on violation
   25403: ALF-6890 - Switch over of user query to database backed query.
   25408: WIP checkpoint for Agenda view refactor:
      - Adds Alfresco.util.friendlyDate to supply "Yesterday/Today/Tomorrow" style date
      - refactors getEvents into a common function in calendar-view.js (calendar-view-month not touched because it gets elements from the DOM rather than API)
      - Uses DataTables to display agenda events (currently unformatted)
   25410: Merged BRANCHES/DEV/V3.4-BUG-FIX to BRANCHES/V3.4-TEAM:
      25409: Merged BRANCHES/V3.4 to BRANCHES/DEV/V3.4-BUG-FIX:
           25407: Merged BRANCHES/V3.3 to BRANCHES/V3.4:
                25401: Allow continuous.xml database drop/create on postgresql and mysql to support the database being on a different machine
                25406: We no longer need a 2nd _test database for the unit tests, so remove the code that created/removed them during the continuous build
   25411: Fix to allow application logo to be uploaded with same filename as a previous logo.
   25416: Implementation of ALF-7100. Comments webscript doesn't return dates in iso8601.
   I added iso8601-formatted date fields jsut as for ALF-7024.
   25418: Implementation of ALF-7173. Remove the RatingService restriction whereby a single user can only rate a single node with one RatingScheme.
   Change to the RatingService javadoc so that it doesn't mention the restriction.
   Additional method in RatingService: getRatingsByCurrentUser - to return multiple ratings.
   Reimpl's testOneUserRatesInTwoSchemes test case from a -ve to a +ve test case.
   Rewrote the REST test cases slightly to cover the case of a single user multiply rating a node.
   Various changes through the apply() case to support this.
   25419: Change the Site Loading for ALF-6567 from a bootstrap to a patch. This means that if a site is loaded then deleted, it won't be re-loaded again.
   25420: Fixed unit test for ALF-6911: RTEAM 02: Record and expose system attributes
    - Forgot to prompt user usage changes to check numbers against
   25422: Addition of selfRatingAllowed field to ratingdefinitions.get webscript.
   As this is now a configurable property on a scheme, it should be reflected in the REST API.
   25423: Node rows that transition to the deleted state (not archive) are given type sys:deleted
   25425: Add an example extension context file to patch-load an exported Site, and allow the import path to use defaults to reduce the number of settings required
   25426: ALF-6597: Added temporary tooltip code for DashletToolbarActions (and updated to WebView dashlet to use it)
   25427: ALF-6789: Removed dynamic welcome dashlet from add dashlets menu
   25428: ALF-6599: Removed encoding of spaces in displayed location name on DND upload to folder
   25430: ALF-6890 - tweaks to query and person service for user limit stuff.
   25432: ALF-6597: Updated DashletToolBarActions to ensure fade in on first mouseover
   25433: Implemented ALF-6613, ALF-6614, ALF-6615, ALF-6616, ALF-6617, ALF-6618, ALF-6619, ALF-6620, ALF-6621, ALF-6622 - PART #1 
   - ALF-6613 TR22: Document Details page improvements
   - ALF-6614 Page redesign and refactor
     * Components are atomic and doesn't need global events to work.
   - ALF-6615 Document Actions panel
   - ALF-6616 Tags panel - NEW, replaces the old "info (tags+permissions)" component
   - ALF-6617 Share links panel
   - ALF-6618 Properties panel
   - ALF-6619 Permissions panel - NEW, replaces the old "info (tags+permissions)" component
   - ALF-6620 Workflows panel
   - ALF-6621 Version History panel
   - ALF-6622 Comment component redesign and refactor
   - alfresco-macros.lib.ftl
     * <#function uriTemplate id> 
       Helper for getting a uriTemplate in freemarker
     * <#function userProfileLink> 
        Helper fopr rendering a userProfile link in freemarker
   - alfresco-util.js - Rhino Javascript-helpers
     * function error(code, message, redirect) 
       Helper for redriting and throwing a webscript error
     * function param(name, defaultValue)
       Helper for placing a webscript "param" in the model, lloks for param in the following order args, page.templateArgs, properties, defaultValue. 
       If no value is found and no default value was given an error is thrown.
       Useful to avoid webscripts "crashing" when accessed from /service/ rather than from /page/ path, i.e. when refreshed/reloaded using ajax.
     * function getRepositoryUrl()
     * function getRootNode()
     * function getDocumentDetails(nodeRef, site)
   - alfresco.js
     * New in Alfresco.util.DataTable
       c.dataSource.doBeforeParseData - to modify response before rendering, i.e. if an array is the respons rather than an object
       c.dataTable.config.className - if another css class than alfresco-datatable shall be used
       c.paginator.history - set to false to avoid browser history management to kick in
       reloadDataTable() - to reload
       getData(record) - to get data related to a row in the table
     * sanitizeMarkup() - moved out code from request(), strips out <script> tags from html
     * New in Alfresco.base.Component
       - createYUIButtons()
       - attachLinkClickListeners()
       - refresh(url) - gets new markup from server and replaces the old and unregisteres the js component instance
   - base.css 
     * .alfresco-twister-actions - use this class to place actions in the twisters that are visible when twister is opened
     * .document-version - common css class for version label
     * .alfresco-datatable - Common styling for datatables created from Alfresco.util.DataTable, 
        gives list like appearence and removes headers and bprders.
   - NOTE! Tested in FF3.5 & SF4, PART #2 will contain: 
     x-browser testing, tidy up comments form, social gadgets in header, activities after new version upload
   25437: ALF-6789: Added confirmation dialog for welcome dashlet close
   25439: More WIP for Team's Agenda view. General clean up, code commenting and start of styling.
   25443: ALF-6597: Added actions to remaining dashlets
   25451: Site label suffix removed from title bar
   25452: ALF-7053 - Disable Replication Service
   25453: ALF-6599: Disabled DocLib DND upload when viewing non path filters (and fixed filter view bug that was previously introduced)
   25454: Stub out the user upload via CSV webscripts
   25455: Implemented ALF-6613, ALF-6614, ALF-6615, ALF-6616, ALF-6617, ALF-6618, ALF-6619, ALF-6620, ALF-6621, ALF-6622 - PART #2
   - components doesn't break when accessing a working copy OR a repository document (non site)
   - remove som unecessary code that slipped in with comments-list.js
   - "Add comments" now clears the editor before the next add
   - Comment paginator is only visible when necessary (happens to all paginators by default,force show with c.paginator.hide=false)
   - removed the document-details.ftl instantion of the javascript class
   - version panel isn't rendered on doc details page for working copies 
   - versions panel had white background under text "No previous verisions exist"
   - code commenting sweep 
   25457: ALF-6599: DND event listener fix
   25460: CSS tweak to document path
   25461: ALF-6790: Updated links for invite and upload for managers/contributors
   25462: ALF-6811: Added upload users CSV button to existing user admin console page. Stubbed code for invoking WebScript
   25470: Some build fixes
   - in general running without an authenticated user
   - getPerson -> getRestrictions without any security context
   25473: Added csv, xsl, xslx formats/mimetypes to default list for webscripts.
   25475: ALF-6608: Inline property editing - name field
   ALF-6625: TR04: Balloon popup (tooltip) component
   Also Document Library restyling: rollover style, text removed from most buttons, new icons.
   25476: Repository Browser brought up-to-speed with latest Site DocLib changes.
   25477: TEAM build fixes
   - fix unprotected service not to use public services - allows repoAdminService to be wired up to personService
   - There may be collateral damage to test using the messageService
   25482: Add the Apache Commons CSV library, and also fix the classpath breakage caused by the postgresql jdbc jar switch
   25483: Implementation of ALF-7005. TR24: Remove inappropriate rule script actions.
   Both sets of script actions (email templates and scripts) are built up using FolderContentsParameterConstraint objects.
   Using this class a location in the repo is specified and all cm:content children under that location (recursive) are included.
   I have added a new, optional property to that class which allows the specification of a list of file extensions, which is used as an inclusion filter for the content nodes.
   I decided against using a MIMEtype-based filter as there are situations where users add e.g. .js files as text/plain.
   Then I inject "js" and "ftl" as inclusion filters in the relevant action-constraint beans in the action service.
   We can easily add further file extensions should it be necessary.
   
   25484: ALF-6597: Fixed IE6 selector issue
   25486: ALF-6597: CSS correction to r25484
   25488: Small adjustments to descriptor logging during startup.
   25489: Team Eclipse project
   25491: ALF-6789: CSS tweaks to welcome dashlet columns
   25492: Get the basics in place for the user CSV upload - provides a sample csv file, loads it, process the contents and reports a JSON response, but doesn't yet create the users
   25495: ALF-6642: TR08: Site only view - remove Repository view.
   Copy and Move to dialogs only display Sites destination in this mode.
   Note: Page mapping not removed until it's clear how this will integrate with the installer; hence manually browsing to the Repository Browser is not pretty right now.
   25496: Minor follow-up fix for Repository Browser.
   25497: Support for ALF-6642 on details pages.
   25499: Document Library sort improvements: individual sort parameters can now be given a default sort order (like the Share search results page). Currently configured as name: ascending, popularity: descending.
   Also added support for "#upload" in URL to show the upload dialog.
   25500: ALF-7120: TR03: Test and integrate sample site into bootstrap process
   
   NOTE: This will install the Work In Progress sample site to your repository next time you start the repo. 2 new users will be added and will count towards your allocated users, you can safely delete the site and the users, they will not get re-loaded.
   25501: When generating the example file for the user CSV upload, have the webscript generate .xls and .xlsx versions, as well as the previous .csv one.
   25502: ALF-6790: Update upload link to #upload to get upload dialog
   25503: Team build fix: Fix message service tests after changing the beans wired up
   25505: New requirements for ALF-6617 "Share links panel", now only displaying link to current page
   25507: ALF-6640 - WIP. Initial styling pass, event actions, etc.
   25511: ALF-6789/ALF-6790: Removed old welcome dashlets
   25512: Resolve ALF-7099: Duplicate view:reference entries in an ACP export created using multiple noderefs
   25514: General cleanup of implementation and use runAs to query Admin-only service
   25516: More ALF-6893: RTEAM 03: Expose restrictions using RepoAdminService
    - Added 'licenseValidUntil' to web script returns (may be null)
   25518: Harden MessageServiceImplTest against leaked transactions
   25519: Refactor the common code for dealing with tenant usernames + tenant domain checking, during person creation, out to the person service
   25521: ALF-7099 export follow up: emit associations after all objects
   25523: Add support to the User CSV Upload webscript to actually create the people and users, using the new common service methods in common with share
   25524: Implementation of ALF-7093. Transfer/replication actions must not be displayed when the transfer service is disabled.
   
   Note: It is the ReplicationService which is enabled/disabled as opposed to the TransferService.
   A new webscript has been added (available at GET /api/replication-service-status) which returns 
   {"data": {"enabled": true}}
   
   Also a new REST test case.
   25525: ALF-6911: RTEAM 02: Record and expose system attributes
    - made getRestrictions() accessible to 'guest'
   25526: Update the user csv upload webscript with some debug log entries, and excel support
   25528: ALF-6602: Updated to new (temporary) images, updates to CSS
   25535: Removed deep svn:mergeinfo.  Please merge from base of code lines and remove spurious svn:mergeinfo
   25536: Merged V3.4 to V3.4-Team
      25399: Fix for ALF-6991: "Connection pool causes poor performance in some test suites"
             - applied constructor fix recommended by https://issues.apache.org/jira/browse/DBCP-330
      25400: Fix for ALF-6991: "Connection pool causes poor performance in some test suites"
             - commit missed file
      25474: Eclipse classpath tweaks to prevent element-based entry for Commons DBCP
   25537: ALF-7094: First cut of TR24: JSF-based login screens should warn unsupported when in Team mode. The wording needs reviewing and changing as does the position and styling of the text.
   25542: Implementation of ALF-7182. TR20: When a user 'likes' a document it appears in the activities feed.
   MikeH gave me the JavaScript changes for this in Share tier. Thanks Mike.
   I added some ftl and properties.
   25546: ALF-6602: Further image and CSS tweaks to doc lib assistance
   25548: Enhancements to user limit error reporting (ALF-6890: RTEAM 16: License-based restrictions: Number of users)
    - Report the usernames being added that generate the limit violation
   25549: ALF-6789: CSS updates
   25551: Fixed bug in Alfresco.util.DataTable when setting default css class name (appearing i.e. on trash can admin ui)
   25552: Minor cleanup in createPerson code.
   25554: ALF-6635 "TR12: Browser based administation - JMX admin console pages"
   25557: Updated version of sample site for Team, the full page width welcome dashlet is now present for both users.
   25559: First phase of ALF-6835:
    - Share now retrieves repository license/restrictions via REST API on first user login
    - Dynamically applies override config onto Alfresco config based on license info - allows Enterprise/Team specific tweaks to UI etc.
      - also constructs an object representing the license/restrictions that can be read by Surf components
    - Share Footer component now dynamically switches Community/Enterprise/Team logos and text based on config
    - Removed team project from source tree - NOTE: remove it from your local Eclipse projects
    - Removed team build targets - NOTE: devenv team targets will no longer work
    - Removed enterprise overlay for footer and share enterprise logo (no longer required due to dynamic footer configuration)
   25562: ALF-6835 - About Share dialog now displays appropriate edition logo and background based on license details
   25566: Allow users of the Mail action to pass in extra model options for their templates to use. 
   25568: When processing user CSV uploads, skip cleanly over blank lines
   25570: ALF-6811: Updated users admin console page and associated scripts to process WebScript feedback
   25572: ALF-6884 - TR25: Reload license file on live server via JMX operation on LicenseDescriptor mbean.
   25575: Agenda View WIP. Added add/edit/show more events functionality, bug fixes and styling. Updated Calendar API to include event description!
   25578: Bring user limit warnings in line with PersonService (create time) warnings
   25579: Repo usage monitoring done every 12 hours
   25580: ALF-6599: Update folder target highlighting & update temporary images
   25583: Fixes bug in Calendar Agenda view - number of days shown by default (was: from now - end of current month, is: from now until now + 30)
   25584: ALF-6602: Fix broken links on assistance panel
   25585: Branding and CSS tweaks from Linton
   25587: Wrap the User CSV upload result json in a data block, to better fit the current pattern
   25591: In the User CSV upload webscript, correct line numbers in error messages for excel uploads
   25593: Dashlet title rollover behaviour changes. Insitu edit balloon now removed when textbox loses focus.
   25596: Impl of ALF-7175 Comment order ... changed.
   This check-in adds a repo-side webscript parameter to reverse the order of comments
   25599: ALF-7233 remove doc for changing server.transaction.allow-writes
   25601: ALF-6811: Update to users.js to handle modified JSON response from WebScript
   25602: Agenda View, Bug fixes and CSS tweaks.
   25605: The empty 'Operations' set no longer appears in view mode and made the mail.password field behave like a password field
   25606: Tweak the JSON to better fit the current layout standards
   25607: Add a few more fields to the User CSV upload, based on the fields in Share
   25609: ALF-6645 - Branding tweaks
   25613: Help URLs moved to new edition based config - removed enterprise overlay.
    - NOTE: final 3.5 URLs still to be decided!
   25624: ALF-6789/ALF-6790: Updates to CSS/DOM to achieve completely fluid vertical and horizontal layout
   25626: ALF-6789: Updated profile to provide #edit hash and welcome daslet to make use of it
   25628: ALF-7207 - activities feed email / mail action executor
   - mail action executor should not get (+ auto-create) person when running as System
   - prepare / send email for each person as a separate txn
   - also: add actual / max feed item counts to template model  (as per ALF-6834)
   25631: Share Admin Console tool groupings
    - Implemented basic groups of tools in the admin console
    - First attempt at grouping tools - needs review by Linton/MikeF
   25644: Disable repository searching for team license configuration.
   25646: ALF-6835 - License details shown on License Descriptor admin page
    - Fixed up out-of-date JMX form bean names (changed on repo side since original JMX form config)
   25647: Team Agenda View - no events text, and other minor fixes
   25648: ALF-6811: Updates CSV WebScript response, added HTML format handling, added results panel to user console.
   25650: File missed from check in 25647
   25652: Start to convert the User CSV uploader to using localised error messages and error responses rather than non-localise exceptions
   25653: Added MikeF's url templates for ALF-6628 TR23: Preview support for Flash Video and HTML5 video.
   
   25654: ALF-6835 - Edition Interceptor improvements
   25655: Update how the User CSV Upload webscript returns messages and errors. Makes use of a property loaded via a resource bundle, and a new extension to WebScriptExtension which is driven by a supplied ResourceBundle, rather than the system-wide ones (which don't hold webscript specific messages)
   25656: ALF-6789/ALF-6790: Updated text, CSS/DOM tweaks & update to site-members to provide all members hash for welcome dashlet
   25658: ALF-6811: Updates to HTML format response for CSV request to support HTML uploader
   25659: Partial implementation of ALF-7230.
   This check-in changes the bootstrap data within the acp such that the sample JavaScript files in Data Dictionary/scripts are now bootstrapped as *.js.sample.  Their content has not been changed.
   Note that this applies to backup.js, example test script.js, backup and log.js, append copyright.js, alfresco docs.js and test return value.js.
   A separate solution will be provided for the command-*.js scripts.
   
   25660: Better reporting of the script causing stream errors
   25661: ALF-7231: RTEAM 32: FileFolderService method to get localised file
    - Locate the base translation using the well-known QName path (selectNodes) - this is the current way.
    - Call this additional method to locate any localized siblings
   25662: ALF-7263 - Track multiple reasons why we are read only otherwise we can't go back to read/write.
   ALF-7220 - Repo Usage Component Unlock
   25663: ALF-7256 - Ensure license reload does not damage server after upgrades
   25666: ALF-6811: Fix success message for all users uploaded
   25668: Increased user limit to 10 users for trial license
   25672: Some formatting
   25673: Minor comments format from Javadoc to inline
   25674: User count reporting: Keep track of disabled users on person
    - Disabling a user adds an aspect to the related person object
    - Should be able to export after disabling user
    - Don't count disabled persons
    - User count is reduced by 1 to cater for 'guest'
    - RTEAM 16: License-based restrictions: Number of users
   25679: A little more information is now returned if an error occurs whilst persisting MBean attributes or invoking an MBean operation.
   
   The sample site root node is prevented from being archived when it's deleted during the sample site bootstrap process.
   25681: ALF-6789: Change "Close" to "Remove"
   25685: Agenda View: Fixes Tagging.
   25686: IE fixes and slight change to the "automatic" binding from button/links against a component (value/rel attribute is now treated as a simple string instead of as an object)
   25688: Agenda view - new sketch logo from Linton for when there are no events
   25689: Feed edit icon css class
   25690: Invite test uses disabled users
   25691: ALF-7229 - partial (for Activities Feed Notifier)
   - also cleanup IoC deps
   25693: Work in progress ALF-6593: TR04: Update dashlets to provide consistent look & feel, include thumbnails, help text, action links where applicable
   25694: MERGED V3.4-BUGFIX to V3.4-TEAM
      24898 : Fix to FixUserQNamesPatch
   25695: ALF-6789/ALF-6790: Added new icons, removed old ones
   25697: ALF-7231: RTEAM 32: FileFolderService method to get localised file
    - Fixed extraction of 'base' name to be parts before *first* period
    - Changed unit test to use 'Something.html.ftl'
   25698: IE7 bug fix (a comma sign had slipped in by mistake)
   25701: Continued implementation of ALF-7230. Bootstrap data amendments and additions for Team.
   This changes the name of DataDictionary/EmailTemplates/NotifyEmailTemplates/notify_user_email.ftl to .../notify_user_email.ftl.sample.
   With this check-in there will now be no .ftl files available for the Rules UI's "send email" action. The "Use Template" dropdown will have no contents. A future check-in will add the new (i18n'd) ftl files.
   25702: Adds options support to Alfresco.widget.Resizer & updates console and calendar templates to use it. Tweaks styling on calendar to make it behave.
   25703: Update the FileFolder localised version tests to do both Standard.html/Standard_fr.html and Another.get.html.ftl/Another_fr.get.html.ftl so we test both cases
   25704: Provide a util helper for building Share and Alfresco (Explorer) urls up from SysAdminParams
   25705: ALF-6628TR23: Preview support for Flash Video and HTML5 video.
   - Customisable plugin architecture added for web-preview component, ootb plugins are:
     * WebPreviewer: for documents (and image & flash movies) in other words the "good ol previewer"
     * FlashFox: .mp4 & .flv videos for users w FlashPlayer 9
     * StrobeMediaPlayer: .mp4 & .flv videos for users w FlashPlayer 10
     * Video: HTML5 <video> element, support depends on the browser, but if youre lucky it might support .webm & .ogv movies
     * Image: Displays images using the <img> tag (if taken from the nodes content and the image is larger than 0.5 mb, a link must be clicked to get the conten displayed).
     * Flash: embeds flash content using swf-object
     * plugin kicks in depending on node's mimeTYpe & thumbnail in combination w rules defined in web-preview.get.config.xml
   - Added new mime types to repo:"video/ogg", "audio/ogg", "application/ogg" & "video/webm"
   25706: ALF-6628TR23: Preview support for Flash Video and HTML5 video. part 2
   - some strange white space characters had made their way in 25705
   25708: Add new notifyPerson method to the Person service. This sends an email to the newly added user telling them their credentials, where to log in etc. 
   (Email template patch to follow)
   25709: Use the new user notification method on the Person Service if requested, through the user CSV upload and person script service. It is on by default for CSV uploads, and off by default for javascript (Share)
   25710: Add security file missing from earlier PersonService.notifyPerson checkin
   25711: Further impl of ALF-7230.
     Ensuring that the (recently renamed) notify_user_email.ftl.sample file has a qname path which is .sample-based.
   25712: ALF-6835, ALF-7093 - Various improvements to Admin Console related to showing appropriate components based on license edition and admin console tool groupings.
    - JMX tools now only available when an appropriate Enterprise license is found
    - Subset of JMX tools available for TEAM edition
   25713: Library updates for rev 25712
   25719: Fix Alfresco.util.DataTable first request after r25693. Slight tweak to console tools list CSS for readability. Also modify how item separators work in social panel.
   25722: Fixes broken links in wiki page within Team sample site
   25732: Added quicktime move to the list of supported previews
   25733: Added localised model title and descriptions for all the cm:person properties
   25735: Revert non-English message bundles
   25736: Document Library folders defaulted to visible on first use.
   25739: Workaround for exceptions during bootstrap of clean db.
   Changes to the email template acp introduced an exception. The changes are related to ALF-7230.
   25740: Added read-write locking around veto code
   25741: Patches runAs 'System' to allow execution even in read-only environment
   25742: Patches runAs 'System' to allow execution even in read-only environment
   25743: Removed some javadoc-style comments within methods
   25744: Enhanced usage GET method
    - Currently, I have problems preventing real data from being returned; so see dummy data
    - Made usage GET a guest operation
    - Included 'level', 'warnings' and 'errors'; see usage.get.desc.xml.
   25745: Fix typo in error message
   25748: ALF-7094: TR24: JSF-based login screens should warn unsupported when in Team mode (final text from Linton/docs)
   25749: Make an unrestricted license available in the build classpath of each version
   25750: ALF-6622 "Comment component redesign and refactor"
   - Current user's avatar is displaye in add comment
   - editor is correctly configured and styled and uses full width
   25751: ALF-6602 - Final drag'n'drop icons and text from Linton/docs.
   25752: Email templates for new user notifications, and a patch for this (applicable to both new and existing installs)
   Note - acp may need a refresh later for tweaked templates, and description tweaks, but it shouldn't be a problem for anyone who gets this version now
   25753: Reduced property path console logging on startup
   25755: More acp hacking for ALF-7230.
     Now the property key is defined in bootstrap-spaces.properties. Oops. Mustn't forget that next time.
   25756: Update the User CSV scripts to use the new titles and descriptions for the person model, in both the template, and in the upload when skipping over title rows
   25757: Tweak the User CSV upload template to show the descriptions properly in all excel versions
   25758: Usage messages for usage web scripts
    - Fixed unit test fallout
    - Added license timeout as a restriction/usage element
   25759: Fix for making "poster" attribute to videos understand the filesuffix of a thumbnail
   25761: Fixed template to remove redundant 'warnings'
   25762: Add a note about why this class generates mail text itself, via dedicated template service calls, instead of following the new pattern of passing a template noderef + model to the Mail Action Executor
   25763: Update the site invitation mail action to enable the use of localised email templates (where present), and update to the new noderef+model pattern (rather than processing the template in the class)
   25764: Fixed bug where it was only possible to upload a new version once on the docuemnt detais page, also small css tweaking in the version list
   25765: Fix for ALF-7337 Email with content shorter than 5 chars causes exception in MailActionExecuter.
   A simple fix that tightens up some string comparison.
   25766: JMX MBean error handling: UI now shows the error message returned from the form processor. As the raw error message is being shown I have also localised the error messages on the server.
   25768: Sample site users are now loaded in a disabled state so they do not count towards the user count. The main wiki page also had a broken link to one of the images in the project library which is now fixed.
   25771: Removed organization id from the CSV upload as it's not used anywhere in the UI
   25772: Added protection for the usage.users or usage.documents properties being null
   25775: Removed unused warning suppress
   25776: Minor formatting
   25777: Added ability to get transactions that don't respect read-only vetos
    - Typically used by doing
          RetryingTransactionHelper txnHelper = transactionService.getRetryingTransactionHelper();
          txnHelper.setForceWritable(true);
          ...
    - This ranks with the 'Run As System' for permissions, but allows a clean separation between permissions and transactions.
    - Don't have to force everything to run as 'System' to get a writable transaction, but 'System' will still have one.
    - ALF-7236 RTEAM 34: Reload Licence fallout
      - ALF-7256: Ensure license reload does not damage server after upgrades
   25778: Allow patches to run against read-only system
    - Made a write-forcing RetryingTransactionHelper available for patches and their offspring worker threads
    - main upgrade thread is already running as 'System' user
    - ALF-7236 RTEAM 34: Reload Licence fallout
      - ALF-7256: Ensure license reload does not damage server after upgrades
   25779: ALF-7257: Changed read-only setting to server.allowWrite to avoid mixing with Spring config
   25780: Further impl of ALF-7230.
     This check-in includes a patch which bootstraps a .html.ftl notification email template and placeholder templates for supported locales es, fr, de, it. (The notification email has a broken link in it. I will fix that today.)
   25781: Inbound Email admin console tool disabled for Team edition
   25782: Agenda View style fixes, non-default theme updates and description expand.
   25784: Added MBean form config for the IMAP susbystem.
   25786: ALF-6635 - Added IMAP admin console component
   ALF-6835 - License component improvements
   25790: ALF-6835 - Show license info warnings/errors. Show SysAdmin JMX console component so share host/port can be set for email templates.
   25791: Build fix for recent changes (labels being added, scripts being renamed and site membership URL cleanup)
   25794: Add missing admin user exclude to the people export with a site
   25795: Further impl of ALF-7230.
     Added a new acp containing a new example JavaScript file & a patch to bootstrap it in.
   25796: Removing unnecessary property values. As part of ALF-7230.
   25799: Improved the order of the fields in the sysAdmin MBean form, fixed typos in a couple of labels and provided more explicit labels (there were 2 fields each called Context, Host, Port and Protocol)
   25800: Removed the loading of the command-*.js files that end up in Data Dictionary/Scripts. If they turn out to be required by something (we can't find any code reference to them anywhere) then they will need to be added back but to a different location.
   25802: ALF-6884 "TR25: Reload license file on live server via JMX operation on LicenseDescriptor mbean."
   25804: Agenda View polishing: Style tweaks, removed refresh jump, added "Today" button (currently uses page refresh), new Sketch icon, etc.
   25805: Fix up license admin component after previous checkin
   25806: Update the new user email template acp to have localised descriptions for the templates
   25808: ALF-6621 "Version History panel"
   - activitiy filed after new version upload
   - fixed bug where revert didn't work
   - components refresh inline instead of page reload
   - made alfresco-macros.lib.ftl work when "page" attribute isn't present
   25811: Update the site invite email templates to be localised and html. For new installs, you will get the html versions from the acp. For old installs, the text version will remain in DD, and you'll get (+ start using) the new html ones.
   (Change also pushes some freemarker model logic from the people invite into template service, so the site import can use it.)
   25812: For new installs, don't bootstrap load the old invite-email.ftl, as we now get the new html ones from an acp patch that always runs
   25813: Merged V3.4-BUG-FIX to V3.4-TEAM (3.4.1 changes)
      24884: adding back runBare over-ride - test was deadlocking
      24894: Merged BRANCHES/V3.3 to BRANCHES/DEV/V3.4-BUG-FIX:
         24892: Fix ALF-6729: Corrected build paths for WQS following upgrade of commons-pool library
      24901: Fix ALF-6590: Requesting details of many assets using a GET request was causing Tomcat to close the socket connection. Changed so that we use a POST for this request.
      24905: Merged V3.3 to V3.4-BUG-FIX
          24904: Fixes ALF-5964: Installer height too small RHEL (records only)
      24928: Merged V3.3 to V3.4-BUG-FIX
         24927: Fixed ALF-5025 (ALF-6206): Support background processing of archiving
             - Added property: xam.archive.forceBackgroundStoreMove=false
      24930: Merged V3.3 to V3.4-BUG-FIX
         24929: Merged DEV/DAVEW/SAP to V3.3
            24925: ALF-6667: Fixed possible deadlock where index merger is never rescheduled under heavy load
      24941: Merged BRANCHES/DEV/BRIAN/wqs-caching to BRANCHES/DEV/V3.4-BUG-FIX:
         24613: WQS: Added caching layer for asset collections. Improves rendering time of homepage by 23% at steady state.
      24944: ALF-6662 - Transfer/replication servers need to be compatible versions
   25814: Convert the activities email templates patch/bootstrap from a single xml + classpath ftl, to an acp containing localised html versions following the new pattern
   25815: Merged V3.4 to V3.4-TEAM (RECORD ONLY)
      24946: Merged V3.4-BUG-FIX to V3.4 (RECORD ONLY)
         24752: Merged V3.4 to V3.4-BUG-FIX
            24751: Merged V3.3-BUG-FIX to V3.4 (RECORD ONLY)
               Restored V3.3-BUG-FIX mergeinfo, somehow truncated in revision 24274
         24757: Merged BRANCHES/V3.4 to BRANCHES/DEV/V3.4-BUG-FIX:
            24756: Fix for ALF-6269: WebForm (Edit Web Content Wizard) ERROR on Alfresco Community Edition 3.4.b and 3.4.c
         24771: Merged BRANCHES/V3.4 to BRANCHES/DEV/V3.4-BUG-FIX:
            24767: Merged BRANCHES/V3.3 to BRANCHES/V3.4:
               24765: ALF-6547: fix intermittent test failure (AssetServiceImplTest renameFile/renameFolder) - fallout from ALF-1948
         24802: Merged BRANCHES/V3.4 to BRANCHES/DEV/V3.4-BUG-FIX:
            24801: Fix for ALF-3055: "SecurityTestSuite hangs when run in DOD5015 context - failed authentication audit hangs on DB connection"
                - do failed audits in a separate thread (from a thread pool)
         24822: Merged BRANCHES/V3.4 to BRANCHES/DEV/V3.4-BUG-FIX:
            24821: Fix for ALF-3055: "SecurityTestSuite hangs when run in DOD5015 context - failed authentication audit hangs on DB connection"
               - fix up unit tests
         24838: Merged BRANCHES/V3.4 to BRANCHES/DEV/V3.4-BUG-FIX:
            24828: Merged BRANCHES/DEV/BELARUS/V3.4-2011_01_13 to BRANCHES/V3.4:
                24824: ALF-6361: web-client-config-custom.xml doesn't work in /alfresco/tomcat/shared/classes/alfresco/extension
         24857: Merged V3.4 to V3.4-BUG-FIX
            24853: Merged V3.3 to V3.4 
               24852: Fixed ALF-6573 "Incorrect name of subgroups on "Groups" page"
         24858: Merged BRANCHES/V3.4 to BRANCHES/DEV/V3.4-BUG-FIX:
            24750: Limit installer builds to 2 threads
         24874: Merged V3.4 to V3.4-BUG-FIX
      24948: Merged V3.4-BUG-FIX to V3.4
         24718: Merged V3.3 to V3.4-BUG-FIX
            24717: Fix ALF-5555: It is impossible to edit review date from record's details page
         24719: Fix for ALF-6106: Error on Check In operation with % symbol (SPP)
         24733: Better fix for ALF-6106: Error on Check In operation with % symbol
         24734: Fix for ALF-6089: Incorrect order of fields at 'Create Series', 'Create Category' and 'Create Folder' forms
            The name, title and description fields are now placed in their own group on the server, all other non custom rm fields are put in an 'other' group, the client side config then declares a set for each group and orders them appropriately.
         24753: Merged V3.3-BUG-FIX to V3.4-BUG-FIX
            23870: Merge Dev to V3.3_BUG_FIX
               ALF-4243: F5 load-balancer sending regular HTTP requests to Alfresco server causing Faces Servlet to throw java.lang.NullPointerException (MyFaces upgrade to from 1.1.5 to 1.1.7)
            23897: Additional fixes and tweaks since introduction of MyFaces 1.1.7 library.
            23919: More JSF component id related fixes.
            23945: More MyFaces1.1.7 JSF page fix ups
            23959: Another MyFaces 1.1.7 dup id issue fixed.
            24008: ALF-4243
               - Upgraded MyFaces from 1.1.7 to 1.1.8 to fix a bug seen in 1.1.7
               - Added handling for the fact that valuebound properties that result in null now cause an exception where-as they were perfectly valid in 1.1.5.
            24419: Merge from V3.3 to V3.3-BUG-FIX
               r.24418 Fix for ALF-6075. Running out of /tmp space on the server is causing uploads to fail.
         24768: Fixes ALF-6295: Allows MySQL to not be installed via unattended installer invocation
         24779: Merge V3.3 to V3.4-BUG-FIX
            24497 : ALF-3092 - deployment service - catch Throwable from Begin.
            24684 : Merge DEV/BELARUS/V3.3-BUG-FIX-2010_10_04 to V3.3
               23498 : ALF-5498 In Windows XP, placing a Folder with a Name that already Exists Removes all Content of the Existing Folder
            24749 :  ALF-6174 - Transfer Service fails with double peer assoc custom content type
            24766 : ALF-5603 - It is impossible to assign workflow from workflow console to non-admin user
         24812: Fix ALF-6316: A new "spoof" multivalue text property (cm:tagScopeSummary) is now made available for TagScope nodes when accessed via the getProperty or getProperties operations on the standard node service. The values of this property take the form "<tagname>=<tagcount>". A new interceptor has been added to the node service to do this (TagScopePropertyMethodInterceptor). WQS has been tweaked to make use of this new property, and the now defunct behaviour has been removed.
         24820: Work in progress refactoring transaction handling of transfer unit tests.
         24834: ALF-6468 - Update the scheduled actions folder bootstrap to use localisable names and descriptions, following the normal pattern
         24836: Added system property 'system.cache.disableImmutableSharedCaches' (false by default)
            - Equivalent to disabling Hibernate L2 cache for *immutable* entities
            - Allows distinction between mutable and immutable cache entries
         24850: Fix ALF-6562: Moved property that is used to label the WQS dashlet on the "configure site dashboard" page out of the Slingshot project and into the WQS Share Module project. Corrected its value to "Web Quick Start" rather than "WCM Quick Start".
         24860: ALF-6673 - bootstrap folders and rename
         24870: Removed svn:mergeinfo from root
         24873: Merged V3.3 to V3.4-BUG-FIX (RECORD ONLY)
            21789: ALF-4333: Fix
               - Updated RepoPrimaryManifestProcessorImpl so it can handle deletions that are reported by either pre-delete noderef or archived noderef (previously only handled the latter).
               - Updated TransferManifestNodeFactory so that it handles the case where the status of the node to transfer is "deleted".
               - Updated UnitTestTransferManifestNodeFactory so that it handles the change to TransferManifestNodeFactory above.
               - Added new tests for deletion cases.
            23259: Merged HEAD to V3.3
               23256: Fix ALF-4573: Start Workflow action is absent for edited document and working copy in Share
            23346: Brought WebQS module in (including build process but not installer elements yet)
            23371: "Simply" added wcmqs to installer
            23391: ALF-5367: Copy dlls into tomcat/bin as appropriate.
            23485: Merged V3.4 to V3.3 (fix backported for V3.3.x lines)
               23472: Fixed ALF-5408: SQL Server missing ON DELETE CASCADE declarations
            23515: Merged PATCHES/V3.2.0 to V3.3
               23514: ALF-5554: Merged HEAD to V3.2.0
                  23153: When updating tag scopes following system shutdown/restore, be smarter about quickly skipping tag scopes that another (new) thread is currently working on
                  23283: More debugging level logging for tagging updates, to help identify the problem with periodic multi-threaded test failures on bamboo
            23535: Merged V3.4 to V3.3 (complements 23517: ALF-5552)
               23508: Fixed ALF-5559: Permission interceptors can fail if Lucene returns invalid NodeRefs
            23564: ALF-5600: Merged V3.4 to V3.3
               23424: Fixes: ALF-2989 - Incorrect sideId reference in URL for event in Site Calendar Dashlet
                  Adds support for displaying events that start in the past but finish in the future (previously only events that start in the future were shown)
            23586: MERGED V3.4 to V3.3
               22864: Fix for ALF-5005: "Create and edit functions on AWE become "confused""
               23042: Fix ALF-5127: Impossible to create an article/blog (WCMQS) [Must clear panel hideEvent handler if manually hiding a YUI panel]
               23561: Fixes: ALF-4569 - Removes universal override of input width box and switches the editor form panel to adjust it's width based on content rather than window size. 
                  Fixes: ALF-4570 - Adds an override for the CSS 'top' property of the form dialogue to ensure it's always below the ribbon. (Was being set automatically by the YUI widget.panel call)
               23569: Fixes: ALF-5606 - Ribbon wasn't resizing correctly after the form events.
            23630: Backport of installer
            23631: Added 64-bit & deployment installers
            23664: Fixes ALF-5691: TransferService: Multi-byte characters are not encoded correctly
            23681: Fixes ALF-5699: TransferService: Snapshot file from source repo never contains complete MLText properties
            23695: Fixed bug exposed after fixing ALF-5699. Parsing of MLText properties out of the transfer snapshot file was incorrect, and that was causing multi-lingual property values to be duplicated
            23709: ALF-5699: Fix NPE in ManifestIntegrationTest
            23734: Merged V3.4 to V3.3
               23731: Fixes for ALF-3098 and ALF-3097
                  - Share - Security check on Personal Dashboard - only the owning user can view a user dashboard page
                  - Share - Security issue on Customize Site Dashboard - private and moderated site dashboard pages no longer visible to non-members, customise site and dashboard pages only accessible to SiteManager
            23747: ALF-5696: Merged V3.4 to V3.3
               23585: Fixed ALF-5372 "JavaScript error on Groups management dialog with IE8 : document.getElementById is null"
            23790: Fixed ALF-3823 "Share: RSS feed can't be read: http://cds-srv.sun.com:8700/rss/update/public/sunalert_update.xml - ok with other RSS client."
            23883: Fixes ALF-5759: WQS: Attempt to copy a website section fails
            23907: Merged DEV/BELARUS/V3.3-BUG-FIX-2010_09_20 to V33
               22750: ALF-4846: Update rules are firing on inbound actions 
            23931: Undid rev 23907 (Reverse-merged /alfresco/BRANCHES/DEV/BELARUS/V3.3-BUG-FIX-2010_09_20:r22750)
            23961: Fixed ALF-5686 "Incorrect behaviour of "All" filter in "My Tasks" dashlet"
               - Variables assigned in a <#macro> shall always be assigned using <#local> (using <#assign> makes them globally available which might cause naming collisions)
            24132: Disable intermittent failing unit test
            24148: ALF-6007: Merged HEAD to V3.3
               23049: Fixed ALF-5099: Error when trying to go back in Create Web Content Wizard (only with certain XSDs)
            24263: Merged from V3.3-BUG-FIX to V3.3
            24264: V3.3-BUG-FIX to V3.3
               24262: Stress test code for ALF-5025: Support background processing of archiving
            24287: Added missing import
            24336: Merged V3.4 to V3.3
               23205: Fix for ALF-2111 - Download URLS are different on different pages, authentication fails when URL sent
            24353: Merged V3.4 to V3.3
               24352: Fix SQL fallout from ALF-6078
            24510: Merged V3.4 to V3.3
               21960: First round of date refactoring: Document Library pages now expect XML dates (ISO8601) from Share data webscripts
               21961: Share client-side I18N utility now emulates sever-side handling of doubled-up single quotes.
            24526: Merged V3.4 to V3.3
               24402: Fix for performance degredation related to ALF-3823. 
                  RSS feed processing in JavaScript relies on Rhino impl of regex - this is extreemly slow as Rhino regex is by far the slowest component of the library. 
                  Switched code to use the Java Regex libraries to improve performance and reduce memory usage.
            24587: Merged V3.4 to V3.3
               24564: Fix for ALF-3727: Custom permissions aren't visible in Explorer UI
            24604: Merged V3.4 to V3.3 
               24602: Build fix for RM permission model loading - collateral damage for R 24564
            24774: Merged BRANCHES/V3.4 to BRANCHES/V3.3:
               23492: Fixed ALF-5550: DB2: Unable to insert values into alf_string_value
            24813: Merged BRANCHES/V3.4 to BRANCHES/V3.3:
               24750: Limit installer builds to 2 threads
         24880: Merged V3.3 to V3.4-BUG-FIX
            24463: Fixed ALF-4398 "Path to rule set is not displayed" ($html alias was missing from a merge)
            24465: Merge V3.3 to V3.4 (RECORD ONLY)
               24463: Fixed ALF-4398 "Path to rule set is not displayed" ($html alias was missing from a merge)
            24493: Fix for Mac OS X CIFS logon problem, change UID to start at one as zero has special meaning, plus other minor fixes. JLAN-112.
            24569: Fix for ALF-5333: Webdav - Online editing of files in a folder with German umlauts does not report correct characters
            24611: Fix broken build due to merge #fail (r24460 / ALF-4015)
            24668: ALF-4557 - Upgrade of large repository to latest 3.3 fails on excession of mysql table lock size
            24707: Fix for handling of null first/last name in wiki page list
            24710: ALF-5535 - Fix to correctly format json number values (not as numeric human readable strings)
            24794: Fix for ALF-4984 - Outdated custom-slingshot-application-context.xml.sample file for share
            24798: Fix for ALF-5806: Lucene query does not return expected result.
               - Alfresco FTS now supports the prefixes ~ and = for phrase queries
            24814: Build fix after r24798: Fix for ALF-5806: Lucene query does not return expected result.
            24823: Synchronization improvements to RemoteClient and http proxy hosts
            24825: Fixed #3 of ALF-6308 "Share data issues"
               - Share falls back to use "html uploader" (in all browsers except IE) when "JSESSIONID" cookie is unreachable from javascript (like when "HttpOnly cookies" is activated on the server.
            24835: Fixed ALF-5484: Check-in does not update association
               - Copy code when copying over an existing target node was NOT processing associations
               - Fallout from refactor and subsequent fixes related to ALF-958 (Target associations aren't copied)
               - Some commented-out unit tests reintroduced
            24842: Fix for ALF-6308 item #4 - validate the redirect URL to ensure it is a relative url
            24845: Merged DEV/DAVEW/SAP to V3.3
               23874: ALF-5822: Correct Lucene throttling mechanism to prevent build up of excessive committed deltas
                  - Also correct BatchProcessor's mechanism for single-threading batches with cross dependencies
                  - Single-threaded batches must be sequenced in order
               23876: ALF-5822: Default lucene.indexer.mergerTargetOverlaysBlockingFactor to 2 for better write performance under load
               24022: ALF-5822: Refinement of fix
                  - Don't block a thread that has already entered the prepare phase with another indexer (e.g. a cross-store commit). Otherwise it could block indefinitely and never enter the commit phase
                  - Also added extra debug diagnostics and handle all Throwables on failure
               24023: ALF-5822: Minor correction to debug log message
               24421: ALF-6134: Do not export org.hibernate.jmx.StatisticsService through JMX to avoid excessive blocking under load
               24422: ALF-6135: Remove lock contention from concurrent Lucene searches
                  - Added a RW Lock and Thread local-based solution to org.apache.lucene.store.FSDirectory.FSIndexInput.readInternal() to avoid contention during multiple parallel Lucene searches. This is already recognized as a bottleneck by the Lucene developers, who offer NIOFSDirectory as an alternative, which unfortunately doesn't work on Windows.
                  - Added RW lock to org.apache.lucene.index.TermInfosReader.ensureIndexIsRead()
                  - Threads no longer hanging in lucene searches during load tests. Woohoo!
               24423: ALF-6136: Don't call through to org.apache.log4j.NDC unless debug is enabled as it's heavily synchronized. Also avoid dynamic method invocation by using a delegate.
               24426: ALF-6138 (SURF - PARTIAL): 'Warm' the java.beans.Introspector cache for key Freemarker accessible bean classes on loading in static initializers
               24428: ALF-6139 (SURF - PARTIAL): First log in to Share is expensive due to 'lazy' dashboard creation and excessive synchronization
                  - Added AVMRemoteStore.createDocuments() for creating multiple XML documents at once, all embedded within the same master XML document in the request body 
                  - Added corresponding saveDocuments() methods to Store, RemoteStore, Model, ModelObjectManager and ModelObjectPersister on the Surf side 
                  - Used this in PresetsManager 
                  - Removed excessive synchronization from StoreModelObjectPersister 
               24429: ALF-6140 (SURF - PARTIAL): Surf tweaks to allow concurrent execution of web scripts
                  - Use StrongCacheStorage instead of MruCacheStorage in RepositoryTemplateProcessor to avoid use of a synchronized cache
                  - Tweak cache sizes in FreeMarkerProcessor
                  - Use thread local object wrapper delegates in QNameAwareObjectWrapper and PresentationTemplateProcessor to work around synchronization in DefaultObjectWrapper
                  - Swap in the same object wrapper to WrappingTemplateModel
                  - Use a concurrent HashMap in ModelObjectCache and ModelHelper and remove excessive synchronization
                  - Use RW locks rather than synchronized blocks in AbstractWebScript
               24431: ALF-6141: Improvements to IBatis DAO performance under load
                  - Use lazyLoadingEnabled="false", enhancementEnabled="false" to avoid unnecessary blocking and generation of CGI proxies in IBATIS DAOs
                  - Use useTransactionAwareDataSource="false" to prevent Spring from agressively unwrapping DBCP connections and bypassing the prepared statement cache
               24432: ALF-6142: Remove dependency between RepositoryAuthenticationDAO and Lucene
                  - Reworked RepositoryAuthenticationDAO to use a node service lookup by child association QName
                  - This required adding a patch to 'upgrade' the qnames of existing authentication nodes, which previously all had the same QName
               24433: ALF-6143: Remove net.sf.ehcache.use.classic.lru setting from EhCacheManagerFactoryBean and InternalEhCacheManagerFactoryBean to prevent serialization of accesses to shared caches by multiple executing threads
               24434: ALF-6144:  DirtySessionMethodInterceptor was causing contention between multiple threads calling the same DAO.
                  - Unfortunately method.getAnnotation() is a synchronized call, and thus causes concurrent calls to the same method to contended with each other. 
                  - Added a non-blocking cache so that DAOs can be accessed in multiple threads without contending. 
               24435: ALF-6145: Use RW Locks in Subsystem Framework
                  - The operations relied on by the dynamic proxies wrapping subsystems were synchronized and thus caused contention when multiple threads were calling in to the same subsystem
                  - Replaced synchronized blocks with use of read write locks, thus allowing multiple concurrent readers
               24436: ALF-6146: Regulate PermissionModel accesses with RW locks, rather than synchronized blocks and an excessive number of concurrent hashmaps.
               24438: ALF-6136: Fix build classpath
               24439: ALF-6142: Fixed seeding of admin user password
               24444: ALF-6142: Fix unit test fallout
                  - InviteServiceTest needs a transaction
                  - RepositoryAuthenticationDao must listen for Person username changes and update authentication node qname accordingly
                  - Correction to MT handling in RepositoryAuthenticationDao
                  - Repository Authentication Component must 'normalize' the username before passing it through the DAO
               24445: ALF-6145: Correction to lock handling when propagating destroy() events
               24446: ALF-6142: Add new dependencies to unit test
               24448: ALF-6142: Further fix ups
               24461: ALF-6142: Fix unit test
               24664: ALF-6408: Prevent possible deadlock during reindexing
                  - waitForHeadOfQueue() now only called in beforeCommit() phase rather than afterCommit() to prevent deadlocking with Lucene throttler
                  - indexes are also flushed beforehand in beforeCommit() so that indexing work can still be parallelized
                  - also prevent potential deadlock caused by clearing of IndexInfo.thisThreadPreparing in a nested transaction
               24810: ALF-6653: Use read write lock in Hibernate ReadWriteCache to avoid needless contention on L2 cache reads
               24817: ALF-4725: Avoid excessive lock contention in dbcp by upgrading to 1.4
                  - also upgraded commons pool
               24818: ALF-6658: Remove synchronization from LockService - transaction local collections used anyway
               24844: ALF-6681: Don't let the PostLookup job stack up in multiple threads
                  - Now only executes in one thread at a time and skips scheduled slots where it is already running
            24864: Fix for ALF-5904: Explorer - Space model rights not duplicated when creating a space based on a template
               - copy service no longer uses hasPermission
               - added tests for permission copy scenarios with assorted rights
               - this fix assumed there is nothing special about templates - ie that they should always carry permissions and is the "default" copy behaviour to copy permissions if possible
            24865: ALF-6145: Fix failing unit test
            24878: ALF-6146: Correction to write lock around requiredPermissionsCache
         24881: Increment version revision
         24884: adding back runBare over-ride - test was deadlocking
         24894: Merged BRANCHES/V3.3 to BRANCHES/DEV/V3.4-BUG-FIX:
            24892: Fix ALF-6729: Corrected build paths for WQS following upgrade of commons-pool library
         24898: Fixed merge issue in FixUserQNamesPatch
         24901: Fix ALF-6590: Requesting details of many assets using a GET request was causing Tomcat to close the socket connection. Changed so that we use a POST for this request.
         24905: Merged V3.3 to V3.4-BUG-FIX
            24904: Fixes ALF-5964: Installer height too small RHEL (records only)
         24928: Merged V3.3 to V3.4-BUG-FIX
            24927: Fixed ALF-5025 (ALF-6206): Support background processing of archiving
               - Added property: xam.archive.forceBackgroundStoreMove=false
         24930: Merged V3.3 to V3.4-BUG-FIX
            24929: Merged DEV/DAVEW/SAP to V3.3
               24925: ALF-6667: Fixed possible deadlock where index merger is never rescheduled under heavy load
         24941: Merged BRANCHES/DEV/BRIAN/wqs-caching to BRANCHES/DEV/V3.4-BUG-FIX:
            24613: WQS: Added caching layer for asset collections. Improves rendering time of homepage by 23% at steady state.
         24944: ALF-6662 - Transfer/replication servers need to be compatible versions
   25816: Removed unused config files; superceded by subsystem configuration
   25817: Tweak how the html notification/invite template ACPs are patched/bootstrapped to better fit the pre-existing pattern
   25819: ALF-7230. Fixed the document link sent out in the notification email.
   This document link is now a Share link and requires the admin to have configured SysAdminParams with server config data such as port number etc.
   Added the SysAdminParams bean to the ServiceRegistry
   Added a helper method to TemplateNode to get the Share URL for a (document) node.
   Updated the email templates within the acp to use the helper method in TemplateNode.
   25820: Merged V3.4 to V3.4-TEAM
      24885: Fix ALF-6694: V3.4.0 schema inconsistencies
         - ALF-6712: DB2: alf_authority missing index 'authority' during upgrade
         - ALF-6714: ALL: alf_prop_unique_ctx missing FK index on upgrade from 3.3 and 3.2
      24889: Disabled intermittently failing test (ALF-6700) until it can be made more reliable.
      24951: Merged DEV/DAVEW/SAP to V3.4
         24950: ALF-6698: Allow clearBatchSize and updateBatchSize properties of userUsageTrackingComponent to be controlled through system.usages.clearBatchSize and system.usages.updateBatchSize global properties
      24966: Fixed ALF-6363: Transaction status incorrect during afterCommit phase
         - Covered by unit tests
         - afterCommit or afterRollback will report "Not in transaction"
      24969: Fixed ALF-4372: JavaDocs don't match code for Index Recovery Modes (VALIDATE)
      24970: WQS: Fixed web publishing transfer service Spring definition (hopefully permanently now) following change to TransferService requirements
      24974: Fix ALF-6813: WQS: Specifying the sort order in the query of a dynamic asset collection has no effect
      24978: WebDAV: minor debug logging fixes
         - fix WebDAVHelper logger name to be consistent (with rest of WebDAV and other filesys protocols)
         - log service call as info (separate from rest of debug)
      24983: Step 1 of ALF-3891: Policy beforeDeleteChildAssociation not fired on delete node
         - Clean up deprecated beforeCreateChildAssociation, which could only be used *after* the event
      24985: Attempt to fix ALF-6820: Slow CMIS unit tests on build box
      24994: Fixes: ALF-6815 - terminology change (also fixes encoding bug that was preventing files being loaded into translation memory)
      24995: ALF-6572 - WCM: virt svr - enable "lazyDeploy" by default
         - can be disabled (in server.xml)
      24997: correction/kludge of DescriptorServiceTest.
      25002: Fix up test.
      25029: Merged DEV to V3.4
         25009: ALF-5829: Cannot upload files to Records Management site using WebDav from Mac OS X
             - Configuration constant that maps User-Agent pattern to response status code was added to WebDAVMethod.
             - Method that determines response status for AccessDeniedExeption using ‘User-Agent’ header was added.
             - AccessDeniedException processing was changed to return appropriate status.
      25043: Merged DEV to V3.4
         25012: ALF-6758: Potential JGroups Locking issue requiring jgroups upgrade
         JGroups was upgraded to the latest available stable version 2.11.1 Final:
            - jar was upgraded;
            - sources were upgraded;
            - classpath of the ‘3rd Party’ project was upgraded;
            - AlfrescoJGroupsChannelFactory was upgraded according to extension in superclass 
      25061: Merged DEV to V3.4
         24920: ALF-1787: Slow performances when many workflow are opened
             1. Implementation of a custom query for JBPMEngine.getAssignedTasks.
             2. Uint test for creating and testing neccessary items in DB.
         25014: ALF-1787: Slow performances when many workflow are opened
             1. HQL query for TaskInstance properties chache. 
         Also:
            - Moved back to query.list() - no difference with scroll
            - Checked query plan for batching queries and found no problems
            - Batch queries *have* to be limited in the IN clause
            - Although not using scrolling, there was a missing close statement
      25072: Reversed change 25043: Slow performances when many workflow are opened
      25094: Resolve ALF-6736: CMIS Web Services: getObjectByPath() should return an objectNotFound error if the given path doesn't exist
      25107: Resolve ALF-6754: CMIS nameConstraintViolation errors are not returned to client
      25122: Merged HEAD to BRANCHES/V3.4:
         25115: Fixes: ALF-6336 - resolved incorrectly translated date formatting strings.
      25144: ALF-6841 - IMAP Sync Errors
      25148: ALF-6991: Connection pool causes poor performance in some test suites
         - Added explicit 'forceMultipleResultSetSupport=false' in case someone wants to change it.  
         - This is not a fix (or actually a change at all) just a documentation of the options available
      25149: Added transaction leak checks in security tests.
         - Just helpful for diagnosis when one test fails and brings the others down.
      25182: Merged PATCHES/V3.4.0 to V3.4
         25180: Merged DEV/TEMPORARY to PATCHES/V3.4.0
            25150: ALF-6918: Editing a Share document simultaneously using Share HTTP and Webdav breaks the document - working copy relationship.
               User can't unlock and edit original node that was checked out by him. 
               WebDAVMethod-> checkNode() was changed to return Http Status 423 if node has a working copy
         25181: Merged DEV/TEMPORARY to PATCHES/V3.4.0 (with corrections)
            25102: ALF-6894: Share IMAP - Modifier and date/time incorrect.
               ImapServiceImpl.checkForFlaggableAspect() method was modified to  disable "auditable" behavior before adding "flaggable" aspect and then enable it again.
      25193: Fix ALF-7039: Unable to specify target MIME type for renditions generated by the TemplateRenderingEngine
         The "mime-type" parameter is now exposed by any rendering engine that is derived from the BaseTemplateRenderingEngine
      25205: Merged V2.2 to V3.4
         25184: ALF-6914: Use RetryingTransactionHelper in WorkspaceClipboardItem
            - Also decoded the mysterious looping logic
      25214: Merged BRANCHES/DEV/BELARUS/V3.4-2011_01_13 to BRANCHES/V3.4:
         25045: ALF-6435: SPP doesn't work with MT users
      25216: Merged HEAD to BRANCHES/V3.4:
         25100: Fix for build issue Steve was encountering on new build boxes using Ant 1.8.x
      25219: Fix for ALF-6312: "Incorrect work of AWE functionality"
      25222: Merged BRANCHES/DEV/BELARUS/V3.3-2010_12_20 to BRANCHES/V3.4:
         24943: ALF-6103: Explorer - Version type not set by auto version
      25224: Fixed ALF-6992: PersonUsagePatch is sequenced incorrectly and is too slow
         - Added direct SQL update for cm:sizeCurrent (adds a type NULL property just like the Java patch did)
         - Removed the Java patch; ensured that new patch has the old as an 'alternative' and that the old patch is now a NoOp.
         - Tested with 50K users upgrading from 2.1
         - Can be backported safely to 3.2 and later.
         - Will provide instructions in the JIRA for working around.
      25225:ALF-6992: PersonUsagePatch
         - Fixed alf_applied_patch entry
      25229: Fix for ALF-6661: Fixed issue with navigation handling in JSF client, although seen via WebDAV in the bug description, it's actually the same for any inline editing.
      25237: Fix for ALF-6463: Collaborator and Editor cannot rename items via WebDav
      25244: Fix for ALF-6858: Uninitialized FormUI options parameter causes UI to be unusable
      25245: A new schema version range for 3.4.1
      25246: Merged BRANCHES/DEV/BELARUS/V3.4-2011_01_13 to BRANCHES/V3.4:
         25226: ALF-6348: Edit the event to reccurent and backward doesn't work
      25253: ALF-7059: Excessive webscript loading times in v3.3 and v3.4
         - Corrected escaping of Lucene document searches in RepoStore
         - The '-' character was getting interpreted as an operator when searching for package-desc.xml
      25256: ALF-5143: Eliminate use of non-I18N friendly FileWriter
      25258: Undid fix for ALF-6992 revs 25224 and 25225
      25259: Fixed ALF-6992: PersonUsagePatch is sequenced incorrectly and is too slow
         - Fixes ALF-6954, too: CLONE - Attempt to login into Alfresco fails for previously created users ...
         - Follows previous fix removal
         - Moved SQL from bootstrap to patch execution, but still do a mass update
         - Ensure that QNames are present prior to SQL execution
         - 'patch.authorityDefaultZonesPatch' depends on 'patch.personUsagePatch'
      25261: Merged DEV to V3.4
         25160: ALF-1787: Slow performances when many workflow are opened
             1. Implementation of a custom query for JBPMEngine.getAssignedTasks.
             2. Uint test for creating and testing neccessary items in DB.
             3. HQL query for TaskInstance properties chache.
             4. HQL query for ContextInstance variables chache.
      25270: Fix for ALF-6271. ThumbnailRegistry loading definitions without transaction.
      25275: Merged DEV to V3.4
         25243: ALF-6583: when a LDAP admin removes its own account, account cannot be useed anymore and cannot be recreated
             - Full path to node calculating logic was extracted from ‘org.alfresco.filesys.repo.NodeMonitor.beforeDeleteNode()’ policy handler:
             - ‘NodeMonitor’ performs lookup operations as 'System' user
         25251: ALF-6583: when a LDAP admin removes its own account, account cannot be useed anymore and cannot be recreated
             - Additional persons’ cache controlling was added:
                - currently, ‘org.alfresco.repo.security.person.PersonServiceImpl.getPersonOrNull()’ checks all ‘User Home’ NodeRefs before using;
                - all inexistent NodeRefs will be removed from the cache 
      25281: Attempt to prevent build hang in ChainingUserRegistrySynchronizer
      25287: Merged DEV/TEMPORARY to V3.4 (with correction)
         25284: ALF-5596: Alfresco WebDAV does not work when repository is in read only mode.
      25295: Merged DEV/DAVEW/SAP to V3.4
         25207: ALF-6856: Avoid checkout failures under heavy load
            - Stop absorbing all exceptions in checkin / checkout / cancel-checkout
            - Propagate object wrapping code, message and cause instead
         25208: ALF-7062: Use a shared cache in RepositoryAuthenticationDao
         25209: ALF-7063: Use nodeService.exists() instead of a Lucene search in Search.findNode()
         25210: ALF-7064: Use caching plus a read write lock to avoid contention in SubsystemChainingAuthenticationService under load
         25211: ALF-7065: Use cached authorityService.getContainingAuthorities() method to improve performance of SiteServiceImpl.getPermissionGroups()
         25220: ALF-7062: MT fix
         25221: ALF-7062: Fix AuthenticationTest
         25223: ALF-7065: Refinement to use of cached authorities in SiteServiceImpl.getPermissionGroups() that preserves current 'direct memberships take precedence' semantics.
            - First fetch cached recursive group memberships. If there are zero or one, they can be returned immediately.
            - Otherwise, fetch immediate group memberships and work it out from there.
         25230: Extend ehcache cluster sample with socketTimeoutMillis=10000. Increase timeout from its 1 second default to avoid lots of RMI and cache integrity errors under load.
      25297: Fixed merge issue in 25295
      25302: ALF-6067: Unable to run read-only server without error
        - The latest error could not be reproduced
        - Added double-check to bypass audit if the system is in read-only mode (TransactionService.getAllowWrite())
      25306: ALF-5596: Merged DEV/BM to V3.4
         24726: BM - tweak WebDAV propfind (to use read-only txn)
      25326: Fixes for DB coverage: ALF-1787: Slow performances when many workflow are opened
         - Refactored query to use neat JOIN syntax
         - Added back batch size limiting to prevent Oracle blow-outs
         - Added in parameters to cover boolean query conditions
      25334: Added missing quotes in invitation service properties file
      25336: Merged V3.3 to V3.4:
         - 24918: ALF-6496: Browsing large File Plan is slow			
         - 24940: - Fix up issue with over enthusiastic caching of capability results.
              - Rename troublesome capability test so as not to hold up the build.  				
         - 24947: Fix-up to capabilities test.
         - 24973: Unit test fixes
         - 25046: Build fixes
         - 25080: RM: Fix transaction cache key
         - 25260: ALF-7000: RM: Cuttoff action for folder is missing when record is frozen
      25344: Updated capability tests.  More to come.
      25370: Fix for ALF-3339 - Modifying the properties of a link on a Folder does not show up after pressing the OK button but after pressing the 'close' button
      25374: Fix for ALF-6691 - Incorrect behavior of RSS feed for Wiki. Also fixes other minor RSS feed validation issues (pubdate format).
      25389: RM: Build fixes
      25414: Fix for ALF-3202: ALL field not fully implemented in LuceneQueryParser for wildcards, prefixes, and fuzzy
        - all current fields behave sensibly or throw unsupported
      25424: Fix for ALF-6576 - Search by tags shows not empty results on the site which has no content
      25467: Resolve ALF-7074: CMIS web services do not appear to allow ticket authentication
      25508: Fix for ALF-7110 - JSF custom component Form submit value encoding
      25538: ALF-6497: Updates to disposition schedules in progress do no complete with large record sets
         - Updates to records under the control of an edited disposition schedule is now performed in the background
         - A quartz job manages the record updates
         - UI updates to show whether there is a unpublished update to the disposition action pending 
      25539: RM: Ensure not "all" behaviours are switched off when processing disposition action defintions updates.
         - rm search information is now being populated and shown in the Ui correctly post publish
         - see ALF-6497
      25545: Merged V3.3 to V3.4
         ALF-7196: Records only
      25573: Deleted : /alfresco/BRANCHES/V3.4/root/modules/dod-5015/source/java/org/alfresco/module/org_alfresco_module_dod5015/model/FilePlanComponentAspectTest.java
      25603: Updated Postrgresql install switch
      25608: Fix Eclipse classpath after Postgres driver move
      25620: Fix for escalated issue ALF-7218: Advanced Search in Share breaks with custom type which contains underscores in type name
      25622: Merged BRANCHES/DEV/BELARUS/V3.4-2010_12_14 to BRANCHES/V3.4:
         24647: ALF-6307: Compliance for Third Party jars with Source Modified
      25623: ALF-6309: Changes to notice.txt and addition of license files
      25627: Fixes ALF-7222: Updated linux installer window height (with taller image to hide additonal background)
      25633: Fix intermittent unit test failure - retrying txn in RecordsManagementAuditServiceImplTest
      25637: Merged DEV/TEMPORARY to V3.4
         25215: ALF-6696 : Upgrade from 2.1.7 to 3.3.4 failing Due to "out of memory"  
            All large db scripts for all supported dialects was modified to follow batching approach.
         25325: ALF-6696 : Upgrade from 2.1.7 to 3.3.4 failing Due to "out of memory"
            1. Upgrade scripts for all supported dialects was corrected to follow mysql style after David's review of batching porting work.
         25398: ALF-6696 : Upgrade from 2.1.7 to 3.3.4 failing Due to "out of memory"
            Some errors was corrected in upgrade scripts after David's review.
      25643: Initial commit of reworked Japanese language pack
      25669: Merged BRANCHES/DEV/dwebster/ to BRANCHES/V3.4:
         25665: Spanish Language Pack update from Gloria
      25671: Updated installer with simple Easy install.  Fixed binaries inclusion.
      25684: Fixes: ALF-7102 - minor (consistent) typo in i18n string.
      25692: ALF-7293 - Handle error condition of unsupported RSS XML format (RDF in this case)
      25707: ALF-6993 Fixed AlfrescoTimer so that it no longer ends the task if the Timer is set to repeat.
      25715: Fix intermittent failing unit test by increasing time window
      25718: Merged PATCHES/V3.4.0 to V3.4
         25700: Fix for ALF-7059: Webscripts: Startup: webscript loading takes about 10 minutes to complete.
            - QNAME:simpleToken will go down an optimised route
      25720: Fix for ALF-7318: patch.calendarNamespaceUri fails as the TYPE field no longer supports prefix queries
         Part fix for ALF-6291: Inconsistencies in lucene search queries with wildcards and single letters.
      25721: Fixed ALF-7319.  Removed ';'.
      25734: Updated copyright to 2011
      25738: Fix to issue with groups display and wrong panel returned to after cancel group edit
      25773: Merged BRANCHES/DEV/BELARUS/V3.4-2011_02_16 to BRANCHES/V3.4:
         25747: ALF-6307 Compliance for Third Party jars with Source Modified
      25798: Merged PATCHES/V3.4.0 to V3.4
         25789: Merged DEV/TEMPORARY to PATCHES/V3.4.0
            25783: ALF-7079: concurrent access to share site using the Share web UI and webdav by two users break the copy.
               1. The WebDAV MOVE and DELETE methods were modified to properly handle the "MS Word shuffle" for working copies.
         25793: Merged DEV/TEMPORARY to PATCHES/V3.4.0
            25395: ALF-7079 : concurrent access to share site using the Share web UI and webdav by two users break the copy.
               UnlockMethod (webdav) was modified to correctly handle working copies.
      25803: Merged V3.3 to V3.4 (RECORD ONLY)
         25015: ALF-6749: Merged V3.4 to V3.3
            24601: Fix for ALF-6032: It's impossible to create meeting items
         25062: Merged V3.4 to V3.3
            25061: Merged DEV to V3.4
               24920: ALF-1787: Slow performances when many workflow are opened
                   1. Implementation of a custom query for JBPMEngine.getAssignedTasks.
                   2. Uint test for creating and testing neccessary items in DB.
               25014: ALF-1787: Slow performances when many workflow are opened
                   1. HQL query for TaskInstance properties chache. 
               Also:
                  - Moved back to query.list() - no difference with scroll
                  - Checked query plan for batching queries and found no problems
                  - Batch queries *have* to be limited in the IN clause
                  - Although not using scrolling, there was a missing close statement
         25276: Merged V3.4 to V3.3
            25261: Merged DEV to V3.4
               25160: ALF-1787: Slow performances when many workflow are opened
                   1. Implementation of a custom query for JBPMEngine.getAssignedTasks.
                   2. Uint test for creating and testing neccessary items in DB.
                   3. HQL query for TaskInstance properties chache.
                   4. HQL query for ContextInstance variables chache.
         25328: Merged V3.4 to V3.3
            25326: Fixes for DB coverage: ALF-1787: Slow performances when many workflow are opened
                - Refactored query to use neat JOIN syntax
                - Added back batch size limiting to prevent Oracle blow-outs
                - Added in parameters to cover boolean query conditions
         25373: Merged HEAD to V3.3
            25100: Fix for build issue Steve was encountering on new build boxes using Ant 1.8.x
      25807: Merged BRANCHES/DEV/V3.4-BUG-FIX to BRANCHES/V3.4:
         25785: Add the WQS client API to the "generate-javadoc" build target
         25792: Fix ALF-7345: WQS: Unable to place a WQS on the root context of a web container easily. This fix enables the web context of a WQS website to be set to "/" to indicate that it lives at the root of the URI namespace of the web container.
      25809: Merged V3.3 to V3.4
         24899: (RECORD ONLY) Merged V3.4-BUG-FIX to V3.3
            24898: Fixed merge issue in FixUserQNamesPatch
         24913: Merged BRANCHES/DEV/BELARUS/V3.3-2010_12_20 to BRANCHES/V3.3:
            24890: ALF-837 Firefox: Incorrect behaviour of Insert/Edit image option on creating content based on web form
         24962: (RECORD ONLY) Merged PATCHES/V3.3.3 to V3.3
            24959: ALF-6780: Merged V3.4 to PATCHES/V3.3.3
               23385: Fix for ALF-5166: After restore of indexes - AUTO hangs
                  - bulk deletes are now handled as such during index tracking and rebuild (as they are normally)
         25011: Attempt to resolve latest build deadlock: Specify inputstring="" in junit invocations in order to work around Ant bug https://issues.apache.org/bugzilla/show_bug.cgi?id=37887
         25012: Reverse previous checkin.
         25033: ALF-6535: Changes to enable session sticky sessions for SPP
         25034: Merged DEV/TEMPORARY to V3.3
            25026: ALF-6763 : Malformed web.xml prevents 3.3.5 340 JBoss deployment, org.apache.myfaces.ERROR_HANDLING param should be replaced
               1. Web.xml was modified for web-client to allow bootstrap alfresco on Jboss EAP 5.1.0.
         25060: (RECORD ONLY) ALF-6114: Rules for updated items are triggered before users commit any changes.
         25063: Merged DEV/TEMPORARY to V3.3
            25059: ALF-608 Errors when uploading content via CIFS result in zero byte files
               Closing file operations wrapped by transaction in ContentDiskDriver.
               Catching IOException in NTProtocolHandler.procCloseFile() was changed to catching Throwable to avoid delay.
         25067: For for ALF-6807: TinyMCE: This is a follow up of: http://issues.alfresco.com/jira/browse/ALF-5420 (escalation)
         25177: ALF-6855: Adding versionable aspect as rule in share site causes errors
         25186: Merged PATCHES/V3.3.3 to V3.3
            25065: Fix for ALF-6780 Full re index seems to not ends up under certain circumstances.
               - A full rebuild only creates nodes
               - Fixed issue repeating all previous deletes already processed in the transaction (for deletes and updates to nodes)  with every delete/update in the transaction
               - Closed TermDocs enumerations
         25372: ALF-5933: Updated mysql collate encoding
         25456: Fix for ALF-7078: CLONE -Impossible to reject invitation due to script error
         25478: Fix for ALF-6756 - JSON delete should not pass body for request
         25498: (RECORD ONLY) ALF-5964: Updated installer window height for linux
         25533: ALF-6946: Correction to WAS libraries.xml
         25558: (RECORD ONLY) Fixes ALF-6268
         25560: Fixed ALF-7210: User workflow tasks query fails on RHEL
            - Case-sensitivity in the table aliases cause failure on unix
            - Must be 'processInstance' not 'processinstance'
            - Fallout from ALF-1787: Slow performances when many workflow are opened
      25810: Merged V3.3 to V3.4 (RECORD ONLY)
         25070: Reversed revision 25062
   25822: First embryo of social items on doc details page.
   25823: ALF-7336 - License file to be loadable from configurable location
   25824: ALF-7333: TR24: IMAP, CIFS, WebDAV & FTP should not mount company & user home by default
    - Added global property 'protocols.rootPath' defaulting to protocols.rootPath=/${spaces.company_home.childname}
    - Included 'protocols.rootPath' in file-servers config and IMAP config
    - TODO: Get 'protocols.rootPath' into WebDAVServlet
   25825: Fixed Eclipse classpath which contained a reference to someone's Tomcat directory
    - To avoid having to update the classpath, create a project in Eclipse called "Enterprise Runner"
      and pull in the "Enterprise Repository" into that.  Then run tests in context of "Enterprise Runner".
      Additional jars and paths can be pulled in as required.
   25826: Merged V3.4 to V3.4-TEAM
      25301: (RECORD ONLY) Merged V3.4-TEAM to V3.4
         25189: Expose getAllowWrite on the TransactionService API
      25821: ALF-5841 Applied fix to queryTasks() to stop the process definition hibernate query exceeding the limit of 1000 arguments.
   25828: New i18n labels for social interactions
   25830: Working "likes" added to document header on doc details page, using the Alfresco.Like widget found in share.js
   25831: More work in progress ALF-6593: TR04: Update dashlets to provide consistent look & feel, include thumbnails, help text, action links where applicable
   25832: Remove placeholder text (unused)
   25833: Some improvements on the "likes" in share.js, such as calling it Alfresco.Like instead of Alfresco.Favourite...  :-)
   25835: Build fixes for RM related tests
   25836: Added "favourite" on doc details page's header suing Alfresco.Favourite foun din share.js ALF-6614 "Page redesign and refactor"
   25837: Update the new html templates - remove the share_or_team flag (switching to just being "Alfresco"), and rationalise on shareUrl rather than a mix of shareUrl and share_url
   Also tweaks how shareUrl is injected into the model
   25838: I have no idea why FormServiceImplTest is failing on the build server, it runs fine locally. In the interest of getting a successful build this weekend I'm disabling the failing checks until I have time to investigate the environment difference on the build server.
   25839: Fixes to siteURL macro and param reader following recent refactoring.
   25841: ALF-7358 - RTEAM 38: User count is not decremented when users are removed
   ALF-7378 - RTEAM 39: Excess users error is not accurate for an end-user
   25842: Removed deep permission checks in RepoUsageComponent
   25844: Url fix for "like activity" posted from doc details page ALF-6614 "Page redesign and refactor" activities
   25847: ALF-6614 "Page redesign and refactor" added missing peice "comments" in doc detail header
   25848: Update the InviteSenderTest to work with the new way of passing the template details+model to the MailActionExecutor, rather than rendering the text itself
   25856: Change the User CSV Upload webscript to handle the transaction itself. This means that if the transaction commit fails (eg user limit exceeded, custom person validation fails) then we get to send the client our own error message+status code. 
   (Previously the commit failure was trapped by RepositoryContainer, and so the webscript had no control over the error reporting process, which is required in this case to meet share UI needs)
   25858: When generating WebScriptExceptions from a resource bundle (instead of the more usual system properties), ensure that the underlying cause (if present) is included
   25864: Added back logging of subsystem start/stop.
   25865: Removed unused code and comments
   25871: General license fixes
    - Apply forced read-write to transactions
    - Heartbeat code synchronization around enable/disable
    - Fixed license test to check for heartbeat state correctly
   25872: Merged V3.4 to V3.4-TEAM
      25849: Fixed ALF-7379: PostgreSQL patch.migrateAttrAVMLocks error when upgrading to Enterprise 3.4
         - PostgreSQL doesn't accept column aliases without 'as'
         - Probably version-dependent
      25850: Merged BRANCHES/DEV/dwebster/ to BRANCHES/V3.4:
         25843: Updated FR files received from Gloria 2011-02-25
         25845: Updated IT files received from Gloria 2011-02-25
         25846: Updated DE files received from Gloria 2011-02-25
      25859: Merged PATCHES/V3.4.0 to V3.4
         25857: ALF-7376: Detect concurrency problems in PutMethod
      25867: Fixes: ALF-5628 - Meeting Workspace Calendar Entry issue.
      25868: ALF-7274: Reinstate &characterEncoding=UTF-8 into default MySQL JDBC URL, using proper encoding of & for an XML file (&amp;)
   25882: License tests: Narrow down failures (doesn't fail locally) and also deal with logging problems
   25883: ALF-6593: TR04: Update dashlets to provide consistent look & feel, include thumbnails, help text, action links where applicable.
   New placeholder filetype icons @ 32x32.
   New avatar get URL (internal): /slingshot/profile/avatar/{username} or /slingshot/profile/avatar/{username}/thumbnail/{thumbnailname}
   Added "avatar32" thumbnail preset.
   25885: Remove reference to non-existent file. Add folder icons back into path on the details page.
   25886: Added new avatar photo placeholder icons from Linton
   25893: Fixed Legal and License url in About dialog
   25895: Fix for ALF-6622 "Comment component redesign and refactor"
   * show new comments component where required
   * comments in correct order 
   * displaying ok in 1024x768
   25897: Fix for ALF-6622 "Comment component redesign and refactor" part 2 (#svnuserfail)
   * show new comments component where required
   * comments in correct order 
   * displaying ok in 1024x768
   25907: Clean up redundant javadoc
   25909: Wrapped setup and tearDown work in retries
   25910: More ALF-7120: TR03: Test and integrate sample site into bootstrap process
    - Pulled everything into first-level patch
    - Removed build-time dependencies
    - Fixed authentication wrapping
    - Fixed I18N messages for patch
    - Note: The patch ID has changed, but this will not cause problems on re-application
   25912: Fixed test fallout from rev 25910 (ALF-7120: TR03: Test and integrate sample site into bootstrap process)
   25926: Even more ALF-7120: TR03: Test and integrate sample site into bootstrap process
   - Removed exclusions from build script for XML file no longer present
   - Fixed an re-enabled JavaScript test in SiteServiceImplTest that was disabled earlier
   25928: - Added form config for ActivitiesFeed MBean ready for addition to admin console
   - Made all boolean fields use a checkbox
   - Re-ordered Fileservers fields to tidy up form and fixed labels
   25937: Build fixes, updated counts for groups as there are now more groups in a default repo due to sample site being created.
   25940: Added Activities feed admin console component
   Fixed label reference in IMAP admin console component
   25955: Merged V3.4 to V3.4-TEAM
      25946: ALF-7191: Generate duplicate _en resource bundles, using location of _fr bundles as a guide for ALL bundles under alfresco and share WEB-INF/classes 
      25947: ALF-7191: Reverse accidentally committed changes to WebDAV in 25946!
      25954: ALF-7191 - Generate _en bundles for all message bundles for Explorer and Share - using known location of message bundles
   25959: Extra logging around ALF-7336: License file to be loadable from configurable location
   25962: Updated example JavaScript patch to include an example that starts a pooled review and approve workflow for all the members of the site the document being acted upon belongs to. The script has no effect if the document lives outside a site.
   25965: Fixes and tweaks from Alfresco Team UI review meeting
   25973: Fixed issue where some form field labels were not returned, was caused by a bean in the enterprise forms context file having a duplicated name.
   
   Also re-enabled the forms tests I disabled as these should now be fixed too.
   25977: More TR28: Prevent the IMAP 'Email Actions' folder from being created during bootstrap. The folder structure contains rules that point to the scripts we also no longer bootstrap. This folder is used for optional IMAP functionality which can be enabled by manually importing the ACPs if required.
   25982: Merged V3.4 to V3.4-TEAM
      25890: Fix for ALF-5796 - It's impossible to add tag in Japanese language (IE specific)
      25894: Fixed Legal and License url in About dialog
      25896: ALF-6476 -translation on Transfer Target configuration
      25899: First cut of French transfer properties.  Mostly English! but has 3 lines of French.
      25900: Fix for ALF-6916: More Deployment Reports action causes an error
      25916: Updated support URL in readme
      25925: Fix for ALF-6885: alfresco-enterprise-3.4.0.zip package has 2 issues with apply_amps.sh
      25936: ALF-6469 - transfer folders internationalized
      25949: Fixes: ALF-6521 and ALF-6493 (Site discussion's handling of tags with special characters in them)
      25950: Fixes: ALF-6489 - encodes the content's name to make it safe for a URL.
      25951: Fixes: ALF-6487 Adjusts styling for rename panel
      25956: Allow a bit of leeway with audit timing during delete tests
      25957: Fixed ALF-7341: Upload performance degradation when uploading contents to folders with content rules applied.
         - Action executions were being recorded by the ActionTrackingService for all actions
         - Post-commit updates of the action node was reducing performance
         - Added 'trackStatus' to ActionExecuter, ActionDefinition and Action
         - Default 'trackStatus' is false; exceptions: 'replicationActionExecutor' and 'commit-transfer'
         - Adjusted tests accordingly
         - General cleanup around modifications
      25964: ALF-5625 - When viewing properties in version history hitting close results in loop
      25970: Merged BRANCHES/DEV/V3.4-BUG-FIX to BRANCHES/V3.4:
         25967: Fix ALF-7440: WQS: commons-pool library has been upgraded, but WQS build properties have not been changed accordingly
      25974: Reverted rev 25964 - as fix is scheduled for 3.4.2
      25979: Disabling intermittent failing unit test. ALF-7443 logged.
   25989: ALF-7457: Update to Team UI following 01/03/2011 review
   25990: Fix initial load of my tasks dashlet. Dashlet pagination now hidden if dashlet empty.
   25991: Agenda View: fixes minor bugs & attempts to slightly improve usability of Event Info box.
   25993: Fix for ALF-7444: RTEAM 41: ActivitiesFeedNotifier fails to send emails (when built using exploded target)
   25997: License management debug logging
   25998: Temporary logging for license and heartbeat
   26008: Merged BRANCHES/V3.4/ to BRANCHES/V3.4-TEAM:
      25891: Fixes: ALF-7363 (updated JA translation)
      25901: Fixes: ALF-6847 (Italian Translation)
      25902: Fixes: ALF-6861 (incorrectly encoded German character)
      25904: Fixes: ALF-6755 (translation quoting error)
      25911: Fixes: ALF-6478 - French translation correction
      25915: Updates TinyMCE translation as requested in ALF-6486.
      25917: Fixes: ALF-6482, wrong word order in FR has been corrected.
      25913: Fixes: ALF-6334 and ALF-6477 (Profile Edit style issues - makes mark up consistent, clears floats to allow for foreign languages being a tad more verbose than English and adjusts padding to help input boxes line up.
      25919: Fixes: ALF-6655 updated to allow enough space for verbose languages (e.g. FR, ES)
      25941: Merged BRANCHES/DEV/dwebster/ to BRANCHES/V3.4:
           25939: Latest JA update from Translators, received: 2011-02-28
      25943: Merged BRANCHES/DEV/dwebster/ to BRANCHES/V3.4:
           25942: Language updates for property string changes and additions between 3.4.0 and 3.4.1
   26009: Fixes double byte comma issue in JA.
   26010: License loading: Further use of the license change callback
    - Added notification for license failures
    - Heartbeat uses callbacks
    - ALF-6884, ALF-6905, ALF-6888
   26015: Updated sample site, now contains images that can be distributed.
   26016: Temporarily disable failing test: runs locally
   26018: Final version of English HTML email templates.
   26025: Debug logging to test to trace during builds.
   26029: Team unit test fixes and analysis
    - Reintroduced UserUsageTrackingComponentTest with debug logging to aid trackability
    - Fixed at least one LicenseComponentTest (Trial license generation for forcing read-only mode)
    - Added further logging of failed licenses to aid tracability on build box
    - Removed temporary debug logging (build box debug logging working fine)
   26031: Fixed embedded license loading and logging
   26038: Updated Contents.acp of sample site, fixes the broken image link in the wiki's main page
   26041: Merged V3.4 to V3.4-TEAM
      26024: ALF-7466 - Links do not appear correctly in the management Console (RM)
      26033: Correct database cleaning behaviour of continuous build - dir.test.data was never set. dir.root was never getting cleaned.
         - dir.test.data replaced with dir.root
      26036: ALF-6403: Merged V3.4 to V3.4 (lost revision)
         25627: Fixes ALF-7222: Updated linux installer window height (with taller image to hide additional background)
      26039: Fix intermittent failures in InviteServiceTest.tearDown()
      26040: Fix intermittent failures in InviteServiceTest.setUp()
   26046: Test cleanup of license restrictions
   26047: Prevent real embedded license from being picked up during unit tests of embedded license
   26053: Added in loop to wait for asynchronous post-failure auditing (ALF-3055)
   26054: Separation of embedded license location for HeartbeatTest
   26055: Merged V3.4 to V3.4-TEAM
      26014: ALF-7087 - Cannot override webscript files in case of using jboss 5.1GA
      26043: Sync up run-junit-test with junit macros so that it can be used to run unit tests in an enterprise environment (e.g. DB2 / Oracle)
      26044: Possibly fix intermittent TransferServiceImplTest failures by using org.alfresco.repo.transaction.RetryingTransactionInterceptor
      26052: Do not wait indefinitely for a heartbeat in HeartBeatTest. A broken heartbeat would cause the build to hang forever!
   26062: ALF-7492 - MT support for new Team/Enterprise license info retrieval in web-tier.
   26064: Fixed ALF-7419: RTEAM 40: Duplicate warning and error messages when user limit reached
   26066: Fixed ALF-7489: Team - default outbound email settings need removing
    - Now: mail.host=smtp.example.com
    - Added this to build env. on bamboo and bamboo2: mail.host=smtp.alfresco.com
   26069: Removed unused remote-api bootstrap files
   26070: Use PropertyCheck to check for valid property values
   26071: Extra debugging during 'split person' processing
   26072: ALF-7333: TR24: IMAP, CIFS, WebDAV & FTP should not mount company & user home by default
    - WebDAV obeys 'protocols.rootPath'
      - Use dedicated bean to ingest properties so that Spring takes care of the placeholders
      - Servlet gets the bean instead of using web.xml config values
    - Added global property 'protocols.storeName' and injected it into protocol configurations
   26073: Follow-up on rev 26069: Removed unused remote-api bootstrap files
   26074: ALF-7468: Update to Team UI following 03/03/2011 review
   ALF-7474: Check supported mimetypes for new icon support
   26075: Latest dashlet help balloon and empty content text. Missing file from r26074. Consolidated Site and Repository DocLib renderers.
   26076: Fix to base style for Content I'm Editing dashlet
   26078: Fixed the "RM part" of ALF-7013 "Fix up refactored Document Details page and components for RM and WCMQS modules"
   26079: Merged V3.4-BUG-FIX to V3.4-TEAM
      26057: Fix for ALF-6691 - Incorrect behavior of RSS feed for Wiki. Resolves a number of niggly auth related issues with RSS feeds and auth.
      26060: Improvements to error 500 handling page for Share. Complete exception output as HTML comment for administrators and developers. Web-tier server errors now output to the console again also.
   26080: ALF-7358 - RTEAM 38: User count is not decremented when users are removed
    - Added listening during modification of user (enable/disable)
    - Use common warning and error logging: the same logging that is displayed to admin
    - Also fixed erroneous logging of person splitting when a user was changed (it was not actually doing anything)
   26083: JA file moved to reflect changes made while translation was being done.
   26085: Fixed ALF-7529 "No doclib action on details" - caused by double encoding of vtiServer property
   26086: ALF-6835 - Report license errors to all users and warnings+errors to admin on first login.
   26087: Final implementation of ALF-7230.
    - Changed ImapServiceImpl to look for localised siblings of the Imap Email templates. Using the normal FileFolderService method, email templates for IMAP clients will be selected based on server locale.
    - Added new email templates for locales: de, es, fr, it.
    - Changed existing default locale to use ACP for consistency.
   26090: Updated sample site, now includes a video file to highlight new video previewing capabilities
   26091: Fixed ALF-7013 "Fix up refactored Document Details page and components for RM and WCMQS modules" part 2 - WCMQS
   26092: Addition of patch for non-default locale templates for Imap Clients. (ALF-7230)
   Also stepped the db version number.
   26098: Minor updates to dashlet help text.
   26103: Fixed test after default config for email settings were changed.
   26105: ALF-7533: Drag and Drop no longer works into FF3.6 browser
   ALF-7532: Content Rule on RM site (other than Folder) creates 'GUID' folder in Share (fixed as part of general RM fixes)
   
   Also: RM and WCM QuickStart Document Library extensions patched to latest code. WCM QuickStart toolbar extension removed. Drag and Drop refactored to work in Repository Browser and WCM QuickStart; switched off for RM. English property files created when using Slingshot exploded target. Header conditions updated to use correct Community edition string.
   26106: Remove debug output.
   26108: Fix for ALF-7331. Thumbnails in Share do not change from initial generic filetype icon...
   The fix is to have StreamContent.java use the actual resource's modification timestamp for the Last-Modified header.
   It was using the mod-time of a newly created file, which held a copy of the classpath resource.
   This led to a race condition between putting a timestamp on the placeholder and putting a timestamp on the cm:thumbnail node.
   26113: Fix slingshot-exploded target - missed commit from yesterday.
   26114: Merged V3.4 to V3.4-TEAM
      26077: Upped LOGFILSIZ to avoid failures in unit tests with large transactions on DB2
      26084: Avoid intermittent test failures in AbstractTestFormRestApi by using retrying transactions
      26096: Correction to DB2 drop / create commands
      26097: Fixes: ALF-7102, typo in property string.
      26102: Attempt to avoid intermittent failures in TaggingServiceImplTest by upping wait time
      26109: Another go at executing the db2 creation statements synchronously through db2cmd
      26111: ALF-6764 - Copyright year on Share login page out of date
   26118: Made the JMXFormProcessorTest more resilient to changes in the email configuration.
   26122: Fix customize site page following refactoring in r26078. Added Data List page icon.
   26126: Merged V3.4-BUG-FIX to V3.4-TEAM
      26099: Resolve ALF-7539: Tomcat sessions are created unnecessarily when invoking CMIS web scripts from Web Quick Start
   26129: ALF-6929: RTEAM 21: activities feed notifier - add per user on/off flag
   26149: Removed old System.out
   26150: Fixed ALF-3856: Version History lost when Versionable Content renamed via CIFS
    - Added fileservers property: filesystem.renameShufflePattern=(.*\.tmp)|(.*\.wbk)|(.*\.bak)|(\\~.*)
    - Any rename that does not match the pattern on either the source or target names will not be shuffled
    - Requires retesting of use cases involving CIFS and MS Word.
   26151: ALF-6626 TR15: Email notification preferences
   Cleanup to related components
   26161: Fix full installer.
   26162: Updated calendar help with latest icons and styling to match.
   26168: Use new install builder 7.0.3
   26169: Localized installer.
   26173: Tweak to display of warnings/errors after login - reduced impact on server
   26200: Locate Postgres data within alf_data directory
   26209: Locate Postgres data within alf_data directory for Team
   26210: Set license path to include install dir, and set protocol root to Sites
   26215: The ContentTransformerRegistry and the ContentService used to only expose the 'best' transformer for a given (srcMime, targetMime, options). This check-in adds access to the full list of active transformers for any (srcMime, targetMime, options) to those two classes.
   As part of a subsequent fix for ALF-5084, the ThumbnailService will use this list to improve create-thumbnail retry behaviour for problem files.
   26227: Merged V3.4-BUG-FIX to V3.4-TEAM
      26226: Merged DEV/SWIFT to V3.4-BUG-FIX
         26225: 'renameShuffle' detection pattern needed extending and logic was slightly incorrect
                 - Fallout from fix for ALF-3856 detected by new unit tests
   26235: Merged V3.4 to V3.4-TEAM
      26233: Fixes ALF-6019: Ensure PostGres services deleted after installation cancel
   26264: ALF-7653 - sys-admin panel no longer editable
   26265: Merged V3.4-BUG-FIX to TEAM
      26263: Merged DEV/SWIFT to V3.4-BUG-FIX
         26262: Fixed regex patterns to cater for .properties file escapes (ALF-3856)
   26266: ALF-7651 - WebM and OGG Video have 'unknown' mimetype in Team
   26267: ALF-7578 - When importing from an ACP a node with the versioned aspect on it, have an initial version history created starting at the current version label.
   26268: ALF-7687 - Ability to use wild character in People search - Should add configuration to allow zero characters for all search in Team config.
   26272: ALF-7578 - Add unit test for versionable ACP import, and fix the default aspect includes now that we handle versionable
   26287: Fixes ALF-7439: Prevent check on alfrescowcm component
   26290: Fixes ALF-7439: Ensure that virtual server shortcuts don't get created for Team
   26294: Fixed @since tags and some minor coding standards fixes
   26316: Fix for ALF-5084, ALF-5644 and general thumbnail improvements in the area of failing thumbnails.
   
   This check in adds extra functionality to the create-thumbnail action in order to improve how Alfresco handles failing thumbnails.
   The requirements agreed between Services & Prod Mgt were
    - When thumbnails fail we should limit how often they are retried. So the system should remember when a thumbnail has failed for a node. 
    - The retries will be initiated in the same way they are now: by users navigating to a page that asks for the thumbnail (lazy creation), primarily doclib. 
    - Retries will occur at a throttled rate (all the below parameters to be configurable by sys admin, but not yet by JMX). 
    - Initially, retries will be limited to a maximum rate e.g. 1 per minute. 
    - These retries will be allowed up to a maximum count e.g. 2 failed attempts. 
    - After that count is reached, the content will be considered "difficult" and thumbnail creation should be retried at a much reduced maximum frequency e.g. once a week 
    - Retries of difficult content shall be enabled by default, but can be disabled.
   
   This check-in adds a new aspect and a type to the content model. These hold the thumbnail failure information.
   The create-thumbnail action now has a compensating action which is run when it fails.
     AddFailedThumbnailActionExecuter decorates the content node with failure information.
   create-thumbnail now has an action-condition, which means that it will only run if a node is "eligible" for a thumbnail creation attempt.
   Eligibility is controlled by some new properties and is configurable. Default behaviour is as described above.
   
   There should be no change in behaviour for most content nodes in Alfresco.
   However, for those documents which fail to produce doclib or webpreview thumbnails - and most especially those which consume 100% cpu for some time before failing - we expect to see the same behaviour initially on upload (cpu grind as Alfresco or a 3rd party library attempts to produce a thumbnail), but that as time passes, Alfresco should prevent thumbnail creation that will likely not succeed. This should save cpu on the repo server.
   
   And tests. Of course.
   26323: Upgraded login warning to WARN_ALL when user limit reached
    - This now matches the specification document
    - ALF-6832:TR25: License restriction reporting
   26326: Merged V3.4 to V3.4-TEAM
      26142: Merged PATCHES/V3.4.0 to V3.4
         25999: ALF-7377: Validate and reject partial WebDAV requests sometimes produced by NetDrive
      26143: Merged PATCHES/V3.4.0 to V3.4
         26005: Merged V3.4-BUG-FIX to PATCHES/V3.4.0
            26002: ALF-7282 Updated NodeListConverter so that it now implements the method revert(Object, ProcessDefinition)
      26158: Merged DEV/TEMPORARY to V3.4
         26154: ALF-7571: Create Web Project wizard - Step 3
            Superfluous “cellpadding” elements were removed. Missing space was added.
      26164: ALF-6885: Changed svn:eol-style from native to LF for all .sh scripts
      26178: Merged DEV/TEMPORARY to V3.4
         26172: ALF-7601: 3.4.1 SDK WebServiceSamples multiple problems
            Configuration properties for WebServiceSamples was moved to correct place.
            Dependency to SDK AlfrescoEmbedded was added to classpath. It is required for FileCopyUtils from Spring which is used in WebServiceSamples.
      26190: Reversed 26165 / 26161 - breaks installer building
      26192: Convert TaggingServiceImplTest to use retrying transactions!
      26194: ALF-7045: AVM upgrade - re-implement AVM "rename duplicates" patch as a DB upgrade script
      26195: Update installer overlay files
      26197: Final installer updates - built and tested on OSX
      26199: Allow relocatable data for postgres - part2
      26204: Attempt to avoid intermittent unit test failures in RecordsManagementAuditServiceImplTest by adding some Thread.sleep() calls to allow for asynchronous audit behaviour
      26207: Set site notification to false on install (ALF-6181)
      26212: Merged DEV to V3.4
         26203: ALF-7605 PostgreSQL: Upgrade from 2.1.7 to 3.4.1 is failing - constraint "alf_access_control_entry_acl_id_key" does not exist
             1. The statements which are drop constraints, marked as optional
             2. The alter statements with new constraint names were added
      26256: Fixes ALF-7679: Remove webscript-framework-config-custom.xml file
      26270: License updates from Ashutosh
      26274: Fix intermittent unit test failure with retrying transaction
      26275: Possible fix to intermittent test failure.
      26295: Reduce scope of retrying transaction, in a hope of fixing TaggingServiceImplTest.testOnStartupJob()
      26303: And the prize for the largest number of retrying transactions in a single unit test goes to...
      26307: Fixes: ALF-7704: Japanese language option not appearing in dropdown box on log in page.
      26314: Another defensive sleep() in RecordsManagementAuditServiceImplTest
      26325: Moved defensive sleep() in RecordsManagementAuditServiceImplTest
   26336: Fixes ALF-7713: Prevent folder/documents from being draggable in DocLib
   26348: Fix for ALF-7751 - encode all params on new Team dynamic welcome dashlet
   26351: Removed svn:mergeinfo
   26353: ALF-7745 - Add pop-up balloon validation helper to create site dialog.
   URL Name (shortName) is now also auto-generated from the site name (siteTitle) by removing characters other than 0-9, a-z, A-Z and "-", replacing spaces with "-" and converting to lower case. Auto-generation is stopped if the user edits the URL Name field themselves and restarted if they empty the field.
   Update to Preference Service to allow "-" character in preference keys.
   26355: ALF-7743 - Increase delay on "More actions panel" in document library
   26361: ALF-7758 - Site Dashboard: Welcome widget isn't removed immediately
   26364: Updated UI Text strings following review by Linton.
   26366: Fix for ALF-7757 - Calendar agend view encoding
   26368: Fix for ALF-7739 - Click activity link for a file after DnD upload results in an error
   26369: Merged V3.4-BUG-FIX to V3.4-TEAM
      26340: Fixed ALF-6377 "Incorrect behavior of Overdue filter in My Tasks Dashlet"
   26374: Further UI text updates from Linton
   26377: Updates to ACPs as part of ALF-7382 Translate/Localise HTML email templates.
     This check in adds localisations in de, es, fr, it, ja for the following email templates:
       activities-email
       imap_message_text_html
       imap_message_text_plain
       invite-email
       new-user-email
       notify
   26381: Set site invites on by default for Team.
   26384: ALF-7733 - Data list's type isn't included for deleted activities
   26385: ALF-3709 - User Status on Profile
   26389: Merged V3.4-BUG-FIX to V3.4-TEAM
      26372: Fix for ALF-7791 - no longer spews masses of exceptions when doc details page for a missing node is displayed.
             Node Metadata retrieval service now returns valid JSON in all cases.
   26390: Fixed ALF-7689 "Team: Dashlet names don't match dashlet titles"
   26391: ALF-7718 - Handle excel files without a freezepane, eg those created by hand rather than using the friendly template
   26394: Merged V3.4-BUG-FIX to TEAM
      26392: Removed code which sets the cm:title property to the filename in the upload webscript. This was causing an unnecessary auditable update.
      26393: Line endings
   26403: Fix for ALF-7832 - Licence warning for all users on WARN_ALL
   26409: ALF-7763 - Updates to dashlets in Team following usability studies, including: presentation of "no data" made consistent. Page-level inline JavaScript wrapped in module mark-up.
   26410: Fix license location for Win installs
   26425: Fixed ALF-7726: 'Repository Descriptor (Originally Installed)' form doesn't contain Name and Edition information.
   
   Also updated the 'Heartbeat Disabled' field in the License form to use a checkbox control.
   26426: ALF-7742 - Remove title field on simple edit metadata pop-ups
   26427: ALF-7665 - Team: Duplicate Help links in toolbar
   26434: ALF-7875 - CLONE -Unable to browse into folders in Share Site
   26435: Moved of Ent/Team logos to overlays, empty logos in place
   26437: Merged HEAD to V3.4-TEAM
      24723: ALF-5799: Type-ahead functionality for tags
   26438: Merged BRANCHES/DEV/dwebster to BRANCHES/V3.4-TEAM:
      26431: Latest Spanish language Pack updates
      26429: Latest Italian language Pack updates
      26428: Latest French language Pack updates
      26422: Latest German language Pack updates
   26444: Merged V3.4-BUG-FIX to V3.4-TEAM
      26186: Improvements to tree node handling and Bubbling library following investigation for ALF-6960 and ALF-7296
      26189: (Partial merge due to refactoring) ALF-7077 - Unable to set a Repository library root node by XPATH
             Merged HEAD to V3.4-BUG-FIX
                24021: Share Repository Browser support for xpath starting location. See comments in "RepositoryLibrary" section of share-config-custom.xml.sample.
                26183: ALF-6960 - Actions "Copy to..." and "Move to..." Repository don't display the Path. ALF-7296 - Copy or Move content from a site document library to the repository do not work.
      26191: Prevent MooTools JavaScript library being compressed on every build. Added minimized file to source tree. Added target "minimize-mootools-javascript" which inserts a reminder comment to the top of the minimized file.
             Also reverted inadvertant line-endings swap in build.xml from r25479
      26282: ALF-6728 - Unable to open office documents via Share Site > Document Library > All Documents > Edit Online
             Reworked calculations around the "location" field so that the attributes within are returned more consistently.
      26297: ALF-3113 - Data Lists: Delete/duplicate multiple items should affect only selected items on current page
      26298: ALF-7609 - Items numbering in document library in Share appears quite ambiguous in case of documents with working copies
      26312: ALF-4220 - Alfresco Share - Tag component - Unable to view more than 100 tags
             Object finder-based pickers now look for "maxSearchResults" in the control params (rather than the args property bag)
   26445: Merged V3.4 to V3.4-TEAM:
      26443: Installer build updates
   26447: Merged V3.4-BUG-FIX to V3.4-TEAM
      25975: ALF-5625 - When viewing properties in version history hitting close results in loop
      26174: *Record only* Fix spring-surf library versions after merge in rev 26144
      26175: Fix for ALF-7201 - Unable to create group with other name if group identifier is already exists
      26187: Fix for ALF-7297 - Share Advanced Search does not work if the property name include a minus (or any symbol not supported by SQL92 identifier standard)
      26240: Fix for ALF-7462 - Share - User profile / Non-ASCII characters display (double encoding of user description field)
      26242: ALF-3767 - Creating account with 0 quota in Share gives unlimited quota
      26279: ALF-7682 - Fix to correctly take the 'external-auth' config setting into account when testing for login auth against the default alfresco endpoint.
      26280: Fix for ALF-7391 - In the search properties in share, repository is spelt wrong.
      26401: Fix for ALF-7428 - Share: User cannot add comment to content when the 'admin' user is not in administrator group
      26405: Fixed ALF-7224 "Share - Scrollbar issue on dashboard customization page"
   26451: Merged V3.4-BUG-FIX to V3.4-TEAM
      26399: Fix for ALF-5863 - DOCLIB: large number of tags slows doclib rendering to unusable.
             Number of tags to display in the Tags filters is now configuration and defaults to 100 items. Can be configured with value of -1 to show all tags.
   26456: Merged BRANCHES/DEV/dwebster/ to BRANCHES/V3.4-TEAM:
      26450: Latest Japanese language Pack updates
   26458: Merged BRANCHES/V3.4/ to BRANCHES/V3.4-TEAM:
      26417: Fixes: ALF-7414, confused and hardcoded date-formatting & date formatting translations fixed.
      26414: Fixes: ALF-7697 - Rewording the URL help text on the create site dialogue
      26413: Fixes: ALF-7765 - ensures naming consistency
   26461: Merged V3.4-BUG-FIX to V3.4-TEAM
      26243: Fixes ALF-7301: IE6 CSS updates to prevent layout corruption on datagrid
      26404: Fixes ALF-7348: Copy to/Move to width changes for IE6 & IE7
      26453: Fix unreported issue with the appearance of tags in the object finder being stacked vertically rather than horizontally for IE6 and IE7.
   26464: Merged V3.4-BUG-FIX to V3.4-TEAM
      26463: Follow-up fix to r26453 for full-page edit mode
   26465: ALF-7869 - Layout is broken if many tags are added to the item (Document Library browse view)
   26466: Merged BRANCHES/DEV/dwebster/ to BRANCHES/V3.4-TEAM:
      26459: Fixes incorrectly translated stirngs.
   26467: Merged V3.4-BUG-FIX to V3.4-TEAM
      26334: Fixed ALF-6289 "Contributor is absent in Permissions section at the details page" part 2 - now also on folder details page
   
   26468: Fixed bug when content size was 0, now the "Preparing previewer..." message is replaced with a message saying "This document has no content"
   26469: Fixed ALF-7744: Ensure that new options.limit gets set when updating RSS feed results
   26472: Activity list: css class for each activity type into config
   26473: Remove references to non-existent client-side "document-details.js" file
   26475: Calendar UI Bug fixes & improvements from usability feedback (inc. ALF-7592, ALF-7588, ALF-7590, ALF-7594, ALF-7589, ALF-7595, ALF-6959)
   26477: IE6/IE7 css fixes: Fix footer layout and prevent unnecessary horizontal scrollbar
   26482: Merged BRANCHES/DEV/dwebster/ to BRANCHES/V3.4-TEAM:
      26480: Latest Update from Translators via Gloria.
   26485: Fix for ALF-7728. Incorrect information at the Trash page.
     The 'archived by' as returned from the REST API was not the user who archived the node, but was instead the
     original owner of that node. This has now been corrected.
   26494: Small fix from translator
   26496: Installer NLS updates
   26498: Merged V3.4-BUG-FIX to V3.4-TEAM
      26486: Fix for ALF-7602, ALF-7734 - Incorrect behavior of groups - groups in non-default zone displayed in Share UI
   26501: Added translations for "Contributor" role.
   26506: Merge V3.4 to V3.4-TEAM:
      Fixes ALF-7735: Update to postgres.xml to make use of vcruntime on 64-bit windows (fix dependent upon additional update to ALF-BINARIES)
   26513: Merged V3.4-BUG-FIX to V3.4-TEAM
      26512: Fix for ALF-7921 - Script error occurs when is added 'Image preview' dashlet.
   26516: Fixed ALF-7791 "Clicking the activity link for a file after deleting that file results in an error"
   26517: Removed unused component files since document details page refactor
   26532: ALF-7946 - It's impossble to destinate More+ administrator menu.
   combinePaths() function reworked to maintain trailing "/" if the last argument ends with one.
   26536: ALF-7948 - IE Specific - It's impossible to download document via Download button at the details page
   26541: Fixed ALF-7868: Import site doesn't work (QA were trying a scenario that we aren't supporting, removing the old sample context file to avoid problem/confusion)
   26545: Fixed ALF-7001 "Customize site drag and drop - page item is added to end of list if quickly dragged and dropped"
   26550: Fixes: ALF-7935, typo in message string.
   26556: UI improvements and Ajax-ified performance improvements to Image Summary dashlet
   26561: Fix for ALF-7888. Sites are not recovered.
   The fix applied is to mark site nodes with the sys:temporary aspect within the SiteService in order to have them be fully deleted immediately and not go into the trashcan.
   26562: ALF-7925 - Incorrect behaviour of Categories cloud at the Document Library page
   26563: ALF-7912 - Incorrect behavior of items marked as favorite - IE specific
   26570: Update build to correct installer file names.
   26572: Team installer build tweak (added back project filename removed during merge)
   26573: Merged V3.4-BUG-FIX to V3.4-TEAM
      26564: Fix for ALF-7965 - Content page of user profile not updating properly (modified docs always shown in the recently added list)
             Improvements to show filetype icon - FreeMarker macro to mirror basic functionality of Alfresco.util.getFileIcon
   26574: ALF-7962 - Team: Create Site dialog fields aren't cleared on Cancel
   26575: ALF-7970 - Links 'Show Earlier Events/Show Later Events' don't work in IE browser
   26578: Merged V3.4 to V3.4-TEAM:
      26542: Fixes ALF-7954: Ensure that installer copies SWFTools to correct location
   26586: Added script model object "msg" helper to retrieve I18N messages for template level JS controller (mirroring the support in WebScript component JS model)
   26595: ALF-7982 - Filetype icon isn't displayed for topic's reply in activities
   26597: Fixes ALF-7845: Provide tooltip assistance when DocLib upload dialog launched from site welcome dashlet (when DnD is available)
   26605: Fixed ALF-7681 "Renames of Document Library not reflected in page title."
   26617: removed svn:mergeinfo
   26622: JMX Admin pages UX fixes:
   - The Save & Cancel buttons on the jmx admin console pages have been configured not to be displayed.
   - A a "Cancel" link is present instead. 
   - The "Operations" header has been removed
   - The "save operation" button now has an "Update" label instead of "Save"
   26625: Reduced distribution artifacts to minimum (now no E3.5 planned)
   26653: Merged BRANCHES/DEV/V3.4-BUG-FIX to BRANCHES/V3.4-TEAM:
     26619: ALF-6244 - Creating the initial version of a node shouldn't update the Auditable properties
     26623: Add new Version Service method "ensureVersioningEnabled".
     26624: ALF-6121 + ALF-6244 - When activating lazy versioning for share, use a ScriptNode call to the Version Service
   26654: Merged BRANCHES/DEV/V3.4-BUG-FIX to BRANCHES/V3.4-TEAM:
      26631: Improvement related to ALF-6650. Secured PDFs in Acrobat 9 fail to rendition.
   26657: Merged V3.4-BUG-FIX to V3.4-TEAM
      26655: Add parameter comments around ensureVersioningEnabled() function call.
   26660: Fixes ALF-7955: Update error message when dropping zero byte size files or folders into doc lib
   26662: Merged V3.4-BUG-FIX to V3.4-TEAM
      26661: ALF-8053 - Document Library is attempting to create thumbnails for types that are not subtypes of cm:content. Also prevent thumbnail webscripts from attempting to generate thumbnails for in the same cases.
   26665: Fixed ALF-8042 "Renamed page component reverts to default name when moved (Customize Site page)"
   26673: Merged V3.4-BUG-FIX to V3.4-TEAM
      26672: Consolidate multiple occurrences of "#yui-history-iframe" style into base.css
   
   Also fixed markup issue in console-tools that was confusing MSIE browsers.
   26676: Additional fix for ALF-7687 "Ability to use wild character in People search - Should add configuration to allow zero characters for all search in Team config."
   - start workflow component now picks up global min & max search length config
   26677: ALF-8019 - Delete folder window has incorect name
   26678: Merged V3.4-BUG-FIX to TEAM
      26383: Fixed ALF-7692: Non-admin users can move content into Company Home
      26430: More ALF-7692: Non-admin users can move content into Company Home
      - Handles duplicate ALF-7923
   26679: Merged BRANCHES/DEV/V3.4-BUG-FIX to BRANCHES/V3.4-TEAM:
      26439: Probable fix for ALF-7482. Custom ImageMagick parameters not being accepted on Linux Alfresco server.
   
   26680: Merged BRANCHES/DEV/V3.4-BUG-FIX to BRANCHES/V3.4-TEAM:
      26474: Fix for ALF-6730 Preview and thumbnails are not update with new revision of the document is uploaded.
          Added a compensating action to ensure that renditions are deleted when re-renditions fail on new content.
   26682: Merged BRANCHES/DEV/V3.4-BUG-FIX to BRANCHES/V3.4-TEAM:
      26675: Fix for ALF-7334 Could not upload new Version all Dokuments.
            Issue was resolved by adding "RunAs System" boilerplate to the few places that load (and in the case of the WQS, delete) rendition definitions.
            We purposely did not add this boilerplate within the RenditionServiceImpl.loadRenditionDefiition() method as we want to retain effective permission controls for normal client code.
            Added some javadoc to highlight the permissions issues involved.
            I also took the opportunity to add a convenience method to the RenditionService, namely render(NodeRef, QName) which will allow client code to execute built-in rendition definitions (e.g. thumbnails) without worrying about permissions on Data Dictionary. That method wraps the equivalent render(NodeRef, RenditionDefinition) in a RunAs System.
   
   26685: Fixed ALF-7880 "Download version form version history shows incorrect document name"
   26688: ALF-7919 - Use 'Properties' instead of 'Metadata' in actions, titles etc.
   26690: Partial fox for ALF-8014. thumbnail and file type aren't generated for *.eps files
     A placeholder 'doclib' icon is now available for .eps files.
   26697: ALF-7004: TR28: Create HTML email templates (Implemented Linton's richer HTML email template design)
   
   Also removed the timestamp from the email subject for the Activities email as the timestamp is now within the body of the email.
   
   NOTE: You need to start with a clean database in order to see the new templates.
   26698: Build fix since label change of Start operation button in admin console (JMX) forms.
   26699: Fixed ALF-7886 "Click here to Download gives incorrect document name"
   26700: Fixed ALF-7801 "Incorrect hint for Upload new version action in Versions pane"
   26702: Fixed ALF-7857 "Team: Inconsistency between DocLib action and tooltip text"
   26703: Fixes ALF-7762: Add tooltips to dashlet toolbar actions
   26704: Fix for ALF-7785 - Agenda View doesn't always update list after Edit/Delete of an item
   26708: Merged V3.4-BUG-FIX to TEAM
      26664: Fix build (DOD5015 security context and test refactor)
   26709: Slight reworking (and rewording) of the tooltip on the upload dialogs when drag and drop is available (the "#upload" use case)
   26710: Move style fixes into IE specific CSS files to avoid breaking layout on other browsers
   26712: Merged V3.4-BUG-FIX to V3.4-TEAM
      26711: ALF-3833 - Share - Phrase tags
   26714: ALF-8081 - W3C: a highlighting of drop-down menu (Sites, People) in toolbar is invisible in Safari.
   26715: Tweak to imagesummary dashlet node cloning performance
   26716: ALF-8082 - W3C: it's impossible to select a lot of links in Safari
   ALF-8083 - W3C: it's impossible to select Site Pages in Safari
   26718: Fixes for ALF-7874, ALF-8012 - Mimetype map additions, filetype icons.
   - also replaced worlds-largest if-else freemarker statement with inline map for Forms mimetype lookup
   26719: Further fix for ALF-8014. Thumbnail and filetype not generated for *.eps files.
     I've added a -file-48.png for the .eps mimetype.
     I copied it from one of the other image -48.png files as they're all generic 'img' icons anyway.
   26721: Fix for ALF-7963 Team: Can edit another user's email notification settings
   26722: Collapsed/expanded state of Properties panel wasn't being remembered on Details page. Removed "collapsed" parameter for Alfresco.util.createTwister which won't work with our current implementation. Pre-empted "alfresco-twister" class for slow-loading components.
   26723: Changed component initialisation event from onContentReady to onAvailable which should improve appearance/decoration times slightly.
   26724: ALF-8089 - W3C: a highlighting of "Show Earlier Events" and "Show Later Events" links in toolbar is invisible in Safari
   26731: ALF-8095 - Error shown after clicking the accept or reject link in a site invitation email
   26733: Merged V3.4 to V3.4-TEAM
      26530: Fixes ALF-7949: Remove service script on uninstall
      26610: Fix for: ALF-8007: Lucene index not coherent or not up to date or we can not rely on it to check that a working copy exist.
   26734: Merged V3.4 to V3.4-TEAM (RECORD ONLY)
      25971: ALF-7441: Help URLs pointing to new doc system (1 of 2)
      25972: ALF-7441: Help URLs pointing to new doc system (2 of 2)
      25980: Merged V3.4-BUG-FIX to V3.4
         25978: ALF-7394 - Alfresco Network dashlet, now Alfresco Support information
      26056: Merged V3.4-TEAM to V3.4
         26053: Added in loop to wait for asynchronous post-failure auditing (ALF-3055)
      26100: Merged V3.4-TEAM to V3.4
         25985: Another cycle of fixing installer from Win builds.  Still waiting for official fix from Bitrock.
         26067: Fixes for installer builds on Windows
      26127: Merged V3.4-TEAM to V3.4
         26120: Fix postgres.bki on Win builds
      26165: Merged V3.4-TEAM to V3.4
         26161: Fix full installer.
   26737: Google Docs: Added better handling of unsupported mimetypes
   
     * Meaningful exception raised when mimetype unsupported by GDoc (rather then non-specific error from google)
     * Message not reflected in UI, but log contains details of failure
   
   26738: Clarified browser relevance for "in-memory-limit" config parameter following ALF-8093 being raised.
   26740: Quick build fix following Google Docs updates in r26737
   26741: Build Fix
     * Added missed exception class
     * backout previous fixes
   
   26746: Fixed ALF-8080 "WebM playback not working for Team and Chrome"
   26750: Prettifying the delete url for comments to avoid two ampersands following each other, i.e: "&&". This is NOT a fix for deleting content with "%" in the name.
   26753: Fixed ALF-7807 "It's possible to rename component with spaces"
   26756: ALF-8102 - Edit Properties, Edit tags, Manage permissions, Start workfow icons are not visible - IE 7 specific
   26758: ALF-8106 - "Go Back" button doesn't work on the "User Profile" page
   26763: Fixes: ALF-7815 - Added .ics extension and site name to downloaded file.
   26779: Merged V3.4 to V3.4-TEAM
     26760 : Enterprise unlimited licenses get invalidated turning the system into read-only mode
   26782: Fixed ALF-7001 "Customize site drag and drop - page item is added to end of list if quickly dragged and dropped"
   26784: Minor height adjustment to "My Documents" dashlet on first use
   26786: Correction to merge 26779


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@26795 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
2011-04-11 19:26:26 +00:00

4109 lines
162 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.filesys.repo;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Serializable;
import java.net.InetAddress;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.Callable;
import java.util.regex.Pattern;
import javax.transaction.UserTransaction;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.filesys.alfresco.AlfrescoContext;
import org.alfresco.filesys.alfresco.AlfrescoDiskDriver;
import org.alfresco.filesys.alfresco.AlfrescoNetworkFile;
import org.alfresco.jlan.server.SrvSession;
import org.alfresco.jlan.server.core.DeviceContext;
import org.alfresco.jlan.server.core.DeviceContextException;
import org.alfresco.jlan.server.filesys.AccessDeniedException;
import org.alfresco.jlan.server.filesys.AccessMode;
import org.alfresco.jlan.server.filesys.DirectoryNotEmptyException;
import org.alfresco.jlan.server.filesys.DiskDeviceContext;
import org.alfresco.jlan.server.filesys.DiskFullException;
import org.alfresco.jlan.server.filesys.DiskInterface;
import org.alfresco.jlan.server.filesys.DiskSizeInterface;
import org.alfresco.jlan.server.filesys.FileAttribute;
import org.alfresco.jlan.server.filesys.FileInfo;
import org.alfresco.jlan.server.filesys.FileName;
import org.alfresco.jlan.server.filesys.FileOpenParams;
import org.alfresco.jlan.server.filesys.FileSharingException;
import org.alfresco.jlan.server.filesys.FileStatus;
import org.alfresco.jlan.server.filesys.NetworkFile;
import org.alfresco.jlan.server.filesys.SearchContext;
import org.alfresco.jlan.server.filesys.SrvDiskInfo;
import org.alfresco.jlan.server.filesys.TreeConnection;
import org.alfresco.jlan.server.filesys.cache.FileState;
import org.alfresco.jlan.server.filesys.cache.FileStateLockManager;
import org.alfresco.jlan.server.filesys.pseudo.MemoryNetworkFile;
import org.alfresco.jlan.server.filesys.pseudo.PseudoFile;
import org.alfresco.jlan.server.filesys.pseudo.PseudoFileInterface;
import org.alfresco.jlan.server.filesys.pseudo.PseudoFileList;
import org.alfresco.jlan.server.filesys.pseudo.PseudoNetworkFile;
import org.alfresco.jlan.server.filesys.quota.QuotaManager;
import org.alfresco.jlan.server.filesys.quota.QuotaManagerException;
import org.alfresco.jlan.server.locking.FileLockingInterface;
import org.alfresco.jlan.server.locking.LockManager;
import org.alfresco.jlan.server.locking.OpLockInterface;
import org.alfresco.jlan.server.locking.OpLockManager;
import org.alfresco.jlan.smb.SharingMode;
import org.alfresco.jlan.smb.WinNT;
import org.alfresco.jlan.smb.server.SMBServer;
import org.alfresco.jlan.smb.server.SMBSrvSession;
import org.alfresco.jlan.util.MemorySize;
import org.alfresco.jlan.util.WildCard;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.admin.SysAdminParams;
import org.alfresco.repo.node.archive.NodeArchiveService;
import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.repo.security.authentication.AuthenticationContext;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.lock.LockService;
import org.alfresco.service.cmr.lock.LockType;
import org.alfresco.service.cmr.lock.NodeLockedException;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentIOException;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.security.AccessPermission;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.Pair;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.config.ConfigElement;
/**
* Content repository filesystem driver class
*
* <p>Provides a filesystem interface for various protocols such as SMB/CIFS and FTP.
*
* @author gkspencer
*/
public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterface, FileLockingInterface, OpLockInterface, DiskSizeInterface
{
// Logging
private static final Log logger = LogFactory.getLog(ContentDiskDriver.class);
// Configuration key names
private static final String KEY_STORE = "store";
private static final String KEY_ROOT_PATH = "rootPath";
private static final String KEY_RELATIVE_PATH = "relativePath";
// File status values used in the file state cache
public static final int FileUnknown = FileStatus.Unknown;
public static final int FileNotExist = FileStatus.NotExist;
public static final int FileExists = FileStatus.FileExists;
public static final int DirectoryExists = FileStatus.DirectoryExists;
public static final int CustomFileStatus= FileStatus.MaxStatus + 1;
public static final int FileRenamed = CustomFileStatus;
public static final int DeleteOnClose = CustomFileStatus + 1;
// File state attributes
public static final String AttrLinkNode = "ContentLinkNode";
// List of content properties to copy during rename
private static QName[] _copyProperties = { ContentModel.PROP_AUTHOR, ContentModel.PROP_TITLE, ContentModel.PROP_DESCRIPTION };
// List of property namespaces to exclude from copy during rename
private static Set<String> _excludedNamespaces = new TreeSet<String>(Arrays.asList(new String[]
{
NamespaceService.CONTENT_MODEL_1_0_URI, NamespaceService.SYSTEM_MODEL_1_0_URI
}));
// Disk sizing contants
private static final int DiskBlockSize = 512; // bytes per block
private static final long DiskAllocationUnit = 32 * MemorySize.KILOBYTE;
private static final long DiskBlocksPerUnit = DiskAllocationUnit / DiskBlockSize;
// Disk size returned in the content store does not support free/total size
protected static final long DiskSizeDefault = 1 * MemorySize.TERABYTE;
protected static final long DiskFreeDefault = DiskSizeDefault / 2;
// Services and helpers
private CifsHelper cifsHelper;
private NamespaceService namespaceService;
private NodeService nodeService;
private SearchService searchService;
private ContentService contentService;
private MimetypeService mimetypeService;
private PermissionService permissionService;
private FileFolderService fileFolderService;
private NodeArchiveService nodeArchiveService;
private LockService lockService;
private DictionaryService dictionaryService;
private AuthenticationContext authContext;
private AuthenticationService authService;
private SysAdminParams sysAdminParams;
private BehaviourFilter policyBehaviourFilter;
private NodeMonitorFactory m_nodeMonitorFactory;
private static FileStateLockManager _lockManager;
/**
* Class constructor
*
* @param serviceRegistry to connect to the repository services
*/
public ContentDiskDriver(CifsHelper cifsHelper)
{
this.cifsHelper = cifsHelper;
}
/**
* Return the CIFS helper
*
* @return CifsHelper
*/
public final CifsHelper getCifsHelper()
{
return this.cifsHelper;
}
/**
* Return the authentication service
*
* @return AuthenticationService
*/
public final AuthenticationService getAuthenticationService()
{
return authService;
}
/**
* Return the authentication context
*
* @return AuthenticationContext
*/
public final AuthenticationContext getAuthenticationContext() {
return authContext;
}
/**
* Return the node service
*
* @return NodeService
*/
public final NodeService getNodeService()
{
return this.nodeService;
}
/**
* Return the content service
*
* @return ContentService
*/
public final ContentService getContentService()
{
return this.contentService;
}
/**
* Return the namespace service
*
* @return NamespaceService
*/
public final NamespaceService getNamespaceService()
{
return this.namespaceService;
}
/**
* Return the search service
*
* @return SearchService
*/
public final SearchService getSearchService(){
return this.searchService;
}
/**
* Return the file folder service
*
* @return FileFolderService
*/
public final FileFolderService getFileFolderService() {
return this.fileFolderService;
}
/**
* Return the permission service
*
* @return PermissionService
*/
public final PermissionService getPermissionService() {
return this.permissionService;
}
/**
* Return the node archive service
*
* @param NodeArchiveService
*/
public final NodeArchiveService getNodeArchiveService() {
return nodeArchiveService;
}
/**
* Return the lock service
*
* @return LockService
*/
public final LockService getLockService() {
return lockService;
}
/**
* Get the policy behaviour filter, used to inhibit versioning on a per transaction basis
*/
public BehaviourFilter getPolicyFilter()
{
return policyBehaviourFilter;
}
/**
* Return the dictionary service
*
* @return DictionaryService
*/
public final DictionaryService getDictionaryService() {
return dictionaryService;
}
/**
* @param contentService the content service
*/
public void setContentService(ContentService contentService)
{
this.contentService = contentService;
}
/**
* @param namespaceService the namespace service
*/
public void setNamespaceService(NamespaceService namespaceService)
{
this.namespaceService = namespaceService;
}
/**
* @param nodeService the node service
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* @param searchService the search service
*/
public void setSearchService(SearchService searchService)
{
this.searchService = searchService;
}
/**
* Set the permission service
*
* @param permissionService PermissionService
*/
public void setPermissionService(PermissionService permissionService)
{
this.permissionService = permissionService;
}
/**
* Set the authentication context
*
* @param authContext AuthenticationContext
*/
public void setAuthenticationContext(AuthenticationContext authContext)
{
this.authContext = authContext;
}
/**
* Set the authentication service
*
* @param authService AuthenticationService
*/
public void setAuthenticationService(AuthenticationService authService)
{
this.authService = authService;
}
/**
* Sets the sys admin params.
*
* @param sysAdminParams
* the sys admin params
*/
public void setSysAdminParams(SysAdminParams sysAdminParams)
{
this.sysAdminParams = sysAdminParams;
}
/**
* Set the file folder service
*
* @param fileService FileFolderService
*/
public void setFileFolderService(FileFolderService fileService)
{
fileFolderService = fileService;
}
/**
* @param mimetypeService service for helping with mimetypes and encoding
*/
public void setMimetypeService(MimetypeService mimetypeService)
{
this.mimetypeService = mimetypeService;
}
/**
* Set the node monitor factory
*
* @param nodeMonitorFactory NodeMonitorFactory
*/
public void setNodeMonitorFactory(NodeMonitorFactory nodeMonitorFactory) {
m_nodeMonitorFactory = nodeMonitorFactory;
}
/**
* Set the node archive service
*
* @param NodeArchiveService nodeArchiveService
*/
public void setNodeArchiveService(NodeArchiveService nodeArchiveService) {
this.nodeArchiveService = nodeArchiveService;
}
/**
* Set the lock service
*
* @param lockService LockService
*/
public void setLockService(LockService lockService) {
this.lockService = lockService;
}
/**
* Set the policy behaviour filter, used to inhibit versioning on a per transaction basis
*
* @param policyFilter PolicyBehaviourFilter
*/
public void setPolicyFilter(BehaviourFilter policyFilter)
{
this.policyBehaviourFilter = policyFilter;
}
/**
* Set the dictionary service
*
* @param dictionaryService DictionaryService
*/
public void setDictionaryService(DictionaryService dictionaryService) {
this.dictionaryService = dictionaryService;
}
/**
* Parse and validate the parameter string and create a device context object for this instance
* of the shared device. The same DeviceInterface implementation may be used for multiple
* shares.
*
* @param shareName String
* @param args ConfigElement
* @return DeviceContext
* @exception DeviceContextException
*/
public DeviceContext createContext(String shareName, ConfigElement cfg) throws DeviceContextException
{
ContentContext context = null;
try
{
// Get the store
ConfigElement storeElement = cfg.getChild(KEY_STORE);
if (storeElement == null || storeElement.getValue() == null || storeElement.getValue().length() == 0)
{
throw new DeviceContextException("Device missing init value: " + KEY_STORE);
}
String storeValue = storeElement.getValue();
// Get the root path
ConfigElement rootPathElement = cfg.getChild(KEY_ROOT_PATH);
if (rootPathElement == null || rootPathElement.getValue() == null || rootPathElement.getValue().length() == 0)
{
throw new DeviceContextException("Device missing init value: " + KEY_ROOT_PATH);
}
String rootPath = rootPathElement.getValue();
// Create the context
context = new ContentContext();
context.setDeviceName(shareName);
context.setStoreName(storeValue);
context.setRootPath(rootPath);
context.setSysAdminParams(this.sysAdminParams);
// Check if a relative path has been specified
ConfigElement relativePathElement = cfg.getChild(KEY_RELATIVE_PATH);
if ( relativePathElement != null)
{
// Make sure the path is in CIFS format
String relPath = relativePathElement.getValue().replace( '/', FileName.DOS_SEPERATOR);
context.setRelativePath(relPath);
}
}
catch (Exception ex)
{
logger.error("Error during create context", ex);
}
// Check if URL link files are enabled
ConfigElement urlFileElem = cfg.getChild( "urlFile");
if ( urlFileElem != null)
{
// Get the pseudo file name and web prefix path
ConfigElement pseudoName = urlFileElem.getChild( "filename");
if ( pseudoName != null)
{
context.setURLFileName(pseudoName.getValue());
}
}
// Check if locked files should be marked as offline
ConfigElement offlineFiles = cfg.getChild( "offlineFiles");
if ( offlineFiles != null)
{
context.setOfflineFiles(true);
}
// Install the node service monitor
if ( cfg.getChild("disableNodeMonitor") == null) {
// Create the node monitor
context.setDisableNodeMonitor(true);
}
// Check if oplocks are enabled, if so then enable oplocks in the lock manager
if ( cfg.getChild("disableOplocks") != null) {
context.setDisableOplocks( true);
}
// Register the device context
registerContext(context);
// Return the context for this shared filesystem
return context;
}
/**
* Registers a device context object for this instance
* of the shared device. The same DeviceInterface implementation may be used for multiple
* shares.
*
* @param ctx the context
* @exception DeviceContextException
*/
@Override
public void registerContext(DeviceContext ctx) throws DeviceContextException
{
super.registerContext(ctx);
ContentContext context = (ContentContext)ctx;
// Wrap the initialization in a transaction
UserTransaction tx = getTransactionService().getUserTransaction(true);
try
{
// Use the system user as the authenticated context for the filesystem initialization
AuthenticationUtil.pushAuthentication();
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getSystemUserName());
// Start the transaction
if ( tx != null)
tx.begin();
// Get the store
String storeValue = context.getStoreName();
StoreRef storeRef = new StoreRef(storeValue);
// Connect to the repo and ensure that the store exists
if (! nodeService.exists(storeRef))
{
throw new DeviceContextException("Store not created prior to application startup: " + storeRef);
}
NodeRef storeRootNodeRef = nodeService.getRootNode(storeRef);
// Get the root path
String rootPath = context.getRootPath();
// Find the root node for this device
List<NodeRef> nodeRefs = searchService.selectNodes(storeRootNodeRef, rootPath, null, namespaceService, false);
NodeRef rootNodeRef = null;
if (nodeRefs.size() > 1)
{
throw new DeviceContextException("Multiple possible roots for device: \n" +
" root path: " + rootPath + "\n" +
" results: " + nodeRefs);
}
else if (nodeRefs.size() == 0)
{
// Nothing found
throw new DeviceContextException("No root found for device: \n" +
" root path: " + rootPath);
}
else
{
// We found a node
rootNodeRef = nodeRefs.get(0);
}
// Check if a relative path has been specified
String relPath = context.getRelativePath();
if ( relPath != null && relPath.length() > 0)
{
// Find the node and validate that the relative path is to a folder
NodeRef relPathNode = cifsHelper.getNodeRef( rootNodeRef, relPath);
if ( cifsHelper.isDirectory( relPathNode) == false)
throw new DeviceContextException("Relative path is not a folder, " + relPath);
// Use the relative path node as the root of the filesystem
rootNodeRef = relPathNode;
}
else {
// Make sure the default root node is a folder
if ( cifsHelper.isDirectory( rootNodeRef) == false)
throw new DeviceContextException("Root node is not a folder type node");
}
// Commit the transaction
tx.commit();
tx = null;
// Record the root node ref
context.setRootNodeRef(rootNodeRef);
}
catch (Exception ex)
{
logger.error("Error during create context", ex);
}
finally
{
// Restore authentication context
AuthenticationUtil.popAuthentication();
// If there is an active transaction then roll it back
if ( tx != null)
{
try
{
tx.rollback();
}
catch (Exception ex)
{
logger.warn("Failed to rollback transaction", ex);
}
}
}
// Check if locked files should be marked as offline
if ( context.getOfflineFiles() )
{
// Enable marking locked files as offline
cifsHelper.setMarkLockedFilesAsOffline( true);
// Logging
logger.info("Locked files will be marked as offline");
}
// Enable file state caching
context.enableStateCache( true);
context.getStateCache().setCaseSensitive( false);
// Initialize the I/O control handler
if ( context.hasIOHandler())
context.getIOHandler().initialize( this, context);
// Install the node service monitor
if ( !context.getDisableNodeMonitor() && m_nodeMonitorFactory != null) {
// Create the node monitor
NodeMonitor nodeMonitor = m_nodeMonitorFactory.createNodeMonitor( this, context);
context.setNodeMonitor( nodeMonitor);
}
// Create the lock manager
_lockManager = new FileStateLockManager( context.getStateCache());
// Check if oplocks are enabled
if ( context.getDisableOplocks() == true)
logger.warn("Oplock support disabled for filesystem " + ctx.getDeviceName());
// Start the quota manager, if enabled
if ( context.hasQuotaManager()) {
try {
// Start the quota manager
context.getQuotaManager().startManager( this, context);
logger.info("Quota manager enabled for filesystem");
}
catch ( QuotaManagerException ex) {
logger.error("Failed to start quota manager", ex);
}
}
}
/**
* Check if pseudo file support is enabled
*
* @param context ContentContext
* @return boolean
*/
public final boolean hasPseudoFileInterface(ContentContext context)
{
return context.hasPseudoFileInterface();
}
/**
* Return the pseudo file support implementation
*
* @param context ContentContext
* @return PseudoFileInterface
*/
public final PseudoFileInterface getPseudoFileInterface(ContentContext context)
{
return context.getPseudoFileInterface();
}
/**
* Determine if the disk device is read-only.
*
* @param sess Server session
* @param ctx Device context
* @return boolean
* @exception java.io.IOException If an error occurs.
*/
public boolean isReadOnly(SrvSession sess, DeviceContext ctx) throws IOException
{
if (cifsHelper.isReadOnly())
{
return true;
}
else
{
return false;
}
}
/**
* Get the file information for the specified file.
*
* @param sess Server session
* @param tree Tree connection
* @param name File name/path that information is required for.
* @return File information if valid, else null
* @exception java.io.IOException The exception description.
*/
public FileInfo getFileInformation(SrvSession session, TreeConnection tree, String path) throws IOException
{
// Start a transaction
beginReadTransaction( session);
// Get the device root
ContentContext ctx = (ContentContext) tree.getContext();
NodeRef infoParentNodeRef = ctx.getRootNode();
if ( path == null || path.length() == 0)
path = FileName.DOS_SEPERATOR_STR;
String infoPath = path;
try
{
// Check if the path is to a pseudo file
FileInfo finfo = null;
if ( hasPseudoFileInterface(ctx))
{
// Make sure the parent folder has a file state, and the path exists
String[] paths = FileName.splitPath( path);
FileState fstate = ctx.getStateCache().findFileState( paths[0]);
if ( fstate == null)
{
NodeRef nodeRef = getNodeForPath(tree, paths[0]);
if ( nodeRef != null)
{
// Get the file information for the node
finfo = cifsHelper.getFileInformation(nodeRef);
}
// Create the file state
fstate = ctx.getStateCache().findFileState( paths[0], true);
fstate.setFileStatus( DirectoryExists);
fstate.setFilesystemObject( nodeRef);
// Add pseudo files to the folder
getPseudoFileInterface( ctx).addPseudoFilesToFolder( session, tree, paths[0]);
// Debug
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_INFO))
logger.debug( "Added file state for pseudo files folder (getinfo) - " + paths[0]);
}
else if ( fstate.hasPseudoFiles() == false)
{
// Make sure the file state has the node ref
if ( fstate.hasFilesystemObject() == false)
{
// Get the node for the folder path
fstate.setFilesystemObject( getNodeForPath( tree, paths[0]));
}
// Add pseudo files for the parent folder
getPseudoFileInterface( ctx).addPseudoFilesToFolder( session, tree, paths[0]);
// Debug
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_INFO))
logger.debug( "Added pseudo files for folder (exists) - " + paths[0]);
}
// Get the pseudo file
PseudoFile pfile = getPseudoFileInterface(ctx).getPseudoFile( session, tree, path);
if ( pfile != null)
{
// DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_INFO))
logger.debug("getInfo using pseudo file info for " + path);
FileInfo pseudoFileInfo = pfile.getFileInfo();
if (cifsHelper.isReadOnly())
{
int attr = pseudoFileInfo.getFileAttributes();
if (( attr & FileAttribute.ReadOnly) == 0)
{
attr += FileAttribute.ReadOnly;
pseudoFileInfo.setFileAttributes(attr);
}
}
return pfile.getFileInfo();
}
}
// Get the node ref for the path, chances are there is a file state in the cache
NodeRef nodeRef = getNodeForPath(tree, infoPath);
if ( nodeRef != null)
{
// Get the file information for the node
finfo = cifsHelper.getFileInformation(nodeRef);
// DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_INFO))
logger.debug("getInfo using cached noderef for path " + path);
}
// If the required node was not in the state cache, the parent folder node might be
if ( finfo == null)
{
String[] paths = FileName.splitPath( path);
if ( paths[0] != null && paths[0].length() > 1)
{
// Find the node ref for the folder being searched
nodeRef = getNodeForPath(tree, paths[0]);
if ( nodeRef != null)
{
infoParentNodeRef = nodeRef;
infoPath = paths[1];
// DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_INFO))
logger.debug("getInfo using cached noderef for parent " + path);
}
}
// Access the repository to get the file information
finfo = cifsHelper.getFileInformation(infoParentNodeRef, infoPath);
// DEBUG
if (logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_INFO))
logger.debug("Getting file information: path=" + path + " file info: " + finfo);
}
// Set the file id for the file using the relative path
if ( finfo != null) {
// Set the file id
long id = DefaultTypeConverter.INSTANCE.convert(Long.class, nodeService.getProperty(nodeRef, ContentModel.PROP_NODE_DBID));
finfo.setFileId((int) (id & 0xFFFFFFFFL));
// Copy cached file details, if available
FileState fstate = getStateForPath(tree, infoPath);
if ( fstate != null) {
// Copy cached timestamps
if ( fstate.hasAccessDateTime())
finfo.setAccessDateTime(fstate.getAccessDateTime());
if ( fstate.hasChangeDateTime())
finfo.setChangeDateTime(fstate.getChangeDateTime());
if ( fstate.hasModifyDateTime())
finfo.setModifyDateTime(fstate.getModifyDateTime());
// File allocation size
if ( fstate.hasAllocationSize() && fstate.getAllocationSize() > finfo.getSize())
finfo.setAllocationSize( fstate.getAllocationSize());
}
else {
// Create a file state for the file/folder
fstate = ctx.getStateCache().findFileState( path, true);
if ( finfo.isDirectory())
fstate.setFileStatus( DirectoryExists);
else
fstate.setFileStatus( FileExists);
fstate.setFilesystemObject( nodeRef);
}
}
// Return the file information
return finfo;
}
catch (FileNotFoundException e)
{
// Debug
if (logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_INFO))
logger.debug("Get file info - file not found, " + path);
throw e;
}
catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
{
// Debug
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_INFO))
logger.debug("Get file info - access denied, " + path);
// Convert to a filesystem access denied status
throw new AccessDeniedException("Get file information " + path);
}
catch (AlfrescoRuntimeException ex)
{
// Debug
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_INFO))
logger.debug("Get file info error", ex);
// Convert to a general I/O exception
throw new IOException("Get file information " + path);
}
}
/**
* Start a new search on the filesystem using the specified searchPath that may contain
* wildcards.
*
* @param sess Server session
* @param tree Tree connection
* @param searchPath File(s) to search for, may include wildcards.
* @param attrib Attributes of the file(s) to search for, see class SMBFileAttribute.
* @return SearchContext
* @exception java.io.FileNotFoundException If the search could not be started.
*/
public SearchContext startSearch(SrvSession sess, TreeConnection tree, String searchPath, int attributes) throws FileNotFoundException
{
// Access the device context
ContentContext ctx = (ContentContext) tree.getContext();
try
{
String searchFileSpec = searchPath;
NodeRef searchRootNodeRef = ctx.getRootNode();
FileState searchFolderState = null;
// Create the transaction
beginReadTransaction( sess);
// If the state table is available see if we can speed up the search using either cached
// file information or find the folder node to be searched without having to walk the path
String[] paths = FileName.splitPath(searchPath);
if ( ctx.hasStateCache())
{
// See if the folder to be searched has a file state, we can avoid having to walk the path
if ( paths[0] != null && paths[0].length() >= 1)
{
// Find the node ref for the folder being searched
NodeRef nodeRef = getNodeForPath(tree, paths[0]);
// Get the file state for the folder being searched
searchFolderState = getStateForPath(tree, paths[0]);
if ( searchFolderState == null)
{
// Create a file state for the folder
searchFolderState = ctx.getStateCache().findFileState( paths[0], true);
}
// Make sure the associated node is set
if ( searchFolderState.hasFilesystemObject() == false)
{
// Set the associated node for the folder
searchFolderState.setFilesystemObject( nodeRef);
}
// Add pseudo files to the folder being searched
if ( hasPseudoFileInterface(ctx))
getPseudoFileInterface(ctx).addPseudoFilesToFolder( sess, tree, paths[0]);
// Set the search node and file spec
if ( nodeRef != null)
{
searchRootNodeRef = nodeRef;
searchFileSpec = paths[1];
// DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_SEARCH))
logger.debug("Search using cached noderef for path " + searchPath);
}
}
}
// Convert the all files wildcard
if ( searchFileSpec.equals( "*.*"))
searchFileSpec = "*";
// Debug
long startTime = 0L;
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_SEARCH))
startTime = System.currentTimeMillis();
// Perform the search
List<NodeRef> results = cifsHelper.getNodeRefs(searchRootNodeRef, searchFileSpec);
// Debug
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_SEARCH)) {
long endTime = System.currentTimeMillis();
if (( endTime - startTime) > 500)
logger.debug("Search for searchPath=" + searchPath + ", searchSpec=" + searchFileSpec + ", searchRootNode=" + searchRootNodeRef + " took "
+ ( endTime - startTime) + "ms results=" + results.size());
}
// Check if there are any pseudo files for the folder being searched, for CIFS only
PseudoFileList pseudoList = null;
if ( sess instanceof SMBSrvSession && searchFolderState != null && searchFolderState.hasPseudoFiles())
{
// If it is a wildcard search use all pseudo files
if ( WildCard.containsWildcards(searchFileSpec))
{
// Get the list of pseudo files for the search path
pseudoList = searchFolderState.getPseudoFileList();
// Check if the wildcard is for all files or a subset
if ( searchFileSpec.equals( "*") == false && pseudoList != null && pseudoList.numberOfFiles() > 0)
{
// Generate a subset of pseudo files that match the wildcard search pattern
WildCard wildCard = new WildCard( searchFileSpec, false);
PseudoFileList filterList = null;
for ( int i = 0; i > pseudoList.numberOfFiles(); i++)
{
PseudoFile pseudoFile = pseudoList.getFileAt( i);
if ( wildCard.matchesPattern( pseudoFile.getFileName()))
{
// Add the pseudo file to the filtered list
if ( filterList == null)
filterList = new PseudoFileList();
filterList.addFile( pseudoFile);
}
}
// Use the filtered pseudo file list, or null if there were no matches
pseudoList = filterList;
}
}
else if ( results == null || results.size() == 0)
{
// Check if the required file is in the pseudo file list
String fname = paths[1];
if ( fname != null)
{
// Search for a matching pseudo file
PseudoFile pfile = searchFolderState.getPseudoFileList().findFile( fname, true);
if ( pfile != null)
{
// Create a file list with the required file
pseudoList = new PseudoFileList();
pseudoList.addFile( pfile);
}
}
}
}
// Build the search context to store the results, use the cache lookup search for wildcard searches
SearchContext searchCtx = null;
if ( searchFileSpec.equals( "*"))
{
// Use a cache lookup search context
CacheLookupSearchContext cacheContext = new CacheLookupSearchContext(cifsHelper, results, searchFileSpec, pseudoList, paths[0], ctx.getStateCache());
searchCtx = cacheContext;
// Set the '.' and '..' pseudo file entry details
if ( searchFolderState != null && searchFolderState.hasFilesystemObject())
{
// Get the '.' pseudo entry file details
FileInfo finfo = cifsHelper.getFileInformation((NodeRef) searchFolderState.getFilesystemObject());
// Blend in any cached timestamps
if ( searchFolderState != null) {
if ( searchFolderState.hasAccessDateTime())
finfo.setAccessDateTime( searchFolderState.getAccessDateTime());
if ( searchFolderState.hasChangeDateTime())
finfo.setChangeDateTime( searchFolderState.getChangeDateTime());
if ( searchFolderState.hasModifyDateTime())
finfo.setModifyDateTime( searchFolderState.getModifyDateTime());
}
// Set the '.' pseudo entry details
cacheContext.setDotInfo( finfo);
// Check if the search folder has a parent, if we are at the root of the filesystem then re-use
// the file information
if ( searchFolderState.getPath().equals( FileName.DOS_SEPERATOR_STR)) {
// Searching the root folder, re-use the search folder file information for the '..' pseudo entry
cacheContext.setDotDotInfo( finfo);
}
else {
// Get the parent folder path
String parentPath = searchFolderState.getPath();
if ( parentPath.endsWith( FileName.DOS_SEPERATOR_STR) && parentPath.length() > 1)
parentPath = parentPath.substring(0, parentPath.length() - 1);
int pos = parentPath.lastIndexOf( FileName.DOS_SEPERATOR_STR);
if ( pos != -1)
parentPath = parentPath.substring(0, pos + 1);
// Get the file state for the parent path, if available
FileState parentState = ctx.getStateCache().findFileState( parentPath);
NodeRef parentNode = null;
if ( parentState != null)
parentNode = (NodeRef) parentState.getFilesystemObject();
if ( parentState == null || parentNode == null)
parentNode = getNodeForPath( tree, parentPath);
// Get the file information for the parent folder
finfo = cifsHelper.getFileInformation( parentNode);
// Blend in any cached timestamps
if ( parentState != null) {
if ( parentState.hasAccessDateTime())
finfo.setAccessDateTime( parentState.getAccessDateTime());
if ( parentState.hasChangeDateTime())
finfo.setChangeDateTime( parentState.getChangeDateTime());
if ( parentState.hasModifyDateTime())
finfo.setModifyDateTime( parentState.getModifyDateTime());
}
// Set the '..' pseudo entry details
cacheContext.setDotDotInfo( finfo);
}
}
}
else
searchCtx = new ContentSearchContext(cifsHelper, results, searchFileSpec, pseudoList, paths[0]);
// Debug
if (logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_SEARCH))
logger.debug("Started search: search path=" + searchPath + " attributes=" + attributes + ", ctx=" + searchCtx);
// Return the search context
return searchCtx;
}
catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
{
// Debug
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_SEARCH))
logger.debug("Start search - access denied, " + searchPath);
// Convert to a file not found status
throw new FileNotFoundException("Start search " + searchPath);
}
catch (AlfrescoRuntimeException ex)
{
// Debug
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_SEARCH))
logger.debug("Start search", ex);
// Convert to a file not found status
throw new FileNotFoundException("Start search " + searchPath);
}
}
/**
* Check if the specified file exists, and whether it is a file or directory.
*
* @param sess Server session
* @param tree Tree connection
* @param name java.lang.String
* @return int
* @see FileStatus
*/
public int fileExists(SrvSession sess, TreeConnection tree, String name)
{
ContentContext ctx = (ContentContext) tree.getContext();
int status = FileStatus.Unknown;
FileState fstate = null;
try
{
// Check for a cached file state
if ( ctx.hasStateCache())
fstate = ctx.getStateCache().findFileState(name, true);
if ( fstate != null && fstate.getFileStatus() != FileUnknown)
{
status = fstate.getFileStatus();
if ( status >= CustomFileStatus)
status = FileNotExist;
// DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_INFO))
logger.debug("Cache hit - fileExists() " + name + ", sts=" + status);
}
else
{
// Check if pseudo files are enabled
if ( hasPseudoFileInterface(ctx))
{
// Check if the file name is a pseudo file name
if ( getPseudoFileInterface( ctx).isPseudoFile(sess, tree, name)) {
// Make sure the parent folder has a file state, and the path exists
String[] paths = FileName.splitPath( name);
fstate = ctx.getStateCache().findFileState( paths[0]);
if ( fstate == null) {
// Check if the path exists
if ( fileExists( sess, tree, paths[0]) == FileStatus.DirectoryExists)
{
// Create the file state
fstate = ctx.getStateCache().findFileState( paths[0], true);
fstate.setFileStatus( DirectoryExists);
// Get the node for the folder path
beginReadTransaction( sess);
fstate.setFilesystemObject( getNodeForPath( tree, paths[0]));
// Add pseudo files to the folder
getPseudoFileInterface( ctx).addPseudoFilesToFolder( sess, tree, paths[0]);
// Debug
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_PSEUDO))
logger.debug( "Added file state for pseudo files folder (exists) - " + paths[0]);
}
}
else if ( fstate.hasPseudoFiles() == false)
{
// Make sure the file state has the node ref
if ( fstate.hasFilesystemObject() == false)
{
// Create the transaction
beginReadTransaction( sess);
// Get the node for the folder path
fstate.setFilesystemObject( getNodeForPath( tree, paths[0]));
}
// Add pseudo files for the parent folder
getPseudoFileInterface( ctx).addPseudoFilesToFolder( sess, tree, paths[0]);
// Debug
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_PSEUDO))
logger.debug( "Added pseudo files for folder (exists) - " + paths[0]);
}
// Check if the path is to a pseudo file
PseudoFile pfile = getPseudoFileInterface(ctx).getPseudoFile( sess, tree, name);
if ( pfile != null)
{
// Indicate that the file exists
status = FileStatus.FileExists;
}
else
{
// Failed to find pseudo file
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_PSEUDO))
logger.debug( "Failed to find pseudo file (exists) - " + name);
}
}
}
// If the file is not a pseudo file then search for the file
if ( status == FileStatus.Unknown)
{
// Create the transaction
beginReadTransaction( sess);
// Get the file information to check if the file/folder exists
FileInfo info = getFileInformation(sess, tree, name);
if (info.isDirectory())
{
status = FileStatus.DirectoryExists;
}
else
{
status = FileStatus.FileExists;
}
// Update the file state status
if ( fstate != null)
fstate.setFileStatus( status);
}
}
}
catch (FileNotFoundException e)
{
status = FileStatus.NotExist;
if ( fstate != null)
fstate.setFileStatus( status);
}
catch (IOException e)
{
// Debug
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_INFO))
logger.debug("File exists error, " + name, e);
status = FileStatus.NotExist;
}
// Debug
if (logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_INFO))
logger.debug("File status determined: name=" + name + " status=" + fileStatusString(fstate.getFileStatus()));
// Return the file/folder status
return status;
}
/**
* Open a file or folder
*
* @param sess SrvSession
* @param tree TreeConnection
* @param params FileOpenParams
* @return NetworkFile
* @exception IOException
*/
public NetworkFile openFile(SrvSession sess, TreeConnection tree, FileOpenParams params) throws IOException
{
// Create the transaction
beginReadTransaction( sess);
ContentContext ctx = (ContentContext) tree.getContext();
try
{
// Check if pseudo files are enabled
if ( hasPseudoFileInterface(ctx))
{
// Check if the file name is a pseudo file name
String path = params.getPath();
if ( getPseudoFileInterface( ctx).isPseudoFile(sess, tree, path)) {
// Make sure the parent folder has a file state, and the path exists
String[] paths = FileName.splitPath( path);
FileState fstate = ctx.getStateCache().findFileState( paths[0]);
if ( fstate == null) {
// Check if the path exists
if ( fileExists( sess, tree, paths[0]) == FileStatus.DirectoryExists)
{
// Create the file state and add any pseudo files
fstate = ctx.getStateCache().findFileState( paths[0], true);
fstate.setFileStatus( DirectoryExists);
getPseudoFileInterface( ctx).addPseudoFilesToFolder( sess, tree, paths[0]);
// Debug
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_PSEUDO))
logger.debug( "Added file state for pseudo files folder (open) - " + paths[0]);
}
}
else if ( fstate.hasPseudoFiles() == false)
{
// Add pseudo files for the parent folder
getPseudoFileInterface( ctx).addPseudoFilesToFolder( sess, tree, paths[0]);
// Debug
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_PSEUDO))
logger.debug( "Added pseudo files for folder (open) - " + paths[0]);
}
// Check if the path is to a pseudo file
PseudoFile pfile = getPseudoFileInterface(ctx).getPseudoFile( sess, tree, params.getPath());
if ( pfile != null)
{
// Create a network file to access the pseudo file data
return pfile.getFile( params.getPath());
}
else
{
// Failed to find pseudo file
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_PSEUDO))
logger.debug( "Failed to find pseudo file (open) - " + params.getPath());
}
}
}
// Not a pseudo file, try and open a normal file/folder node
NodeRef nodeRef = getNodeForPath(tree, params.getPath());
// Check permissions on the file/folder node
//
// Check for read access
if ( params.hasAccessMode(AccessMode.NTRead) &&
permissionService.hasPermission(nodeRef, PermissionService.READ) == AccessStatus.DENIED)
throw new AccessDeniedException("No read access to " + params.getFullPath());
// Check for write access
if ( params.hasAccessMode(AccessMode.NTWrite) &&
permissionService.hasPermission(nodeRef, PermissionService.WRITE) == AccessStatus.DENIED)
throw new AccessDeniedException("No write access to " + params.getFullPath());
// Check for delete access
// if ( params.hasAccessMode(AccessMode.NTDelete) &&
// permissionService.hasPermission(nodeRef, PermissionService.DELETE) == AccessStatus.DENIED)
// throw new AccessDeniedException("No delete access to " + params.getFullPath());
// Check if the file has a lock
String lockTypeStr = (String) nodeService.getProperty( nodeRef, ContentModel.PROP_LOCK_TYPE);
if ( params.hasAccessMode(AccessMode.NTWrite) && lockTypeStr != null)
throw new AccessDeniedException("File is locked, no write access to " + params.getFullPath());
// Check if there is a file state for the file
FileState fstate = null;
if ( ctx.hasStateCache())
{
// Check if there is a file state for the file
fstate = ctx.getStateCache().findFileState( params.getPath());
if ( fstate != null)
{
// Check if the file exists
if ( fstate.exists() == false)
throw new FileNotFoundException();
}
else {
// Create a file state for the path
fstate = ctx.getStateCache().findFileState( params.getPath(), true);
}
// Check if the current file open allows the required shared access
boolean nosharing = false;
// TEST
if ( params.getAccessMode() == AccessMode.NTFileGenericExecute && params.getPath().toLowerCase().endsWith( ".exe") == false) {
// DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE)) {
logger.debug( "Execute access mode, path" + params.getPath());
logger.debug( " Fstate=" + fstate);
}
throw new AccessDeniedException("Invalid access mode");
}
if ( fstate.getOpenCount() > 0) {
// Check for impersonation security level from the original process that opened the file
if ( params.getSecurityLevel() == WinNT.SecurityImpersonation && params.getProcessId() == fstate.getProcessId())
nosharing = false;
// Check if the caller wants read access, check the sharing mode
else if ( params.isReadOnlyAccess() && (fstate.getSharedAccess() & SharingMode.READ) != 0)
nosharing = false;
// Check if the caller wants write access, check the sharing mode
else if (( params.isReadWriteAccess() || params.isWriteOnlyAccess()) && (fstate.getSharedAccess() & SharingMode.WRITE) == 0)
{
// DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Sharing mode disallows write access path=" + params.getPath());
// Access not allowed
throw new AccessDeniedException( "Sharing mode (write)");
}
// Check if the file has been opened for exclusive access
else if ( fstate.getSharedAccess() == SharingMode.NOSHARING)
nosharing = true;
// Check if the required sharing mode is allowed by the current file open
else if ( ( fstate.getSharedAccess() & params.getSharedAccess()) != params.getSharedAccess())
nosharing = true;
// Check if the caller wants exclusive access to the file
else if ( params.getSharedAccess() == SharingMode.NOSHARING)
nosharing = true;
}
// Check if the file allows shared access
if ( nosharing == true)
{
if ( params.getPath().equals( "\\") == false) {
// DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Sharing violation path=" + params.getPath() + ", sharing=0x" + Integer.toHexString(fstate.getSharedAccess()));
// File is locked by another user
throw new FileSharingException("File already open, " + params.getPath());
}
}
// Update the file sharing mode and process id, if this is the first file open
fstate.setSharedAccess( params.getSharedAccess());
fstate.setProcessId( params.getProcessId());
// DEBUG
if ( logger.isDebugEnabled() && fstate.getOpenCount() == 0 && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Path " + params.getPath() + ", sharing=0x" + Integer.toHexString(params.getSharedAccess()) + ", PID=" + params.getProcessId());
}
// Check if the node is a link node
NodeRef linkRef = (NodeRef) nodeService.getProperty(nodeRef, ContentModel.PROP_LINK_DESTINATION);
AlfrescoNetworkFile netFile = null;
if ( linkRef == null)
{
// Check if the file is already opened by this client/process
if ( tree.openFileCount() > 0) {
// Search the open file table for this session/virtual circuit
int idx = 0;
while ( idx < tree.getFileTableLength() && netFile == null) {
// Get the current file from the open file table
NetworkFile curFile = tree.findFile( idx);
if ( curFile != null && curFile instanceof ContentNetworkFile) {
// Check if the file is the same path and process id
ContentNetworkFile contentFile = (ContentNetworkFile) curFile;
if ( contentFile.getProcessId() == params.getProcessId() &&
contentFile.getFullName().equalsIgnoreCase( params.getFullPath())) {
// Check that the access mode is the same
if (( params.isReadWriteAccess() && contentFile.getGrantedAccess() == NetworkFile.READWRITE) ||
( params.isReadOnlyAccess() && contentFile.getGrantedAccess() == NetworkFile.READONLY)) {
// Found a match, re-use the open file
netFile = contentFile;
// Increment the file open count, last file close will actually close the file/stream
contentFile.incrementOpenCount();
// DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Re-use existing file open Path " + params.getPath() + ", PID=" + params.getProcessId() + ", params=" +
( params.isReadOnlyAccess() ? "ReadOnly" : "Write") + ", file=" +
( contentFile.getGrantedAccess() == NetworkFile.READONLY ? "ReadOnly" : "Write"));
}
else if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Not re-using file path=" + params.getPath() + ", readWrite=" + (params.isReadWriteAccess() ? "true" : "false") +
", readOnly=" + (params.isReadOnlyAccess() ? "true" : "false") +
", grantedAccess=" + contentFile.getGrantedAccessAsString());
}
}
// Update the file table index
idx++;
}
}
// Create the network file, if we could not match an existing file open
if ( netFile == null) {
// Create a new network file for the open request
netFile = ContentNetworkFile.createFile(nodeService, contentService, mimetypeService, cifsHelper, nodeRef, params, sess);
}
}
else
{
// Get the CIFS server name
String srvName = null;
SMBServer cifsServer = (SMBServer) sess.getServer().getConfiguration().findServer( "CIFS");
if ( cifsServer != null)
{
// Use the CIFS server name in the URL
srvName = cifsServer.getServerName();
}
else
{
// Use the local server name in the URL
srvName = InetAddress.getLocalHost().getHostName();
}
// Convert the target node to a path, convert to URL format
String path = getPathForNode( tree, linkRef);
path = path.replace( FileName.DOS_SEPERATOR, '/');
// Build the URL file data
StringBuilder urlStr = new StringBuilder();
urlStr.append("[InternetShortcut]\r\n");
urlStr.append("URL=file://");
urlStr.append( srvName);
urlStr.append("/");
urlStr.append( tree.getSharedDevice().getName());
urlStr.append( path);
urlStr.append("\r\n");
// Create the in memory pseudo file for the URL link
byte[] urlData = urlStr.toString().getBytes();
// Get the file information for the link node
FileInfo fInfo = cifsHelper.getFileInformation( nodeRef);
// Set the file size to the actual data length
fInfo.setFileSize( urlData.length);
// Create the network file using the in-memory file data
netFile = new LinkMemoryNetworkFile( fInfo.getFileName(), urlData, fInfo, nodeRef);
netFile.setFullName( params.getPath());
}
// Generate a file id for the file
if ( netFile != null) {
long id = DefaultTypeConverter.INSTANCE.convert(Long.class, nodeService.getProperty(nodeRef, ContentModel.PROP_NODE_DBID));
netFile.setFileId(( int) ( id & 0xFFFFFFFFL));
}
// If the file has been opened for overwrite then truncate the file to zero length, this will
// also prevent the existing content data from being copied to the new version of the file
if ( params.isOverwrite() && netFile != null)
{
// Truncate the file to zero length
netFile.truncateFile( 0L);
}
// Create a file state for the open file
if ( ctx.hasStateCache())
{
if ( fstate == null)
fstate = ctx.getStateCache().findFileState(params.getPath(), true);
// Update the file state, cache the node
fstate.incrementOpenCount();
fstate.setFilesystemObject(nodeRef);
// Store the state with the file
netFile.setFileState( fstate);
// Set the file access date/time, if available
if ( fstate.hasAccessDateTime())
netFile.setAccessDate( fstate.getAccessDateTime());
}
// Debug
if (logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Opened network file: path=" + params.getPath() + " file open parameters=" + params + " network file=" + netFile);
// Return the network file
return netFile;
}
catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
{
// Debug
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Open file - access denied, " + params.getFullPath());
// Convert to a filesystem access denied status
throw new AccessDeniedException("Open file " + params.getFullPath());
}
catch (AlfrescoRuntimeException ex)
{
// Debug
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Open file error", ex);
// Convert to a general I/O exception
throw new IOException("Open file " + params.getFullPath());
}
}
/**
* Create a new file on the file system.
*
* @param sess Server session
* @param tree Tree connection
* @param params File create parameters
* @return NetworkFile
* @exception java.io.IOException If an error occurs.
*/
public NetworkFile createFile(SrvSession sess, final TreeConnection tree, final FileOpenParams params) throws IOException
{
final ContentContext ctx = (ContentContext) tree.getContext();
try
{
// Access the repository in a retryable write transaction
Pair<String, NodeRef> result = doInWriteTransaction(sess, new CallableIO<Pair<String, NodeRef>>(){
public Pair<String, NodeRef> call() throws IOException
{
// Get the device root
NodeRef deviceRootNodeRef = ctx.getRootNode();
String path = params.getPath();
String parentPath = null;
// If the state table is available then try to find the parent folder node for the new file
// to save having to walk the path
if (ctx.hasStateCache())
{
// See if the parent folder has a file state, we can avoid having to walk the path
String[] paths = FileName.splitPath(path);
if ( paths[0] != null && paths[0].length() > 1)
{
// Find the node ref for the folder being searched
NodeRef nodeRef = getNodeForPath(tree, paths[0]);
if ( nodeRef != null)
{
deviceRootNodeRef = nodeRef;
path = paths[1];
// DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Create file using cached noderef for path " + paths[0]);
}
parentPath = paths[0];
}
}
// Create it - the path will be created, if necessary
NodeRef nodeRef = cifsHelper.createNode(deviceRootNodeRef, path, ContentModel.TYPE_CONTENT);
nodeService.addAspect(nodeRef, ContentModel.ASPECT_NO_CONTENT, null);
return new Pair<String, NodeRef>(parentPath, nodeRef);
}});
// Get or create the file state for the parent folder
FileState parentState = null;
String parentPath = result.getFirst();
if (parentPath != null)
{
parentState = getStateForPath(tree, parentPath);
if (parentState == null && ctx.hasStateCache())
parentState = ctx.getStateCache().findFileState(parentPath, true);
}
// Create the network file
ContentNetworkFile netFile = ContentNetworkFile.createFile(nodeService, contentService, mimetypeService, cifsHelper, result.getSecond(), params, sess);
// Always allow write access to a newly created file
netFile.setGrantedAccess(NetworkFile.READWRITE);
// Set the owner process id for this open file
netFile.setProcessId( params.getProcessId());
// Truncate the file so that the content stream is created
netFile.truncateFile( 0L);
// Generate a file id for the file
if ( netFile != null) {
long id = DefaultTypeConverter.INSTANCE.convert(Long.class, nodeService.getProperty(netFile.getNodeRef(), ContentModel.PROP_NODE_DBID));
netFile.setFileId((int) (id & 0xFFFFFFFFL));
}
// Add a file state for the new file/folder
if ( ctx.hasStateCache())
{
FileState fstate = ctx.getStateCache().findFileState(params.getPath(), true);
if ( fstate != null)
{
// Save the file sharing mode, needs to be done before the open count is incremented
fstate.setSharedAccess( params.getSharedAccess());
fstate.setProcessId( params.getProcessId());
// Indicate that the file is open
fstate.setFileStatus( FileExists);
fstate.incrementOpenCount();
fstate.setFilesystemObject(result.getSecond());
// Track the intial allocation size
fstate.setAllocationSize( params.getAllocationSize());
// Store the file state with the file
netFile.setFileState( fstate);
// DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Create file, state=" + fstate);
}
// Update the parent folder file state
if ( parentState != null)
parentState.updateModifyDateTime();
}
// Debug
if (logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Created file: path=" + params.getPath() + " file open parameters=" + params + " node=" + result.getSecond() + " network file=" + netFile);
// Return the new network file
return netFile;
}
catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
{
// Debug
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Create file - access denied, " + params.getFullPath());
// Convert to a filesystem access denied status
throw new AccessDeniedException("Create file " + params.getFullPath());
}
catch (ContentIOException ex)
{
// Debug
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Create file - content I/O error, " + params.getFullPath());
// Convert to a filesystem disk full status
throw new DiskFullException("Create file " + params.getFullPath());
}
catch (AlfrescoRuntimeException ex)
{
// Debug
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Create file error", ex);
// Convert to a general I/O exception
throw new IOException("Create file " + params.getFullPath());
}
}
/**
* Create a new directory on this file system.
*
* @param sess Server session
* @param tree Tree connection.
* @param params Directory create parameters
* @exception java.io.IOException If an error occurs.
*/
public void createDirectory(SrvSession sess, final TreeConnection tree, final FileOpenParams params) throws IOException
{
final ContentContext ctx = (ContentContext) tree.getContext();
try
{
// Access the repository in a retryable write transaction
Pair<String, NodeRef> result = doInWriteTransaction(sess, new CallableIO<Pair<String, NodeRef>>()
{
public Pair<String, NodeRef> call() throws IOException
{
// get the device root
NodeRef deviceRootNodeRef = ctx.getRootNode();
String path = params.getPath();
String parentPath = null;
// If the state table is available then try to find the parent folder node for the new folder
// to save having to walk the path
if ( ctx.hasStateCache())
{
// See if the parent folder has a file state, we can avoid having to walk the path
String[] paths = FileName.splitPath(path);
if (paths[0] != null && paths[0].length() > 1)
{
// Find the node ref for the folder being searched
NodeRef nodeRef = getNodeForPath(tree, paths[0]);
if (nodeRef != null)
{
deviceRootNodeRef = nodeRef;
path = paths[1];
// DEBUG
if (logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Create file using cached noderef for path " + paths[0]);
}
parentPath = paths[0];
}
}
// Create it - the path will be created, if necessary
NodeRef nodeRef = cifsHelper.createNode(deviceRootNodeRef, path, ContentModel.TYPE_FOLDER);
return new Pair<String, NodeRef>(parentPath, nodeRef);
}
});
// Get or create the file state for the parent folder
FileState parentState = null;
String parentPath = result.getFirst();
if (parentPath != null)
{
parentState = getStateForPath(tree, parentPath);
if (parentState == null && ctx.hasStateCache())
parentState = ctx.getStateCache().findFileState(parentPath, true);
}
// Add a file state for the new folder
if ( ctx.hasStateCache())
{
FileState fstate = ctx.getStateCache().findFileState( params.getPath(), true);
if ( fstate != null)
{
// Indicate that the file is open
fstate.setFileStatus( DirectoryExists);
fstate.setFilesystemObject(result.getSecond());
// DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Create folder, state=" + fstate);
}
// Update the parent folder file state
if ( parentState != null)
parentState.updateModifyDateTime();
}
// Debug
if (logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Created directory: path=" + params.getPath() + " file open params=" + params + " node=" + result.getSecond());
}
catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
{
// Debug
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Create directory - access denied, " + params.getFullPath());
// Convert to a filesystem access denied status
throw new AccessDeniedException("Create directory " + params.getFullPath());
}
catch (AlfrescoRuntimeException ex)
{
// Debug
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Create directory error", ex);
// Convert to a general I/O exception
throw new IOException("Create directory " + params.getFullPath());
}
}
/**
* Delete the directory from the filesystem.
*
* @param sess Server session
* @param tree Tree connection
* @param dir Directory name.
* @exception java.io.IOException The exception description.
*/
public void deleteDirectory(SrvSession sess, TreeConnection tree, final String dir) throws IOException
{
// get the device root
ContentContext ctx = (ContentContext) tree.getContext();
final NodeRef deviceRootNodeRef = ctx.getRootNode();
try
{
NodeRef nodeRef = doInWriteTransaction(sess, new CallableIO<NodeRef>(){
public NodeRef call() throws IOException
{
// Get the node for the folder
NodeRef nodeRef = cifsHelper.getNodeRef(deviceRootNodeRef, dir);
if (fileFolderService.exists(nodeRef))
{
// Check if the folder is empty
if ( cifsHelper.isFolderEmpty( nodeRef))
{
// Delete the folder node
fileFolderService.delete(nodeRef);
return nodeRef;
}
else
{
throw new DirectoryNotEmptyException( dir);
}
}
return null;
}});
if (nodeRef != null && ctx.hasStateCache())
{
// Remove the file state
ctx.getStateCache().removeFileState(dir);
// Update, or create, a parent folder file state
String[] paths = FileName.splitPath(dir);
if ( paths[0] != null && paths[0].length() > 1)
{
// Get the file state for the parent folder
FileState parentState = getStateForPath(tree, paths[0]);
if ( parentState == null && ctx.hasStateCache())
parentState = ctx.getStateCache().findFileState( paths[0], true);
// Update the modification timestamp
parentState.updateModifyDateTime();
}
}
// Debug
if (logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Deleted directory: directory=" + dir + " node=" + nodeRef);
}
catch (FileNotFoundException e)
{
// Debug
if (logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Delete directory - file not found, " + dir);
}
catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
{
// Debug
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Delete directory - access denied, " + dir);
// Convert to a filesystem access denied status
throw new AccessDeniedException("Delete directory " + dir);
}
catch (AlfrescoRuntimeException ex)
{
// Debug
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Delete directory", ex);
// Convert to a general I/O exception
throw new IOException("Delete directory " + dir);
}
}
/**
* Flush any buffered output for the specified file.
*
* @param sess Server session
* @param tree Tree connection
* @param file Network file context.
* @exception java.io.IOException The exception description.
*/
public void flushFile(SrvSession sess, TreeConnection tree, NetworkFile file) throws IOException
{
// Debug
ContentContext ctx = (ContentContext) tree.getContext();
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILEIO))
logger.debug("Flush file=" + file.getFullName());
// Flush the file data
file.flushFile();
}
/**
* Close the file.
*
* @param sess Server session
* @param tree Tree connection.
* @param param Network file context.
* @exception java.io.IOException If an error occurs.
*/
public void closeFile(SrvSession sess, TreeConnection tree, final NetworkFile file) throws IOException
{
// Get the associated file state
final ContentContext ctx = (ContentContext) tree.getContext();
FileState toUpdate = null;
// Check for a content file
if ( file instanceof ContentNetworkFile) {
// Update the file state
if ( ctx.hasStateCache())
{
FileState fstate = ctx.getStateCache().findFileState(file.getFullName());
if ( fstate != null) {
// If the file open count is now zero then reset the stored sharing mode
if ( fstate.decrementOpenCount() == 0)
fstate.setSharedAccess( SharingMode.READWRITE + SharingMode.DELETE);
// Check if there is a cached modification timestamp to be written out
if ( file.hasDeleteOnClose() == false && fstate.hasModifyDateTime() && fstate.hasFilesystemObject() && fstate.isDirectory() == false) {
// Update the modification date on the file/folder node
toUpdate = fstate;
}
}
}
// Decrement the file open count
ContentNetworkFile contentFile = (ContentNetworkFile) file;
if ( contentFile.decrementOpenCount() > 0) {
// DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Deferred file close, path=" + file.getFullName() + ", openCount=" + contentFile.getOpenCount());
// Defer the file close to the last reference
return;
}
else if ( logger.isDebugEnabled())
logger.debug("Last reference to file, closing, path=" + file.getFullName() + ", access=" + file.getGrantedAccessAsString() + ", fid=" + file.getProtocolId() +
", modified=" + contentFile.isModified());
}
// Check if there is a quota manager enabled
long fileSize = 0L;
if ( ctx.hasQuotaManager() && file.hasDeleteOnClose()) {
// Make sure the content stream has been opened, to get the current file size
if ( file instanceof ContentNetworkFile) {
ContentNetworkFile contentFile = (ContentNetworkFile) file;
if ( contentFile.hasContent() == false)
contentFile.openContent( false, false);
// Save the current file size
fileSize = contentFile.getFileSize();
}
}
// Depending on whether the node has the NO_CONTENT aspect, we may have to wipe it out on error
final CallableIO<Void> errorHandler = new CallableIO<Void>()
{
public Void call() throws IOException
{
if (file instanceof NodeRefNetworkFile)
{
NodeRef nodeRef = ((NodeRefNetworkFile) file).getNodeRef();
if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_NO_CONTENT))
{
fileFolderService.delete(nodeRef);
}
}
return null;
}
};
try
{
// Perform repository updates in a retryable write transaction
final FileState finalFileState = toUpdate;
Pair<NodeRef, Boolean> result = doInWriteTransaction(sess, new CallableIO<Pair<NodeRef, Boolean>>()
{
public Pair<NodeRef, Boolean> call() throws IOException
{
// Check if the file is an OpenOffice document and hte truncation flag is set
//
// Note: Check before the timestamp update
if ( file instanceof OpenOfficeContentNetworkFile) {
OpenOfficeContentNetworkFile ooFile = (OpenOfficeContentNetworkFile) file;
if ( ooFile.truncatedToZeroLength()) {
// Inhibit versioning for this transaction
getPolicyFilter().disableBehaviour( ContentModel.ASPECT_VERSIONABLE);
// Debug
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("OpenOffice file truncation update only, inhibit versioning, " + file.getFullName());
}
}
// Update the modification date on the file/folder node
if (finalFileState != null && file instanceof ContentNetworkFile)
{
NodeRef nodeRef = (NodeRef) finalFileState.getFilesystemObject();
// Check if the file data has been updated, if not then inhibit versioning for this txn
// so the timestamp update does not generate a new file version
ContentNetworkFile contentFile = (ContentNetworkFile) file;
if ( contentFile.isModified() == false && nodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE)) {
// Stop a new file version being generated
getPolicyFilter().disableBehaviour( ContentModel.ASPECT_VERSIONABLE);
// Debug
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Timestamp update only, inhibit versioning, " + file.getFullName());
}
// Update the modification timestamp
getPolicyFilter().disableBehaviour(nodeRef, ContentModel.ASPECT_AUDITABLE);
if (permissionService.hasPermission((NodeRef) finalFileState.getFilesystemObject(), PermissionService.WRITE_PROPERTIES) == AccessStatus.ALLOWED)
{
Date modifyDate = new Date(finalFileState.getModifyDateTime());
nodeService.setProperty(nodeRef, ContentModel.PROP_MODIFIED, modifyDate);
// Debug
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Updated modification timestamp, " + file.getFullName() + ", modTime=" + modifyDate);
}
}
// Defer to the network file to close the stream and remove the content
file.closeFile();
// Remove the node if marked for delete
if (file.hasDeleteOnClose())
{
// Check if the file is a noderef based file
if ( file instanceof NodeRefNetworkFile)
{
NodeRefNetworkFile nodeNetFile = (NodeRefNetworkFile) file;
NodeRef nodeRef = nodeNetFile.getNodeRef();
// We don't know how long the network file has had the reference, so check for existence
if (fileFolderService.exists(nodeRef))
{
try
{
boolean isVersionable = nodeService.hasAspect( nodeRef, ContentModel.ASPECT_VERSIONABLE);
try
{
// Delete the file
fileFolderService.delete(nodeRef);
}
catch ( Exception ex)
{
// Propagate retryable errors. Log the rest.
if (RetryingTransactionHelper.extractRetryCause(ex) != null)
{
if (ex instanceof RuntimeException)
{
throw (RuntimeException)ex;
}
else
{
throw new AlfrescoRuntimeException("Error during delete on close, " + file.getFullName(), ex);
}
}
if ( logger.isWarnEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.warn("Error during delete on close, " + file.getFullName(), ex);
}
// Return a node ref to update in the state table
return new Pair<NodeRef, Boolean>(nodeRef, isVersionable);
}
catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
{
// Debug
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Delete on close - access denied, " + file.getFullName());
// Convert to a filesystem access denied exception
throw new AccessDeniedException("Delete on close " + file.getFullName());
}
}
}
}
return null;
}});
if (result != null)
{
// Check if there is a quota manager enabled, release space back to the user quota
if ( ctx.hasQuotaManager())
ctx.getQuotaManager().releaseSpace(sess, tree, file.getFileId(), file.getFullName(), fileSize);
// Set the file state to indicate a delete on close
if (ctx.hasStateCache())
{
if (result.getSecond())
{
// Get, or create, the file state
FileState fState = ctx.getStateCache().findFileState(file.getFullName(), true);
// Indicate that the file was deleted via a delete on close request
fState.setFileStatus(DeleteOnClose);
// Make sure the file state is cached for a short while, save the noderef details
fState.setExpiryTime(System.currentTimeMillis() + FileState.RenameTimeout);
fState.setFilesystemObject(result.getFirst());
}
else
{
// Remove the file state
ctx.getStateCache().removeFileState(file.getFullName());
}
}
}
else if (file.hasDeleteOnClose() && (file instanceof PseudoNetworkFile || file instanceof MemoryNetworkFile)
&& hasPseudoFileInterface(ctx))
{
// Delete the pseudo file
getPseudoFileInterface(ctx).deletePseudoFile(sess, tree, file.getFullName());
}
// DEBUG
if (logger.isDebugEnabled() && (ctx.hasDebug(AlfrescoContext.DBG_FILE) || ctx.hasDebug(AlfrescoContext.DBG_RENAME))) {
logger.debug("Closed file: network file=" + file + " delete on close=" + file.hasDeleteOnClose());
if ( file.hasDeleteOnClose() == false && file instanceof ContentNetworkFile) {
ContentNetworkFile cFile = (ContentNetworkFile) file;
logger.debug(" File " + file.getFullName() + ", version=" + nodeService.getProperty( cFile.getNodeRef(), ContentModel.PROP_VERSION_LABEL));
}
}
}
// Make sure we clean up before propagating exceptions
catch (IOException e)
{
try
{
doInWriteTransaction(sess, errorHandler);
}
catch (Throwable t)
{
logger.error(t.getMessage(), t);
}
throw e;
}
catch (RuntimeException e)
{
try
{
doInWriteTransaction(sess, errorHandler);
}
catch (Throwable t)
{
logger.error(t.getMessage(), t);
}
throw e;
}
catch (Error e)
{
try
{
doInWriteTransaction(sess, errorHandler);
}
catch (Throwable t)
{
logger.error(t.getMessage(), t);
}
throw e;
}
}
/**
* Delete the specified file.
*
* @param sess Server session
* @param tree Tree connection
* @param file NetworkFile
* @exception java.io.IOException The exception description.
*/
public void deleteFile(final SrvSession sess, final TreeConnection tree, final String name) throws IOException
{
// Get the device context
final ContentContext ctx = (ContentContext) tree.getContext();
try
{
// Check if pseudo files are enabled
if ( hasPseudoFileInterface(ctx))
{
// Check if the file name is a pseudo file name
if ( getPseudoFileInterface( ctx).isPseudoFile(sess, tree, name)) {
// Make sure the parent folder has a file state, and the path exists
String[] paths = FileName.splitPath( name);
FileState fstate = ctx.getStateCache().findFileState( paths[0]);
if ( fstate != null) {
// Check if the path is to a pseudo file
PseudoFile pfile = getPseudoFileInterface(ctx).getPseudoFile( sess, tree, name);
if ( pfile != null)
{
// Delete the pseudo file
getPseudoFileInterface( ctx).deletePseudoFile( sess, tree, name);
return;
}
}
}
}
// Check if there is a quota manager enabled, if so then we need to save the current file size
final QuotaManager quotaMgr = ctx.getQuotaManager();
// Perform repository updates in a retryable write transaction
Callable<Void> postTxn = doInWriteTransaction(sess, new CallableIO<Callable<Void>>()
{
public Callable<Void> call() throws IOException
{
// Get the node and delete it
final NodeRef nodeRef = getNodeForPath(tree, name);
Callable<Void> result = null;
if (fileFolderService.exists(nodeRef))
{
// Get the size of the file being deleted
final FileInfo fInfo = quotaMgr == null ? null : getFileInformation(sess, tree, name);
// Check if the node is versionable
final boolean isVersionable = nodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE);
fileFolderService.delete(nodeRef);
// Return the operations to perform when the transaction succeeds
result = new Callable<Void>()
{
public Void call() throws Exception
{
// Remove the file state
if (ctx.hasStateCache())
{
// Check if the node is versionable, cache the node details for a short while
if (isVersionable == true)
{
// Make sure the file state is cached for a short while, a new file may be
// renamed to the same name
// in which case we can connect the file to the previous version history
FileState delState = ctx.getStateCache().findFileState(name, true);
delState.setExpiryTime(System.currentTimeMillis() + FileState.DeleteTimeout);
delState.setFileStatus(DeleteOnClose);
delState.setFilesystemObject(nodeRef);
}
else
{
// Remove the file state
ctx.getStateCache().removeFileState(name);
}
// Update, or create, a parent folder file state
String[] paths = FileName.splitPath(name);
if (paths[0] != null && paths[0].length() > 1)
{
// Get the file state for the parent folder
FileState parentState = getStateForPath(tree, paths[0]);
if (parentState == null && ctx.hasStateCache())
parentState = ctx.getStateCache().findFileState(paths[0], true);
// Update the modification timestamp
parentState.updateModifyDateTime();
}
}
// Release the space back to the users quota
if (quotaMgr != null)
quotaMgr.releaseSpace(sess, tree, fInfo.getFileId(), name, fInfo.getSize());
return null;
}
};
}
// Debug
if (logger.isDebugEnabled() && (ctx.hasDebug(AlfrescoContext.DBG_FILE) || ctx.hasDebug(AlfrescoContext.DBG_RENAME)))
logger.debug("Deleted file: " + name + ", node=" + nodeRef);
return result;
}
});
// Perform state updates after the transaction succeeds
postTxn.call();
}
catch (NodeLockedException ex)
{
// Debug
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Delete file - access denied (locked)");
// Convert to a filesystem access denied status
throw new AccessDeniedException("Delete " + name);
}
catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
{
// Debug
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Delete file - access denied");
// Convert to a filesystem access denied status
throw new AccessDeniedException("Delete " + name);
}
catch (IOException ex)
{
// Allow I/O Exceptions to pass through
throw ex;
}
catch (Exception ex)
{
// Debug
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Delete file error", ex);
// Convert to a general I/O exception
IOException ioe = new IOException("Delete file " + name);
ioe.initCause(ex);
throw ioe;
}
}
/**
* Rename the specified file.
*
* @param sess Server session
* @param tree Tree connection
* @param oldName java.lang.String
* @param newName java.lang.String
* @exception java.io.IOException The exception description.
*/
public void renameFile(final SrvSession sess, final TreeConnection tree, final String oldName, final String newName)
throws IOException
{
// Create the transaction (initially read-only)
beginReadTransaction(sess);
// Get the device context
final ContentContext ctx = (ContentContext) tree.getContext();
// DEBUG
if (logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
logger.debug("Rename oldName=" + oldName + ", newName=" + newName);
try
{
// Get the file/folder to move
final NodeRef nodeToMoveRef = getNodeForPath(tree, oldName);
// Check if the node is a link node
if ( nodeToMoveRef != null && nodeService.getProperty(nodeToMoveRef, ContentModel.PROP_LINK_DESTINATION) != null)
throw new AccessDeniedException("Cannot rename link nodes");
// Get the new target folder - it must be a folder
String[] splitPaths = FileName.splitPath(newName);
String[] oldPaths = FileName.splitPath(oldName);
final NodeRef targetFolderRef = getNodeForPath(tree, splitPaths[0]);
final NodeRef sourceFolderRef = getNodeForPath(tree, oldPaths[0]);
final String name = splitPaths[1];
// Check if this is a rename within the same folder
final boolean sameFolder = splitPaths[0].equalsIgnoreCase(oldPaths[0]);
// Get the file state for the old file, if available
final FileState oldState = ctx.getStateCache().findFileState(oldName, true);
// Check if we are renaming a folder, or the rename is to a different folder
boolean isFolder = cifsHelper.isDirectory(nodeToMoveRef);
if ( isFolder == true || sameFolder == false) {
// Rename or move the file/folder
doInWriteTransaction(sess, new CallableIO<Void>()
{
public Void call() throws IOException
{
if (sameFolder == true)
cifsHelper.rename(nodeToMoveRef, name);
else
cifsHelper.move(nodeToMoveRef, sourceFolderRef, targetFolderRef, name);
return null;
}
});
// Update the old file state
if (oldState != null)
{
// Update the file state index to use the new name
ctx.getStateCache().renameFileState(newName, oldState, true);
}
// DEBUG
if (logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
logger.debug(" Renamed " + (isFolder ? "folder" : "file") + " using "
+ (sameFolder ? "rename" : "move"));
}
else {
// Rename a file within the same folder
//
// Check if the target file already exists
final int newExists = fileExists(sess, tree, newName);
final FileState newState = ctx.getStateCache().findFileState(newName, true);
List<Runnable> postTxn = doInWriteTransaction(sess, new CallableIO<List<Runnable>>()
{
public List<Runnable> call() throws IOException
{
List<Runnable> postTxn = new LinkedList<Runnable>();
NodeRef targetNodeRef = null;
boolean isFromVersionable = nodeService.hasAspect( nodeToMoveRef, ContentModel.ASPECT_VERSIONABLE);
boolean typesCompatible = true;
// HACK ALF-3856: Version History lost when Versionable Content renamed via CIFS
// This code will move into the repo layer (or just above it)
// and this complexity removed from here.
// Attempt to detect normal renames. Hack alert!
String oldNameLower = oldName.toLowerCase();
String newNameLower = newName.toLowerCase();
boolean renameShuffle = false;
Pattern renameShufflePattern = ctx.getRenameShufflePattern();
renameShuffle = renameShuffle || renameShufflePattern.matcher(oldNameLower).matches();
renameShuffle = renameShuffle || renameShufflePattern.matcher(newNameLower).matches();
if (logger.isDebugEnabled())
{
logger.debug(
"Rename file: \n" +
" Old name: " + oldName + "\n" +
" New name: " + newName + "\n" +
" Pattern: " + renameShufflePattern.pattern() + "\n" +
" Is shuffle: " + renameShuffle + "\n" +
" Source folder: " + sourceFolderRef + "\n" +
" Target folder: " + targetFolderRef + "\n" +
" Node: " + nodeToMoveRef + "\n" +
" Aspects: " + nodeService.getAspects(nodeToMoveRef));
}
if ( newExists == FileStatus.FileExists)
{
// Use the existing file as the target node
targetNodeRef = getNodeForPath( tree, newName);
}
else if (renameShuffle)
{
// Check if the target has a renamed or delete-on-close state
if ( newState.getFileStatus() == FileRenamed) {
// DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
logger.debug(" Using renamed node, " + newState);
NodeRef newStateNode = (NodeRef)newState.getFilesystemObject();
QName oldType = nodeService.getType(nodeToMoveRef);
QName newType = nodeService.getType(newStateNode);
if (oldType.equals(newType)) {
// Use the renamed node to clone aspects/state if it is of the correct type
cloneNode(name, newStateNode, nodeToMoveRef, ctx);
}
else
{
// Otherwise we must create a node of the correct type
targetNodeRef = cifsHelper.createNode(ctx.getRootNode(), newName, newType);
// Force a copy to this target
typesCompatible = false;
// DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
logger.debug(" Created new node for " + newName + " type " + newType);
// Copy aspects from the original state
cloneNode( name, newStateNode, targetNodeRef, ctx);
}
}
else if ( newState.getFileStatus() == DeleteOnClose) {
// DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
logger.debug(" Restoring delete-on-close node, " + newState);
// Restore the deleted node so we can relink the new version to the old history/properties
NodeRef archivedNode = getNodeArchiveService().getArchivedNode((NodeRef) newState.getFilesystemObject());
// DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
logger.debug(" Found archived node " + archivedNode);
if ( archivedNode != null )
{
// Restore the node
targetNodeRef = getNodeService().restoreNode( archivedNode, null, null, null);
// DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
logger.debug(" Restored node " + targetNodeRef + ", version=" + nodeService.getProperty( targetNodeRef, ContentModel.PROP_VERSION_LABEL));
// Check if the deleted file had a linked node, due to a rename
NodeRef linkNode = (NodeRef) newState.findAttribute( AttrLinkNode);
if ( linkNode != null && nodeService.exists( linkNode)) {
// Clone aspects from the linked node onto the restored node
cloneNode( name, linkNode, targetNodeRef, ctx);
// DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME)) {
logger.debug(" Moved aspects from linked node " + linkNode);
// Check if the node is a working copy
if ( nodeService.hasAspect( targetNodeRef, ContentModel.ASPECT_WORKING_COPY)) {
// Check if the main document is still locked
NodeRef mainNodeRef = (NodeRef) nodeService.getProperty( targetNodeRef, ContentModel.PROP_COPY_REFERENCE);
if ( mainNodeRef != null) {
LockType lockTyp = lockService.getLockType( mainNodeRef);
logger.debug(" Main node ref lock type = " + lockTyp);
}
}
}
}
}
}
// Check if the node being renamed is versionable
else if ( isFromVersionable == true) {
// Create a new node for the target
targetNodeRef = cifsHelper.createNode(ctx.getRootNode(), newName, nodeService.getType(nodeToMoveRef));
// DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
logger.debug(" Created new node for " + newName);
// Copy aspects from the original file
cloneNode( name, nodeToMoveRef, targetNodeRef, ctx);
}
}
// If the original or target nodes are not versionable and types are compatible then just use a standard rename of the node
if ( !renameShuffle ||
( !isFromVersionable &&
typesCompatible &&
( targetNodeRef == null || nodeService.hasAspect( targetNodeRef, ContentModel.ASPECT_VERSIONABLE) == false)))
{
// Rename the file/folder
cifsHelper.rename(nodeToMoveRef, name);
postTxn.add(new Runnable()
{
public void run()
{
// Mark the new file as existing
newState.setFileStatus(FileExists);
newState.setFilesystemObject(nodeToMoveRef);
// Make sure the old file state is cached for a short while, the file may not be open so the
// file state could be expired
oldState.setExpiryTime(System.currentTimeMillis() + FileState.DeleteTimeout);
// Indicate that this is a renamed file state, set the node ref of the file that was renamed
oldState.setFileStatus(FileRenamed);
oldState.setFilesystemObject(nodeToMoveRef);
}
});
// DEBUG
if (logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
logger.debug(" Use standard rename for " + name + "(versionable=" + isFromVersionable + ", targetNodeRef=" + targetNodeRef + ")");
}
else {
// Make sure we have a valid target node
if ( targetNodeRef == null) {
// DEBUG
if (logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
logger.debug(" No target node for rename");
// Throw an error
throw new AccessDeniedException("No target node for file rename");
}
// Copy content data from the old file to the new file
copyContentData(sess, tree, nodeToMoveRef, targetNodeRef, newName);
final NodeRef finalTargetNodeRef = targetNodeRef;
postTxn.add(new Runnable()
{
public void run()
{
// Mark the new file as existing
newState.setFileStatus(FileExists);
newState.setFilesystemObject(finalTargetNodeRef);
// Make sure the old file state is cached for a short while, the file may not be open so the
// file state could be expired
oldState.setExpiryTime(System.currentTimeMillis() + FileState.DeleteTimeout);
// Indicate that this is a deleted file state, set the node ref of the file that was renamed
oldState.setFileStatus( DeleteOnClose);
oldState.setFilesystemObject(nodeToMoveRef);
// Link to the new node, a new file may be renamed into place, we need to transfer aspect/locks
oldState.addAttribute( AttrLinkNode, finalTargetNodeRef);
// DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug( AlfrescoContext.DBG_RENAME))
logger.debug(" Cached delete state for " + oldName);
}
});
// Delete the old file
nodeService.deleteNode(nodeToMoveRef);
}
return postTxn;
}
});
// Run the required state-changing logic once the retrying transaction has completed successfully
for (Runnable runnable : postTxn)
{
runnable.run();
}
}
}
catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
{
// Debug
if (logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
logger.debug("Rename file - access denied, " + oldName);
// Convert to a filesystem access denied status
throw new AccessDeniedException("Rename file " + oldName);
}
catch (NodeLockedException ex)
{
// Debug
if (logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
logger.debug("Rename file", ex);
// Convert to an filesystem access denied exception
throw new AccessDeniedException("Node locked " + oldName);
}
catch (AlfrescoRuntimeException ex)
{
// Debug
if (logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
logger.debug("Rename file", ex);
// Convert to a general I/O exception
throw new AccessDeniedException("Rename file " + oldName);
}
}
/**
* Set file information
*
* @param sess SrvSession
* @param tree TreeConnection
* @param name String
* @param info FileInfo
* @exception IOException
*/
public void setFileInformation(SrvSession sess, final TreeConnection tree, final String name, final FileInfo info) throws IOException
{
// Get the device context
final ContentContext ctx = (ContentContext) tree.getContext();
try
{
// Check if pseudo files are enabled
if ( hasPseudoFileInterface(ctx) &&
getPseudoFileInterface(ctx).isPseudoFile( sess, tree, name))
{
// Allow the file information to be changed
return;
}
final FileState fstate = getStateForPath(tree, name);
doInWriteTransaction(sess, new CallableIO<Pair<Boolean, Boolean>>(){
public Pair<Boolean, Boolean> call() throws IOException
{
// Get the file/folder node
NodeRef nodeRef = getNodeForPath(tree, name);
// Check permissions on the file/folder node
if ( permissionService.hasPermission(nodeRef, PermissionService.WRITE) == AccessStatus.DENIED)
throw new AccessDeniedException("No write access to " + name);
if ( permissionService.hasPermission(nodeRef, PermissionService.DELETE) == AccessStatus.DENIED)
throw new AccessDeniedException("No delete access to " + name);
// Inhibit versioning for this transaction
getPolicyFilter().disableBehaviour( ContentModel.ASPECT_VERSIONABLE);
// Check if the file is being marked for deletion, if so then check if the file is locked
if ( info.hasSetFlag(FileInfo.SetDeleteOnClose) && info.hasDeleteOnClose())
{
// Check if the node is locked
if ( nodeService.hasAspect( nodeRef, ContentModel.ASPECT_LOCKABLE))
{
// Get the lock type, if any
String lockTypeStr = (String) nodeService.getProperty( nodeRef, ContentModel.PROP_LOCK_TYPE);
if ( lockTypeStr != null)
throw new AccessDeniedException("Node locked, cannot mark for delete");
}
// Get the node for the folder
if (fileFolderService.exists(nodeRef))
{
// Check if it is a folder that is being deleted, make sure it is empty
boolean isFolder = true;
if ( fstate != null)
isFolder = fstate.isDirectory();
else {
ContentFileInfo cInfo = cifsHelper.getFileInformation( nodeRef);
if ( cInfo != null && cInfo.isDirectory() == false)
isFolder = false;
}
// Check if the folder is empty
if ( isFolder == true && cifsHelper.isFolderEmpty( nodeRef) == false)
throw new DirectoryNotEmptyException( name);
}
// DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_INFO))
logger.debug("Set deleteOnClose=true file=" + name);
}
// Set the creation and modified date/time
Map<QName, Serializable> auditableProps = new HashMap<QName, Serializable>(5);
if ( info.hasSetFlag(FileInfo.SetCreationDate))
{
// Set the creation date on the file/folder node
Date createDate = new Date( info.getCreationDateTime());
auditableProps.put(ContentModel.PROP_CREATED, createDate);
}
if ( info.hasSetFlag(FileInfo.SetModifyDate)) {
// Set the modification date on the file/folder node
Date modifyDate = new Date( info.getModifyDateTime());
auditableProps.put(ContentModel.PROP_MODIFIED, modifyDate);
}
// Did we have any cm:auditable properties?
if (auditableProps.size() > 0)
{
getPolicyFilter().disableBehaviour(nodeRef, ContentModel.ASPECT_AUDITABLE);
nodeService.addProperties(nodeRef, auditableProps);
// DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_INFO))
logger.debug("Set auditable props: " + auditableProps + " file=" + name);
}
return null;
}});
// Check if the file is being marked for deletion, if so then check if the file is locked
// Update the change date/time
if (fstate != null)
{
if (info.hasSetFlag(FileInfo.SetDeleteOnClose) && info.hasDeleteOnClose()
|| info.hasSetFlag(FileInfo.SetCreationDate))
{
fstate.updateChangeDateTime();
}
// Set the modification date/time
if (info.hasSetFlag(FileInfo.SetModifyDate))
{
// Update the change date/time, clear the cached modification date/time
fstate.updateChangeDateTime();
fstate.updateModifyDateTime(0L);
}
}
}
catch (org.alfresco.repo.security.permissions.AccessDeniedException ex)
{
// Debug
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_INFO))
logger.debug("Set file information - access denied, " + name);
// Convert to a filesystem access denied status
throw new AccessDeniedException("Set file information " + name);
}
catch (AlfrescoRuntimeException ex)
{
// Debug
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_INFO))
logger.debug("Open file error", ex);
// Convert to a general I/O exception
throw new IOException("Set file information " + name);
}
}
/**
* Truncate a file to the specified size
*
* @param sess Server session
* @param tree Tree connection
* @param file Network file details
* @param size New file length
* @exception java.io.IOException The exception description.
*/
public void truncateFile(SrvSession sess, TreeConnection tree, NetworkFile file, long size) throws IOException
{
// Keep track of the allocation/release size in case the file resize fails
ContentContext ctx = (ContentContext) tree.getContext();
long allocSize = 0L;
long releaseSize = 0L;
// Check if there is a quota manager
QuotaManager quotaMgr = ctx.getQuotaManager();
if ( ctx.hasQuotaManager()) {
// Check if the file content has been opened, we need the content to be opened to get the
// current file size
if ( file instanceof ContentNetworkFile) {
ContentNetworkFile contentFile = (ContentNetworkFile) file;
if ( contentFile.hasContent() == false)
contentFile.openContent( false, false);
}
else
throw new IOException("Invalid file class type, " + file.getClass().getName());
// Determine if the new file size will release space or require space allocating
if ( size > file.getFileSize()) {
// Calculate the space to be allocated
allocSize = size - file.getFileSize();
// Allocate space to extend the file
quotaMgr.allocateSpace(sess, tree, file, allocSize);
}
else {
// Calculate the space to be released as the file is to be truncated, release the space if
// the file truncation is successful
releaseSize = file.getFileSize() - size;
}
}
// Check if this is a file extend, update the cached allocation size if necessary
if ( file instanceof ContentNetworkFile) {
// Get the cached state for the file
ContentNetworkFile contentFile = (ContentNetworkFile) file;
FileState fstate = contentFile.getFileState();
if ( fstate != null && size > fstate.getAllocationSize())
fstate.setAllocationSize( size);
}
// Set the file length
try {
file.truncateFile(size);
}
catch (IOException ex) {
// Check if we allocated space to the file
if ( allocSize > 0 && quotaMgr != null)
quotaMgr.releaseSpace(sess, tree, file.getFileId(), null, allocSize);
// Rethrow the exception
throw ex;
}
// Check if space has been released by the file resizing
if ( releaseSize > 0 && quotaMgr != null)
quotaMgr.releaseSpace(sess, tree, file.getFileId(), null, releaseSize);
// Debug
if (logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILEIO))
logger.debug("Truncated file: network file=" + file + " size=" + size);
}
/**
* Read a block of data from the specified file.
*
* @param sess Session details
* @param tree Tree connection
* @param file Network file
* @param buf Buffer to return data to
* @param bufPos Starting position in the return buffer
* @param siz Maximum size of data to return
* @param filePos File offset to read data
* @return Number of bytes read
* @exception java.io.IOException The exception description.
*/
public int readFile(
SrvSession sess, TreeConnection tree, NetworkFile file,
byte[] buffer, int bufferPosition, int size, long fileOffset) throws IOException
{
// Check if the file is a directory
if(file.isDirectory())
throw new AccessDeniedException();
// If the content channel is not open for the file then start a transaction
if ( file instanceof ContentNetworkFile)
{
ContentNetworkFile contentFile = (ContentNetworkFile) file;
if ( contentFile.hasContent() == false)
beginReadTransaction( sess);
}
// Read a block of data from the file
int count = file.readFile(buffer, size, bufferPosition, fileOffset);
if ( count == -1)
{
// Read count of -1 indicates a read past the end of file
count = 0;
}
// Debug
ContentContext ctx = (ContentContext) tree.getContext();
if (logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILEIO))
logger.debug("Read bytes from file: network file=" + file + " buffer size=" + buffer.length + " buffer pos=" + bufferPosition +
" size=" + size + " file offset=" + fileOffset + " bytes read=" + count);
return count;
}
/**
* Seek to the specified file position.
*
* @param sess Server session
* @param tree Tree connection
* @param file Network file.
* @param pos Position to seek to.
* @param typ Seek type.
* @return New file position, relative to the start of file.
*/
public long seekFile(SrvSession sess, TreeConnection tree, NetworkFile file, long pos, int typ) throws IOException
{
// Check if the file is a directory
if ( file.isDirectory())
throw new AccessDeniedException();
// If the content channel is not open for the file then start a transaction
ContentNetworkFile contentFile = (ContentNetworkFile) file;
if ( contentFile.hasContent() == false)
beginReadTransaction( sess);
// Set the file position
return file.seekFile(pos, typ);
}
/**
* Write a block of data to the file.
*
* @param sess Server session
* @param tree Tree connection
* @param file Network file details
* @param buf byte[] Data to be written
* @param bufoff Offset within the buffer that the data starts
* @param siz int Data length
* @param fileoff Position within the file that the data is to be written.
* @return Number of bytes actually written
* @exception java.io.IOException The exception description.
*/
public int writeFile(SrvSession sess, TreeConnection tree, NetworkFile file,
byte[] buffer, int bufferOffset, int size, long fileOffset) throws IOException
{
// If the content channel is not open for the file then start a transaction
if ( file instanceof ContentNetworkFile)
{
ContentNetworkFile contentFile = (ContentNetworkFile) file;
if ( contentFile.hasContent() == false)
beginReadTransaction( sess);
}
// Check if there is a quota manager
ContentContext ctx = (ContentContext) tree.getContext();
QuotaManager quotaMgr = ctx.getQuotaManager();
long curSize = file.getFileSize();
if ( quotaMgr != null) {
// Check if the file requires extending
long extendSize = 0L;
long endOfWrite = fileOffset + size;
if ( endOfWrite > curSize) {
// Calculate the amount the file must be extended
extendSize = endOfWrite - file.getFileSize();
// Allocate space for the file extend
quotaMgr.allocateSpace(sess, tree, file, extendSize);
}
}
// Write to the file
file.writeFile(buffer, size, bufferOffset, fileOffset);
// Check if the file size was reduced by the write, may have been extended previously
if ( quotaMgr != null) {
// Check if the file size reduced
if ( file.getFileSize() < curSize) {
// Release space that was freed by the write
quotaMgr.releaseSpace( sess, tree, file.getFileId(), file.getFullName(), curSize - file.getFileSize());
}
}
// Debug
if (logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILEIO))
logger.debug("Wrote bytes to file: network file=" + file + " buffer size=" + buffer.length + " size=" + size + " file offset=" + fileOffset);
return size;
}
/**
* Get the node for the specified path
*
* @param tree TreeConnection
* @param path String
* @return NodeRef
* @exception FileNotFoundException
*/
public NodeRef getNodeForPath(TreeConnection tree, String path)
throws FileNotFoundException
{
// Check if there is a cached state for the path
ContentContext ctx = (ContentContext) tree.getContext();
if ( ctx.hasStateCache())
{
// Try and get the node ref from an in memory file state
FileState fstate = ctx.getStateCache().findFileState(path);
if ( fstate != null && fstate.hasFilesystemObject() && fstate.exists() )
{
// Check that the node exists
if (fileFolderService.exists((NodeRef) fstate.getFilesystemObject()))
{
// Bump the file states expiry time
fstate.setExpiryTime(System.currentTimeMillis() + FileState.DefTimeout);
// Return the cached noderef
return (NodeRef) fstate.getFilesystemObject();
}
else
{
ctx.getStateCache().removeFileState(path);
}
}
}
// Search the repository for the node
return cifsHelper.getNodeRef(ctx.getRootNode(), path);
}
/**
* Convert a node into a share relative path
*
* @param tree TreeConnection
* @param nodeRef NodeRef
* @return String
* @exception FileNotFoundException
*/
public String getPathForNode( TreeConnection tree, NodeRef nodeRef)
throws FileNotFoundException
{
// Convert the target node to a path
ContentContext ctx = (ContentContext) tree.getContext();
List<org.alfresco.service.cmr.model.FileInfo> linkPaths = null;
try {
linkPaths = fileFolderService.getNamePath( ctx.getRootNode(), nodeRef);
}
catch ( org.alfresco.service.cmr.model.FileNotFoundException ex)
{
throw new FileNotFoundException();
}
// Build the share relative path to the node
StringBuilder pathStr = new StringBuilder();
for ( org.alfresco.service.cmr.model.FileInfo fInfo : linkPaths) {
pathStr.append( FileName.DOS_SEPERATOR);
pathStr.append( fInfo.getName());
}
// Return the share relative path
return pathStr.toString();
}
/**
* Get the file state for the specified path
*
* @param tree TreeConnection
* @param path String
* @return FileState
* @exception FileNotFoundException
*/
public FileState getStateForPath(TreeConnection tree, String path)
throws FileNotFoundException
{
// Check if there is a cached state for the path
ContentContext ctx = (ContentContext) tree.getContext();
FileState fstate = null;
if ( ctx.hasStateCache())
{
// Get the file state for a file/folder
fstate = ctx.getStateCache().findFileState(path);
}
// Return the file state
return fstate;
}
/**
* Connection opened to this disk device
*
* @param sess Server session
* @param tree Tree connection
*/
public void treeClosed(SrvSession sess, TreeConnection tree)
{
// Nothing to do
}
/**
* Connection closed to this device
*
* @param sess Server session
* @param tree Tree connection
*/
public void treeOpened(SrvSession sess, TreeConnection tree)
{
// Nothing to do
}
/**
* Return the lock manager used by this filesystem
*
* @param sess SrvSession
* @param tree TreeConnection
* @return LockManager
*/
public LockManager getLockManager(SrvSession sess, TreeConnection tree) {
return _lockManager;
}
/**
* Return the oplock manager implementation associated with this virtual filesystem
*
* @param sess SrvSession
* @param tree TreeConnection
* @return OpLockManager
*/
public OpLockManager getOpLockManager(SrvSession sess, TreeConnection tree) {
return _lockManager;
}
/**
* Enable/disable oplock support
*
* @param sess SrvSession
* @param tree TreeConnection
* @return boolean
*/
public boolean isOpLocksEnabled(SrvSession sess, TreeConnection tree) {
// Check if oplocks are enabled
ContentContext ctx = (ContentContext) tree.getContext();
return ctx.getDisableOplocks() ? false : true;
}
/**
* Copy content data from file to file
*
* @param sess SrvSession
* @param tree TreeConnection
* @param fromNode NodeRef
* @param toNode NodeRef
* @param newName String
*/
private void copyContentData( SrvSession sess, TreeConnection tree, NodeRef fromNode, NodeRef toNode, String newName)
{
ContentData content = (ContentData) nodeService.getProperty(fromNode, ContentModel.PROP_CONTENT);
if ( newName != null)
content = ContentData.setMimetype( content, mimetypeService.guessMimetype( newName));
nodeService.setProperty(toNode, ContentModel.PROP_CONTENT, content);
}
/**
* Clone/move aspects/properties between nodes
*
* @param newName String
* @param fromNode NodeRef
* @param toNode NodeRef
* @param ctx ContentContext
*/
private void cloneNodeAspects( String newName, NodeRef fromNode, NodeRef toNode, ContentContext ctx)
{
// We need to remove various aspects/properties from the original file, and move them to the new file
//
// Check for the lockable aspect
if ( nodeService.hasAspect( fromNode, ContentModel.ASPECT_LOCKABLE)) {
// Remove the lockable aspect from the old working copy, add it to the new file
nodeService.removeAspect( fromNode, ContentModel.ASPECT_LOCKABLE);
nodeService.addAspect( toNode, ContentModel.ASPECT_LOCKABLE, null);
// DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
logger.debug(" Moved aspect " + ContentModel.ASPECT_LOCKABLE + " to new document");
}
// Check for the working copy aspect
if ( nodeService.hasAspect( fromNode, ContentModel.ASPECT_WORKING_COPY)) {
// Add the working copy aspect to the new file
Map<QName, Serializable> workingCopyProperties = new HashMap<QName, Serializable>(1);
workingCopyProperties.put(ContentModel.PROP_WORKING_COPY_OWNER, nodeService.getProperty( fromNode, ContentModel.PROP_WORKING_COPY_OWNER));
nodeService.addAspect( toNode, ContentModel.ASPECT_WORKING_COPY, workingCopyProperties);
// Remove the working copy aspect from old working copy file
nodeService.removeAspect( fromNode, ContentModel.ASPECT_WORKING_COPY);
// DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
logger.debug(" Moved aspect " + ContentModel.ASPECT_WORKING_COPY + " to new document");
}
// Check for the copied from aspect
if ( nodeService.hasAspect( fromNode, ContentModel.ASPECT_COPIEDFROM)) {
// Add the copied from aspect to the new file
NodeRef copiedFromNode = (NodeRef) nodeService.getProperty( fromNode, ContentModel.PROP_COPY_REFERENCE);
Map<QName, Serializable> copiedFromProperties = new HashMap<QName, Serializable>(1);
copiedFromProperties.put(ContentModel.PROP_COPY_REFERENCE, copiedFromNode);
nodeService.addAspect( toNode, ContentModel.ASPECT_COPIEDFROM, copiedFromProperties);
// Remove the copied from aspect from old working copy file
nodeService.removeAspect( fromNode, ContentModel.ASPECT_COPIEDFROM);
// DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
logger.debug(" Moved aspect " + ContentModel.ASPECT_COPIEDFROM + " to new document");
// Check if the original node is locked
if ( lockService.getLockType( copiedFromNode) == null) {
// Add the lock back onto the original file
lockService.lock( copiedFromNode, LockType.READ_ONLY_LOCK);
// DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
logger.debug(" Re-locked copied from node " + copiedFromNode);
}
}
// Copy over all aspects from non-system namespaces (we will copy their properties later)
for (QName aspectName : nodeService.getAspects(fromNode))
{
if (!_excludedNamespaces.contains(aspectName.getNamespaceURI()))
{
nodeService.addAspect(toNode, aspectName, null);
}
}
// Copy over all other properties from non system namespaces
for ( Map.Entry<QName, Serializable> entry : nodeService.getProperties(fromNode).entrySet()) {
QName propName = entry.getKey();
if (!_excludedNamespaces.contains(propName.getNamespaceURI()))
{
nodeService.setProperty( toNode, propName, entry.getValue());
}
}
// Check if the new file name is a temporary file, remove any versionable aspect from it
String newNameNorm = newName.toLowerCase();
if ( newNameNorm.endsWith( ".tmp") || newNameNorm.endsWith( ".temp")) {
// Remove the versionable aspect
if ( nodeService.hasAspect( toNode, ContentModel.ASPECT_VERSIONABLE))
nodeService.removeAspect( toNode, ContentModel.ASPECT_VERSIONABLE);
// Add the temporary aspect, also prevents versioning
nodeService.addAspect( toNode, ContentModel.ASPECT_TEMPORARY, null);
// DEBUG
if ( logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_RENAME))
logger.debug(" Removed versionable aspect from temp file");
}
// Copy over various properties
for ( QName propName : _copyProperties) {
Serializable nodeProp = nodeService.getProperty( fromNode, propName);
if ( nodeProp != null)
nodeService.setProperty( toNode, propName, nodeProp);
}
}
private void cloneNode(String newName, NodeRef fromNode, NodeRef toNode, ContentContext ctx) {
cloneNodeAspects(newName, fromNode, toNode, ctx);
// copy over the node creator and owner properties
// need to disable the auditable aspect first to prevent default audit behaviour
boolean alreadyDisabled = policyBehaviourFilter.disableBehaviour(ContentModel.ASPECT_AUDITABLE);
try
{
nodeService.setProperty(toNode, ContentModel.PROP_CREATOR, nodeService.getProperty(fromNode, ContentModel.PROP_CREATOR));
nodeService.setProperty(toNode, ContentModel.PROP_OWNER, nodeService.getProperty(fromNode, ContentModel.PROP_OWNER));
}
finally
{
if(!alreadyDisabled)
{
policyBehaviourFilter.enableBehaviour(ContentModel.ASPECT_AUDITABLE);
}
}
Set<AccessPermission> permissions = permissionService.getAllSetPermissions(fromNode);
permissionService.deletePermissions(fromNode);
for(AccessPermission permission : permissions)
{
permissionService.setPermission(toNode, permission.getAuthority(), permission.getPermission(), (permission.getAccessStatus() == AccessStatus.ALLOWED));
}
}
/**
* Return the file state status as a string
*
* @param sts int
* @return String
*/
private final String fileStatusString( int sts) {
String fstatus = "Unknown";
switch ( sts) {
case FileUnknown:
fstatus = "Unknown";
break;
case FileNotExist:
fstatus = "NotExist";
break;
case FileExists:
fstatus = "FileExists";
break;
case DirectoryExists:
fstatus = "DirectoryExists";
break;
case FileRenamed:
fstatus = "FileRenamed";
break;
case DeleteOnClose:
fstatus = "DeleteOnClose";
break;
}
return fstatus;
}
/**
* Get the disk information for this shared disk device.
*
* @param ctx DiskDeviceContext
* @param diskDev SrvDiskInfo
* @exception IOException
*/
public void getDiskInformation(DiskDeviceContext ctx, SrvDiskInfo diskDev)
throws IOException {
// Set the block size and blocks per allocation unit
diskDev.setBlockSize( DiskBlockSize);
diskDev.setBlocksPerAllocationUnit( DiskBlocksPerUnit);
// Get the free and total disk size in bytes from the content store
long freeSpace = contentService.getStoreFreeSpace();
long totalSpace= contentService.getStoreTotalSpace();
if ( totalSpace == -1L) {
// Use a fixed value for the total space, content store does not support size information
totalSpace = DiskSizeDefault;
freeSpace = DiskFreeDefault;
}
// Convert the total/free space values to allocation units
diskDev.setTotalUnits( totalSpace / DiskAllocationUnit);
diskDev.setFreeUnits( freeSpace / DiskAllocationUnit);
}
}