Merged V2.2 to HEAD

7498: Deployment callback and event changes
   7499: Build fix
   7505: Fixed deployment script issue in IE
   7525: Added sample job that will clean deployment attempts older than 180 days (by default)
   7526: Typo compilation fix


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@8383 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2008-02-26 15:13:48 +00:00
parent ff15cf4079
commit fecfd82767
9 changed files with 418 additions and 45 deletions

View File

@@ -0,0 +1,178 @@
/*
* 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 java.util.Calendar;
import java.util.Date;
import org.alfresco.model.WCMAppModel;
import org.alfresco.repo.importer.ImporterBootstrap;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.transaction.TransactionService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Bean that is responsible for locating expired content and routing
* it for review to the most relevant user.
*
* @author gavinc
*/
public class AVMDeploymentAttemptCleaner
{
// defaults in case these properties are not configured in Spring
protected String adminUserName = "admin";
protected long maxAge = 180L;
protected NodeService nodeService;
protected TransactionService transactionService;
protected SearchService searchService;
protected ImporterBootstrap importerBootstrap;
private static Log logger = LogFactory.getLog(AVMDeploymentAttemptCleaner.class);
public AVMDeploymentAttemptCleaner()
{
}
public void setAdminUserName(String adminUserName)
{
this.adminUserName = adminUserName;
}
public void setMaxAge(long maxAge)
{
this.maxAge = new Long(maxAge);
}
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
public void setTransactionService(TransactionService transactionService)
{
this.transactionService = transactionService;
}
public void setSearchService(SearchService searchService)
{
this.searchService = searchService;
}
public void setImporterBootstrap(ImporterBootstrap importerBootstrap)
{
this.importerBootstrap = importerBootstrap;
}
/**
* Executes the expired content processor.
* The work is performed within a transaction running as the system user.
*/
public void execute()
{
// setup a wrapper object to run the processor within a transaction.
AuthenticationUtil.RunAsWork<String> authorisedWork = new AuthenticationUtil.RunAsWork<String>()
{
public String doWork() throws Exception
{
RetryingTransactionCallback<String> expiredContentWork = new RetryingTransactionCallback<String>()
{
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();
}
}
}
}

View File

@@ -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.
*
* <p>
* The following parameters are required:
* <ul>
* <li><b>deploymentAttemptCleaner</b>: The deployment attempt cleaner instance</li>
* </ul>
*
* @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();
}
}

View File

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

View File

@@ -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<DeploymentCallback> 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<DeploymentCallback> 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<DeploymentCallback> callbacks = new ArrayList<DeploymentCallback>();
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<DeploymentCallback> callbacks = new ArrayList<DeploymentCallback>();
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<DeploymentCallback> callbacks = new ArrayList<DeploymentCallback>();
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,