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(); + } }