Files
alfresco-community-repo/source/java/org/alfresco/web/bean/wcm/SubmitDialog.java
Derek Hulley 5f9d3cb6b1 Merged BRANCHES/DEV/V3.3-DAO-REFACTOR-5 to HEAD:
20678: DAO5 branch: Preparation for merge back to HEAD
   20689: Merged DAO4 to DAO5
        - Removed all 'dbscripts/create/3.x/SomeDialect' and replaced with 'dbscripts/create/SomeDialect'
          DB create scripts are taken from latest DAO4
        - TODO: FixAuthoritiesCrcValuesPatch needs query implementation in PatchDAO
        Merged DAO3 to DAO4
           - Reapplied fixes for ALF-713 (race condition on Usages)
           19350: Merged BRANCHES/DEV/V3.3-DAO-REFACTOR-2 to BRANCHES/DEV/V3.3-DAO-REFACTOR-3:
               18939: SAIL-4 :2nd stage branch for DAO refactor off HEAD rev 18898
               18948: Merged V3.3-DAO-REFACTOR to V3.3-DAO-REFACTOR-2
                    18202: Dev branch for DAO refactor
                    18252: SAIL-233: QName.hbm.xml
                    18295: Added missing CREATE TABLE statements for QName-related code
                    18324: SAIL-234: Node.hbm.xml: Node aspects initial integration
                    18355: Added 'setValue' method to manually update the cached value
                    18356: MV property stressing lowered to speed test up
                    18357: SAIL-234: Node.hbm.xml
                    18376: Pulled all Alfresco-related create SQL into script
                    18389: SAIL-234: Permissions DAO refactor - initial checkpoint
                    18390: Formatting only (line-endings)
                    18400: SAIL-234: Node.hbm.xml
                    18418: SAIL-234: Node.hbm.xml: 'alf_node_assoc' CRUD
                    18429: SAIL-234: Node.hbm.xml: Cleaned out all Hibernate references to NodeAssocImpl
                    18457: SAIL-234: Permissions DAO refactor
               18959: Merged DEV/V3.3-DAO-REFACTOR to DEV/V3.3-DAO-REFACTOR-2
                    18479: SAIL-234: Node.hbm.xml - fix updateNode (missing id when saving oldDummyNode)
                    18482: SAIL-235: remove Permissions.hbm.xml
                    18517: SAIL-235: Permissions DAO refactor
                    18523: SAIL-234: Node.hbm.xml
                    18524: SAIL-235: Permissions DAO refactor
               18960: Merged DEV/V3.3-DAO-REFACTOR to DEV/V3.3-DAO-REFACTOR-2
                    18533: Flipped back to Windows line endings
                    18535: Formatting-only (eol)
                    18540: Formatting-only (eol)
                    18541: SAIL-235: Permissions DAO refactor
                    18543: SAIL-234: Node.hbm.xml: Start alf_store changes
                    18567: SAIL-235: Permissions DAO refactor
                    18596: SAIL-305:  Alfresco DDL - formatted/rationalized and added missing indexes & fk constraints
                    18603: SAIL-311: Minor cleanup for schema upgrade scripts (V3.3)
                    18604: SAIL-311: Remove empty dirs
                    18619: SAIL-274: Locale.hbm.xml
                    18621: Added method to create default ACL
                    18622: SAIL-234: Node.hbm.xml: Store, Transaction, Server and some node
                    18624: Formatting only (eol)
                    18631: SAIL-235: Permissions DAO refactor
                    18633: SAIL-235: Permissions DAO refactor - do not expose CRUD for AceContext (or AuthorityAlias) since currently unused
                    18639: getLocale(Locale) should return null if it doesn't exist
                    18640: SAIL-234 NodeDAO: More replacement of node queries and updates
                    18648: SAIL-310: Create SQL script for core repo tables (All DB ports)
                    18651: SAIL-234 NodeDAO: Moves across stores handle presence of target deleted nodes
               18961: Merged DEV/V3.3-DAO-REFACTOR to DEV/V3.3-DAO-REFACTOR-2
                    18658: SAIL-274 Locale DAO: Missing getValueKey() method
                    18662: SAIL-235: Permissions DAO refactor - further cleanup (of DbAccessControlList usage, including copyACLs)
                    18664: DB scripts porting for PostgreSQL finished.
                    18668: SAIL-234 Node DAO: Note in case Transaction Change ID is dropped from indexes
                    18669: SAIL-234 Node DAO: deleteNode and archive (store move) fixes
                    18672: DB scripts porting for Oracle finished. 
                    18675: SAIL-235: Permissions DAO refactor 
                    18677: DB scripts porting for DB2 finished.
               18964: Merged DEV/V3.3-DAO-REFACTOR to DEV/V3.3-DAO-REFACTOR-2
                    18687: Execute a callback with retries
                    18688: SAIL-234 Node DAO: Child association creation
                    18690: SAIL-234 Node DAO: Comment out raw creation of stores as it breaks subsequent bootstrap checks
                    18691: SAIL-234 Node DAO: More replacement of alf_child_assoc handling
                    18713: Commented about needing a more efficient removeChildAssociation method
                    18714: SAIL-234 Node DAO: Replaced queries on alf_child_assoc
                    18715: SAIL-234 Node DAO: More alf_child_assoc query replacement
                    18727: SAIL-234 Node DAO: alf_child_assoc queries complete
                    18737: SAIL-234 Node DAO: Tweaks to newNode and implemented prependPaths
                    18741: SAIL-234 and SAIL-334: Moved UsageDelta Hibernate code and queries over to UsageDeltaDAO
                    18748: SAIL-234 Node DAO: fix NPE (EditionServiceImplTest)
                    18769: SAIL-234 Node DAO: alf_node_properties ground work
                    18786: SAIL-234 Node DAO: alf_node_properties and cm:auditable properties
                    18810: Added EqualsHelper.getMapComparison
                    18813: TransactionalCache propagates cache clears and removals during rollback
                    18826: SAIL-234 Node DAO: Moved over sundry references to NodeDaoService to NodeDAO
                    18849: SAIL-237: UsageDelta.hbm.xml - eol formatting only (including removal of unwanted svn:eol-style=native property)
                    18869: SAIL-234 NodeDAO: Fixed more references to 'nodeDaoService'
                    18895: SAIL-234 NodeDAO: Queries for alf_transaction
                    18899: SAIL-234 Node DAO: Fixed bean fetching for 'nodeDAO'
                    18909: SAIL-234 NodeDAO: Fixes to getNodeRefStatus and various txn queries
                    18916: SAIL-234 NodeDAO: Fixed moveNode alf_child_assoc updates
                    18922: SAIL-235: DAO refactoring: Permission.hbm.xml
                    18930: SAIL-235: DAO refactoring: Permission.hbm.xml
                    18932: SAIL-234 NodeDAO: Fixing up gotchas, javadocs and some naming
                    18933: SAIL-234 NodeDAO: Minor neatening
                    18935: SAIL-234 Node DAO: Caches for ID to NodeRef and StoreRef
                    18936: EHCache config files line endings
                    18938: SAIL-237: Usage DAO refactor - initial checkpoint
                    18945: SAIL-235: DAO refactoring: Permission.hbm.xml. Move Node.
               18975: Fix for move-node ACL jiggery-pokery
               19067: SAIL-4: fix VersionHistoryImpl.getSuccessors (causing VersionServiceImplTest.testGetVersionHistorySameWorkspace failure)
               19068: SAIL-234: fix VersionMigratorTest.testMigrateOneVersion
               19074: SAIL-237: Usage DAO - update to common iBatis mapping pattern(s) to ease DB porting
               19076: SAIL-231: Activities DAO - update to common iBatis mapping pattern(s)
               19077: SAIL-232: AppliedPatch DAO - minor cleanup (comments & formatting only)
               19092: Merging HEAD to DEV/V3.3-DAO-REFACTOR-2
                     18973: Temporarily comment out AVMTestSuite and run AVM tests individually
                     19056: AVM unit test improvements
               19097: SAIL-235: DAO refactoring: Permission.hbm.xml: Additional index to support queries to find the id and acl id for the primary children of a node.
               19185: SAIL-238: Permissions DAO - (minor) update to common iBatis mapping pattern
               19289: SAIL-234 NodeDAO: Node cache replaces NodeRef cache
               19302: SAIL-234 Node DAO: Added cache for node properties
               19318: SAIL-4: AVM DAO - (minor) update to common iBatis mapping pattern
   20690: Merged BRANCHES/DEV/V3.3-DAO-REFACTOR-4 to BRANCHES/DEV/V3.3-DAO-REFACTOR-5:
        20063: (RECORD ONLY) DAO refactor branch V4
        20146: Merged BRANCHES/DEV/V3.3-DAO-REFACTOR-3 to BRANCHES/DEV/V3.3-DAO-REFACTOR-4:
             19401: SAIL-234 Node DAO: Fix permission service tests (setPrimaryChildrenSharedAclId needs to invalidate nodesCache)
             19428: Fixed TransactionalCache issue with null and NullValueMarker
             19429: Took empty cm:content creation out of FileFolderService#createImpl
             19430: SAIL-234 Node DAO: Tweaks around caching and cm:auditable
             19431: SAIL-4 DAO Refactor: Exception thrown when attempting writes in read-only txn have changed
             19436: SAIL-234 Node DAO: Fix NPE during cm:auditable update
             19475: Allow debugging of code without stepping into trivial stuff
             19476: Follow-up on 19429 by ensuring CIFS/FTP set a  mimetype on the ContentWriter
             19477: SAIL-234 Node DAO: Leverage DAO better for NodeService.addProperties
             19478: SAIL-234 NodeDAO: Added toString() for ParentAssocsInfo (cache value for parent assocs)
             19479: SAIL-234 Node DAO: Fixed for parent association and property caches
             19480: Made TransactionAwareSingleton bind-key a GUID
             19481: SAIL-234 Node DAO: Reinstated 100K collection property tests
             19482: SAIL-234 Node DAO: Node and property cache fixes highlighted by unit tests
             19483: SAIL-234 Node DAO: Start on NodeBulkLoader implementation
             19595: SAIL-234 Node DAO: Fix moveNode to detect cyclic relationship prior to updating ACLs for moved tree FileFolderServiceImplTest.testETHREEOH_3088_MoveIntoSelf)
        20147: Merged BRANCHES/DEV/V3.3-DAO-REFACTOR-3 to BRANCHES/DEV/V3.3-DAO-REFACTOR-4:
             19602: (RECORD ONLY) Reintegrated with HEAD up to rev 19433
             19621: (RECORD ONLY) SAIL-347
             19683: (RECORD ONLY) Reverse-merged 19621 for SAIL-347
             19722: (RECORD ONLY) Merged /alfresco/HEAD:r19434-19721
        20150: Merged BRANCHES/DEV/V3.3-DAO-REFACTOR-3 to BRANCHES/DEV/V3.3-DAO-REFACTOR-4:
             19741: Merged DEV\V3.3-DAO-REFACTOR-2 to DEV\V3.3-DAO-REFACTOR-3
                   19739: Extended "move" tests
             19743: Fix AuditableAspectTest.testAddAspect (to allow for node modified date tolerance)
             19748: Remaining part of merge from HEAD to V3.3-DAO-REFACTOR-3
                   19367: Merged BRANCHES/V3.2 to HEAD:
                       19286: Fix for ALF-626 "Using 'null' as an authority argument in clearPermissions() cause a java.lang.NullPointerException"
             19755: SAIL-234 Node DAO: Fix RepoAdminServiceImplTest.testConcurrentDynamicModelDelete (handle InvalidNodeRefException after getChildAssocs)
   20692: Merged BRANCHES/DEV/V3.3-DAO-REFACTOR-4 to BRANCHES/DEV/V3.3-DAO-REFACTOR-5:
        - Retired all 1.3 and 1.4 upgrade scripts ... R.I.P.
        - Fixed CRC patch for Authorities (only tested on MySQL)
        - Fixed SQL patch revision numbers and bumped version schema number up
        20158: Merged BRANCHES/DEV/V3.3-DAO-REFACTOR-3 to BRANCHES/DEV/V3.3-DAO-REFACTOR-4:
             19773: SQL mappings and scripts: SAIL-310, SAIL-304, SAIL-303 and SAIL-347
             19774: Futher fix for SAIL-310: Sequence patch must take into account sequences created for 3.3
             19851: SAIL-371 (SAIL-294) NodeDAO fallout: Fix QName and Namespace read/write handling and bean name in unit test
        20183: Merged DAO3 to DAO4
             19852: SAIL-370: Remove LinkValidation
             19853: SAIL-239 (SAIL-294) Attributes.hbm.xml: Added ability to attach arbitrary property to unique context
             19857: SAIL-373 Fallout from Permissions DAO refactor (SAIL-235)
             19864: SAIL-239 (SAIL-294): Removed AttributeService RMI API
             19865: More SAIL-239 (SAIL-294): Removed AttributeService RMI API
        20208: DAO-refactor implementation of ALF-2712 query improvements
        20209: Merged BRANCHES/DEV/V3.3-DAO-REFACTOR-3 to BRANCHES/DEV/V3.3-DAO-REFACTOR-4:
             20060: Removal of AttributeService for SAIL-239 (SAIL-294)
        20348: SAIL-371 (SAIL-294): Protect collection properties during map insert and retrieval
        20547: SAIL-371 (SAIL-294) Attributes.hbm.xml: implement getAttributes + fixes
        20573: SAIL-371 (SAIL-294): NodeDAO: Fix unit tests and other fallout
        20597: SAIL-239 Attributes.hbm.xml: WCM/AVM locking test fixes (wip)
        20598: SAIL-239 Attributes.hbm.xml: WCM/AVM locking test fixes (wip) - fix AssetServiceImplTest.testSimpleLockFile NPE
        20600: Fix PropertyValueDAOTest.testPropertyValue_Enum (follow-on to r20060 for SAIL-239 - which introduces ENUM prop vals)
        20601: Fix UsageDAOTest.testCreateAndDeleteUsageDeltas NPE (would also affect ContentStoreCleanerScalabilityRunner)
        20603: Fix CMISPropertyServiceTest.* (fallout from r20146 <- r19429 <- Took empty cm:content creation out of FileFolderService#createImpl)
        20604: SAIL-371 (SAIL-294): NodeDAO: Fix unit tests - TransferServiceImplTest.*
        20618: SAIL-371 (SAIL-294): NodeDAO: AuditableAspectTest (fix testCreateNodeWithAuditableProperties_ALF_2565 + add remove aspect test)
        20624: SAIL-371 (SAIL-294): NodeDAO: Fix unit tests - UserUsageTest.*
        20626: Fixed random keys for RuleTrigger NodeRef tracking
        20635: SAIL-371 (SAIL-294): NodeDAO: Fix unit tests - PersonTest.testSplitDuplicates
        20642: SAIL-371 (SAIL-294) DAO: Fixed CacheTest
        20643: Removed must of the 'distribute' target's dependencies.  Not for HEAD
        20645: Follow-on to r20643 (Removed most of the 'distribute' target's dependencies.  Not for HEAD)
        20654: SAIL-371 (SAIL-294): NodeDAO: DMDeploymentTargetTest.* (do not try to remove mandatory aspects)
        20655: SAIL-371 (SAIL-294): NodeDAO: Initial fix for TaggingServiceImplTest.testTagScopeUpdateViaNodePolicies (+ minor test cleanup)
        20657: SAIL-371 (SAIL-294): NodeDAO: Fix unit tests - VersionMigratorTest.testMigrateOneVersion (cm:accessed not returned if null)
        20658: Merged (back merge only - no merge info) BRANCHES/V3.3 to BRANCHES/DEV/V3.3-DAO-REFACTOR-4:
             20090: Dynamic models: minor improvements to DictionaryModelType
             20554: Improvement to model delete validation (investigating intermittent failure of RepoAdminServiceImplTest.testSimpleDynamicModelViaNodeService)
        20662: SAIL-371 (SAIL-294): NodeDAO: Fix unit tests - RecordsManagementAuditServiceImplTest.* (we now ignore attempt to update 'cm:modifier' prop so update 'cm:title' prop instead)
        20666: SAIL-371 (SAIL-294): NodeDAO: Fix unit tests - ADMLuceneTest.*
        20668: SAIL-239 (SAIL-294) - delete WCM locks + tests (follow-on to r20060)
        20674: SAIL-371 (SAIL-294) NodeDAO fallout: Cleaner and additional checks for ContentStoreCleaner
        20675: SAIL-371 (SAIL-294) NodeDAO fallout: Fixed handling of ContentData


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@20693 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
2010-06-17 19:35:49 +00:00

1075 lines
34 KiB
Java

/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
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.repo.avm.AVMNodeConverter;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.web.scripts.FileTypeImageUtils;
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.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.workflow.WorkflowDefinition;
import org.alfresco.service.cmr.workflow.WorkflowService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.springframework.extensions.surf.util.ISO8601DateFormat;
import org.alfresco.util.NameMatcher;
import org.alfresco.wcm.sandbox.SandboxFactory;
import org.alfresco.wcm.sandbox.SandboxService;
import org.alfresco.web.app.Application;
import org.alfresco.web.app.servlet.DownloadContentServlet;
import org.alfresco.web.app.servlet.FacesHelper;
import org.alfresco.web.bean.BrowseBean;
import org.alfresco.web.bean.dialog.BaseDialogBean;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.forms.Form;
import org.alfresco.web.forms.FormInstanceData;
import org.alfresco.web.forms.FormNotFoundException;
import org.alfresco.web.forms.FormsService;
import org.alfresco.web.forms.Rendition;
import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.common.component.UIListItem;
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
{
private static final long serialVersionUID = -2445905376358150000L;
public static final String PARAM_LOAD_SELECTED_NODES_FROM_BROWSE_BEAN = "loadSelectedNodesFromBrowseBean";
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 loadSelectedNodesFromBrowseBean = false;
private boolean autoDeploy = false;
private Date defaultExpireDate;
private Date launchDate;
private List<ItemWrapper> submitItems;
private List<ItemWrapper> warningItems;
private HashSet<FormWorkflowWrapper> workflows;
private Map<String, Date> expirationDates;
private List<UIListItem> workflowItems;
private Map<QName, Serializable> workflowParams;
protected AVMBrowseBean avmBrowseBean;
transient private AVMService avmService;
transient private WorkflowService workflowService;
transient private AVMSyncService avmSyncService;
transient private FormsService formsService;
transient private SandboxFactory sandboxFactory;
transient private SandboxService sandboxService;
transient private NameMatcher nameMatcher;
/** Current workflow for dialog context */
protected WorkflowConfiguration actionWorkflow = null;
private static final Log logger = LogFactory.getLog(SubmitDialog.class);
/**
* @param avmService The AVM Service to set.
*/
public void setAvmService(AVMService avmService)
{
this.avmService = avmService;
}
protected AVMService getAvmService()
{
if (avmService == null)
{
avmService = Repository.getServiceRegistry(FacesContext.getCurrentInstance()).getAVMService();
}
return avmService;
}
/**
* @param avmSyncService The AVMSyncService to set.
*/
public void setAvmSyncService(AVMSyncService avmSyncService)
{
this.avmSyncService = avmSyncService;
}
protected AVMSyncService getAvmSyncService()
{
if (this.avmSyncService == null)
{
this.avmSyncService = Repository.getServiceRegistry(FacesContext.getCurrentInstance()).getAVMSyncService();
}
return this.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;
}
protected WorkflowService getWorkflowService()
{
if (workflowService == null)
{
workflowService = Repository.getServiceRegistry(FacesContext.getCurrentInstance()).getWorkflowService();
}
return workflowService;
}
/**
* @param nameMatcher The nameMatcher to set.
*/
public void setNameMatcher(NameMatcher nameMatcher)
{
this.nameMatcher = nameMatcher;
}
/**
* @return nameMatcher
*/
protected NameMatcher getNameMatcher()
{
//check for null for cluster environment
if (nameMatcher == null)
{
nameMatcher = (NameMatcher) FacesHelper.getManagedBean(FacesContext.getCurrentInstance(), "globalPathExcluder");
}
return nameMatcher;
}
/**
* @param formsService The FormsService to set.
*/
public void setFormsService(final FormsService formsService)
{
this.formsService = formsService;
}
protected FormsService getFormsService()
{
if (formsService == null)
{
formsService = (FormsService) FacesHelper.getManagedBean(FacesContext.getCurrentInstance(), "FormsService");
}
return formsService;
}
public void setSandboxService(final SandboxService sandboxService)
{
this.sandboxService = sandboxService;
}
protected SandboxService getSandboxService()
{
if (sandboxService == null)
{
sandboxService = Repository.getServiceRegistry(FacesContext.getCurrentInstance()).getSandboxService();
}
return sandboxService;
}
// TODO - refactor ... push down into sandbox service (submit to workflow)
public void setSandboxFactory(final SandboxFactory sandboxFactory)
{
this.sandboxFactory = sandboxFactory;
}
protected SandboxFactory getSandboxFactory()
{
if (sandboxFactory == null)
{
sandboxFactory = (SandboxFactory) FacesHelper.getManagedBean(FacesContext.getCurrentInstance(), "SandboxFactory");
}
return sandboxFactory;
}
/**
* @see org.alfresco.web.bean.dialog.BaseDialogBean#init(java.util.Map)
*/
@Override
public void init(Map<String, String> parameters)
{
super.init(parameters);
this.comment = null;
this.label = null;
this.submitItems = null;
this.warningItems = null;
this.workflowItems = null;
this.workflows = new HashSet<FormWorkflowWrapper>(4);
this.expirationDates = new HashMap<String, Date>(8);
this.defaultExpireDate = new Date();
this.workflowSelectedValue = null;
this.launchDate = null;
this.autoDeploy = false;
this.workflowParams = null;
// determine if the dialog has been started from a workflow
this.loadSelectedNodesFromBrowseBean = Boolean.valueOf(this.parameters.get(PARAM_LOAD_SELECTED_NODES_FROM_BROWSE_BEAN));
}
@Override
protected String finishImpl(FacesContext context, String outcome) throws Exception
{
// NOTE: This does not get called in this dialog as we have overridden finish()
return null;
}
@Override
public String finish()
{
// NOTE: We need to handle the transaction ourselves in this dialog as the store needs
// to be committed and the virtualisation server informed of the workflow
// sandbox BEFORE the workflow gets started. This is so that the link validation
// service can use the virtualisation server to produce the link report.
// The best solution would be for the link check node of the workflow to be
// asynchronous and to wait until the initiating transaction had committed
// before running but there's no support for this.
// We therefore need to use 2 transactions, one to create the workflow store
// (if necessary) and one to start the workflow
if (getSubmitItemsSize() == 0)
{
return null;
}
FacesContext context = FacesContext.getCurrentInstance();
String outcome = null;
// check the isFinished flag to stop the finish button
// being pressed multiple times
if (this.isFinished == false)
{
this.isFinished = true;
try
{
// note: always submit via workflow (always defaults to direct submit workflow)
//outcome = submitViaWorkflow(context);
String workflowName = null;
if ((this.workflowSelectedValue != null) && (this.workflowSelectedValue.length > 0))
{
// get the defaults from the workflow configuration attached to the selected workflow
workflowName = this.workflowSelectedValue[0];
for (FormWorkflowWrapper wrapper : this.workflows)
{
if (wrapper.name.equals(workflowName))
{
this.workflowParams = wrapper.params;
}
}
if (this.workflowParams == null)
{
// create error msg for display in dialog - the user must configure the workflow params
Utils.addErrorMessage(Application.getMessage(context, MSG_ERR_WORKFLOW_CONFIG));
return outcome;
}
}
final String finalWorkflowName = workflowName;
List<ItemWrapper> items = getSubmitItems();
final List<String> relativePaths = new ArrayList<String>(items.size());
for (ItemWrapper wrapper : items)
{
relativePaths.add(AVMUtil.getStoreRelativePath(wrapper.getDescriptor().getPath()));
}
final String sbStoreId = this.avmBrowseBean.getSandbox();
String submitLabel = this.label;
String submitComment = this.comment;
// crop to maximum length
if (submitLabel != null && submitLabel.length() > 255)
{
submitLabel = submitLabel.substring(0, 255);
}
if (submitComment != null && submitComment.length() > 255)
{
submitComment = submitComment.substring(0, 255);
}
final String finalSubmitLabel = submitLabel;
final String finalSubmitComment = submitComment;
// note: always submit via workflow (if no workflow selected, then defaults to direct submit workflow)
// This nees to run with higher rights to push into the work flow store ....
AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>() {
public Object doWork() throws Exception
{
getSandboxService().submitListAssets(sbStoreId, relativePaths,
finalWorkflowName, workflowParams,
finalSubmitLabel, finalSubmitComment,
expirationDates, launchDate, autoDeploy);
return null;
}
}, AuthenticationUtil.getSystemUserName());
// if we get this far return the default outcome
outcome = this.getDefaultFinishOutcome();
}
finally
{
// reset the flag so we can re-attempt the operation
isFinished = false;
}
}
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<String, Date> 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 Flag to indicate whether the changes should be deployed upon approval
*/
public boolean isAutoDeploy()
{
return this.autoDeploy;
}
/**
* @param autoDeploy Flag to indicate whether the changes should be deployed upon approval
*/
public void setAutoDeploy(boolean autoDeploy)
{
this.autoDeploy = autoDeploy;
}
/**
* @return List of UIListItem object representing the available workflows for the website
*/
@SuppressWarnings("unchecked")
public List<UIListItem> 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<ChildAssociationRef> webWorkflowRefs = getNodeService().getChildAssocs(
websiteRef, WCMAppModel.ASSOC_WEBWORKFLOWDEFAULTS, RegexQNamePattern.MATCH_ALL);
List<FormWorkflowWrapper> workflowMatchers = new ArrayList<FormWorkflowWrapper>(webWorkflowRefs.size());
for (ChildAssociationRef ref : webWorkflowRefs)
{
NodeRef wfDefaultsRef = ref.getChildRef();
String wfName = (String)getNodeService().getProperty(wfDefaultsRef, WCMAppModel.PROP_WORKFLOW_NAME);
Map<QName, Serializable> params = (Map<QName, Serializable>)AVMWorkflowUtil.deserializeWorkflowParams(
wfDefaultsRef);
String matchPattern = (String)getNodeService().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<FormWorkflowWrapper> matchers = new ArrayList<FormWorkflowWrapper>(workflowMatchers);
for (int i=0; i<matchers.size(); i++)
{
FormWorkflowWrapper matcher = matchers.get(i);
// see if the file path matches this workflow path pattern
if (matcher.matchesPath(path) == true)
{
// found a match - remove the workflow from the list of ones to check
this.workflows.add(matcher);
workflowMatchers.remove(matcher);
}
}
// if all workflows are matched, there is no need to continue looping
if (workflowMatchers.size() == 0) break;
}
// build a UI item for each available workflow
List<UIListItem> items = new ArrayList<UIListItem>(this.workflows.size());
for (FormWorkflowWrapper wrapper : this.workflows)
{
WorkflowDefinition workflowDef = getWorkflowService().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<ItemWrapper> 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<ItemWrapper> 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<AVMNodeDescriptor> selected;
if (this.loadSelectedNodesFromBrowseBean)
{
// if the dialog was started from a workflow the AVM browse bean should
// have the list of nodes that need submitting
selected = this.avmBrowseBean.getNodesForSubmit();
this.avmBrowseBean.setNodesForSubmit(null);
}
// if the dialog was started from the UI determine what nodes the user selected to submit
else 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<AVMDifference> diffs = this.getAvmSyncService().compare(-1, userStore, -1, stagingStore, getNameMatcher());
selected = new ArrayList<AVMNodeDescriptor>(diffs.size());
for (AVMDifference diff : diffs)
{
selected.add(getAvmService().lookup(-1, diff.getSourcePath(), true));
}
}
else if (this.avmBrowseBean.getAvmActionNode() == null)
{
// multiple items selected
selected = this.avmBrowseBean.getSelectedSandboxItems();
}
else
{
// single item selected
selected = new ArrayList<AVMNodeDescriptor>(1);
selected.add(getAvmService().lookup(-1, this.avmBrowseBean.getAvmActionNode().getPath(), true));
}
if (selected == null)
{
this.submitItems = Collections.<ItemWrapper>emptyList();
this.warningItems = Collections.<ItemWrapper>emptyList();
}
else
{
Set<String> submittedPaths = new HashSet<String>(selected.size());
this.submitItems = new ArrayList<ItemWrapper>(selected.size());
this.warningItems = new ArrayList<ItemWrapper>(selected.size() >> 1);
for (AVMNodeDescriptor node : selected)
{
if (AVMWorkflowUtil.isInActiveWorkflow(AVMUtil.getStoreName(node.getPath()), node))
{
this.warningItems.add(new ItemWrapper(node));
continue;
}
NodeRef ref = AVMNodeConverter.ToNodeRef(-1, node.getPath());
if (submittedPaths.contains(node.getPath()))
{
continue;
}
boolean isForm = getNodeService().hasAspect(ref, WCMAppModel.ASPECT_FORM_INSTANCE_DATA);
boolean isRendition = getNodeService().hasAspect(ref, WCMAppModel.ASPECT_RENDITION);
if (((!isForm) && (!isRendition)) || (node.isDeleted() && (!isForm)))
{
// found single item for submit
// note: could be a single deleted rendition - to enable deletion of old renditions (eg. if template no longer applicable)
this.submitItems.add(new ItemWrapper(node));
submittedPaths.add(node.getPath());
}
else
{
// item is a form (note: could be deleted) or a rendition
FormInstanceData fid = null;
try
{
if (isRendition)
{
// 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
fid = getFormsService().getRendition(ref).getPrimaryFormInstanceData(true);
}
else
{
fid = getFormsService().getFormInstanceData(ref);
}
}
catch (FormNotFoundException fnfe)
{
logger.warn(fnfe);
}
if (fid != null)
{
// add the form instance data file to the list for submission
if (!submittedPaths.contains(fid.getPath()))
{
this.submitItems.add(new ItemWrapper(getAvmService().lookup(-1, fid.getPath(), true)));
submittedPaths.add(fid.getPath());
}
// locate renditions for this form instance data file and add to list for submission
for (final Rendition rendition : fid.getRenditions(true))
{
final String renditionPath = rendition.getPath();
if (!submittedPaths.contains(renditionPath))
{
this.submitItems.add(new ItemWrapper(getAvmService().lookup(-1, renditionPath, true)));
submittedPaths.add(renditionPath);
}
}
// lookup the workflow defaults for that form and store into the list of available workflows
Form f = null;
try
{
f = fid.getForm();
WorkflowDefinition defaultWfDef = f.getDefaultWorkflow();
if (defaultWfDef != null)
{
this.workflows.add(new FormWorkflowWrapper(defaultWfDef.getName(),
fid.getForm().getDefaultWorkflowParameters()));
}
}
catch (FormNotFoundException fnfe)
{
logger.warn(fnfe);
}
}
// See WCM-1090 ACT-1551
// cannot depend on renditions of the form instance to contain the present
// node. Add it here if it hasn't been added by the above process.
if (!submittedPaths.contains(node.getPath()))
{
this.submitItems.add(new ItemWrapper(node));
submittedPaths.add(node.getPath());
}
}
}
}
tx.commit();
}
catch (Throwable e)
{
// rollback the transaction on error
try { if (tx != null) {tx.rollback();} } catch (Exception ex) {}
// rethrow the exception to highlight the problem
throw (RuntimeException)e;
}
}
/**
* 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<ItemWrapper> 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 static final long serialVersionUID = -6264439015998987731L;
private String name;
private Map<QName, Serializable> params;
private QName type;
private String strFilenamePattern;
private Pattern filenamePattern;
FormWorkflowWrapper(String name, Map<QName, Serializable> params)
{
this.name = name;
this.params = params;
}
FormWorkflowWrapper(String name, Map<QName, Serializable> 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<QName, Serializable> getParams()
{
return this.params;
}
public void setParams(Map<QName, Serializable> params)
{
this.params = params;
}
public QName getType()
{
return this.type;
}
public void setType(QName type)
{
this.type = type;
}
boolean matchesPath(String path)
{
return (filenamePattern != null &&
filenamePattern.matcher(path).matches());
}
@Override
public int hashCode()
{
return this.name.hashCode();
}
@Override
public boolean equals(Object obj)
{
return (obj instanceof FormWorkflowWrapper &&
this.name.equals(((FormWorkflowWrapper)obj).name));
}
}
/**
* Wrapper class to provide UI RichList component getters for an AVM node descriptor
*/
public class ItemWrapper implements Serializable
{
private static final long serialVersionUID = 6079164681664703986L;
private static final String rootPath = '/' + JNDIConstants.DIR_DEFAULT_APPBASE;
private AVMNodeDescriptor descriptor;
public ItemWrapper(AVMNodeDescriptor descriptor)
{
this.descriptor = descriptor;
}
public boolean getFile()
{
return this.descriptor.isFile();
}
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)getNodeService().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()
{
return AVMUtil.getPreviewURI(descriptor.getPath());
}
public AVMNodeDescriptor getDescriptor()
{
return this.descriptor;
}
public String getIcon()
{
return (descriptor.isFile() || descriptor.isDeletedFile()
? FileTypeImageUtils.getFileTypeImage(descriptor.getName(), true)
: SPACE_ICON);
}
@Override
public boolean equals(Object obj)
{
return (obj instanceof ItemWrapper &&
((ItemWrapper)obj).descriptor.getPath().equals(descriptor.getPath()));
}
@Override
public int hashCode()
{
return descriptor.getPath().hashCode();
}
}
}