/* * 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.web.bean.wcm; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; import javax.faces.context.FacesContext; import javax.faces.event.ActionEvent; import javax.transaction.UserTransaction; import org.alfresco.config.JNDIConstants; import org.alfresco.model.ContentModel; import org.alfresco.model.WCMAppModel; import org.alfresco.model.WCMWorkflowModel; import org.alfresco.repo.avm.AVMDAOs; import org.alfresco.repo.avm.AVMNodeConverter; import org.alfresco.repo.avm.wf.AVMSubmittedAspect; import org.alfresco.repo.domain.PropertyValue; import org.alfresco.repo.workflow.WorkflowModel; import org.alfresco.service.cmr.avm.AVMNodeDescriptor; import org.alfresco.service.cmr.avm.AVMService; import org.alfresco.service.cmr.avmsync.AVMDifference; import org.alfresco.service.cmr.avmsync.AVMSyncService; 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.workflow.WorkflowDefinition; import org.alfresco.service.cmr.workflow.WorkflowPath; import org.alfresco.service.cmr.workflow.WorkflowService; import org.alfresco.service.cmr.workflow.WorkflowTask; import org.alfresco.service.cmr.workflow.WorkflowTaskState; import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.util.ISO8601DateFormat; import org.alfresco.util.NameMatcher; import org.alfresco.web.app.Application; import org.alfresco.web.app.servlet.DownloadContentServlet; import org.alfresco.web.bean.BrowseBean; import org.alfresco.web.bean.dialog.BaseDialogBean; import org.alfresco.web.bean.repository.Repository; import org.alfresco.web.config.ClientConfigElement; import org.alfresco.web.forms.FormInstanceData; import org.alfresco.web.forms.FormInstanceDataImpl; import org.alfresco.web.forms.Rendition; import org.alfresco.web.ui.common.Utils; import org.alfresco.web.ui.common.component.UIListItem; import org.alfresco.web.ui.wcm.WebResources; import org.alfresco.util.VirtServerUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Submit items for WCM workflow dialog. * * @author Kevin Roast */ public class SubmitDialog extends BaseDialogBean { public static final String PARAM_STARTED_FROM_WORKFLOW = "startedFromWorkflow"; private static final String SPACE_ICON = "/images/icons/" + BrowseBean.SPACE_SMALL_DEFAULT + ".gif"; private static final String MSG_DELETED_ITEM = "avm_node_deleted"; private static final String MSG_ERR_WORKFLOW_CONFIG = "submit_workflow_config_error"; private String comment; private String label; private String[] workflowSelectedValue; private boolean enteringExpireDate = false; private boolean startedFromWorkflow = false; private Date defaultExpireDate; private Date launchDate; private List submitItems; private List warningItems; private HashSet workflows; private Map formWorkflowMap; private Map expirationDates; private List workflowItems; // The virtualization server might need to be notified // because one or more of the files submitted could alter // the behavior the virtual webapp in the target of the submit. // For example, the user might be submitting a new jar or web.xml file. // // This must take place after the transaction has been completed; // therefore, a variable is needed to store the path to the // updated webapp so it can happen in doPostCommitProcessing. private String virtUpdatePath; protected AVMService avmService; protected AVMSubmittedAspect avmSubmittedAspect; protected AVMBrowseBean avmBrowseBean; protected WorkflowService workflowService; protected AVMSyncService avmSyncService; protected NameMatcher nameMatcher; /** Current workflow for dialog context */ protected WorkflowConfiguration actionWorkflow = null; private static Log logger = LogFactory.getLog(SubmitDialog.class); /** * @param avmService The AVM Service to set. */ public void setAvmService(AVMService avmService) { this.avmService = avmService; } /** * @param avmSubmittedAspect The AVM Submitted Aspect to set. */ public void setAvmSubmittedAspect(AVMSubmittedAspect avmSubmittedAspect) { this.avmSubmittedAspect = avmSubmittedAspect; } /** * @param avmSyncService The AVMSyncService to set. */ public void setAvmSyncService(AVMSyncService avmSyncService) { this.avmSyncService = avmSyncService; } /** * @param avmBrowseBean The AVM BrowseBean to set */ public void setAvmBrowseBean(AVMBrowseBean avmBrowseBean) { this.avmBrowseBean = avmBrowseBean; } /** * @param workflowService The WorkflowService to set. */ public void setWorkflowService(WorkflowService workflowService) { this.workflowService = workflowService; } /** * @param nameMatcher The nameMatcher to set. */ public void setNameMatcher(NameMatcher nameMatcher) { this.nameMatcher = nameMatcher; } /** * @see org.alfresco.web.bean.dialog.BaseDialogBean#init(java.util.Map) */ @Override public void init(Map parameters) { super.init(parameters); this.comment = null; this.label = null; this.submitItems = null; this.warningItems = null; this.workflowItems = null; this.workflows = new HashSet(4); this.expirationDates = new HashMap(8); this.defaultExpireDate = new Date(); this.workflowSelectedValue = null; this.launchDate = null; // determine if the dialog has been started from a workflow Boolean bool = new Boolean(this.parameters.get(PARAM_STARTED_FROM_WORKFLOW)); this.startedFromWorkflow = bool; // walk all the web forms attached the website, and lookup the workflow defaults for each NodeRef websiteRef = this.avmBrowseBean.getWebsite().getNodeRef(); List webFormRefs = this.nodeService.getChildAssocs( websiteRef, WCMAppModel.ASSOC_WEBFORM, RegexQNamePattern.MATCH_ALL); this.formWorkflowMap = new HashMap(webFormRefs.size(), 1.0f); for (ChildAssociationRef ref : webFormRefs) { NodeRef webFormRef = ref.getChildRef(); String form = (String)this.nodeService.getProperty(webFormRef, WCMAppModel.PROP_FORMNAME); List wfRefs = this.nodeService.getChildAssocs( webFormRef, WCMAppModel.TYPE_WORKFLOW_DEFAULTS, RegexQNamePattern.MATCH_ALL); if (wfRefs.size() == 1) { NodeRef wfDefaultsRef = wfRefs.get(0).getChildRef(); String wfName = (String)this.nodeService.getProperty(wfDefaultsRef, WCMAppModel.PROP_WORKFLOW_NAME); Map params = (Map)AVMWorkflowUtil.deserializeWorkflowParams( wfDefaultsRef); this.formWorkflowMap.put(form, new FormWorkflowWrapper(wfName, params)); } } } /** * @see org.alfresco.web.bean.dialog.BaseDialogBean#finishImpl(javax.faces.context.FacesContext, java.lang.String) */ @Override protected String finishImpl(FacesContext context, String outcome) throws Exception { if (getSubmitItemsSize() == 0) { return null; } // get the defaults from the workflow configuration attached to the selected workflow if (this.workflowSelectedValue != null) { Map params = null; String workflowName = this.workflowSelectedValue[0]; for (FormWorkflowWrapper wrapper : this.workflows) { if (wrapper.name.equals(workflowName)) { params = wrapper.params; } } if (params != null) { // start the workflow to get access to the start task WorkflowDefinition wfDef = workflowService.getDefinitionByName(workflowName); WorkflowPath path = this.workflowService.startWorkflow(wfDef.id, null); if (path != null) { // extract the start task List tasks = this.workflowService.getTasksForWorkflowPath(path.id); if (tasks.size() == 1) { WorkflowTask startTask = tasks.get(0); if (startTask.state == WorkflowTaskState.IN_PROGRESS) { // Create workflow sandbox for workflow package SandboxInfo sandboxInfo = SandboxFactory.createWorkflowSandbox( this.avmBrowseBean.getStagingStore() ); // create container for our avm workflow package final List items = this.getSubmitItems(); final List srcPaths = new ArrayList(items.size()); for (ItemWrapper wrapper : items) { // Example srcPath: // mysite--alice:/www/avm_webapps/ROOT/foo.txt String srcPath = wrapper.getDescriptor().getPath(); // We *always* want to update virtualization server // when a workflow sandbox is given data in the // context of a submit workflow. Without this, // it would be impossible to see workflow data // in context. The raw operation to create a // workflow sandbox does not notify the virtualization // server that it exists because it's useful to // defer this operation until everything is already // in place; this allows pointlessly fine-grained // notifications to be suppressed (they're expensive). // // Therefore, just derive the name of the webapp // in the workflow sandbox from the 1st item in // the submiot list (even if it's not in WEB-INF), // and force the virt server notification after the // transaction has completed via doPostCommitProcessing. if (this.virtUpdatePath == null) { // Example workflow main store name: // mysite--workflow-9161f640-b020-11db-8015-130bf9b5b652 String workflowMainStoreName = sandboxInfo.getMainStoreName(); // The virtUpdatePath looks just like the srcPath // except that it belongs to a the main store of // the workflow sandbox instead of the sandbox // that originated the submit. this.virtUpdatePath = workflowMainStoreName + srcPath.substring(srcPath.indexOf(':'),srcPath.length()); } // process the expiration date (if any) processExpirationDate(srcPath); srcPaths.add(srcPath); } final NodeRef workflowPackage = AVMWorkflowUtil.createWorkflowPackage(srcPaths, sandboxInfo, path, this.avmSubmittedAspect, this.avmSyncService, this.avmService, this.workflowService, this.nodeService); params.put(WorkflowModel.ASSOC_PACKAGE, workflowPackage); // add submission parameters params.put(WorkflowModel.PROP_WORKFLOW_DESCRIPTION, getComment()); params.put(WCMWorkflowModel.PROP_LABEL, getLabel()); params.put(WCMWorkflowModel.PROP_FROM_PATH, AVMUtil.buildStoreRootPath(this.avmBrowseBean.getSandbox())); params.put(WCMWorkflowModel.PROP_LAUNCH_DATE, this.launchDate); params.put(WCMWorkflowModel.ASSOC_WEBPROJECT, this.avmBrowseBean.getWebsite().getNodeRef()); // update start task with submit parameters this.workflowService.updateTask(startTask.id, params, null, null); // end the start task to trigger the first 'proper' task in the workflow this.workflowService.endTask(startTask.id, null); } } } } else { // create error msg for display in dialog - the user must configure the workflow params Utils.addErrorMessage(Application.getMessage(context, MSG_ERR_WORKFLOW_CONFIG)); outcome = null; // set the isFinished flag to allow the dialog to be finished again after the error isFinished = true; } } else { // direct submit to the staging area without workflow List items = getSubmitItems(); // construct diffs for selected items for submission String sandboxPath = AVMUtil.buildSandboxRootPath(this.avmBrowseBean.getSandbox()); String stagingPath = AVMUtil.buildSandboxRootPath(this.avmBrowseBean.getStagingStore()); List diffs = new ArrayList(items.size()); for (ItemWrapper wrapper : items) { String srcPath = sandboxPath + wrapper.getPath(); String destPath = stagingPath + wrapper.getPath(); AVMDifference diff = new AVMDifference(-1, srcPath, -1, destPath, AVMDifference.NEWER); diffs.add(diff); // If nothing has required notifying the virtualization server // so far, check to see if destPath forces a notification // (e.g.: it might be a path to a jar file within WEB-INF/lib). if ( (this.virtUpdatePath == null) && VirtServerUtils.requiresUpdateNotification( destPath ) ) { this.virtUpdatePath = destPath; } // process the expiration date (if any) processExpirationDate(srcPath); } // write changes to layer so files are marked as modified this.avmSyncService.update(diffs, null, true, true, false, false, this.label, this.comment); AVMDAOs.Instance().fAVMNodeDAO.flush(); avmSyncService.flatten(sandboxPath, stagingPath); } return outcome; } /** * Handle notification to the virtualization server * (this needs to occur after the sandbox is updated). */ @Override protected String doPostCommitProcessing(FacesContext context, String outcome) { // Force the update because we've already determined // that update_path requires virt server notification. if (this.virtUpdatePath != null) { // Examples of destPath that require virt server notification: // // mysite:/www/avm_webapps/ROOT/WEB-INF/web.xml // mysite:/www/avm_webapps/ROOT/WEB-INF/lib/moo.jar AVMUtil.updateVServerWebapp(this.virtUpdatePath, true); } return outcome; } /** * @see org.alfresco.web.bean.dialog.BaseDialogBean#getFinishButtonDisabled() */ @Override public boolean getFinishButtonDisabled() { return (getSubmitItemsSize() == 0); } /** * @return Returns the workflow comment. */ public String getComment() { return this.comment; } /** * @param comment The workflow comment to set. */ public void setComment(String comment) { this.comment = comment; } /** * @return Returns the snapshot label. */ public String getLabel() { return this.label; } /** * @param label The snapshot label to set. */ public void setLabel(String label) { this.label = label; } /** * @return The default expiration date */ public Date getDefaultExpireDate() { return this.defaultExpireDate; } /** * @param defaultExpireDate The default expiration date */ public void setDefaultExpireDate(Date defaultExpireDate) { this.defaultExpireDate = defaultExpireDate; } /** * @return true if a default expiration date is being entered */ public boolean isEnteringExpireDate() { return this.enteringExpireDate; } /** * @return Map of expiration dates for the modified items */ public Map getExpiredDates() { return this.expirationDates; } /** * @return Returns the workflow Selected Value. */ public String[] getWorkflowSelectedValue() { return this.workflowSelectedValue; } /** * @param workflowSelectedValue The workflow Selected Value to set. */ public void setWorkflowSelectedValue(String[] workflowSelectedValue) { this.workflowSelectedValue = workflowSelectedValue; } /** * @return Returns the content launch date */ public Date getLaunchDate() { return this.launchDate; } /** * @param launchDate The content launch date */ public void setLaunchDate(Date launchDate) { this.launchDate = launchDate; } /** * @return List of UIListItem object representing the available workflows for the website */ public List getWorkflowList() { if (this.workflowItems == null) { // ensure all workflows have been collected from any form generated assets calcluateListItemsAndWorkflows(); // add the list of workflows for the website itself to the set NodeRef websiteRef = this.avmBrowseBean.getWebsite().getNodeRef(); List webWorkflowRefs = this.nodeService.getChildAssocs( websiteRef, WCMAppModel.ASSOC_WEBWORKFLOWDEFAULTS, RegexQNamePattern.MATCH_ALL); List workflowMatchers = new ArrayList(webWorkflowRefs.size()); for (ChildAssociationRef ref : webWorkflowRefs) { NodeRef wfDefaultsRef = ref.getChildRef(); String wfName = (String)this.nodeService.getProperty(wfDefaultsRef, WCMAppModel.PROP_WORKFLOW_NAME); Map params = (Map)AVMWorkflowUtil.deserializeWorkflowParams( wfDefaultsRef); String matchPattern = (String)this.nodeService.getProperty( wfDefaultsRef, WCMAppModel.PROP_FILENAMEPATTERN); if (matchPattern != null) { // add to temp list with the file name pattern workflowMatchers.add(new FormWorkflowWrapper(wfName, params, matchPattern)); } } // perform match on each submitted file against available workflows for (ItemWrapper wrapper : this.submitItems) { String path = wrapper.getPath(); // shallow copy the list of matchers so we can remove items while looping List matchers = new ArrayList(workflowMatchers); for (int i=0; i items = new ArrayList(this.workflows.size()); for (FormWorkflowWrapper wrapper : this.workflows) { WorkflowDefinition workflowDef = this.workflowService.getDefinitionByName(wrapper.name); UIListItem item = new UIListItem(); item.setValue(workflowDef.getName()); String label = workflowDef.getTitle(); String desc = workflowDef.getDescription(); if (desc != null && desc.length() > 0) { label = label + "(" + desc + ")"; } item.setLabel(label); items.add(item); // add first workflow as default selection if (workflowSelectedValue == null) { workflowSelectedValue = new String[]{workflowDef.getName()}; } } this.workflowItems = items; } return this.workflowItems; } /** * @return size of the workflow selection list */ public int getWorkflowListSize() { return getWorkflowList().size(); } /** * @return the List of bean items to show in the Submit list */ public List getSubmitItems() { if (this.submitItems == null) { // this method builds all submit and warning item data structures calcluateListItemsAndWorkflows(); } return this.submitItems; } /** * @return size of the submit list */ public int getSubmitItemsSize() { return getSubmitItems().size(); } /** * @return the List of bean items to show in the Warning list */ public List getWarningItems() { if (this.warningItems == null) { // this method builds all submit and warning item data structures calcluateListItemsAndWorkflows(); } return this.warningItems; } /** * @return size of the warning list */ public int getWarningItemsSize() { return this.getWarningItems().size(); } /** * Calculate the lists of Submittable Items, Warning items and the list of available workflows. */ private void calcluateListItemsAndWorkflows() { UserTransaction tx = null; try { FacesContext context = FacesContext.getCurrentInstance(); tx = Repository.getUserTransaction(context, true); tx.begin(); List selected; if (this.startedFromWorkflow) { // if the dialog was started from a workflow the AVM browse bean should // have the list of nodes that need submitting selected = this.avmBrowseBean.getExpiredNodes(); } else { // if the dialog was started from the UI determine what nodes the user selected to submit if (this.avmBrowseBean.getAllItemsAction()) { String webapp = this.avmBrowseBean.getWebapp(); String userStore = AVMUtil.buildStoreWebappPath(this.avmBrowseBean.getSandbox(), webapp); String stagingStore = AVMUtil.buildStoreWebappPath(this.avmBrowseBean.getStagingStore(), webapp); List diffs = this.avmSyncService.compare(-1, userStore, -1, stagingStore, nameMatcher); selected = new ArrayList(diffs.size()); for (AVMDifference diff : diffs) { AVMNodeDescriptor node = this.avmService.lookup(-1, diff.getSourcePath(), true); selected.add(node); } } else if (this.avmBrowseBean.getAvmActionNode() == null) { // multiple items selected selected = this.avmBrowseBean.getSelectedSandboxItems(); } else { // single item selected AVMNodeDescriptor node = this.avmService.lookup(-1, this.avmBrowseBean.getAvmActionNode().getPath(), true); selected = new ArrayList(1); selected.add(node); } } if (selected != null) { Set submittedPaths = new HashSet(selected.size()); this.submitItems = new ArrayList(selected.size()); this.warningItems = new ArrayList(selected.size() >> 1); for (AVMNodeDescriptor node : selected) { if (this.avmService.hasAspect(-1, node.getPath(), AVMSubmittedAspect.ASPECT) == false) { NodeRef ref = AVMNodeConverter.ToNodeRef(-1, node.getPath()); if (submittedPaths.contains(node.getPath()) == false) { if (node.isDeleted() == false) { // lookup if this item was created via a form - then lookup the workflow defaults // for that form and store into the list of available workflows if (this.nodeService.hasAspect(ref, WCMAppModel.ASPECT_FORM_INSTANCE_DATA)) { NodeRef formInstanceDataRef = ref; // check if this is a rendition - as they also have the forminstancedata aspect if (this.nodeService.hasAspect(ref, WCMAppModel.ASPECT_RENDITION)) { // found a generated rendition asset - locate the parent form instance data file // and use this to find all generated assets that are appropriate // NOTE: this path value is store relative String strFormInstance = (String)this.nodeService.getProperty( ref, WCMAppModel.PROP_PRIMARY_FORM_INSTANCE_DATA); strFormInstance = this.avmBrowseBean.getSandbox() + ':' + strFormInstance; formInstanceDataRef = AVMNodeConverter.ToNodeRef(-1, strFormInstance); } // add the form instance data file to the list for submission AVMNodeDescriptor formInstanceNode = this.avmService.lookup( -1, AVMNodeConverter.ToAVMVersionPath(formInstanceDataRef).getSecond()); if (submittedPaths.contains(formInstanceNode.getPath()) == false) { this.submitItems.add(new ItemWrapper(formInstanceNode)); submittedPaths.add(formInstanceNode.getPath()); } // locate renditions for this form instance data file and add to list for submission FormInstanceData formImpl = new FormInstanceDataImpl(formInstanceDataRef); for (Rendition rendition : formImpl.getRenditions()) { String renditionPath = rendition.getPath(); if (submittedPaths.contains(renditionPath) == false) { AVMNodeDescriptor renditionNode = this.avmService.lookup(-1, renditionPath); this.submitItems.add(new ItemWrapper(renditionNode)); submittedPaths.add(renditionPath); } } // lookup the associated Form workflow from the parent form property String formName = (String)this.nodeService.getProperty( formInstanceDataRef, WCMAppModel.PROP_PARENT_FORM_NAME); FormWorkflowWrapper wrapper = this.formWorkflowMap.get(formName); if (wrapper != null) { // found a workflow attached to the form this.workflows.add(wrapper); } } else { this.submitItems.add(new ItemWrapper(node)); submittedPaths.add(node.getPath()); } } else { // found a deleted node for submit this.submitItems.add(new ItemWrapper(node)); submittedPaths.add(node.getPath()); } } } else { this.warningItems.add(new ItemWrapper(node)); } } } else { this.submitItems = Collections.emptyList(); this.warningItems = Collections.emptyList(); } tx.commit(); } catch (Throwable e) { // rollback the transaction on error try { if (tx != null) {tx.rollback();} } catch (Exception ex) {} } } /** * Sets up the expiration date for the given source path * * @param srcPath The path to set the expiration date for */ private void processExpirationDate(String srcPath) { // if an expiration date has been set for this item we need to // add the expires aspect and the date supplied Date expirationDate = this.expirationDates.get(srcPath); if (expirationDate != null) { // make sure the aspect is present if (this.avmService.hasAspect(-1, srcPath, WCMAppModel.ASPECT_EXPIRES) == false) { this.avmService.addAspect(srcPath, WCMAppModel.ASPECT_EXPIRES); } // set the expiration date this.avmService.setNodeProperty(srcPath, WCMAppModel.PROP_EXPIRATIONDATE, new PropertyValue(DataTypeDefinition.DATETIME, expirationDate)); if (logger.isDebugEnabled()) logger.debug("Set expiration date of " + expirationDate + " for " + srcPath); } } /** * Action method to setup a workflow for dialog context for the current row */ public void setupConfigureWorkflow(ActionEvent event) { if (this.workflowSelectedValue != null) { String workflowName = this.workflowSelectedValue[0]; for (WorkflowConfiguration wrapper : this.workflows) { if (wrapper.getName().equals(workflowName)) { setActionWorkflow(wrapper); } } } } /** * @return Returns the action Workflow for dialog context */ public WorkflowConfiguration getActionWorkflow() { return this.actionWorkflow; } /** * @param actionWorkflow The action Workflow to set for dialog context */ public void setActionWorkflow(WorkflowConfiguration actionWorkflow) { this.actionWorkflow = actionWorkflow; } /** * Applies the entered default date to all modified items * * @param event The event */ public void applyDefaultExpireDateToAll(ActionEvent event) { if (logger.isDebugEnabled()) logger.debug("applying default expiration date of " + this.defaultExpireDate + " to all modified items"); List items = this.getSubmitItems(); for (ItemWrapper item : items) { if (item.descriptor.getType() == 0) { this.expirationDates.put(item.descriptor.getPath(), this.defaultExpireDate); } } this.enteringExpireDate = false; } /** * Toggles the enteringExpireDate flag * * @param event The event */ public void enterExpireDate(ActionEvent event) { this.enteringExpireDate = true; } /** * Simple structure class to wrap form workflow name and default parameter values */ private static class FormWorkflowWrapper implements WorkflowConfiguration { private String name; private Map params; private QName type; private String strFilenamePattern; private Pattern filenamePattern; FormWorkflowWrapper(String name, Map params) { this.name = name; this.params = params; } FormWorkflowWrapper(String name, Map params, String filenamePattern) { this.name = name; this.params = params; setFilenamePattern(filenamePattern); } public String getName() { return this.name; } public String getFilenamePattern() { return this.strFilenamePattern; } public void setFilenamePattern(String pattern) { if (pattern != null) { this.strFilenamePattern = pattern; this.filenamePattern = Pattern.compile(pattern); } } public Map getParams() { return this.params; } public void setParams(Map params) { this.params = params; } public QName getType() { return this.type; } public void setType(QName type) { this.type = type; } boolean matchesPath(String path) { if (filenamePattern != null) { return filenamePattern.matcher(path).matches(); } else { return false; } } @Override public int hashCode() { return this.name.hashCode(); } @Override public boolean equals(Object obj) { if (obj instanceof FormWorkflowWrapper) { return this.name.equals( ((FormWorkflowWrapper)obj).name ); } else { return false; } } } /** * Wrapper class to provide UI RichList component getters for an AVM node descriptor */ public class ItemWrapper { private static final String rootPath = '/' + JNDIConstants.DIR_DEFAULT_APPBASE; private AVMNodeDescriptor descriptor; public ItemWrapper(AVMNodeDescriptor descriptor) { this.descriptor = descriptor; } public boolean getExpirable() { return this.descriptor.isFile() && (this.descriptor.isDeleted() == false); } public boolean getDeleted() { return descriptor.isDeleted(); } public String getName() { String result = descriptor.getName(); if (descriptor.isDeleted()) { result += " [" + Application.getMessage(FacesContext.getCurrentInstance(), MSG_DELETED_ITEM) + "]"; } return result; } public String getModifiedDate() { return ISO8601DateFormat.format(new Date(descriptor.getModDate())); } public String getExpirationDate() { String expireDate = null; Date date = expirationDates.get(this.descriptor.getPath()); if (date != null) { expireDate = ISO8601DateFormat.format(date); } return expireDate; } public String getDescription() { if (descriptor.isDeleted() == false) { return (String)nodeService.getProperty( AVMNodeConverter.ToNodeRef(-1, descriptor.getPath()), ContentModel.PROP_DESCRIPTION); } else { return ""; } } public String getPath() { return descriptor.getPath().substring(descriptor.getPath().indexOf(rootPath) + rootPath.length()); } public String getFullPath() { return descriptor.getPath(); } public String getUrl() { return DownloadContentServlet.generateBrowserURL( AVMNodeConverter.ToNodeRef(-1, descriptor.getPath()), descriptor.getName()); } public String getPreviewUrl() { ClientConfigElement config = Application.getClientConfig(FacesContext.getCurrentInstance()); String dns = AVMUtil.lookupStoreDNS(AVMUtil.getStoreName(descriptor.getPath())); return AVMUtil.buildAssetUrl(AVMUtil.getSandboxRelativePath(descriptor.getPath()), config.getWCMDomain(), config.getWCMPort(), dns); } public AVMNodeDescriptor getDescriptor() { return this.descriptor; } public String getIcon() { return (descriptor.isFile() || descriptor.isDeletedFile() ? Utils.getFileTypeImage(descriptor.getName(), true) : SPACE_ICON); } @Override public boolean equals(Object obj) { if (obj instanceof ItemWrapper) { return ((ItemWrapper)obj).descriptor.getPath().equals(descriptor.getPath()); } else { return false; } } @Override public int hashCode() { return descriptor.getPath().hashCode(); } } }