From 751fcbb1fa842fbb4d418aa90ce59375e43d325c Mon Sep 17 00:00:00 2001 From: Derek Hulley Date: Mon, 11 Feb 2008 13:19:19 +0000 Subject: [PATCH] Merged V2.2 to HEAD 7307: Re-enabled ability to perform deployments against new model 7278: Added friendly server name property to model and refactored view deployment report dialog 7272: Patch for new deployment features git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@8245 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- config/alfresco/action-services-context.xml | 20 +- .../messages/action-config.properties | 8 +- .../messages/patch-service.properties | 8 +- config/alfresco/model/wcmAppModel.xml | 231 ++++++++++++- .../alfresco/patch/patch-services-context.xml | 19 +- config/alfresco/version.properties | 2 +- .../java/org/alfresco/model/WCMAppModel.java | 36 +++ .../patch/impl/DeploymentMigrationPatch.java | 223 +++++++++++++ .../avm/actions/AVMDeploySnapshotAction.java | 305 ++++++++++++------ .../alfresco/sandbox/SandboxConstants.java | 1 + 10 files changed, 731 insertions(+), 122 deletions(-) create mode 100644 source/java/org/alfresco/repo/admin/patch/impl/DeploymentMigrationPatch.java diff --git a/config/alfresco/action-services-context.xml b/config/alfresco/action-services-context.xml index f921ff4725..d49fdaf2cd 100644 --- a/config/alfresco/action-services-context.xml +++ b/config/alfresco/action-services-context.xml @@ -508,7 +508,25 @@ false - + + + admin + + + admin + + + 50500 + + + 44100 + + + default + + + 30 + diff --git a/config/alfresco/messages/action-config.properties b/config/alfresco/messages/action-config.properties index a40de555ec..f0afab89ef 100644 --- a/config/alfresco/messages/action-config.properties +++ b/config/alfresco/messages/action-config.properties @@ -118,11 +118,9 @@ avm-undo-list.node-list.display-label=The string encoded list of nodes to revert avm-deploy-snapshot.title=Deploy a snapshot to a remote server. avm-deploy-snapshot.description=This deploys a website snapshot to a remote server. avm-deploy-snapshot.website.display-label=NodeRef of the website the deploy is occurring from. -avm-deploy-snapshot.target-server.display-label=The name or IP address of the remote server to deploy to. -avm-deploy-snapshot.default-rmi-port.display-label=The default RMI port to connect to if it is not supplied in target-server parameter. -avm-deploy-snapshot.remote-username.display-label=The username to connect as. -avm-deploy-snapshot.remote-password.display-label=The password for the remote-username. -avm-deploy-snapshot.deploy-callback.display-label=The DeploymentCallback listener object. +avm-deploy-snapshot.server.display-label=NodeRef of the deploymentserver to deploy to. +avm-deploy-snapshot.attempt.display-label=NodeRef of the deploymentattempt this deployment is part of. +avm-deploy-snapshot.callback.display-label=The DeploymentCallback listener object. avm-deploy-snapshot.delay.display-label=An optional delay to apply to the start of a deployment. start-avm-workflow.title=Start a WCM Workflow diff --git a/config/alfresco/messages/patch-service.properties b/config/alfresco/messages/patch-service.properties index 63b4e23014..9e3e2935e1 100644 --- a/config/alfresco/messages/patch-service.properties +++ b/config/alfresco/messages/patch-service.properties @@ -193,4 +193,10 @@ patch.tagRootCategory.description=Adds 'Tags' as new top-level category root. patch.projectsFolder.description=Adds 'Projects' folder to Company Home. -patch.projectTemplate.description=Adds the default Project template folder to the Space Templates folder. \ No newline at end of file +patch.projectTemplate.description=Adds the default Project template folder to the Space Templates folder. + +patch.deploymentMigration.description=Migrates deployment data to the new model. +patch.deploymentMigration.webProjectName=Migrating deployment data for web project ''{0}'' +patch.deploymentMigration.serverMigrated=Server ''{0}'' from web project ''{1}'' has been migrated +patch.deploymentMigration.reportMigrated=Deployment report for ''{0}'' from web project ''{1}'' has been migrated +patch.deploymentMigration.result=Deployment data has been migrated. diff --git a/config/alfresco/model/wcmAppModel.xml b/config/alfresco/model/wcmAppModel.xml index 1c127c7a70..a46c4c9b3b 100644 --- a/config/alfresco/model/wcmAppModel.xml +++ b/config/alfresco/model/wcmAppModel.xml @@ -16,6 +16,25 @@ + + + + + alfresco + file + + + + + + + + live + test + + + + @@ -37,6 +56,7 @@ Default Webapp d:text + Deploy To d:text @@ -51,6 +71,7 @@ Snapshot Version Selected For Deployment d:int + Used as a template website d:boolean @@ -90,6 +111,7 @@ true + false @@ -101,6 +123,29 @@ true + + + + false + false + + + wca:deploymentserver + false + true + + + + + false + false + + + wca:deploymentattempt + false + true + + @@ -158,29 +203,29 @@ - cm:titled - wca:outputpathpattern - + cm:titled + wca:outputpathpattern + Website Web Form Template sys:base - + d:text true - wca:outputpathpattern - + wca:outputpathpattern + Workflow Defaults sys:base - + d:text true @@ -197,13 +242,13 @@ Web Workflow Defaults wca:workflowdefaults - wca:filenamepattern - + wca:filenamepattern + Properties for renditions - sys:base + sys:base Mimetype for generated assets @@ -212,13 +257,145 @@ - wca:outputpathpattern + wca:outputpathpattern XForms Capture Form Folder - cm:folder + cm:folder + + + + Website Deployment Server + sys:base + + + Deployment Type + d:text + + + + + + Deployment Server Type + d:text + + + + + + Host + d:text + true + + true + false + false + + + + Port + d:int + true + + + Display Name + d:text + + + Username + d:text + + + Password + d:text + + + Runtime URL + d:text + + + Deploy Target + d:text + + + Source Path + d:text + + + Allocated To + d:text + + + Deploy On Approval + d:boolean + false + + + + + + Website Deployment Attempt + sys:base + + + Deploy Attempt ID + d:text + true + + true + false + false + + + + Attempt Type + d:text + + + + + + Attempt Type + d:text + true + + true + false + false + + + + Snapshot Version Deployed + d:int + true + + + Servers Deployed To + d:text + true + true + + + Time Of Deploy Attempt + d:datetime + true + + + + + + false + false + + + wca:deploymentreport + false + true + + + @@ -254,11 +431,31 @@ Failure Reason d:text + + Server Display Name + d:text + + + Username Used + d:text + + + Target Used + d:text + + + Source Path Used + d:text + + + Source Path Used + d:text + - + - + Webapp @@ -282,7 +479,7 @@ - + XForms Form @@ -372,11 +569,11 @@ false - + Renditions of this form instance data d:text true - + diff --git a/config/alfresco/patch/patch-services-context.xml b/config/alfresco/patch/patch-services-context.xml index 61cdfbdf43..821ac6a76e 100644 --- a/config/alfresco/patch/patch-services-context.xml +++ b/config/alfresco/patch/patch-services-context.xml @@ -1125,7 +1125,7 @@ - + patch.formsFolder @@ -1212,4 +1212,21 @@ + + patch.deploymentMigration + patch.deploymentMigration.description + 0 + 116 + 117 + + + + + + + + + + + \ No newline at end of file diff --git a/config/alfresco/version.properties b/config/alfresco/version.properties index 7f7cd19746..66d5a17029 100644 --- a/config/alfresco/version.properties +++ b/config/alfresco/version.properties @@ -19,4 +19,4 @@ version.build=@build-number@ # Schema number -version.schema=116 +version.schema=117 diff --git a/source/java/org/alfresco/model/WCMAppModel.java b/source/java/org/alfresco/model/WCMAppModel.java index 5d574e776d..240a11cd8d 100644 --- a/source/java/org/alfresco/model/WCMAppModel.java +++ b/source/java/org/alfresco/model/WCMAppModel.java @@ -43,6 +43,8 @@ public interface WCMAppModel static final QName ASSOC_WEBUSER = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "webuser"); static final QName ASSOC_WEBFORM = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "webform"); static final QName ASSOC_WEBWORKFLOWDEFAULTS = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "webworkflowdefaults"); + static final QName ASSOC_DEPLOYMENTSERVER = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deploymentserver"); + static final QName ASSOC_DEPLOYMENTATTEMPT = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deploymentattempt"); static final QName ASSOC_DEPLOYMENTREPORT = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deploymentreport"); // AVM web user reference @@ -68,6 +70,35 @@ public interface WCMAppModel // AVM web workflow defaults static final QName TYPE_WEBWORKFLOWDEFAULTS = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "webworkflowdefaults"); + // AVM website deployment server + static final String CONSTRAINT_ALFDEPLOY = "alfresco"; + static final String CONSTRAINT_FILEDEPLOY = "file"; + static final String CONSTRAINT_LIVESERVER = "live"; + static final String CONSTRAINT_TESTSERVER = "test"; + static final QName TYPE_DEPLOYMENTSERVER = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deploymentserver"); + static final QName PROP_DEPLOYTYPE = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deploytype"); + static final QName PROP_DEPLOYSERVERTYPE = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deployservertype"); + static final QName PROP_DEPLOYSERVERHOST = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deployserverhost"); + static final QName PROP_DEPLOYSERVERPORT = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deployserverport"); + static final QName PROP_DEPLOYSERVERNAME = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deployservername"); + static final QName PROP_DEPLOYSERVERUSERNAME = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deployserverusername"); + static final QName PROP_DEPLOYSERVERPASSWORD = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deployserverpassword"); + static final QName PROP_DEPLOYSERVERURL = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deployserverurl"); + static final QName PROP_DEPLOYSERVERTARGET = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deployservertarget"); + static final QName PROP_DEPLOYSOURCEPATH = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deploysourcepath"); + static final QName PROP_DEPLOYSERVERALLOCATEDTO = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deployserverallocatedto"); + static final QName PROP_DEPLOYONAPPROVAL = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deployonapproval"); + + // AVM website deployment attempt + static final QName TYPE_DEPLOYMENTATTEMPT = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deploymentattempt"); + static final QName PROP_DEPLOYATTEMPTID = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deployattemptid"); + static final QName PROP_DEPLOYATTEMPTTYPE = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deployattempttype"); + static final QName PROP_DEPLOYATTEMPTSTORE = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deployattemptstore"); + static final QName PROP_DEPLOYATTEMPTVERSION = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deployattemptversion"); + static final QName PROP_DEPLOYATTEMPTSERVERS = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deployattemptservers"); + static final QName PROP_DEPLOYATTEMPTTIME = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deployattempttime"); + static final QName ASSOC_DEPLOYMENTREPORTS = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deploymentreports"); + // AVM website deployment report static final QName TYPE_DEPLOYMENTREPORT = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deploymentreport"); static final QName PROP_DEPLOYSERVER = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deployserver"); @@ -76,6 +107,11 @@ public interface WCMAppModel static final QName PROP_DEPLOYFAILEDREASON = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deployfailedreason"); static final QName PROP_DEPLOYSTARTTIME = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deploystarttime"); static final QName PROP_DEPLOYENDTIME = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deployendtime"); + static final QName PROP_DEPLOYSERVERNAMEUSED = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deployservernameused"); + static final QName PROP_DEPLOYSERVERUSERNAMEUSED = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deployserverusernameused"); + static final QName PROP_DEPLOYSERVERTARGETUSED = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deployservertargetused"); + static final QName PROP_DEPLOYSOURCEPATHUSED = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deploysourcepathused"); + static final QName PROP_DEPLOYSERVERURLUSED = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "deployserverurlused"); // AVM webapp aspect static final QName ASPECT_WEBAPP = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "webapp"); diff --git a/source/java/org/alfresco/repo/admin/patch/impl/DeploymentMigrationPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/DeploymentMigrationPatch.java new file mode 100644 index 0000000000..e2425635bc --- /dev/null +++ b/source/java/org/alfresco/repo/admin/patch/impl/DeploymentMigrationPatch.java @@ -0,0 +1,223 @@ +package org.alfresco.repo.admin.patch.impl; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.alfresco.i18n.I18NUtil; +import org.alfresco.model.ContentModel; +import org.alfresco.model.WCMAppModel; +import org.alfresco.repo.admin.patch.AbstractPatch; +import org.alfresco.repo.domain.PropertyValue; +import org.alfresco.repo.importer.ImporterBootstrap; +import org.alfresco.repo.search.IndexerAndSearcher; +import org.alfresco.sandbox.SandboxConstants; +import org.alfresco.service.cmr.avm.AVMService; +import org.alfresco.service.cmr.dictionary.DataTypeDefinition; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.search.ResultSet; +import org.alfresco.service.cmr.search.SearchService; +import org.alfresco.service.namespace.QName; +import org.alfresco.service.namespace.RegexQNamePattern; +import org.alfresco.util.GUID; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Patch that migrates deployment data to the new deployment model. + * + * @author gavinc + */ +public class DeploymentMigrationPatch extends AbstractPatch +{ + protected ImporterBootstrap importerBootstrap; + protected IndexerAndSearcher indexerAndSearcher; + protected AVMService avmService; + + private static final String MSG_SUCCESS = "patch.deploymentMigration.result"; + private static final String MSG_WEBPROJECT = "patch.deploymentMigration.webProjectName"; + private static final String MSG_SERVER_MIGRATED = "patch.deploymentMigration.serverMigrated"; + private static final String MSG_REPORT_MIGRATED = "patch.deploymentMigration.reportMigrated"; + + private static final String FILE_SERVER_PREFIX = "\\\\"; + + private static final Log logger = LogFactory.getLog(DeploymentMigrationPatch.class); + + public void setIndexerAndSearcher(IndexerAndSearcher indexerAndSearcher) + { + this.indexerAndSearcher = indexerAndSearcher; + } + + public void setImporterBootstrap(ImporterBootstrap importerBootstrap) + { + this.importerBootstrap = importerBootstrap; + } + + public void setAvmService(AVMService avmService) + { + this.avmService = avmService; + } + + @Override + protected String applyInternal() throws Exception + { + String query = "TYPE:\"wca:webfolder\""; + + ResultSet results = null; + try + { + results = this.searchService.query(this.importerBootstrap.getStoreRef(), + SearchService.LANGUAGE_LUCENE, query); + + // iterate through the web projects and migrate the deployment data + if (results.length() > 0) + { + for (NodeRef node : results.getNodeRefs()) + { + if (this.nodeService.exists(node)) + { + migrate(node); + } + } + } + } + finally + { + if (results != null) + { + results.close(); + } + } + + // return success message + return I18NUtil.getMessage(MSG_SUCCESS); + } + + @SuppressWarnings("unchecked") + protected void migrate(NodeRef webProject) + { + // output name of web project currently being migrated + String projectName = (String)this.nodeService.getProperty(webProject, ContentModel.PROP_NAME); + logger.info(I18NUtil.getMessage(MSG_WEBPROJECT, projectName)); + + // see if the web project has any deployment servers configured + List deployTo = (List)this.nodeService.getProperty(webProject, WCMAppModel.PROP_DEPLOYTO); + if (deployTo != null && deployTo.size() > 0) + { + for (String server : deployTo) + { + if (server != null && server.length() > 0) + { + migrateServer(server.trim(), webProject, projectName); + } + } + } + + // migrate any deployment reports present + List deployReportRefs = nodeService.getChildAssocs(webProject, + WCMAppModel.ASSOC_DEPLOYMENTREPORT, RegexQNamePattern.MATCH_ALL); + if (deployReportRefs.size() > 0) + { + // gather data required for deploymentattempt node + String attemptId = GUID.generate(); + String store = (String)this.nodeService.getProperty(webProject, WCMAppModel.PROP_AVMSTORE); + List servers = (List)this.nodeService.getProperty(webProject, + WCMAppModel.PROP_SELECTEDDEPLOYTO); + if (servers == null) + { + servers = new ArrayList(); + } + Integer version = (Integer)this.nodeService.getProperty(webProject, + WCMAppModel.PROP_SELECTEDDEPLOYVERSION); + Date time = (Date)this.nodeService.getProperty( + deployReportRefs.get(0).getChildRef(), WCMAppModel.PROP_DEPLOYSTARTTIME); + + // create a deploymentattempt node for the reports to move to + Map props = new HashMap(8, 1.0f); + props.put(WCMAppModel.PROP_DEPLOYATTEMPTID, attemptId); + props.put(WCMAppModel.PROP_DEPLOYATTEMPTTYPE, WCMAppModel.CONSTRAINT_LIVESERVER); + props.put(WCMAppModel.PROP_DEPLOYATTEMPTSTORE, store); + props.put(WCMAppModel.PROP_DEPLOYATTEMPTVERSION, version); + props.put(WCMAppModel.PROP_DEPLOYATTEMPTSERVERS, (Serializable)servers); + props.put(WCMAppModel.PROP_DEPLOYATTEMPTTIME, time); + NodeRef attempt = this.nodeService.createNode(webProject, + WCMAppModel.ASSOC_DEPLOYMENTATTEMPT, WCMAppModel.ASSOC_DEPLOYMENTATTEMPT, + WCMAppModel.TYPE_DEPLOYMENTATTEMPT, props).getChildRef(); + + // set the attempt id on the staging store + this.avmService.setStoreProperty(store, SandboxConstants.PROP_LAST_DEPLOYMENT_ID, + new PropertyValue(DataTypeDefinition.TEXT, attemptId)); + + // migrate each report found + for (ChildAssociationRef ref : deployReportRefs) + { + migrateReport(ref.getChildRef(), attempt, webProject, projectName); + } + } + + // remove all the deprecated properties in the web project + this.nodeService.removeProperty(webProject, WCMAppModel.PROP_DEPLOYTO); + this.nodeService.removeProperty(webProject, WCMAppModel.PROP_SELECTEDDEPLOYTO); + this.nodeService.removeProperty(webProject, WCMAppModel.PROP_SELECTEDDEPLOYVERSION); + } + + protected void migrateServer(String server, NodeRef webProject, String webProjectName) + { + // work out the host and port + String host = server; + int port = -1; + int idx = server.indexOf(":"); + if (idx != -1) + { + host = server.substring(0, idx); + String strPort = server.substring(idx+1); + port = Integer.parseInt(strPort); + } + + Map props = new HashMap(4, 1.0f); + if (server.startsWith(FILE_SERVER_PREFIX)) + { + // server name starts with \\ so is therefore a file system deployment + props.put(WCMAppModel.PROP_DEPLOYTYPE, WCMAppModel.CONSTRAINT_FILEDEPLOY); + host = host.substring(FILE_SERVER_PREFIX.length()); + } + else + { + // server name does not start with \\ so is therefore an Alfresco server deployment + props.put(WCMAppModel.PROP_DEPLOYTYPE, WCMAppModel.CONSTRAINT_ALFDEPLOY); + } + + // set the properties + props.put(WCMAppModel.PROP_DEPLOYSERVERTYPE, WCMAppModel.CONSTRAINT_LIVESERVER); + props.put(WCMAppModel.PROP_DEPLOYSERVERHOST, host); + if (port != -1) + { + props.put(WCMAppModel.PROP_DEPLOYSERVERPORT, new Integer(port)); + } + + // create the deploymentserver node as a child of the webproject + this.nodeService.createNode(webProject, WCMAppModel.ASSOC_DEPLOYMENTSERVER, + WCMAppModel.ASSOC_DEPLOYMENTSERVER, WCMAppModel.TYPE_DEPLOYMENTSERVER, + props).getChildRef(); + + // inform of migration + logger.info(I18NUtil.getMessage(MSG_SERVER_MIGRATED, server, webProjectName)); + } + + protected void migrateReport(NodeRef report, NodeRef attempt, NodeRef webProject, + String webProjectName) + { + String server = (String)this.nodeService.getProperty(report, WCMAppModel.PROP_DEPLOYSERVER); + + // make the deployment report node a child of the given deploymentattempt node + this.nodeService.moveNode(report, attempt, WCMAppModel.ASSOC_DEPLOYMENTREPORTS, + WCMAppModel.ASSOC_DEPLOYMENTREPORTS); + + // inform of migration + logger.info(I18NUtil.getMessage(MSG_REPORT_MIGRATED, server, webProjectName)); + } +} diff --git a/source/java/org/alfresco/repo/avm/actions/AVMDeploySnapshotAction.java b/source/java/org/alfresco/repo/avm/actions/AVMDeploySnapshotAction.java index 7ecd4f13ee..b5c3a7ab58 100644 --- a/source/java/org/alfresco/repo/avm/actions/AVMDeploySnapshotAction.java +++ b/source/java/org/alfresco/repo/avm/actions/AVMDeploySnapshotAction.java @@ -67,14 +67,16 @@ public class AVMDeploySnapshotAction extends ActionExecuterAbstractBase public static final String NAME = "avm-deploy-snapshot"; public static final String PARAM_WEBSITE = "website"; - public static final String PARAM_TARGET_SERVER = "target-server"; - public static final String PARAM_DEFAULT_RMI_PORT = "default-rmi-port"; - public static final String PARAM_DEFAULT_RECEIVER_RMI_PORT = "default-receiver-rmi-port"; - public static final String PARAM_REMOTE_USERNAME = "remote-username"; - public static final String PARAM_REMOTE_PASSWORD = "remote-password"; - public static final String PARAM_CALLBACK = "deploy-callback"; - public static final String PARAM_DELAY = "delay"; + public static final String PARAM_SERVER = "server"; + public static final String PARAM_ATTEMPT = "attempt"; + public static final String PARAM_CALLBACK = "callback"; + private int delay = -1; + private int defaultAlfRmiPort = 50500; + private int defaultReceiverRmiPort = 44100; + private String defaultRemoteUsername = "admin"; + private String defaultRemotePassword = "admin"; + private String defaultTargetName = "default"; private DeploymentService deployService; private ContentService contentService; private NodeService nodeService; @@ -83,6 +85,96 @@ public class AVMDeploySnapshotAction extends ActionExecuterAbstractBase private static Log delayDeploymentLogger = LogFactory.getLog("alfresco.deployment.delay"); private static final String FILE_SERVER_PREFIX = "\\\\"; + /** + * Calculate the URI representation of a server from the given set of properties + * + * @param props Set of properties to calculate URI from + */ + public static String calculateServerUri(Map props) + { + StringBuilder uri = new StringBuilder(); + + // prefix the uri if necessary + String type = (String)props.get(WCMAppModel.PROP_DEPLOYTYPE); + if (WCMAppModel.CONSTRAINT_FILEDEPLOY.equals(type)) + { + uri.append(FILE_SERVER_PREFIX); + } + + // append server name + uri.append((String)props.get(WCMAppModel.PROP_DEPLOYSERVERHOST)); + + // append port (if present) + Integer port = (Integer)props.get(WCMAppModel.PROP_DEPLOYSERVERPORT); + if (port != null) + { + uri.append(":"); + uri.append(port.toString()); + } + + return uri.toString(); + } + + /** + * Sets the delay to use before starting the deployment + * + * @param delay The delay in seconds + */ + public void setDelay(int delay) + { + this.delay = delay; + } + + /** + * Sets the default RMI port for Alfresco server deployments + * + * @param defaultAlfrescoRmiPort port number + */ + public void setDefaultAlfrescoRmiPort(int defaultAlfrescoRmiPort) + { + this.defaultAlfRmiPort = defaultAlfrescoRmiPort; + } + + /** + * Sets the default RMI port for File system deployments + * + * @param defaultReceiverRmiPort port number + */ + public void setDefaultReceiverRmiPort(int defaultReceiverRmiPort) + { + this.defaultReceiverRmiPort = defaultReceiverRmiPort; + } + + /** + * Sets the default remote username to use for deployments + * + * @param defaultRemoteUsername Default remote username + */ + public void setDefaultRemoteUsername(String defaultRemoteUsername) + { + this.defaultRemoteUsername = defaultRemoteUsername; + } + + /** + * Sets the default remote password to use for deployments + * + * @param defaultRemotePassword Default remote password + */ + public void setDefaultRemotePassword(String defaultRemotePassword) + { + this.defaultRemotePassword = defaultRemotePassword; + } + + /** + * Sets the default target name to use on file system receivers + * + * @param defaultTargetName Default target name + */ + public void setDefaultTargetName(String defaultTargetName) + { + this.defaultTargetName = defaultTargetName; + } + /** * @param service The NodeService instance */ @@ -112,20 +204,12 @@ public class AVMDeploySnapshotAction extends ActionExecuterAbstractBase { paramList.add(new ParameterDefinitionImpl(PARAM_WEBSITE, DataTypeDefinition.NODE_REF, true, getParamDisplayLabel(PARAM_WEBSITE))); - paramList.add(new ParameterDefinitionImpl(PARAM_TARGET_SERVER, DataTypeDefinition.TEXT, true, - getParamDisplayLabel(PARAM_TARGET_SERVER))); - paramList.add(new ParameterDefinitionImpl(PARAM_DEFAULT_RMI_PORT, DataTypeDefinition.INT, true, - getParamDisplayLabel(PARAM_DEFAULT_RMI_PORT))); - paramList.add(new ParameterDefinitionImpl(PARAM_DEFAULT_RECEIVER_RMI_PORT, DataTypeDefinition.INT, true, - getParamDisplayLabel(PARAM_DEFAULT_RECEIVER_RMI_PORT))); - paramList.add(new ParameterDefinitionImpl(PARAM_REMOTE_USERNAME, DataTypeDefinition.TEXT, true, - getParamDisplayLabel(PARAM_REMOTE_USERNAME))); - paramList.add(new ParameterDefinitionImpl(PARAM_REMOTE_PASSWORD, DataTypeDefinition.TEXT, true, - getParamDisplayLabel(PARAM_REMOTE_PASSWORD))); + paramList.add(new ParameterDefinitionImpl(PARAM_SERVER, DataTypeDefinition.NODE_REF, true, + getParamDisplayLabel(PARAM_SERVER))); + paramList.add(new ParameterDefinitionImpl(PARAM_ATTEMPT, DataTypeDefinition.NODE_REF, false, + getParamDisplayLabel(PARAM_ATTEMPT))); paramList.add(new ParameterDefinitionImpl(PARAM_CALLBACK, DataTypeDefinition.ANY, false, getParamDisplayLabel(PARAM_CALLBACK))); - paramList.add(new ParameterDefinitionImpl(PARAM_DELAY, DataTypeDefinition.INT, false, - getParamDisplayLabel(PARAM_DELAY))); } @Override @@ -151,40 +235,81 @@ public class AVMDeploySnapshotAction extends ActionExecuterAbstractBase ") provided does not exist!"); } + // get the NodeRef representing the server to deploy to + NodeRef serverRef = (NodeRef)action.getParameterValue(PARAM_SERVER); + if (this.nodeService.exists(serverRef) == false) + { + throw new IllegalStateException("The server NodeRef (" + serverRef + + ") provided does not exist!"); + } + + // get the NodeRef representing the deployment attempt this one is part of + NodeRef attemptRef = (NodeRef)action.getParameterValue(PARAM_ATTEMPT); + + // TODO: if attempt reference is null create one now for this deployment, for now throw error + if (this.nodeService.exists(attemptRef) == false) + { + throw new IllegalStateException("The attempt NodeRef (" + serverRef + + ") provided does not exist!"); + } + // get the callback object DeploymentCallback callback = (DeploymentCallback)action.getParameterValue(PARAM_CALLBACK); - // get the remote machine - String targetServer = (String)action.getParameterValue(PARAM_TARGET_SERVER); - String remoteUsername = (String)action.getParameterValue(PARAM_REMOTE_USERNAME); - String remotePassword = (String)action.getParameterValue(PARAM_REMOTE_PASSWORD); - int defaultAlfRmiPort = (Integer)action.getParameterValue(PARAM_DEFAULT_RMI_PORT); - int defaultReceiverRmiPort = (Integer)action.getParameterValue(PARAM_DEFAULT_RECEIVER_RMI_PORT); - int delay = -1; - if (action.getParameterValue(PARAM_DELAY) != null) - { - delay = (Integer)action.getParameterValue(PARAM_DELAY); - } + // get the other data from the deploymentserver object + Map serverProps = nodeService.getProperties(serverRef); + String serverUri = calculateServerUri(serverProps); + String host = (String)serverProps.get(WCMAppModel.PROP_DEPLOYSERVERHOST); + Integer port = (Integer)serverProps.get(WCMAppModel.PROP_DEPLOYSERVERPORT); + String remoteUsername = (String)serverProps.get(WCMAppModel.PROP_DEPLOYSERVERUSERNAME); + String remotePassword = (String)serverProps.get(WCMAppModel.PROP_DEPLOYSERVERPASSWORD); + boolean fileServerDeployment = WCMAppModel.CONSTRAINT_FILEDEPLOY.equals( + serverProps.get(WCMAppModel.PROP_DEPLOYTYPE)); + String sourcePath = (String)serverProps.get(WCMAppModel.PROP_DEPLOYSOURCEPATH); + String targetName = (String)serverProps.get(WCMAppModel.PROP_DEPLOYSERVERTARGET); + String targetPath = path; - // determine whether this is a file server or Alfresco server deployment - boolean fileServerDeployment = false; - if (targetServer.startsWith(FILE_SERVER_PREFIX)) - { - fileServerDeployment = true; - } + // TODO: determine if we need to deploy a subfolder of the website - // if "localhost" is passed as the target server add "live" to the end of the - // store name, this store will then get created automatically. - String targetPath = null; - if (targetServer.equalsIgnoreCase("localhost") || targetServer.equalsIgnoreCase("127.0.0.1")) + if (fileServerDeployment == false) { - targetPath = storePath[0] + "live:" + storePath[1]; - } - else - { - // TODO: Check that the actual host name of the machine hasn't been passed + // if "localhost" is passed as the target server add "live" to the end of the + // store name, this store will then get created automatically. - targetPath = path; + // TODO: Check that the actual host name of the machine hasn't been passed + + if (port == null && (host.equalsIgnoreCase("localhost") || host.equalsIgnoreCase("127.0.0.1"))) + { + targetPath = storePath[0] + "live:" + storePath[1]; + } + } + + // get defaults for data not provided in server node + if (port == null) + { + if (fileServerDeployment) + { + port = this.defaultReceiverRmiPort; + } + else + { + port = this.defaultAlfRmiPort; + } + } + + if (remoteUsername == null || remoteUsername.length() == 0) + { + remoteUsername = this.defaultRemoteUsername; + } + + if (remotePassword == null || remotePassword.length() == 0) + { + remotePassword = this.defaultRemotePassword; + } + + if (targetName == null || targetName.length() == 0) + { + targetName = this.defaultTargetName; } // take a note of the current date/time @@ -192,7 +317,7 @@ public class AVMDeploySnapshotAction extends ActionExecuterAbstractBase if (logger.isDebugEnabled()) logger.debug("Starting deployment of " + actionedUponNodeRef.toString() + - " to " + targetServer + " at " + startDate); + " to " + serverUri + " at " + startDate); if (delayDeploymentLogger.isDebugEnabled() && delay > 0) { @@ -207,46 +332,24 @@ public class AVMDeploySnapshotAction extends ActionExecuterAbstractBase DeploymentReport report = null; try { - String host = targetServer; - int port = defaultAlfRmiPort; - if (fileServerDeployment) - { - port = defaultReceiverRmiPort; - } - - // check whether there is a port number present, if so, use it - int idx = targetServer.indexOf(":"); - if (idx != -1) - { - host = targetServer.substring(0, idx); - String strPort = targetServer.substring(idx+1); - port = Integer.parseInt(strPort); - } - - // TODO: we need to capture username/password for the remote server at some - // point, for now we use the configured username/password for all servers - // call the appropriate method to deploy if (fileServerDeployment) { - // remove the prefixed \\ - host = host.substring(FILE_SERVER_PREFIX.length()); - if (logger.isDebugEnabled()) logger.debug("Performing file server deployment to " + host + ":" + port); - // TODO Added new NameMatcher parameter to deploy methods. It acts as a filter. - // Any matching path names are ignored for deployment purposes. + // TODO: Added new NameMatcher parameter to deploy methods. It acts as a filter. + // Any matching path names are ignored for deployment purposes. report = this.deployService.deployDifferenceFS(version, path, host, port, - remoteUsername, remotePassword, "default", null, true, false, false, callback); + remoteUsername, remotePassword, targetName, null, true, false, false, callback); } else { if (logger.isDebugEnabled()) logger.debug("Performing Alfresco deployment to " + host + ":" + port); - // TODO Added new NameMatcher parameter to deploy methods. It acts as a filter. - // Any matching path names are ignored for deployment purposes. + // TODO: Added new NameMatcher parameter to deploy methods. It acts as a filter. + // Any matching path names are ignored for deployment purposes. report = this.deployService.deployDifference(version, path, host, port, remoteUsername, remotePassword, targetPath, null, true, false, false, callback); } @@ -279,16 +382,17 @@ public class AVMDeploySnapshotAction extends ActionExecuterAbstractBase if (report != null) { if (logger.isDebugEnabled()) - logger.debug("Differences successfully applied to " + targetServer); + logger.debug("Differences successfully applied to " + serverUri); } else { if (logger.isDebugEnabled()) - logger.debug("Failed to apply differences to " + targetServer); + logger.debug("Failed to apply differences to " + serverUri); } // create the deployment report node - createDeploymentReportNode(report, targetServer, version, websiteRef, startDate, deployError); + createDeploymentReportNode(report, attemptRef, serverProps, version, + websiteRef, startDate, deployError); } /** @@ -296,7 +400,8 @@ public class AVMDeploySnapshotAction extends ActionExecuterAbstractBase * * @param report The DeploymentReport result from the deploy, * will be null if the deploy failed - * @param targetServer The server the deploy was going to + * @param attempt NodeRef of the attempt the deploy was part of + * @param serverProps The properties of the server the deploy was going to * @param version The version of the site bebing deployed (the snapshot) * @param websiteRef The NodeRef of the folder representing the website * @param startDate The date/time the deployment started @@ -304,30 +409,38 @@ public class AVMDeploySnapshotAction extends ActionExecuterAbstractBase * deployment was successful * @return The created deployment report NodeRef */ - private NodeRef createDeploymentReportNode(DeploymentReport report, String targetServer, - int version, NodeRef websiteRef, Date startDate, Throwable error) + private NodeRef createDeploymentReportNode(DeploymentReport report, NodeRef attempt, + Map serverProps, int version, NodeRef websiteRef, + Date startDate, Throwable error) { NodeRef reportRef = null; - // remove illegal chars from the target server name to create the report name - String reportName = targetServer.replace(':', '_').replace('\\', '_') + - " deployment report.txt"; + String serverUri = calculateServerUri(serverProps); + Map reportProps = new HashMap(4, 1.0f); + reportProps.put(WCMAppModel.PROP_DEPLOYSERVER, serverUri); + reportProps.put(WCMAppModel.PROP_DEPLOYVERSION, version); + reportProps.put(WCMAppModel.PROP_DEPLOYSTARTTIME, startDate); + reportProps.put(WCMAppModel.PROP_DEPLOYENDTIME, new Date()); + reportProps.put(WCMAppModel.PROP_DEPLOYSERVERNAMEUSED, + serverProps.get(WCMAppModel.PROP_DEPLOYSERVERNAME)); + reportProps.put(WCMAppModel.PROP_DEPLOYSERVERUSERNAMEUSED, + serverProps.get(WCMAppModel.PROP_DEPLOYSERVERUSERNAME)); + reportProps.put(WCMAppModel.PROP_DEPLOYSERVERTARGETUSED, + serverProps.get(WCMAppModel.PROP_DEPLOYSERVERTARGET)); + reportProps.put(WCMAppModel.PROP_DEPLOYSOURCEPATHUSED, + serverProps.get(WCMAppModel.PROP_DEPLOYSOURCEPATH)); + reportProps.put(WCMAppModel.PROP_DEPLOYSERVERURLUSED, + serverProps.get(WCMAppModel.PROP_DEPLOYSERVERURL)); - Map props = new HashMap(4, 1.0f); - props.put(ContentModel.PROP_NAME, reportName); - props.put(WCMAppModel.PROP_DEPLOYSERVER, targetServer); - props.put(WCMAppModel.PROP_DEPLOYVERSION, version); - props.put(WCMAppModel.PROP_DEPLOYSTARTTIME, startDate); - props.put(WCMAppModel.PROP_DEPLOYENDTIME, new Date()); - props.put(WCMAppModel.PROP_DEPLOYSUCCESSFUL, (report != null)); + reportProps.put(WCMAppModel.PROP_DEPLOYSUCCESSFUL, (report != null)); if (report == null && error != null) { // add error message as fail reason if appropriate - props.put(WCMAppModel.PROP_DEPLOYFAILEDREASON, error.getMessage()); + reportProps.put(WCMAppModel.PROP_DEPLOYFAILEDREASON, error.getMessage()); } - reportRef = this.nodeService.createNode(websiteRef, - WCMAppModel.ASSOC_DEPLOYMENTREPORT, WCMAppModel.ASSOC_DEPLOYMENTREPORT, - WCMAppModel.TYPE_DEPLOYMENTREPORT, props).getChildRef(); + reportRef = this.nodeService.createNode(attempt, + WCMAppModel.ASSOC_DEPLOYMENTREPORTS, WCMAppModel.ASSOC_DEPLOYMENTREPORT, + WCMAppModel.TYPE_DEPLOYMENTREPORT, reportProps).getChildRef(); ContentWriter writer = contentService.getWriter(reportRef, ContentModel.PROP_CONTENT, true); writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN); writer.setEncoding("UTF-8"); @@ -363,8 +476,8 @@ public class AVMDeploySnapshotAction extends ActionExecuterAbstractBase } if (logger.isDebugEnabled()) - logger.debug("Created deplyoment report node (" + reportRef + ") for targetServer " + - targetServer); + logger.debug("Created deplyoment report node (" + reportRef + ") for server " + + serverUri); return reportRef; } diff --git a/source/java/org/alfresco/sandbox/SandboxConstants.java b/source/java/org/alfresco/sandbox/SandboxConstants.java index 345a65ca18..6063a4bda1 100644 --- a/source/java/org/alfresco/sandbox/SandboxConstants.java +++ b/source/java/org/alfresco/sandbox/SandboxConstants.java @@ -51,4 +51,5 @@ public class SandboxConstants public final static QName PROP_AUTHOR_NAME = QName.createQName(null, ".author.name"); public final static QName PROP_WEB_PROJECT_NODE_REF = QName.createQName(null, ".web_project.noderef"); public final static QName PROP_LINK_VALIDATION_REPORT = QName.createQName(null, ".link.validation.report"); + public final static QName PROP_LAST_DEPLOYMENT_ID = QName.createQName(null, ".deployment.id"); }