()
+ {
+ public String execute() throws Exception
+ {
+ cleanAttempts();
+ return null;
+ }
+ };
+ return transactionService.getRetryingTransactionHelper().doInTransaction(expiredContentWork);
+ }
+ };
+
+ // perform the work as the system user
+ AuthenticationUtil.runAs(authorisedWork, this.adminUserName);
+ }
+
+ /**
+ * Entry point.
+ */
+ private void cleanAttempts()
+ {
+ // calculate the date 'maxAge' days before today
+ long daysInMs = 1000L*60L*60L*24L*this.maxAge;
+ Date toDate = new Date(new Date().getTime() - daysInMs);
+
+ // build the query to find deployment attempts older than this.maxAge
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(toDate);
+ StringBuilder query = new StringBuilder("@");
+ query.append(NamespaceService.WCMAPP_MODEL_PREFIX);
+ query.append("\\:");
+ query.append(WCMAppModel.PROP_DEPLOYATTEMPTTIME.getLocalName());
+ query.append(":[0001\\-01\\-01T00:00:00 TO ");
+ query.append(cal.get(Calendar.YEAR));
+ query.append("\\-");
+ query.append((cal.get(Calendar.MONTH)+1));
+ query.append("\\-");
+ query.append(cal.get(Calendar.DAY_OF_MONTH));
+ query.append("T00:00:00]");
+
+ if (logger.isDebugEnabled())
+ logger.debug("Finding old deploymentattempt nodes using query: " + query.toString());
+
+ // do the query
+ ResultSet results = null;
+ try
+ {
+ // execute the query
+ results = searchService.query(this.importerBootstrap.getStoreRef(),
+ SearchService.LANGUAGE_LUCENE, query.toString());
+
+ if (logger.isDebugEnabled())
+ logger.debug("Deleting " + results.length() + " old deployment attempts");
+
+ // iterate through the attempt nodes and delete them
+ for (NodeRef attempt : results.getNodeRefs())
+ {
+ this.nodeService.deleteNode(attempt);
+
+ if (logger.isDebugEnabled())
+ logger.debug("Deleted deployment attempt: " + attempt);
+ }
+ }
+ finally
+ {
+ if (results != null)
+ {
+ results.close();
+ }
+ }
+ }
+}
diff --git a/source/java/org/alfresco/repo/avm/AVMDeploymentAttemptCleanerJob.java b/source/java/org/alfresco/repo/avm/AVMDeploymentAttemptCleanerJob.java
new file mode 100644
index 0000000000..e868b33169
--- /dev/null
+++ b/source/java/org/alfresco/repo/avm/AVMDeploymentAttemptCleanerJob.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2005-2007 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.avm;
+
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+
+/**
+ * Job to periodically execute the deployment attempt cleaner.
+ *
+ *
+ * The following parameters are required:
+ *
+ * - deploymentAttemptCleaner: The deployment attempt cleaner instance
+ *
+ *
+ * @author gavinc
+ */
+public class AVMDeploymentAttemptCleanerJob implements Job
+{
+ /**
+ * Searches for old deployment attempts and removes them.
+ *
+ * @param context The job context
+ */
+ public void execute(JobExecutionContext context) throws JobExecutionException
+ {
+ // get the expired content processor bean from the job context
+ AVMDeploymentAttemptCleaner cleaner =
+ (AVMDeploymentAttemptCleaner)context.getJobDetail().getJobDataMap().get("deploymentAttemptCleaner");
+ if (cleaner == null)
+ {
+ throw new JobExecutionException("Missing job data: deploymentAttemptCleaner");
+ }
+
+ // execute the cleaner to do the actual work
+ cleaner.execute();
+ }
+}
diff --git a/source/java/org/alfresco/repo/avm/AVMDeploymentAttemptCleanerTest.java b/source/java/org/alfresco/repo/avm/AVMDeploymentAttemptCleanerTest.java
new file mode 100644
index 0000000000..c903352260
--- /dev/null
+++ b/source/java/org/alfresco/repo/avm/AVMDeploymentAttemptCleanerTest.java
@@ -0,0 +1,46 @@
+package org.alfresco.repo.avm;
+
+
+import junit.framework.TestCase;
+
+import org.alfresco.repo.avm.AVMDeploymentAttemptCleaner;
+import org.alfresco.repo.importer.ImporterBootstrap;
+import org.alfresco.service.ServiceRegistry;
+import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.cmr.search.SearchService;
+import org.alfresco.service.transaction.TransactionService;
+import org.alfresco.util.ApplicationContextHelper;
+import org.springframework.context.ApplicationContext;
+
+/**
+ * @see org.alfresco.repo.avm.AVMDeploymentAttemptCleaner
+ *
+ * @author gavinc
+ */
+public class AVMDeploymentAttemptCleanerTest extends TestCase
+{
+ private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
+
+ private AVMDeploymentAttemptCleaner cleaner;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean("ServiceRegistry");
+ ImporterBootstrap importerBootstrap = (ImporterBootstrap)ctx.getBean("spacesBootstrap");
+ NodeService nodeService = serviceRegistry.getNodeService();
+ SearchService searchService = serviceRegistry.getSearchService();
+ TransactionService transactionService = serviceRegistry.getTransactionService();
+ this.cleaner = new AVMDeploymentAttemptCleaner();
+ this.cleaner.setNodeService(nodeService);
+ this.cleaner.setSearchService(searchService);
+ this.cleaner.setTransactionService(transactionService);
+ this.cleaner.setImporterBootstrap(importerBootstrap);
+// this.cleaner.setMaxAge(30);
+ }
+
+ public void testProcessor() throws Exception
+ {
+ this.cleaner.execute();
+ }
+}
diff --git a/source/java/org/alfresco/repo/avm/actions/AVMDeployWebsiteAction.java b/source/java/org/alfresco/repo/avm/actions/AVMDeployWebsiteAction.java
index dc060de470..deecb8605e 100644
--- a/source/java/org/alfresco/repo/avm/actions/AVMDeployWebsiteAction.java
+++ b/source/java/org/alfresco/repo/avm/actions/AVMDeployWebsiteAction.java
@@ -28,7 +28,6 @@ package org.alfresco.repo.avm.actions;
import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;
-import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
@@ -80,6 +79,7 @@ public class AVMDeployWebsiteAction extends ActionExecuterAbstractBase
private String defaultRemoteUsername = "admin";
private String defaultRemotePassword = "admin";
private String defaultTargetName = "default";
+ private List configuredCallbacks;
private DeploymentService deployService;
private ContentService contentService;
private NodeService nodeService;
@@ -176,6 +176,11 @@ public class AVMDeployWebsiteAction extends ActionExecuterAbstractBase
{
this.defaultTargetName = defaultTargetName;
}
+
+ public void setCallbacks(List callbacks)
+ {
+ this.configuredCallbacks = callbacks;
+ }
/**
* @param service The NodeService instance
@@ -335,6 +340,20 @@ public class AVMDeployWebsiteAction extends ActionExecuterAbstractBase
patterns.add(excludes);
regexMatcher.setPatterns(patterns);
}
+
+ // create a list of all the callback objects
+ List callbacks = new ArrayList();
+ if (callback != null)
+ {
+ // if present add the callback passed as a parameter (usually for UI purposes)
+ callbacks.add(callback);
+ }
+ if (this.configuredCallbacks != null && this.configuredCallbacks.size() > 0)
+ {
+ // add the configured callbacks
+ callbacks.addAll(this.configuredCallbacks);
+ }
+
// take a note of the current date/time
Date startDate = new Date();
@@ -362,13 +381,6 @@ public class AVMDeployWebsiteAction extends ActionExecuterAbstractBase
logger.debug("Performing file server deployment to " + host + ":" + port +
" using deploymentserver: " + serverProps);
- // TODO: Added new NameMatcher parameter to deploy methods. It acts as a filter.
- // Any matching path names are ignored for deployment purposes.
- List callbacks = new ArrayList();
- if (callback != null)
- {
- callbacks.add(callback);
- }
report = this.deployService.deployDifferenceFS(version, path, host, port,
remoteUsername, remotePassword, targetName, regexMatcher, true, false, false, callbacks);
}
@@ -378,13 +390,6 @@ public class AVMDeployWebsiteAction extends ActionExecuterAbstractBase
logger.debug("Performing Alfresco deployment to " + host + ":" + port +
" using deploymentserver: " + serverProps);
- // TODO: Added new NameMatcher parameter to deploy methods. It acts as a filter.
- // Any matching path names are ignored for deployment purposes.
- List callbacks = new ArrayList();
- if (callback != null)
- {
- callbacks.add(callback);
- }
report = this.deployService.deployDifference(version, path, host, port,
remoteUsername, remotePassword, targetPath, regexMatcher, true, false, false, callbacks);
}
@@ -393,25 +398,6 @@ public class AVMDeployWebsiteAction extends ActionExecuterAbstractBase
{
deployError = err;
logger.error(deployError);
-
- // report the error to the callback object
- // TODO: See if this can be incorporated into the DeploymentCallback I/F
- if (callback != null)
- {
- // to avoid a circular dependency use reflection to call the method
- try
- {
- Method method = callback.getClass().getMethod("errorOccurred", new Class[] {Throwable.class});
- if (method != null)
- {
- method.invoke(callback, new Object[] {err});
- }
- }
- catch (Throwable e)
- {
- logger.warn("Failed to inform deployment monitor of deployment failure", e);
- }
- }
}
if (report != null)
@@ -472,8 +458,16 @@ public class AVMDeployWebsiteAction extends ActionExecuterAbstractBase
reportProps.put(WCMAppModel.PROP_DEPLOYSUCCESSFUL, (report != null));
if (report == null && error != null)
{
- // add error message as fail reason if appropriate
- reportProps.put(WCMAppModel.PROP_DEPLOYFAILEDREASON, error.getMessage());
+ // add error message as fail reason if appropriate (the reported
+ // exception is a wrapper so get the detail from the cause)
+ String errorMsg = error.getMessage();
+ Throwable cause = error.getCause();
+ if (cause != null)
+ {
+ errorMsg = cause.getMessage();
+ }
+
+ reportProps.put(WCMAppModel.PROP_DEPLOYFAILEDREASON, errorMsg);
}
reportRef = this.nodeService.createNode(attempt,
WCMAppModel.ASSOC_DEPLOYMENTREPORTS, WCMAppModel.ASSOC_DEPLOYMENTREPORTS,
diff --git a/source/java/org/alfresco/repo/coci/WorkingCopyAspect.java b/source/java/org/alfresco/repo/coci/WorkingCopyAspect.java
index 1dce1d1c9e..1d8bbad6ab 100644
--- a/source/java/org/alfresco/repo/coci/WorkingCopyAspect.java
+++ b/source/java/org/alfresco/repo/coci/WorkingCopyAspect.java
@@ -30,6 +30,7 @@ import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.repo.policy.PolicyScope;
import org.alfresco.service.cmr.lock.LockService;
+import org.alfresco.service.cmr.lock.LockStatus;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
@@ -137,9 +138,12 @@ public class WorkingCopyAspect
// Get the origional node
NodeRef origNodeRef = (NodeRef)this.nodeService.getProperty(nodeRef, ContentModel.PROP_COPY_REFERENCE);
if (origNodeRef != null)
- {
- // Release the lock on the origional node
- this.lockService.unlock(origNodeRef);
+ {
+ if (this.lockService.getLockStatus(origNodeRef).equals(LockStatus.NO_LOCK) == false)
+ {
+ // Release the lock on the origional node
+ this.lockService.unlock(origNodeRef);
+ }
}
}
}
diff --git a/source/java/org/alfresco/repo/deploy/DeploymentServiceImpl.java b/source/java/org/alfresco/repo/deploy/DeploymentServiceImpl.java
index fc53aefdc3..082458c380 100644
--- a/source/java/org/alfresco/repo/deploy/DeploymentServiceImpl.java
+++ b/source/java/org/alfresco/repo/deploy/DeploymentServiceImpl.java
@@ -282,7 +282,7 @@ public class DeploymentServiceImpl implements DeploymentService
{
DeploymentEvent event = new DeploymentEvent(DeploymentEvent.Type.FAILED,
new Pair(version, srcPath),
- dstPath);
+ dstPath, e.getMessage());
for (DeploymentCallback callback : callbacks)
{
callback.eventOccurred(event);
@@ -310,7 +310,7 @@ public class DeploymentServiceImpl implements DeploymentService
{
DeploymentEvent event = new DeploymentEvent(DeploymentEvent.Type.FAILED,
new Pair(version, srcPath),
- dstPath);
+ dstPath, e.getMessage());
for (DeploymentCallback callback : callbacks)
{
callback.eventOccurred(event);
@@ -799,10 +799,11 @@ public class DeploymentServiceImpl implements DeploymentService
List callbacks)
{
DeploymentReport report = new DeploymentReport();
- DeploymentReceiverService service = getReceiver(hostName, port);
+ DeploymentReceiverService service = null;
String ticket = null;
try
{
+ service = getReceiver(hostName, port);
DeploymentEvent event = new DeploymentEvent(DeploymentEvent.Type.START,
new Pair(version, srcPath),
target);
@@ -840,12 +841,17 @@ public class DeploymentServiceImpl implements DeploymentService
{
DeploymentEvent event = new DeploymentEvent(DeploymentEvent.Type.FAILED,
new Pair(version, srcPath),
- target);
+ target, e.getMessage());
for (DeploymentCallback callback : callbacks)
{
callback.eventOccurred(event);
}
- service.abort(ticket);
+
+ if (service != null)
+ {
+ service.abort(ticket);
+ }
+
throw new AVMException("Deployment to: " + target + " failed.", e);
}
}
diff --git a/source/java/org/alfresco/repo/domain/hibernate/TransactionImpl.java b/source/java/org/alfresco/repo/domain/hibernate/TransactionImpl.java
index 3423464a77..d9ca8b0f78 100644
--- a/source/java/org/alfresco/repo/domain/hibernate/TransactionImpl.java
+++ b/source/java/org/alfresco/repo/domain/hibernate/TransactionImpl.java
@@ -50,6 +50,7 @@ public class TransactionImpl extends LifecycleAdapter implements Transaction, Se
public TransactionImpl()
{
+ this.commitTimeMs = Long.valueOf(0);
}
@Override
diff --git a/source/java/org/alfresco/service/cmr/avm/deploy/DeploymentEvent.java b/source/java/org/alfresco/service/cmr/avm/deploy/DeploymentEvent.java
index 77ae409852..09997884b3 100644
--- a/source/java/org/alfresco/service/cmr/avm/deploy/DeploymentEvent.java
+++ b/source/java/org/alfresco/service/cmr/avm/deploy/DeploymentEvent.java
@@ -56,6 +56,8 @@ public class DeploymentEvent implements Serializable
private Pair fSource;
private String fDestination;
+
+ private String fMessage;
public DeploymentEvent(Type type, Pair source, String destination)
{
@@ -63,6 +65,13 @@ public class DeploymentEvent implements Serializable
fSource = source;
fDestination = destination;
}
+
+ public DeploymentEvent(Type type, Pair source, String destination, String message)
+ {
+ this(type, source, destination);
+
+ fMessage = message;
+ }
/**
* Get the type of the event.
@@ -90,12 +99,28 @@ public class DeploymentEvent implements Serializable
{
return fDestination;
}
+
+ /**
+ * Get the message.
+ * @return
+ */
+ public String getMessage()
+ {
+ return fMessage;
+ }
/**
* Get a String representation.
*/
public String toString()
{
- return fType + ": " + fSource + " -> " + fDestination;
+ String str = fType + ": " + fSource + " -> " + fDestination;
+
+ if (fMessage != null)
+ {
+ str = str + " (" + fMessage + ")";
+ }
+
+ return str;
}
}