From 088e02a9ad80945ea0d540e68e1d142abf14a60e Mon Sep 17 00:00:00 2001 From: Dave Ward Date: Thu, 11 Aug 2011 18:54:03 +0000 Subject: [PATCH] Merged V3.4-BUG-FIX to HEAD 29484: Merged V3.4 to V3.4-BUG-FIX 29426: ALF-9588: Merged PATCHES/V3.4.2 to V3.4 29402: ALF-9637: Enable Share Advanced Search on properties containing a '-' in the prefix 29469: ALF-8341: Merged missing fragment from ALF-6598 29476: ALF-3061 Need to disable major/minor version radio buttons after [Upload File(s)] 29483: ALF-9407: Escape quote characters in parameterized strings 29488: Build Fix and correct fix for ALF-9632 "CMIS query fails if model name contains numbers" fix - Ensure CMIS query types are ISO9075 encoded - the user has to type them in encoded if encoding is required - the encoded look up name was in fact incorrect - not the lookup 29561: Merge DEV/BELARUS/V3.4-BUG-FIX-2011_07_13 V3.4-BUG-FIX 29422: ALF-7195 Add DisableAuditingInterceptor to NodeService and LockService. 29572: ALF-9601 - Simultaneous deployment of the same web project to two file system targets on the same engine can cause some missing files in one of the targets. 29578: Merged DEV/TEMPORARY to V3.4-BUG-FIX 29334: ALF-7390 : Alfresco ftp server never binds to a single ip address Added default configuration for bindTo property for FTP server. 29587: Merged V3.4 to V3.4-BUG-FIX 29495: Merged DEV/TEMPORARY to V3.4 29494: ALF-7701: Untranslated strings when Quickr module is installed: Task details page Global workflow messages were removed 29502: ALF-8929: Merged DEV/TEMPORARY to V3.4 29499: Rename dictionaryModelBootstrap beans for QuickR model and example model. 29504: ALF-5895: Profile CSS tweaks for other languages (Kev reviewed) 29519: Merged DEV/TEMPORARY to V3.4 (Reviewed by Kev) 29510: ALF-9419: Share - Filename changes in "Upload new version" (with italian language set) Upload WebScript was modified for support locale as a request parameter. 29518: ALF-9419: Share - Filename changes in "Upload new version" (with italian language set) ScriptUtils used for locale change. 29520: ALF-9717: Possible workaround to PolicyTest taking so long to run - Set sun.net.client.defaultConnectTimeout and sun.net.client.defaultReadTimeout System properties so that hanging request for a DTD times out quickly 29596: Merged DEV/TEMPORARY to V3.4-BUG-FIX 29595: ALF-5046: DeclarativeWebScriptRegistry causes blow-out when loading system without content 1. In org.alfresco.repo.web.scripts.RepoStore class added isContentPresent(NodeRef nodeRef) method. 2. In org.alfresco.repo.web.scripts.RepoStore#getScriptDocumentPaths added check isContentPresent(nodeRef). 3. In org.alfresco.repo.web.scripts.RepoStore#getDocumentPaths added check isContentPresent(nodeRef). 4. In org.alfresco.repo.web.scripts.RepoStore#getAllDocumentPaths added check isContentPresent(nodeRef). 29634: ALF-371 Alfresco Explorer: A change of a user's home folder now creates a new folder if it does not exist. If a home folder is shared, other users no longer find their home folder moving. However the content of the home folder must be manually moved. 29637: ALF-9847 High level audit does not include initial node properties or changed path if node moved 29685: Merged PATCHES/V3.4.1 to V3.4-BUG-FIX 29682: ALF-9777: Merged V3.4-BUG-FIX to PATCHES/V3.4.1 28188: Fix for ALF-731 - in a cluster environment (high availibility), when a node goes down, the users are asked to login 29684: ALF-9777: Correction 29686: ALF-2372 Revert action does not restore changes to document metadata Now uses VersionService.revert(...) 29697: ALF-9886: Missing space in apostrophe-laden Italian translation - The world is safe once more 29698: Merged V3.4 to V3.4-BUG-FIX 29672: Merged PATCHES/V3.4.1 to V3.4 29441: ALF-9876 / ALF-9579: Share external authentication fixes 1. Share SSO filter makes touch requests in the name of the external user ID (remoteUser) for unauthenticated users 2. Include WebScriptSSOAuthenticationFilter in external-filter-context.xml to allow cookie-based manual login failover (A Spring Surf patch is required to support this) 3. On the repository tier, web client authentication will send a 401 response for an invalid remote user (with redirect to login page in HTML markup) so that Share SSO authenticator detects this as an authentication failure and redirects to the login page, thus allowing manual login failover. 29454: ALF-9876 / ALF-9579: Share external authentication fixes 4. Spring Surf / Spring webscripts jars (from Kevin Roast) 29563: ALF-8607 / ALF-9596: Guarantee read consistency in AbstractNodeDAOImpl.getNodeRefStatus - Partly achieved by making EntityLookupCache.removeByKey() unconditionally cache removes 29673: ALF-9530: Reverse merged V3.4-BUG-FIX revisions 29124 and 29109 - Postgres service will continue to run as SYSTEM user on Windows. See bug for more details. 29674: ALF-7993: Reversed changes to bitrock files made during removal of 32 bit linux support from the build, as requested by Bitrock (V3.4-BUG-FIX revision 26582) git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@29700 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../example-model-context.xml.sample | 2 +- config/alfresco/public-services-context.xml | 34 +++++ .../default/file-servers-context.xml | 4 + .../default/file-servers.properties | 2 + .../CMISAbstractDictionaryService.java | 5 +- .../DisableAuditableBehaviourInterceptor.java | 118 ++++++++++++++++++ .../repo/audit/access/NodeChange.java | 32 +++-- .../repo/audit/access/NodeInfoFactory.java | 8 ++ .../repo/cache/lookup/EntityLookupCache.java | 10 +- .../repo/domain/node/AbstractNodeDAOImpl.java | 7 +- .../org/alfresco/repo/jscript/ScriptNode.java | 60 +++++++++ .../alfresco/repo/jscript/ScriptUtils.java | 17 +++ 12 files changed, 276 insertions(+), 23 deletions(-) create mode 100644 source/java/org/alfresco/repo/audit/DisableAuditableBehaviourInterceptor.java diff --git a/config/alfresco/extension/example-model-context.xml.sample b/config/alfresco/extension/example-model-context.xml.sample index 1767ad5aa9..293ddb4955 100644 --- a/config/alfresco/extension/example-model-context.xml.sample +++ b/config/alfresco/extension/example-model-context.xml.sample @@ -4,7 +4,7 @@ - + alfresco/extension/exampleModel.xml diff --git a/config/alfresco/public-services-context.xml b/config/alfresco/public-services-context.xml index abdd9130b6..d233b8c133 100644 --- a/config/alfresco/public-services-context.xml +++ b/config/alfresco/public-services-context.xml @@ -80,6 +80,8 @@ + + diff --git a/config/alfresco/subsystems/fileServers/default/file-servers.properties b/config/alfresco/subsystems/fileServers/default/file-servers.properties index 11bfea97db..7671c88936 100644 --- a/config/alfresco/subsystems/fileServers/default/file-servers.properties +++ b/config/alfresco/subsystems/fileServers/default/file-servers.properties @@ -52,6 +52,8 @@ cifs.sessionDebug= ### FTP Server Configuration ### ftp.enabled=true ftp.port=21 +# An empty value indicates bind to all available network adapters +ftp.bindto= # FTP data port range, a value of 0:0 disables the data port range and will use the next available port # Valid range is 1024-65535 diff --git a/source/java/org/alfresco/cmis/dictionary/CMISAbstractDictionaryService.java b/source/java/org/alfresco/cmis/dictionary/CMISAbstractDictionaryService.java index 2ad92f8b8e..ffa76add95 100644 --- a/source/java/org/alfresco/cmis/dictionary/CMISAbstractDictionaryService.java +++ b/source/java/org/alfresco/cmis/dictionary/CMISAbstractDictionaryService.java @@ -41,7 +41,6 @@ import org.alfresco.repo.dictionary.DictionaryListener; import org.alfresco.repo.tenant.TenantService; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.namespace.QName; -import org.alfresco.util.ISO9075; import org.springframework.extensions.surf.util.AbstractLifecycleBean; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -302,7 +301,7 @@ public abstract class CMISAbstractDictionaryService extends AbstractLifecycleBea */ public CMISTypeDefinition findTypeByQueryName(String queryName) { - CMISTypeDefinition typeDef = getRegistry().typeDefsByQueryName.get(ISO9075.encodeSQL(queryName.toLowerCase())); + CMISTypeDefinition typeDef = getRegistry().typeDefsByQueryName.get(queryName.toLowerCase()); return typeDef; } @@ -312,7 +311,7 @@ public abstract class CMISAbstractDictionaryService extends AbstractLifecycleBea */ public CMISPropertyDefinition findPropertyByQueryName(String queryName) { - CMISPropertyDefinition propertyDef = getRegistry().propDefsByQueryName.get(ISO9075.encodeSQL(queryName.toLowerCase())); + CMISPropertyDefinition propertyDef = getRegistry().propDefsByQueryName.get(queryName.toLowerCase()); return propertyDef; } diff --git a/source/java/org/alfresco/repo/audit/DisableAuditableBehaviourInterceptor.java b/source/java/org/alfresco/repo/audit/DisableAuditableBehaviourInterceptor.java new file mode 100644 index 0000000000..84029b98d7 --- /dev/null +++ b/source/java/org/alfresco/repo/audit/DisableAuditableBehaviourInterceptor.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2005-2011 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 . + */ +package org.alfresco.repo.audit; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.policy.BehaviourFilter; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.QName; +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; + +/** + * An interceptor that disables and then enables ASPECT_AUDITABLE behaviours + * around method calls. + * + *
  • The name of the method must match a supplied list (See + * {@link #setMethodNames(List)}).
  • + *
  • For this interceptor to disable and enable policy behaviour, the first + * argument to the method must be a NodeRef or a Collection of NodeRefs. + * The behaviour is disabled on each NodeRef.
  • + *
  • The second argument to the method must optionally match a supplied list of + * values (See {@link #setArgumentValues(List)}. The second argument must be + * a QName. If a list is not supplied the second argument is not checked.
  • + *
  • The BehaviourFilter to be enabled or disabled must be set (See + * {@link #setBehaviourFilter(BehaviourFilter)}). + * + * @author Stas Sokolovsky + */ +public class DisableAuditableBehaviourInterceptor implements MethodInterceptor +{ + private BehaviourFilter behaviourFilter; + private List methodNames; + private List argumentValues; + + public Object invoke(MethodInvocation methodInvocation) throws Throwable + { + String methodName = methodInvocation.getMethod().getName(); + + Object[] args = methodInvocation.getArguments(); + ArrayList nodes = new ArrayList(); + if (args.length > 0) + { + if (args[0] instanceof NodeRef) + { + nodes.add((NodeRef) args[0]); + } + else if (args[0] instanceof Collection) + { + nodes.addAll((Collection) args[0]); + } + } + QName arg1 = null; + if (args.length > 1 && args[1] instanceof QName) + { + arg1 = (QName) args[1]; + } + + if (behaviourFilter != null && + methodNames.contains(methodName) && + (arg1 == null || argumentValues.contains(arg1.toString()))) + { + for (NodeRef nodeRef : nodes) + { + behaviourFilter.disableBehaviour(nodeRef, ContentModel.ASPECT_AUDITABLE); + } + try + { + return methodInvocation.proceed(); + } + finally + { + for (NodeRef nodeRef : nodes) + { + behaviourFilter.enableBehaviour(nodeRef, ContentModel.ASPECT_AUDITABLE); + } + } + } + else + { + return methodInvocation.proceed(); + } + } + + public void setBehaviourFilter(BehaviourFilter behaviourFilter) + { + this.behaviourFilter = behaviourFilter; + } + + public void setMethodNames(List methodNames) + { + this.methodNames = methodNames; + } + + public void setArgumentValues(List argumentValues) + { + this.argumentValues = argumentValues; + } +} diff --git a/source/java/org/alfresco/repo/audit/access/NodeChange.java b/source/java/org/alfresco/repo/audit/access/NodeChange.java index bf33988c69..7a7731edec 100644 --- a/source/java/org/alfresco/repo/audit/access/NodeChange.java +++ b/source/java/org/alfresco/repo/audit/access/NodeChange.java @@ -22,6 +22,7 @@ import static org.alfresco.repo.audit.model.AuditApplication.AUDIT_PATH_SEPARATO import java.io.Serializable; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; @@ -111,7 +112,7 @@ import org.alfresco.service.namespace.QName; private final NodeInfoFactory nodeInfoFactory; private final NamespaceService namespaceService; - private final NodeInfo nodeInfo; + private NodeInfo nodeInfo; private String action; @@ -122,7 +123,6 @@ import org.alfresco.service.namespace.QName; private NodeInfo copyFrom; private NodeInfo moveFrom; - private NodeInfo moveTo; private Map fromProperties; private Map toProperties; @@ -248,21 +248,20 @@ import org.alfresco.service.namespace.QName; private NodeChange setMoveFrom(ChildAssociationRef childAssocRef) { // Don't overwrite original value if multiple calls. - if (this.moveFrom == null) + if (moveFrom == null) { - this.moveFrom = nodeInfoFactory.newNodeInfo(childAssocRef); + moveFrom = nodeInfoFactory.newNodeInfo(childAssocRef); } return this; } private NodeChange setMoveTo(ChildAssociationRef childAssocRef) { - this.moveTo = nodeInfoFactory.newNodeInfo(childAssocRef); + nodeInfo = nodeInfoFactory.newNodeInfo(childAssocRef); // Clear values if we are back to where we started. - if (this.moveTo.equals(moveFrom)) + if (nodeInfo.equals(moveFrom)) { - this.moveTo = null; moveFrom = null; } return this; @@ -359,8 +358,17 @@ import org.alfresco.service.namespace.QName; @Override public void onCreateNode(ChildAssociationRef childAssocRef) { - appendSubAction(new NodeChange(nodeInfoFactory, namespaceService, childAssocRef.getChildRef()). - setAction(CREATE_NODE)); + NodeRef nodeRef = childAssocRef.getChildRef(); + Map fromProperties = Collections.emptyMap(); + Map toProperties = nodeInfoFactory.getProperties(nodeRef); + this.fromProperties = null; // Sometimes onCreateNode policy is out of order (e.g. create a person) + setFromProperties(fromProperties); + setToProperties(toProperties); + + appendSubAction(new NodeChange(nodeInfoFactory, namespaceService, nodeRef). + setAction(CREATE_NODE). + setFromProperties(fromProperties). + setToProperties(toProperties)); } @Override @@ -381,6 +389,12 @@ import org.alfresco.service.namespace.QName; public void onUpdateProperties(NodeRef nodeRef, Map fromProperties, Map toProperties) { + // Sometime we don't get the fromProperties, so just use the latest we have + if (fromProperties.isEmpty() && this.toProperties != null) + { + fromProperties = this.toProperties; + } + setFromProperties(fromProperties); setToProperties(toProperties); diff --git a/source/java/org/alfresco/repo/audit/access/NodeInfoFactory.java b/source/java/org/alfresco/repo/audit/access/NodeInfoFactory.java index 348507e149..710a9b7da5 100644 --- a/source/java/org/alfresco/repo/audit/access/NodeInfoFactory.java +++ b/source/java/org/alfresco/repo/audit/access/NodeInfoFactory.java @@ -18,6 +18,9 @@ */ package org.alfresco.repo.audit.access; +import java.io.Serializable; +import java.util.Map; + import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.InvalidNodeRefException; import org.alfresco.service.cmr.repository.NodeRef; @@ -118,4 +121,9 @@ public class NodeInfoFactory return type; } + + public Map getProperties(NodeRef nodeRef) + { + return nodeService.getProperties(nodeRef); + } } diff --git a/source/java/org/alfresco/repo/cache/lookup/EntityLookupCache.java b/source/java/org/alfresco/repo/cache/lookup/EntityLookupCache.java index 47604a8671..e0ac8660cd 100644 --- a/source/java/org/alfresco/repo/cache/lookup/EntityLookupCache.java +++ b/source/java/org/alfresco/repo/cache/lookup/EntityLookupCache.java @@ -698,18 +698,12 @@ public class EntityLookupCache pair = nodesCache.getByValue(new NodeEntity(nodeRef)); + Node nodeEntity = new NodeEntity(nodeRef); + // Explicitly remove this noderef from the cache, forcing a 'repeatable read' on this noderef from now on. + nodesCache.removeByValue(nodeEntity); + Pair pair = nodesCache.getByValue(nodeEntity); if (pair == null) { // It's not there, so select ignoring the 'deleted' flag diff --git a/source/java/org/alfresco/repo/jscript/ScriptNode.java b/source/java/org/alfresco/repo/jscript/ScriptNode.java index bfca19cc60..ecb7d4bbd4 100644 --- a/source/java/org/alfresco/repo/jscript/ScriptNode.java +++ b/source/java/org/alfresco/repo/jscript/ScriptNode.java @@ -82,6 +82,7 @@ import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.thumbnail.ThumbnailService; import org.alfresco.service.cmr.version.Version; import org.alfresco.service.cmr.version.VersionHistory; +import org.alfresco.service.cmr.version.VersionServiceException; import org.alfresco.service.cmr.version.VersionType; import org.alfresco.service.cmr.workflow.WorkflowInstance; import org.alfresco.service.cmr.workflow.WorkflowService; @@ -1902,6 +1903,65 @@ public class ScriptNode implements Serializable, Scopeable, NamespacePrefixResol return copy; } + /** + * Revert this Node to the specified version. Note this is not a deep revert of + * associations. + * This node must have the cm:versionable aspect. It will be checked out if required + * but will be checked in after the call. + * + * @param versionLabel to revert from + * + * @return the original Node that was checked out if reverted, {@code null} otherwise + * (if the version does not exist). + */ + public ScriptNode revert(String history, boolean majorVersion, String versionLabel) + { + return revert(history, majorVersion, versionLabel, false); + } + + /** + * Revert this Node to the specified version and potentially all child nodes. + * This node must have the cm:versionable aspect. It will be checked out if required + * but will be checked in after the call. + * + * @param history Version history note + * @param majorVersion True to save as a major version increment, false for minor version. + * @param versionLabel to revert from + * @param deep {@code true} for a deep revert, {@code false} otherwise. + * + * @return the original Node that was checked out if reverted, {@code null} otherwise + * (if the version does not exist). + */ + public ScriptNode revert(String history, boolean majorVersion, String versionLabel, boolean deep) + { + if (!getIsVersioned()) + { + return null; + } + + // Get the Version - needed to do the revert + Version version = services.getVersionService().getVersionHistory(nodeRef).getVersion(versionLabel); + if (version == null) + { + return null; + } + + // Checkout the node if required + ScriptNode workingCopy = this; + if (!nodeService.hasAspect(nodeRef, ContentModel.ASPECT_WORKING_COPY)) + { + workingCopy = checkout(); + } + + // Checkin the node - to get the new version + workingCopy = workingCopy.checkin(history, majorVersion); + + // Revert the new (current) version of the node + services.getVersionService().revert(workingCopy.nodeRef, version, deep); + + return workingCopy; + } + /** * Move this Node to a new parent destination. * diff --git a/source/java/org/alfresco/repo/jscript/ScriptUtils.java b/source/java/org/alfresco/repo/jscript/ScriptUtils.java index 89c46a9b44..569beeef34 100644 --- a/source/java/org/alfresco/repo/jscript/ScriptUtils.java +++ b/source/java/org/alfresco/repo/jscript/ScriptUtils.java @@ -19,6 +19,7 @@ package org.alfresco.repo.jscript; import java.util.Date; +import java.util.Locale; import java.util.Map; import org.alfresco.service.ServiceRegistry; @@ -277,4 +278,20 @@ public final class ScriptUtils extends BaseScopableProcessorExtension { services.getRuleService().enableRules(); } + + /** + * Sets current Locale from string + */ + public void setLocale(String language) + { + I18NUtil.setLocale(new Locale(language)); + } + + /** + * Returns current thread's locale + */ + public String getLocale() + { + return I18NUtil.getLocale().toString(); + } }