diff --git a/config/alfresco/extension/custom-repository.properties.sample b/config/alfresco/extension/custom-repository.properties.sample
index 245f573ca6..da3334e256 100644
--- a/config/alfresco/extension/custom-repository.properties.sample
+++ b/config/alfresco/extension/custom-repository.properties.sample
@@ -52,3 +52,21 @@
#
#db.driver=org.postgresql.Driver
#db.url=jdbc:postgresql://localhost:5432/alfresco
+
+# The well known RMI registry port is defined in the alfresco-shared.properties file
+# alfresco.rmi.services.port=50500
+#
+# RMI service ports for the individual services.
+# These six services are available remotely.
+#
+# Assign individual ports for each service for best performance
+# or run several services on the same port. You can even run everything on 50500 if needed.
+#
+# Select 0 to use a random unused port.
+#
+#avm.rmi.service.port=50501
+#avmsync.rmi.service.port=50502
+#attribute.rmi.service.port=50503
+#authentication.rmi.service.port=50504
+#repo.rmi.service.port=50505
+#action.rmi.service.port=50506
diff --git a/config/alfresco/messages/patch-service.properties b/config/alfresco/messages/patch-service.properties
index 3523dbb3e3..c2aac5aec5 100644
--- a/config/alfresco/messages/patch-service.properties
+++ b/config/alfresco/messages/patch-service.properties
@@ -1,4 +1,5 @@
# PatchService messages
+patch.service.preceeded_by_alternative=Preceeded by alternative patch ''{0}''.
patch.service.not_relevant=Not relevant to schema {0}
patch.executer.checking=Checking for patches to apply ...
patch.service.applying_patch=\tApplying patch ''{0}'' ({1}).
@@ -19,6 +20,9 @@ patch.general.property_not_set=Patch property ''{0}'' has not been set on this p
# Individual patch messages
+patch.noOpPatch.description=A placeholder patch; usually marks a superceded patch.
+patch.noOpPatch.result=No-op patch
+
patch.marker.description=Marker patch to record installations and upgrades
patch.marker.result=Marker patch applied
diff --git a/config/alfresco/remote-services-context.xml b/config/alfresco/remote-services-context.xml
index 988a22a68d..588859bf88 100644
--- a/config/alfresco/remote-services-context.xml
+++ b/config/alfresco/remote-services-context.xml
@@ -3,6 +3,8 @@
"http://www.springframework.org/dtd/spring-beans.dtd">
+
+
@@ -31,6 +33,9 @@
${alfresco.rmi.services.port}
+
+ ${avm.rmi.service.port}
+
@@ -55,6 +60,9 @@
${alfresco.rmi.services.port}
+
+ ${avmsync.rmi.service.port}
+
@@ -80,6 +88,9 @@
${alfresco.rmi.services.port}
+
+ ${attribute.rmi.service.port}
+
@@ -96,6 +107,9 @@
${alfresco.rmi.services.port}
+
+ ${authentication.rmi.service.port}
+
@@ -189,5 +206,8 @@
${alfresco.rmi.services.port}
+
+ ${action.rmi.service.port}
+
\ No newline at end of file
diff --git a/config/alfresco/repository.properties b/config/alfresco/repository.properties
index 98deab4120..98ebc23355 100644
--- a/config/alfresco/repository.properties
+++ b/config/alfresco/repository.properties
@@ -231,4 +231,23 @@ avm.remote.idlestream.timeout=30000
system.usages.enabled=true
# Repository endpoint - used by Activity Service
-repo.remote.endpoint.url=http://localhost:8080/alfresco/service
\ No newline at end of file
+repo.remote.endpoint.url=http://localhost:8080/alfresco/service
+
+# The well known RMI registry port is defined in the alfresco-shared.properties file
+# alfresco.rmi.services.port=50500
+#
+# RMI service ports for the individual services.
+# These six services are available remotely.
+#
+# Assign individual ports for each service for best performance
+# or run several services on the same port, you can even run everything on 50500 if
+# running through a firewall.
+#
+# Specify 0 to use a random unused port.
+#
+avm.rmi.service.port=50501
+avmsync.rmi.service.port=50502
+attribute.rmi.service.port=50503
+authentication.rmi.service.port=50504
+repo.rmi.service.port=50505
+action.rmi.service.port=50506
diff --git a/source/java/org/alfresco/filesys/avm/AVMContext.java b/source/java/org/alfresco/filesys/avm/AVMContext.java
index 9f8f79061f..5a10cff2cf 100644
--- a/source/java/org/alfresco/filesys/avm/AVMContext.java
+++ b/source/java/org/alfresco/filesys/avm/AVMContext.java
@@ -31,6 +31,7 @@ import org.alfresco.jlan.server.filesys.DiskInterface;
import org.alfresco.jlan.server.filesys.FileName;
import org.alfresco.jlan.server.filesys.FileSystem;
import org.alfresco.jlan.server.filesys.NotifyChange;
+import org.alfresco.jlan.util.StringList;
import org.alfresco.repo.avm.CreateStoreCallback;
import org.alfresco.repo.avm.CreateVersionCallback;
import org.alfresco.repo.avm.PurgeStoreCallback;
@@ -86,6 +87,11 @@ public class AVMContext extends AlfrescoContext
private int m_showOptions;
+ // List of newly created store names that need adding into the virtualization view
+
+ private StringList m_newStores;
+ private Object m_newStoresLock;
+
/**
* Class constructor
*
@@ -127,6 +133,9 @@ public class AVMContext extends AlfrescoContext
m_virtualView = true;
m_showOptions = showOptions;
+
+ m_newStoresLock = new Object();
+ m_newStores = new StringList();
// Save the associated filesystem driver
@@ -172,6 +181,34 @@ public class AVMContext extends AlfrescoContext
{
return m_virtualView;
}
+
+ /**
+ * Check if there are any new stores queued for adding to the virtualization view
+ *
+ * @return boolean
+ */
+ protected final boolean hasNewStoresQueued() {
+ if ( m_newStores == null || m_newStores.numberOfStrings() == 0)
+ return false;
+ return true;
+ }
+
+ /**
+ * Return the new stores queue, and reset the current queue
+ *
+ * @return StringList
+ */
+ protected StringList getNewStoresQueue() {
+
+ StringList storesQueue = null;
+
+ synchronized ( m_newStoresLock) {
+ storesQueue = m_newStores;
+ m_newStores = new StringList();
+ }
+
+ return storesQueue;
+ }
/**
* Check if normal stores should be shown in the virtualization view
@@ -285,6 +322,11 @@ public class AVMContext extends AlfrescoContext
*/
public void storeCreated(String storeName)
{
+ // Not interested if the virtualization view is not enabled
+
+ if ( isVirtualizationView() == false)
+ return;
+
// Make sure the file state cache is enabled
FileStateTable fsTable = getStateTable();
@@ -297,10 +339,20 @@ public class AVMContext extends AlfrescoContext
if ( rootState != null)
{
- // Delete the root folder file state and recreate it
+ // DEBUG
- fsTable.removeFileState( FileName.DOS_SEPERATOR_STR);
-// m_avmDriver.findPseudoState( new AVMPath( ""), this);
+ if ( logger.isDebugEnabled())
+ logger.debug("Queueing new store " + storeName + " for addition to virtualization view");
+
+ // Add the new store name to the list to be picked up by the next file server access
+ // to the filesystem
+
+ synchronized ( m_newStoresLock) {
+
+ // Add the new store name
+
+ m_newStores.addString( storeName);
+ }
}
}
@@ -311,6 +363,11 @@ public class AVMContext extends AlfrescoContext
*/
public void storePurged(String storeName)
{
+ // Not interested if the virtualization view is not enabled
+
+ if ( isVirtualizationView() == false)
+ return;
+
// Make sure the file state cache is enabled
FileStateTable fsTable = getStateTable();
@@ -367,6 +424,11 @@ public class AVMContext extends AlfrescoContext
*/
public void versionCreated(String storeName, int versionID)
{
+ // Not interested if the virtualization view is not enabled
+
+ if ( isVirtualizationView() == false)
+ return;
+
// Make sure the file state cache is enabled
FileStateTable fsTable = getStateTable();
@@ -432,6 +494,11 @@ public class AVMContext extends AlfrescoContext
*/
public void versionPurged(String storeName, int versionID)
{
+ // Not interested if the virtualization view is not enabled
+
+ if ( isVirtualizationView() == false)
+ return;
+
// Make sure the file state cache is enabled
FileStateTable fsTable = getStateTable();
diff --git a/source/java/org/alfresco/filesys/avm/AVMDiskDriver.java b/source/java/org/alfresco/filesys/avm/AVMDiskDriver.java
index 539fced503..076033940e 100644
--- a/source/java/org/alfresco/filesys/avm/AVMDiskDriver.java
+++ b/source/java/org/alfresco/filesys/avm/AVMDiskDriver.java
@@ -2218,6 +2218,32 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface
if ( avmPath.isPseudoPath() == false)
return null;
+ // Check if there are any new stores to be added to the virtualization view
+
+ if ( avmCtx.hasNewStoresQueued()) {
+
+ // Get the new stores list, there is a chance another thread might get the queue, if the queue is empty
+ // another thread is processing it
+
+ StringList storeNames = avmCtx.getNewStoresQueue();
+
+ while ( storeNames.numberOfStrings() > 0) {
+
+ // Get the current store name
+
+ String curStoreName = storeNames.removeStringAt( 0);
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug("Adding new store " + curStoreName);
+
+ // Add the current store to the virtualization view
+
+ addNewStore( avmCtx, curStoreName);
+ }
+ }
+
// Check if the path is to a store pseudo folder
FileState fstate = null;
@@ -2890,21 +2916,27 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface
// Get the web project that the sandbox is linked to
WebProjectStorePseudoFile webFolder = (WebProjectStorePseudoFile) fullList.findFile( storeFolder.getWebProject(), false);
- int role = webFolder.getUserRole( cInfo.getUserName());
- if ( role == WebProjectStorePseudoFile.RoleContentManager && avmCtx.showStoreType( storeFolder.isStoreType()))
- {
- // User is a content manager, allow access to the store
-
- filterList.addFile( storeFolder);
- }
- else if ( role == WebProjectStorePseudoFile.RolePublisher && avmCtx.showStoreType( storeFolder.isStoreType()))
- {
- // Allow access if the user owns the current folder
+ if ( webFolder != null) {
+ int role = webFolder.getUserRole( cInfo.getUserName());
- if ( storeFolder.getUserName().equalsIgnoreCase( cInfo.getUserName()))
- filterList.addFile( storeFolder);
+ if ( role == WebProjectStorePseudoFile.RoleContentManager && avmCtx.showStoreType( storeFolder.isStoreType()))
+ {
+ // User is a content manager, allow access to the store
+
+ filterList.addFile( storeFolder);
+ }
+ else if ( role == WebProjectStorePseudoFile.RolePublisher && avmCtx.showStoreType( storeFolder.isStoreType()))
+ {
+ // Allow access if the user owns the current folder
+
+ if ( storeFolder.getUserName().equalsIgnoreCase( cInfo.getUserName()))
+ filterList.addFile( storeFolder);
+ }
}
+ else if ( logger.isDebugEnabled())
+ logger.debug("Cannot find associated web folder for store " + storeFolder.getFileName());
+
}
else if ( avmCtx.showNormalStores() || avmCtx.showSiteStores())
{
@@ -2920,4 +2952,190 @@ public class AVMDiskDriver extends AlfrescoDiskDriver implements DiskInterface
return filterList;
}
+
+ /**
+ * Add a new store to the top level folder list
+ *
+ * @param avmCtx AVMContext
+ * @param storeName String
+ */
+ protected void addNewStore( AVMContext avmCtx, String storeName) {
+
+ // Get the root folder file state
+
+ FileState fstate = avmCtx.getStateTable().findFileState( FileName.DOS_SEPERATOR_STR, true, false);
+ if ( fstate == null)
+ return;
+
+ // Get the properties for the store
+
+ AVMStoreDescriptor storeDesc = m_avmService.getStore( storeName);
+ if ( storeDesc == null)
+ return;
+
+ Map props = m_avmService.getStoreProperties( storeName);
+
+ // Check if the store is a main web project
+
+ if ( props.containsKey( SandboxConstants.PROP_SANDBOX_STAGING_MAIN))
+ {
+ // Get the noderef for the web project
+
+ PropertyValue prop = props.get( SandboxConstants.PROP_WEB_PROJECT_NODE_REF);
+ if ( prop != null) {
+
+ // Get the web project noderef
+
+ NodeRef webNodeRef = new NodeRef( prop.getStringValue());
+
+ // Create the web project pseudo folder
+
+ WebProjectStorePseudoFile webProjFolder = new WebProjectStorePseudoFile( storeDesc, FileName.DOS_SEPERATOR_STR + storeName, webNodeRef);
+ fstate.addPseudoFile( webProjFolder);
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug( " Found web project " + webProjFolder.getFileName());
+
+ // Get the list of content managers for this web project
+
+ List mgrAssocs = m_nodeService.getChildAssocs( webNodeRef, WCMAppModel.ASSOC_WEBUSER, RegexQNamePattern.MATCH_ALL);
+
+ for ( ChildAssociationRef mgrRef : mgrAssocs)
+ {
+ // Get the child node and see if it is a content manager association
+
+ NodeRef childRef = mgrRef.getChildRef();
+
+ if ( m_nodeService.getProperty( childRef, WCMAppModel.PROP_WEBUSERROLE).equals(ROLE_CONTENT_MANAGER))
+ {
+ // Get the user name add it to the web project pseudo folder
+
+ String userName = (String) m_nodeService.getProperty( childRef, WCMAppModel.PROP_WEBUSERNAME);
+
+ webProjFolder.addUserRole( userName, WebProjectStorePseudoFile.RoleContentManager);
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug(" Added content manager " + userName);
+ }
+ }
+ }
+ }
+ else
+ {
+ // Check if this store is a web project sandbox
+
+ int storeType = StoreType.Normal;
+ String webProjName = null;
+ String userName = null;
+
+ if ( props.containsKey( SandboxConstants.PROP_SANDBOX_AUTHOR_MAIN))
+ {
+ // Sandbox store, linked to a web project
+
+ storeType = StoreType.WebAuthorMain;
+
+ // Get the associated web project name
+
+ webProjName = props.get( SandboxConstants.PROP_WEBSITE_NAME).getStringValue();
+
+ // Get the user name from teh store name
+
+ userName = storeName.substring( webProjName.length() + 2);
+ }
+ else if ( props.containsKey( SandboxConstants.PROP_SANDBOX_AUTHOR_PREVIEW))
+ {
+ // Author preview sandbox store, linked to a web project
+
+ storeType = StoreType.WebAuthorPreview;
+
+ // Get the associated web project name
+
+ String projPlusUser = storeName.substring( 0, storeName.length() - "--preview".length());
+ int pos = projPlusUser.lastIndexOf("--");
+ if ( pos != -1)
+ {
+ webProjName = projPlusUser.substring( 0, pos);
+ userName = projPlusUser.substring(pos + 2);
+ }
+ }
+ else if ( props.containsKey( SandboxConstants.PROP_SANDBOX_WORKFLOW_PREVIEW))
+ {
+ // Staging preview sandbox store, linked to a web project
+
+ storeType = StoreType.WebStagingPreview;
+ }
+ else if ( props.containsKey( SandboxConstants.PROP_SANDBOX_STAGING_PREVIEW))
+ {
+ // Staging preview sandbox store, linked to a web project
+
+ storeType = StoreType.WebStagingPreview;
+
+ // Get the associated web project name
+
+ webProjName = storeName.substring( 0, storeName.length() - "--preview".length());
+ }
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug( " Store " + storeDesc.getName() + ", type=" + StoreType.asString( storeType) + ", webproj=" + webProjName + ", username=" + userName);
+
+ // Add a pseudo file for the current store
+
+ if ( avmCtx.showStoreType( storeType))
+ {
+ // Create the pseudo folder for the store
+
+ StorePseudoFile storeFolder = new StorePseudoFile( storeDesc, FileName.DOS_SEPERATOR_STR + storeName, storeType);
+ if ( storeType != StoreType.Normal)
+ {
+ storeFolder.setWebProject( webProjName);
+ storeFolder.setUserName( userName);
+
+ // Add all publisher/reviewer user names to the web project roles list
+
+ if ( storeFolder.hasWebProject())
+ {
+ // Find the associated web project pseudo folder
+
+ PseudoFileList folderList = fstate.getPseudoFileList();
+ if ( folderList != null) {
+
+ // Find the associated web project
+
+ WebProjectStorePseudoFile webProj = (WebProjectStorePseudoFile) folderList.findFile( storeFolder.getWebProject(), true);
+
+ if ( webProj != null) {
+
+ // Strip the web project name from the sandbox store name and extract the user name.
+ // Add the user as a publisher/reviewer to the web project roles list
+
+ userName = storeFolder.getFileName().substring( webProj.getFileName().length() + 2);
+
+ // If the user does not have a content manager role then add as a publisher
+
+ if ( webProj.getUserRole( userName) == WebProjectStorePseudoFile.RoleNone)
+ {
+ webProj.addUserRole( userName, WebProjectStorePseudoFile.RolePublisher);
+
+ // DEBUG
+
+ if ( logger.isDebugEnabled())
+ logger.debug( " Added publisher " + userName + " to " + webProj.getFileName());
+ }
+ }
+ }
+ }
+ }
+
+ // Add the store pseudo folder to the root folder file list
+
+ fstate.addPseudoFile( storeFolder);
+ }
+ }
+ }
}
diff --git a/source/java/org/alfresco/repo/admin/patch/AbstractPatch.java b/source/java/org/alfresco/repo/admin/patch/AbstractPatch.java
index 2caaa41e01..7798d9b1ba 100644
--- a/source/java/org/alfresco/repo/admin/patch/AbstractPatch.java
+++ b/source/java/org/alfresco/repo/admin/patch/AbstractPatch.java
@@ -78,32 +78,27 @@ public abstract class AbstractPatch implements Patch
private String description;
/** a list of patches that this one depends on */
private List dependsOn;
+ /** a list of patches that, if already present, mean that this one should be ignored */
+ private List alternatives;
/** flag indicating if the patch was successfully applied */
private boolean applied;
private boolean applyToTenants;
+ /** track completion * */
+ int percentComplete = 0;
+ /** start time * */
+ long startTime;
/** the service to register ourselves with */
private PatchService patchService;
/** used to ensure a unique transaction per execution */
protected TransactionService transactionService;
- /** support service */
protected NamespaceService namespaceService;
- /** support service */
protected NodeService nodeService;
- /** support service */
protected SearchService searchService;
- /** support service */
protected AuthenticationComponent authenticationComponent;
- /** support service */
protected TenantAdminService tenantAdminService;
- /** track completion * */
- int percentComplete = 0;
-
- /** start time * */
- long startTime;
-
public AbstractPatch()
{
this.fixesFromSchema = -1;
@@ -112,6 +107,7 @@ public abstract class AbstractPatch implements Patch
this.applied = false;
this.applyToTenants = true; // by default, apply to each tenant, if tenant service is enabled
this.dependsOn = Collections.emptyList();
+ this.alternatives = Collections.emptyList();
}
@Override
@@ -144,33 +140,21 @@ public abstract class AbstractPatch implements Patch
this.transactionService = transactionService;
}
- /**
- * Set a generally-used service
- */
public void setNamespaceService(NamespaceService namespaceService)
{
this.namespaceService = namespaceService;
}
- /**
- * Set a generally-used service
- */
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
- /**
- * Set a generally-used service
- */
public void setSearchService(SearchService searchService)
{
this.searchService = searchService;
}
- /**
- * Set a generally-used service
- */
public void setAuthenticationComponent(AuthenticationComponent authenticationComponent)
{
this.authenticationComponent = authenticationComponent;
@@ -303,6 +287,22 @@ public abstract class AbstractPatch implements Patch
this.dependsOn = dependsOn;
}
+ public List getAlternatives()
+ {
+ return alternatives;
+ }
+
+ /**
+ * Set all anti-dependencies. If any of the patches in the list have already been executed, then
+ * this one need not be.
+ *
+ * @param alternatives a list of alternative patches
+ */
+ public void setAlternatives(List alternatives)
+ {
+ this.alternatives = alternatives;
+ }
+
public boolean applies(int version)
{
return ((this.fixesFromSchema <= version) && (version <= fixesToSchema));
@@ -345,7 +345,9 @@ public abstract class AbstractPatch implements Patch
checkPropertyNotNull(authenticationComponent, "authenticationComponent");
if (fixesFromSchema == -1 || fixesToSchema == -1 || targetSchema == -1)
{
- throw new AlfrescoRuntimeException("Patch properties 'fixesFromSchema', 'fixesToSchema' and 'targetSchema' have not all been set on this patch: \n"
+ throw new AlfrescoRuntimeException(
+ "Patch properties 'fixesFromSchema', 'fixesToSchema' and 'targetSchema' " +
+ "have not all been set on this patch: \n"
+ " patch: " + this);
}
}
diff --git a/source/java/org/alfresco/repo/admin/patch/Patch.java b/source/java/org/alfresco/repo/admin/patch/Patch.java
index a2340700b8..be376f0ec1 100644
--- a/source/java/org/alfresco/repo/admin/patch/Patch.java
+++ b/source/java/org/alfresco/repo/admin/patch/Patch.java
@@ -69,6 +69,13 @@ public interface Patch
*/
public List getDependsOn();
+ /**
+ * Get patches that could have done the work already
+ *
+ * @return Returns a list of patches
+ */
+ public List getAlternatives();
+
/**
* Check if the patch is applicable to a given schema version.
*
diff --git a/source/java/org/alfresco/repo/admin/patch/PatchServiceImpl.java b/source/java/org/alfresco/repo/admin/patch/PatchServiceImpl.java
index 64c3e2a4f9..b088a33a7a 100644
--- a/source/java/org/alfresco/repo/admin/patch/PatchServiceImpl.java
+++ b/source/java/org/alfresco/repo/admin/patch/PatchServiceImpl.java
@@ -56,6 +56,7 @@ import org.apache.commons.logging.LogFactory;
public class PatchServiceImpl implements PatchService
{
private static final String MSG_NOT_RELEVANT = "patch.service.not_relevant";
+ private static final String MSG_PRECEEDED_BY_ALTERNATIVE = "patch.service.preceeded_by_alternative";
private static final String MSG_APPLYING_PATCH = "patch.service.applying_patch";
private static final Date ZERO_DATE = new Date(0L);
@@ -245,6 +246,7 @@ public class PatchServiceImpl implements PatchService
boolean success = false;
// first check whether the patch is relevant to the repo
Descriptor repoDescriptor = descriptorService.getInstalledRepositoryDescriptor();
+ String preceededByAlternative = preceededByAlternative(patch);
boolean applies = applies(repoDescriptor, patch);
if (!applies)
{
@@ -252,6 +254,11 @@ public class PatchServiceImpl implements PatchService
report = I18NUtil.getMessage(MSG_NOT_RELEVANT, repoDescriptor.getSchema());
success = true; // this succeeded because it didn't need to be applied
}
+ else if (preceededByAlternative != null)
+ {
+ report = I18NUtil.getMessage(MSG_PRECEEDED_BY_ALTERNATIVE, preceededByAlternative);
+ success = true; // this succeeded because it didn't need to be applied
+ }
else
{
// perform actual execution
@@ -309,6 +316,28 @@ public class PatchServiceImpl implements PatchService
return appliedPatch;
}
+ /**
+ * Identifies if one of the alternative patches has already been executed.
+ *
+ * @param patch the patch to check
+ * @return Returns the ID of any successfully executed alternative patch
+ */
+ private String preceededByAlternative(Patch patch)
+ {
+ // If any alternatives were executed, then bypass this one
+ List alternatives = patch.getAlternatives();
+ for (Patch alternative : alternatives)
+ {
+ // If the patch was executed, then this one was effectively executed
+ AppliedPatch appliedAlternative = patchDaoService.getAppliedPatch(alternative.getId());
+ if (appliedAlternative != null && appliedAlternative.getSucceeded())
+ {
+ return alternative.getId();
+ }
+ }
+ return null;
+ }
+
/**
* Check whether the patch is applicable to the particular version of the repository.
*
diff --git a/source/java/org/alfresco/repo/admin/patch/impl/NoOpPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/NoOpPatch.java
new file mode 100644
index 0000000000..a4f9417543
--- /dev/null
+++ b/source/java/org/alfresco/repo/admin/patch/impl/NoOpPatch.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2005-2008 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program 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 General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.repo.admin.patch.impl;
+
+import org.alfresco.i18n.I18NUtil;
+import org.alfresco.repo.admin.patch.AbstractPatch;
+
+/**
+ * Does nothing.
+ *
+ * @author Derek Hulley
+ * @since 2.2.2
+ */
+public class NoOpPatch extends AbstractPatch
+{
+ private static final String MSG_RESULT = "patch.noOpPatch.result";
+
+ public NoOpPatch()
+ {
+ }
+
+ @Override
+ protected String applyInternal() throws Exception
+ {
+ return I18NUtil.getMessage(MSG_RESULT);
+ }
+}
diff --git a/source/java/org/alfresco/repo/audit/hibernate/HibernateAuditDAO.java b/source/java/org/alfresco/repo/audit/hibernate/HibernateAuditDAO.java
index f293011fac..01f19756e3 100644
--- a/source/java/org/alfresco/repo/audit/hibernate/HibernateAuditDAO.java
+++ b/source/java/org/alfresco/repo/audit/hibernate/HibernateAuditDAO.java
@@ -369,35 +369,66 @@ public class HibernateAuditDAO extends HibernateDaoSupport implements AuditDAO,
}
else
{
-
- InputStream current = new BufferedInputStream(auditInfo.getAuditConfiguration().getInputStream());
- ContentReader reader = contentStore.getReader(auditConfig.getConfigURL());
- reader.setMimetype(MimetypeMap.MIMETYPE_XML);
- reader.setEncoding("UTF-8");
- InputStream last = new BufferedInputStream(reader.getContentInputStream());
- int currentValue = -2;
- int lastValue = -2;
+ InputStream current = null;
+ InputStream last = null;
try
{
- while ((currentValue != -1) && (lastValue != -1) && (currentValue == lastValue))
+ current = new BufferedInputStream(auditInfo.getAuditConfiguration().getInputStream());
+ ContentReader reader = contentStore.getReader(auditConfig.getConfigURL());
+ reader.setMimetype(MimetypeMap.MIMETYPE_XML);
+ reader.setEncoding("UTF-8");
+ last = new BufferedInputStream(reader.getContentInputStream());
+ int currentValue = -2;
+ int lastValue = -2;
+ try
{
- currentValue = current.read();
- lastValue = last.read();
+ while ((currentValue != -1) && (lastValue != -1) && (currentValue == lastValue))
+ {
+ currentValue = current.read();
+ lastValue = last.read();
+ }
+ }
+ catch (IOException e)
+ {
+ throw new AlfrescoRuntimeException("Failed to read and validate current audit configuration against the last", e);
+ }
+ if (currentValue != lastValue)
+ {
+ // Files are different - require a new entry
+ auditConfig = createNewAuditConfigImpl(auditInfo);
+ }
+ else
+ {
+ // No change
}
}
- catch (IOException e)
+ finally
{
- throw new AlfrescoRuntimeException("Failed to read and validate current audit configuration against the last", e);
- }
- if (currentValue != lastValue)
- {
- // Files are different - require a new entry
- auditConfig = createNewAuditConfigImpl(auditInfo);
- }
- else
- {
- // No change
+ if (current != null)
+ {
+ try
+ {
+ current.close();
+ }
+ catch (IOException e)
+ {
+ s_logger.warn(e);
+ }
+ }
+
+ if (last != null)
+ {
+ try
+ {
+ last.close();
+ }
+ catch (IOException e)
+ {
+ s_logger.warn(e);
+ }
+ }
+
}
}
diff --git a/source/java/org/alfresco/repo/coci/CheckOutCheckInServiceImpl.java b/source/java/org/alfresco/repo/coci/CheckOutCheckInServiceImpl.java
index 9ea83ca230..f6b39ea518 100644
--- a/source/java/org/alfresco/repo/coci/CheckOutCheckInServiceImpl.java
+++ b/source/java/org/alfresco/repo/coci/CheckOutCheckInServiceImpl.java
@@ -474,7 +474,7 @@ public class CheckOutCheckInServiceImpl implements CheckOutCheckInService
resultSet = this.searchService.query(
nodeRef.getStoreRef(),
SearchService.LANGUAGE_LUCENE,
- "ASPECT:\"" + ContentModel.ASPECT_WORKING_COPY.toString() + "\" +@\\{http\\://www.alfresco.org/model/content/1.0\\}" + ContentModel.PROP_COPY_REFERENCE.getLocalName() + ":\"" + nodeRef.toString() + "\"");
+ "+ASPECT:\"" + ContentModel.ASPECT_WORKING_COPY.toString() + "\" +@\\{http\\://www.alfresco.org/model/content/1.0\\}" + ContentModel.PROP_COPY_REFERENCE.getLocalName() + ":\"" + nodeRef.toString() + "\"");
if (resultSet.getNodeRefs().size() != 0)
{
workingCopy = resultSet.getNodeRef(0);
diff --git a/source/java/org/alfresco/repo/coci/CheckOutCheckInServiceImplTest.java b/source/java/org/alfresco/repo/coci/CheckOutCheckInServiceImplTest.java
index 0c6c52c23d..02eebffea6 100644
--- a/source/java/org/alfresco/repo/coci/CheckOutCheckInServiceImplTest.java
+++ b/source/java/org/alfresco/repo/coci/CheckOutCheckInServiceImplTest.java
@@ -40,6 +40,7 @@ import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
+import org.alfresco.service.cmr.repository.CopyService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
@@ -73,6 +74,7 @@ public class CheckOutCheckInServiceImplTest extends BaseSpringTest
private LockService lockService;
private TransactionService transactionService;
private PermissionService permissionService;
+ private CopyService copyService;
/**
* Data used by the tests
@@ -116,7 +118,8 @@ public class CheckOutCheckInServiceImplTest extends BaseSpringTest
this.lockService = (LockService)this.applicationContext.getBean("lockService");
this.transactionService = (TransactionService)this.applicationContext.getBean("transactionComponent");
this.permissionService = (PermissionService)this.applicationContext.getBean("permissionService");
-
+ this.copyService = (CopyService)this.applicationContext.getBean("copyService");
+
// Authenticate as system to create initial test data set
AuthenticationComponent authenticationComponent = (AuthenticationComponent)this.applicationContext.getBean("authenticationComponent");
authenticationComponent.setSystemUserAsCurrentUser();
@@ -432,7 +435,56 @@ public class CheckOutCheckInServiceImplTest extends BaseSpringTest
});
NodeRef wk3 = this.cociService.getWorkingCopy(this.nodeRef);
- assertNull(wk3);
+ assertNull(wk3);
+ }
+
+ /**
+ * Test the getWorkingCopy method
+ */
+ public void testETWOTWO_733()
+ {
+ NodeRef origNodeRef = this.nodeService.createNode(
+ this.rootNodeRef,
+ ContentModel.ASSOC_CHILDREN,
+ QName.createQName("{test}test2"),
+ ContentModel.TYPE_CONTENT).getChildRef();
+
+ // Make a copy of the node
+ this.copyService.copyAndRename(
+ origNodeRef,
+ this.rootNodeRef,
+ ContentModel.ASSOC_CHILDREN,
+ QName.createQName("{test}test6"),
+ false);
+
+ NodeRef wk1 = this.cociService.getWorkingCopy(origNodeRef);
+ assertNull(wk1);
+
+ // Check the document out
+ final NodeRef workingCopy = this.cociService.checkout(origNodeRef);
+
+ // Need to commit the transaction in order to get the indexer to run
+ setComplete();
+ endTransaction();
+
+ final NodeRef finalNodeRef = origNodeRef;
+
+ this.transactionService.getRetryingTransactionHelper().doInTransaction(
+ new RetryingTransactionCallback