Java tutorial
/******************************************************************************* * Crafter Studio Web-content authoring solution * Copyright (C) 2007-2016 Crafter Software Corporation. * * 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 3 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, see <http://www.gnu.org/licenses/>. ******************************************************************************/ package org.craftercms.studio.impl.v1.service.workflow; import java.text.SimpleDateFormat; import java.util.*; import net.sf.json.JSONArray; import net.sf.json.JSONException; import net.sf.json.JSONObject; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.craftercms.studio.api.v1.constant.CStudioConstants; import org.craftercms.studio.api.v1.constant.DmConstants; import org.craftercms.studio.api.v1.dal.ObjectMetadata; import org.craftercms.studio.api.v1.dal.ObjectState; import org.craftercms.studio.api.v1.exception.ContentNotFoundException; import org.craftercms.studio.api.v1.exception.ServiceException; import org.craftercms.studio.api.v1.listener.DmWorkflowListener; import org.craftercms.studio.api.v1.log.Logger; import org.craftercms.studio.api.v1.log.LoggerFactory; import org.craftercms.studio.api.v1.service.GeneralLockService; import org.craftercms.studio.api.v1.service.configuration.ServicesConfig; import org.craftercms.studio.api.v1.service.content.ContentService; import org.craftercms.studio.api.v1.service.content.DmRenameService; import org.craftercms.studio.api.v1.service.content.ObjectMetadataManager; import org.craftercms.studio.api.v1.service.dependency.DependencyRule; import org.craftercms.studio.api.v1.service.dependency.DependencyRules; import org.craftercms.studio.api.v1.service.dependency.DmDependencyService; import org.craftercms.studio.api.v1.service.deployment.DeploymentException; import org.craftercms.studio.api.v1.service.deployment.DeploymentService; import org.craftercms.studio.api.v1.service.deployment.DmPublishService; import org.craftercms.studio.api.v1.service.objectstate.ObjectStateService; import org.craftercms.studio.api.v1.service.objectstate.State; import org.craftercms.studio.api.v1.service.objectstate.TransitionEvent; import org.craftercms.studio.api.v1.service.security.SecurityService; import org.craftercms.studio.api.v1.service.site.SiteService; import org.craftercms.studio.api.v1.service.workflow.WorkflowJob; import org.craftercms.studio.api.v1.service.workflow.WorkflowService; import org.craftercms.studio.api.v1.service.notification.NotificationService; import org.craftercms.studio.api.v1.service.workflow.context.GoLiveContext; import org.craftercms.studio.api.v1.service.workflow.context.MultiChannelPublishingContext; import org.craftercms.studio.api.v1.service.workflow.context.RequestContext; import org.craftercms.studio.api.v1.service.workflow.context.RequestContextBuilder; import org.craftercms.studio.api.v1.to.*; import org.craftercms.studio.api.v1.util.DmContentItemComparator; import org.craftercms.studio.api.v1.util.filter.DmFilterWrapper; import org.craftercms.studio.impl.v1.service.workflow.dal.WorkflowJobDAL; import org.craftercms.studio.impl.v1.service.workflow.operation.*; import org.craftercms.studio.impl.v1.util.ContentFormatUtils; import org.craftercms.studio.impl.v1.util.ContentUtils; import org.craftercms.studio.impl.v1.util.GoLiveQueueOrganizer; /** * workflow service implementation */ public class WorkflowServiceImpl implements WorkflowService { private static final Logger logger = LoggerFactory.getLogger(WorkflowServiceImpl.class); protected enum Operation { GO_LIVE, DELETE, SUBMIT_TO_GO_LIVE, REJECT, } protected String JSON_KEY_ITEMS = "items"; protected String JSON_KEY_SCHEDULED_DATE = "scheduledDate"; protected String JSON_KEY_IS_NOW = "now"; protected String JSON_KEY_PUBLISH_CHANNEL = "publishChannel"; protected String JSON_KEY_STATUS_SET = "status"; protected String JSON_KEY_STATUS_MESSAGE = "message"; protected String JSON_KEY_SUBMISSION_COMMENT = "submissionComment"; protected String JSON_KEY_URI = "uri"; protected String JSON_KEY_DELETED = "deleted"; protected String JSON_KEY_SUBMITTED_FOR_DELETION = "submittedForDeletion"; protected String JSON_KEY_SUBMITTED = "submitted"; protected String JSON_KEY_IN_PROGRESS = "inProgress"; protected String JSON_KEY_IN_REFERENCE = "reference"; protected String JSON_KEY_COMPONENTS = "components"; protected String JSON_KEY_DOCUMENTS = "documents"; protected String JSON_KEY_ASSETS = "assets"; protected String JSON_KEY_RENDERING_TEMPLATES = "renderingTemplates"; protected String JSON_KEY_DELETED_ITEMS = "deletedItems"; protected String JSON_KEY_CHILDREN = "children"; protected String JSON_KEY_SEND_EMAIL = "sendEmail"; protected String JSON_KEY_USER = "user"; protected String JSON_KEY_REASON = "reason"; public WorkflowJob createJob(String site, List<String> srcPaths, String processName, Map<String, String> properties) { WorkflowJob job = _workflowJobDAL.createJob(site, srcPaths, processName, properties); job.setCurrentStatus(WorkflowService.STATE_STARTED); job = _workflowJobDAL.updateJob(job); return job; } public List<WorkflowJob> getActiveJobs() { List<WorkflowJob> allJobs = _workflowJobDAL.getJobsByState(null); // Reverse scan and delete STATE_ENDED jobs from list for (int i = allJobs.size(); i > 0;) { WorkflowJob job = allJobs.get(--i); if (job.getCurrentStatus().equals(WorkflowService.STATE_ENDED)) allJobs.remove(i); } return allJobs; } public List<WorkflowJob> getJobsInState(Set<String> states) { return _workflowJobDAL.getJobsByState(states); } public WorkflowJob getJob(String jobId) { return _workflowJobDAL.getJob(jobId); } public WorkflowJob updateJob(WorkflowJob job) { return _workflowJobDAL.updateJob(job); } public boolean deleteJob(String jobId) { return _workflowJobDAL.deleteJob(jobId); } public boolean startJob(String jobId) { return false; } public boolean transitionJobState(String jobId, String state) { return false; } public boolean endJob(String jobId) { return false; } @Override public ResultTO submitToGoLive(String site, String username, String request) throws ServiceException { return submitForApproval(site, username, request, false); } protected ResultTO submitForApproval(final String site, String submittedBy, final String request, final boolean delete) throws ServiceException { RequestContext requestContext = RequestContextBuilder.buildSubmitContext(site, submittedBy); ResultTO result = new ResultTO(); try { SimpleDateFormat format = new SimpleDateFormat(CStudioConstants.DATE_PATTERN_WORKFLOW); JSONObject requestObject = JSONObject.fromObject(request); boolean isNow = (requestObject.containsKey(JSON_KEY_IS_NOW)) ? requestObject.getBoolean(JSON_KEY_IS_NOW) : false; Date scheduledDate = null; if (!isNow) { scheduledDate = (requestObject.containsKey(JSON_KEY_SCHEDULED_DATE)) ? getScheduledDate(site, format, requestObject.getString(JSON_KEY_SCHEDULED_DATE)) : null; } boolean sendEmail = (requestObject.containsKey(JSON_KEY_SEND_EMAIL)) ? requestObject.getBoolean(JSON_KEY_SEND_EMAIL) : false; String submissionComment = (requestObject != null && requestObject.containsKey(JSON_KEY_SUBMISSION_COMMENT)) ? requestObject.getString(JSON_KEY_SUBMISSION_COMMENT) : null; // TODO: check scheduled date to make sure it is not null when isNow // = true and also it is not past JSONArray items = requestObject.getJSONArray(JSON_KEY_ITEMS); int length = items.size(); String schDate = null; if (requestObject.containsKey(JSON_KEY_SCHEDULED_DATE)) { schDate = requestObject.getString(JSON_KEY_SCHEDULED_DATE); } List<String> itemsToDelete = new ArrayList<String>(length); if (length > 0) { List<DmDependencyTO> submittedItems = new ArrayList<DmDependencyTO>(); for (int index = 0; index < length; index++) { String stringItem = items.optString(index); //JSONObject item = items.getJSONObject(index); DmDependencyTO submittedItem = getSubmittedItem(site, stringItem, format, schDate, null); String user = submittedBy; //item.getString(JSON_KEY_USER); submittedItems.add(submittedItem); if (delete) { submittedItem.setSubmittedForDeletion(true); } } List<String> submittedPaths = new ArrayList<String>(); for (DmDependencyTO goLiveItem : submittedItems) { String fullPath = contentService.expandRelativeSitePath(site, goLiveItem.getUri()); submittedPaths.add(fullPath); objectStateService.setSystemProcessing(site, goLiveItem.getUri(), true); DependencyRules rule = new DependencyRules(site); rule.setObjectStateService(objectStateService); rule.setContentService(contentService); Set<DmDependencyTO> depSet = rule.applySubmitRule(goLiveItem); for (DmDependencyTO dep : depSet) { String depPath = contentService.expandRelativeSitePath(site, dep.getUri()); submittedPaths.add(depPath); objectStateService.setSystemProcessing(site, dep.getUri(), true); } } List<DmError> errors = submitToGoLive(submittedItems, scheduledDate, sendEmail, delete, requestContext, submissionComment); result.setSuccess(true); result.setStatus(200); result.setMessage(notificationService.getCompleteMessage(site, NotificationService.COMPLETE_SUBMIT_TO_GO_LIVE)); for (String fullPath : submittedPaths) { objectStateService.setSystemProcessing(site, contentService.getRelativeSitePath(site, fullPath), false); } } } catch (Exception e) { result.setSuccess(false); result.setMessage(e.getMessage()); logger.error("Error while submitting content for approval.", e); } return result; } protected List<DmError> submitToGoLive(List<DmDependencyTO> submittedItems, Date scheduledDate, boolean sendEmail, boolean submitForDeletion, RequestContext requestContext, String submissionComment) throws ServiceException { List<DmError> errors = new ArrayList<DmError>(); String site = requestContext.getSite(); String submittedBy = requestContext.getUser(); for (DmDependencyTO submittedItem : submittedItems) { try { DependencyRules rule = new DependencyRules(site); rule.setContentService(contentService); rule.setObjectStateService(objectStateService); submitThisAndReferredComponents(submittedItem, site, scheduledDate, sendEmail, submitForDeletion, submittedBy, rule, submissionComment); List<DmDependencyTO> children = submittedItem.getChildren(); if (children != null && !submitForDeletion) { for (DmDependencyTO child : children) { if (!child.isReference()) { submitThisAndReferredComponents(child, site, scheduledDate, sendEmail, submitForDeletion, submittedBy, rule, submissionComment); } } } } catch (ContentNotFoundException e) { errors.add(new DmError(site, submittedItem.getUri(), e)); } } return errors; } protected void submitThisAndReferredComponents(DmDependencyTO submittedItem, String site, Date scheduledDate, boolean sendEmail, boolean submitForDeletion, String submittedBy, DependencyRules rule, String submissionComment) throws ServiceException { doSubmit(site, submittedItem, scheduledDate, sendEmail, submitForDeletion, submittedBy, true, submissionComment); Set<DmDependencyTO> stringSet; if (submitForDeletion) { stringSet = rule.applyDeleteDependencyRule(submittedItem); } else { stringSet = rule.applySubmitRule(submittedItem); } for (DmDependencyTO s : stringSet) { String fullPath = contentService.expandRelativeSitePath(site, s.getUri()); ContentItemTO contentItem = contentService.getContentItem(site, s.getUri()); boolean lsendEmail = true; boolean lnotifyAdmin = true; lsendEmail = sendEmail && ((!contentItem.isDocument() && !contentItem.isComponent() && !contentItem.isAsset()) || customContentTypeNotification); lnotifyAdmin = (!contentItem.isDocument() && !contentItem.isComponent() && !contentItem.isAsset()); // notify admin will always be true, unless for dependent document/banner/other-files doSubmit(site, s, scheduledDate, lsendEmail, submitForDeletion, submittedBy, lnotifyAdmin, submissionComment); } } protected void doSubmit(final String site, final DmDependencyTO dependencyTO, final Date scheduledDate, final boolean sendEmail, final boolean submitForDeletion, final String user, final boolean notifyAdmin, final String submissionComment) { //first remove from workflow removeFromWorkflow(site, dependencyTO.getUri(), true); String fullPath = contentService.expandRelativeSitePath(site, dependencyTO.getUri()); DmPathTO path = new DmPathTO(fullPath); ContentItemTO item = contentService.getContentItem(site, dependencyTO.getUri()); // TODO: check if item is locked //if (!persistenceManagerService.getLockStatus(node).equals(LockStatus.NO_LOCK)) { // persistenceManagerService.unlock(node); //} /****** end ******/ Map<String, Object> properties = new HashMap<>(); properties.put(ObjectMetadata.PROP_SUBMITTED_BY, user); properties.put(ObjectMetadata.PROP_SEND_EMAIL, sendEmail ? 1 : 0); properties.put(ObjectMetadata.PROP_SUBMITTED_FOR_DELETION, submitForDeletion ? 1 : 0); properties.put(ObjectMetadata.PROP_SUBMISSION_COMMENT, submissionComment); if (null == scheduledDate) { properties.put(ObjectMetadata.PROP_LAUNCH_DATE, null); } else { properties.put(ObjectMetadata.PROP_LAUNCH_DATE, scheduledDate); } if (!objectMetadataManager.metadataExist(site, dependencyTO.getUri())) { objectMetadataManager.insertNewObjectMetadata(site, dependencyTO.getUri()); } objectMetadataManager.setObjectMetadata(site, dependencyTO.getUri(), properties); if (scheduledDate != null) { objectStateService.transition(site, item, TransitionEvent.SUBMIT_WITH_WORKFLOW_SCHEDULED); } else { objectStateService.transition(site, item, TransitionEvent.SUBMIT_WITH_WORKFLOW_UNSCHEDULED); } dmWorkflowListener.postSubmitToGolive(site, dependencyTO); if (notifyAdmin) { boolean isPreviewable = item.isPreviewable(); notificationService.sendContentSubmissionNotificationToApprovers(site, "admin", dependencyTO.getUri(), user, scheduledDate, isPreviewable, submitForDeletion); } } @Override public void submitToGoLive(String site, List<String> paths, Date scheduledDate, boolean sendApprovedNotice, String submitter) { /* // this needs to be gutted an re-written as workflow handlers that rely on services like dependency, state, content repository // that use the appropriate DAL objects. Now is not the time to pull the thread on that sweater :-/ String submissionComment = ""; //{"items":[{"asset":false,"assets":[],"browserUri":"/","categoryRoot":"","children":[{"asset":false,"assets":[],"browserUri":"/crafter-level-descriptor.level.xml","categoryRoot":"","children":[],"component":true,"components":[],"container":false,"contentType":"/component/level-descriptor","defaultWebApp":"/wem-projects/test-fr/test-fr/work-area","deleted":false,"deletedItems":[],"directory":false,"disabled":false,"document":false,"documents":[],"endpoint":"","eventDate":"2013-04-13T21:45:05","eventDateAsDate":{"date":13,"day":6,"hours":21,"minutes":45,"month":3,"seconds":5,"time":1365903905242,"timezoneOffset":240,"year":113},"floating":false,"form":"/component/level-descriptor","formPagePath":"simple","height":0,"hideInAuthoring":false,"inFlight":false,"inProgress":true,"internalName":"crafter-level-descriptor.level.xml","lastEditDate":{},"lastEditDateAsString":"","levelDescriptor":true,"levelDescriptors":[],"live":false,"lockOwner":"","mandatoryParent":"/site/website/index.xml","metaDescription":"","name":"crafter-level-descriptor.level.xml","navigation":false,"new":true,"newFile":true,"nodeRef":"workspace://SpacesStore/552af5fc-c93e-4032-9e24-66c4f5609cf9","now":false,"numOfChildren":0,"orders":[],"pages":[],"parentPath":"/","path":"/site/website","previewable":false,"properties":{},"reference":false,"renderingTemplate":false,"renderingTemplates":[],"scheduled":false,"scheduledDate":"","scheduledDateAsDate":{},"submissionComment":"","submitted":false,"submittedByFirstName":"","submittedByLastName":"","submittedForDeletion":false,"timezone":"EST5EDT","title":"","uri":"/site/website/crafter-level-descriptor.level.xml","user":"","userFirstName":"","userLastName":"","width":0,"workflowId":""},{"asset":false,"assets":[],"browserUri":"/about","categoryRoot":"","children":[],"component":false,"components":[],"container":true,"contentType":"/page/entry","defaultWebApp":"/wem-projects/test-fr/test-fr/work-area","deleted":false,"deletedItems":[],"directory":false,"disabled":false,"document":false,"documents":[],"endpoint":"","eventDate":"2013-04-18T22:35:22","eventDateAsDate":{"date":18,"day":4,"hours":22,"minutes":35,"month":3,"seconds":22,"time":1366338922741,"timezoneOffset":240,"year":113},"floating":false,"form":"/page/entry","formPagePath":"simple","height":0,"hideInAuthoring":false,"inFlight":false,"inProgress":true,"internalName":"About","lastEditDate":{},"lastEditDateAsString":"","levelDescriptor":false,"levelDescriptors":[],"live":false,"lockOwner":"","mandatoryParent":"/site/website/index.xml","metaDescription":"","name":"index.xml","navigation":false,"new":true,"newFile":true,"nodeRef":"workspace://SpacesStore/ef1d4242-c03a-4eb0-b294-d90ae7246ec9","now":false,"numOfChildren":1,"orders":[{"disabled":"","id":"default","name":"","order":1000,"placeInNav":""}],"pages":[],"parentPath":"/","path":"/site/website/about","previewable":true,"properties":{},"reference":false,"renderingTemplate":false,"renderingTemplates":[{"asset":false,"assets":[],"browserUri":"/templates/web/entry.ftl","categoryRoot":"","children":[],"component":true,"components":[],"container":false,"contentType":"","defaultWebApp":"/wem-projects/test-fr/test-fr/work-area","deleted":false,"deletedItems":[],"directory":false,"disabled":false,"document":false,"documents":[],"endpoint":"","eventDate":"2013-04-13T21:56:03","eventDateAsDate":{"date":13,"day":6,"hours":21,"minutes":56,"month":3,"seconds":3,"time":1365904563607,"timezoneOffset":240,"year":113},"floating":false,"form":"","formPagePath":"","height":0,"hideInAuthoring":false,"inFlight":false,"inProgress":true,"internalName":"entry.ftl","lastEditDate":{},"lastEditDateAsString":"","levelDescriptor":false,"levelDescriptors":[],"live":false,"lockOwner":"","mandatoryParent":"/site/website/about/index.xml","metaDescription":"","name":"entry.ftl","navigation":false,"new":true,"newFile":true,"nodeRef":"workspace://SpacesStore/5a234a22-8f4e-48d5-9da1-7797886e6776","now":false,"numOfChildren":0,"orders":[],"pages":[],"parentPath":"","path":"/templates/web","previewable":false,"properties":{},"reference":true,"renderingTemplate":false,"renderingTemplates":[],"scheduled":false,"scheduledDate":"","scheduledDateAsDate":{},"submissionComment":"","submitted":false,"submittedByFirstName":"","submittedByLastName":"","submittedForDeletion":false,"timezone":"EST5EDT","title":"","uri":"/templates/web/entry.ftl","user":"","userFirstName":"","userLastName":"","width":0,"workflowId":""}],"scheduled":false,"scheduledDate":"","scheduledDateAsDate":{},"submissionComment":"","submitted":false,"submittedByFirstName":"","submittedByLastName":"","submittedForDeletion":false,"timezone":"EST5EDT","title":"","uri":"/site/website/about/index.xml","user":"author","userFirstName":"author","userLastName":"author","width":0,"workflowId":""},{"asset":false,"assets":[],"browserUri":"/about/crafter-level-descriptor.level.xml","categoryRoot":"","children":[],"component":true,"components":[],"container":false,"contentType":"/component/level-descriptor","defaultWebApp":"/wem-projects/test-fr/test-fr/work-area","deleted":false,"deletedItems":[],"directory":false,"disabled":false,"document":false,"documents":[],"endpoint":"","eventDate":"2013-04-18T01:11:04","eventDateAsDate":{"date":18,"day":4,"hours":1,"minutes":11,"month":3,"seconds":4,"time":1366261864668,"timezoneOffset":240,"year":113},"floating":false,"form":"/component/level-descriptor","formPagePath":"simple","height":0,"hideInAuthoring":false,"inFlight":false,"inProgress":true,"internalName":"crafter-level-descriptor.level.xml","lastEditDate":{},"lastEditDateAsString":"","levelDescriptor":true,"levelDescriptors":[],"live":false,"lockOwner":"","mandatoryParent":"/site/website/about/index.xml","metaDescription":"","name":"crafter-level-descriptor.level.xml","navigation":false,"new":true,"newFile":true,"nodeRef":"workspace://SpacesStore/873a99c8-109d-47ac-a245-7c2194b17fdf","now":false,"numOfChildren":0,"orders":[],"pages":[],"parentPath":"/about","path":"/site/website/about","previewable":false,"properties":{},"reference":false,"renderingTemplate":false,"renderingTemplates":[],"scheduled":false,"scheduledDate":"","scheduledDateAsDate":{},"submissionComment":"","submitted":false,"submittedByFirstName":"","submittedByLastName":"","submittedForDeletion":false,"timezone":"EST5EDT","title":"","uri":"/site/website/about/crafter-level-descriptor.level.xml","user":"","userFirstName":"","userLastName":"","width":0,"workflowId":""}],"component":false,"components":[],"container":true,"contentType":"/page/entry","defaultWebApp":"/wem-projects/test-fr/test-fr/work-area","deleted":false,"deletedItems":[],"directory":false,"disabled":false,"document":false,"documents":[],"endpoint":"","eventDate":"2013-04-18T03:25:40","eventDateAsDate":{"date":18,"day":4,"hours":3,"minutes":25,"month":3,"seconds":40,"time":1366269940177,"timezoneOffset":240,"year":113},"floating":false,"form":"/page/entry","formPagePath":"simple","height":0,"hideInAuthoring":false,"inFlight":false,"inProgress":true,"internalName":"Home","lastEditDate":{},"lastEditDateAsString":"","levelDescriptor":false,"levelDescriptors":[],"live":false,"lockOwner":"","mandatoryParent":"","metaDescription":"","name":"index.xml","navigation":false,"new":true,"newFile":true,"nodeRef":"workspace://SpacesStore/47a6796a-f6d0-46bc-a563-f9d08d941b01","now":true,"numOfChildren":3,"orders":[{"disabled":"","id":"default","name":"","order":-1,"placeInNav":""}],"pages":[],"parentPath":"","path":"/site/website","previewable":true,"properties":{},"reference":false,"renderingTemplate":false,"renderingTemplates":[{"asset":false,"assets":[],"browserUri":"/templates/web/entry.ftl","categoryRoot":"","children":[],"component":true,"components":[],"container":false,"contentType":"","defaultWebApp":"/wem-projects/test-fr/test-fr/work-area","deleted":false,"deletedItems":[],"directory":false,"disabled":false,"document":false,"documents":[],"endpoint":"","eventDate":"2013-04-13T21:56:03","eventDateAsDate":{"date":13,"day":6,"hours":21,"minutes":56,"month":3,"seconds":3,"time":1365904563607,"timezoneOffset":240,"year":113},"floating":false,"form":"","formPagePath":"","height":0,"hideInAuthoring":false,"inFlight":false,"inProgress":true,"internalName":"entry.ftl","lastEditDate":{},"lastEditDateAsString":"","levelDescriptor":false,"levelDescriptors":[],"live":false,"lockOwner":"","mandatoryParent":"/site/website/index.xml","metaDescription":"","name":"entry.ftl","navigation":false,"new":true,"newFile":true,"nodeRef":"workspace://SpacesStore/5a234a22-8f4e-48d5-9da1-7797886e6776","now":false,"numOfChildren":0,"orders":[],"pages":[],"parentPath":"","path":"/templates/web","previewable":false,"properties":{},"reference":true,"renderingTemplate":false,"renderingTemplates":[],"scheduled":false,"scheduledDate":"","scheduledDateAsDate":{},"submissionComment":"","submitted":false,"submittedByFirstName":"","submittedByLastName":"","submittedForDeletion":false,"timezone":"EST5EDT","title":"","uri":"/templates/web/entry.ftl","user":"","userFirstName":"","userLastName":"","width":0,"workflowId":""}],"scheduled":false,"scheduledDate":"","scheduledDateAsDate":{},"submissionComment":"","submitted":false,"submittedByFirstName":"","submittedByLastName":"","submittedForDeletion":false,"timezone":"EST5EDT","title":"","uri":"/site/website/index.xml","user":"admin","userFirstName":"Administrator","userLastName":"","width":0,"workflowId":""}],"submissionComment":"","now":"true","scheduledDate":"2010-02-26T15:00:00","sendEmail":"true"} List<DmDependencyTO> submittedItems = new ArrayList<DmDependencyTO>(); RequestContext requestContext = new RequestContext(site, submitter); for(String path : paths) { DmDependencyTO depTO = new DmDependencyTO(); depTO.setUri(path); submittedItems.add(depTO); } try{ List<DmError> errors = _dmSimpleWfService.submitToGoLive( submittedItems, scheduledDate, sendApprovedNotice, false, //submit for delete, requestContext, //request context, submissionComment); } catch(Exception err) { logger.error("submitToGoLive", err); } */ } @Override public Map<String, Object> getGoLiveItems(String site, String sort, boolean ascending) throws ServiceException { DmContentItemComparator comparator = new DmContentItemComparator(sort, ascending, false, false); List<ContentItemTO> items = getGoLiveItems(site, comparator); int total = 0; if (items != null) { for (ContentItemTO item : items) { total += item.getNumOfChildren(); } } Map<String, Object> result = new HashMap<>(); result.put(CStudioConstants.PROPERTY_TOTAL, total); result.put(CStudioConstants.PROPERTY_SORTED_BY, sort); result.put(CStudioConstants.PROPERTY_SORT_ASCENDING, String.valueOf(ascending)); result.put(CStudioConstants.PROPERTY_DOCUMENTS, items); return result; } protected List<ContentItemTO> getGoLiveItems(final String site, final DmContentItemComparator comparator) throws ServiceException { List<String> displayPatterns = servicesConfig.getDisplayInWidgetPathPatterns(site); List<ContentItemTO> categoryItems = getCategoryItems(site); GoLiveQueue queue = new GoLiveQueue(); fillQueue(site, queue, null); //} Set<ContentItemTO> queueItems = queue.getQueue(); ContentItemTO.ChildFilter childFilter = new GoLiveQueueChildFilter(queue); GoLiveQueueOrganizer goLiveQueueOrganizer = new GoLiveQueueOrganizer(contentService, childFilter); for (ContentItemTO queueItem : queueItems) { if (queueItem.getLastEditDate() != null) { queueItem.setEventDate(queueItem.getLastEditDate()); } goLiveQueueOrganizer.addToGoLiveItems(site, queueItem, categoryItems, comparator, false, displayPatterns); } return categoryItems; } /** * get the top category items that to be displayed in UI * * @param site */ protected List<ContentItemTO> getCategoryItems(final String site) { String siteRootPrefix = servicesConfig.getRootPrefix(site); List<ContentItemTO> categories = new ArrayList<>(); List<DmFolderConfigTO> folders = servicesConfig.getFolders(site); for (DmFolderConfigTO folder : folders) { String uri = (folder.isAttachRootPrefix()) ? siteRootPrefix + folder.getPath() : folder.getPath(); // if the flag to read direct children is set to true, get direct // child folders and add them as categories if (folder.isReadDirectChildren()) { ContentItemTO rootItem = contentService.getContentItemTree(site, siteRootPrefix + folder.getPath(), 1); if (rootItem != null) { if (rootItem.children != null) { for (ContentItemTO childItem : rootItem.children) { categories.add(childItem); } } categories.add(rootItem); } } else { ContentItemTO categoryItem = new ContentItemTO(); String timeZone = servicesConfig.getDefaultTimezone(site); categoryItem.setTimezone(timeZone); categoryItem.setName(folder.getName()); categoryItem.setInternalName(folder.getName()); categoryItem.setUri(uri); categoryItem.setPath(uri); categoryItem.setCategoryRoot(uri); categories.add(categoryItem); } } return categories; } public void fillQueue(String site, GoLiveQueue goLiveQueue, GoLiveQueue inProcessQueue) throws ServiceException { List<ObjectState> changeSet = objectStateService.getSubmittedItems(site); // TODO: implement list changed all // the category item to add all other items that do not belong to // regular categories specified in the configuration if (changeSet != null) { // add all content items from each task if task is the review task for (ObjectState state : changeSet) { try { if (contentService.contentExists(state.getSite(), state.getPath())) { ContentItemTO item = contentService.getContentItem(state.getSite(), state.getPath(), 0); Set<String> permissions = securityService.getUserPermissions(site, item.getUri(), securityService.getCurrentUser(), Collections.<String>emptyList()); if (permissions.contains(CStudioConstants.PERMISSION_VALUE_PUBLISH)) { addToQueue(site, goLiveQueue, inProcessQueue, item, state); } } else { _cancelWorkflow(site, state.getPath()); objectStateService.deleteObjectStateForPath(site, state.getPath()); objectMetadataManager.deleteObjectMetadata(site, state.getPath()); } } catch (Exception e) { logger.error("Could not warm cache for [" + state.getSite() + " : " + state.getPath() + "] " + e.getMessage()); } } } } protected void addToQueue(String site, GoLiveQueue queue, GoLiveQueue inProcessQueue, ContentItemTO item, ObjectState itemState) throws ServiceException { if (item != null) { State state = State.valueOf(itemState.getState()); //add only submitted items to go live Q. if (State.isSubmitted(state)) { queue.add(item); } if (inProcessQueue != null) { if (!State.isLive(state)) { inProcessQueue.add(item); inProcessQueue.add(item.getPath(), item); } } } else { objectStateService.deleteObjectState(itemState.getObjectId()); } } public Map<String, Object> getInProgressItems(String site, String sort, boolean ascending, boolean inProgressOnly) throws ServiceException { DmContentItemComparator comparator = new DmContentItemComparator(sort, ascending, true, true); List<ContentItemTO> items = getInProgressItems(site, comparator, inProgressOnly); JSONObject jsonObject = new JSONObject(); int total = 0; if (items != null) { for (ContentItemTO item : items) { total += item.getNumOfChildren(); } } Map<String, Object> result = new HashMap<>(); result.put(CStudioConstants.PROPERTY_TOTAL, total); result.put(CStudioConstants.PROPERTY_SORTED_BY, sort); result.put(CStudioConstants.PROPERTY_SORT_ASCENDING, String.valueOf(ascending)); result.put(CStudioConstants.PROPERTY_DOCUMENTS, items); return result; } protected List<ContentItemTO> getInProgressItems(final String site, final DmContentItemComparator comparator, final boolean inProgressOnly) throws ServiceException { final List<ContentItemTO> categoryItems = new ArrayList<>(); List<ContentItemTO> categoryItems1 = getCategoryItems(site); categoryItems.addAll(categoryItems1); long st = System.currentTimeMillis(); List<ObjectState> changeSet = objectStateService.getChangeSet(site); logger.debug("Time taken listChangedAll() " + (System.currentTimeMillis() - st)); // the category item to add all other items that do not belong to // regular categories specified in the configuration st = System.currentTimeMillis(); if (changeSet != null) { List<String> displayPatterns = servicesConfig.getDisplayInWidgetPathPatterns(site); //List<String> inProgressItems = new FastList<String>(); for (ObjectState state : changeSet) { if (contentService.contentExists(state.getSite(), state.getPath())) { if (ContentUtils.matchesPatterns(state.getPath(), displayPatterns)) { ContentItemTO item = contentService.getContentItem(state.getSite(), state.getPath(), 0); addInProgressItems(site, item, categoryItems, comparator, inProgressOnly); } } } } logger.debug("Time taken after listChangedAll() : " + (System.currentTimeMillis() - st)); return categoryItems; } protected void addInProgressItems(String site, ContentItemTO item, List<ContentItemTO> categoryItems, DmContentItemComparator comparator, boolean inProgressOnly) { if (addToQueue(false, inProgressOnly, true)) { if (!(item.isSubmitted() || item.isInProgress())) { return; } item.setDeleted(false); ContentItemTO found = null; String uri = item.getUri(); for (ContentItemTO categoryItem : categoryItems) { String categoryPath = categoryItem.getPath() + "/"; if (uri.startsWith(categoryPath)) { found = categoryItem; break; } } if (found != null && !found.getUri().equals(item.getUri())) { found.addChild(item, comparator, true); } } } /** * add the current item to the queue? * * @param inProgressOnly * @param includeInProgress * @param includeInProgress * @return */ protected boolean addToQueue(boolean submitted, boolean inProgressOnly, boolean includeInProgress) { // excluded approved or scheduled items if in-progress items are // included. go-live queue case the node is in review if (inProgressOnly && submitted) { return false; } // add items in following cases // 1) if the item is submitted, add if the flag is not in-progress only // 2) if the item is in progress, add if the flag is either in-progress // only or include in progress if (submitted && !inProgressOnly) { return true; } else if (!submitted && (inProgressOnly || includeInProgress)) { return true; } return false; } @Override public boolean removeFromWorkflow(String site, String path, boolean cancelWorkflow) { Set<String> processedPaths = new HashSet<>(); return removeFromWorkflow(site, path, processedPaths, cancelWorkflow); } protected boolean removeFromWorkflow(String site, String path, Set<String> processedPaths, boolean cancelWorkflow) { // remove submitted aspects from all dependent items if (!processedPaths.contains(path)) { processedPaths.add(path); //if (contentService.contentExists(site, path)) { //removeSubmittedAspect(site, fullPath, null, false, DmConstants.DM_STATUS_IN_PROGRESS); // cancel workflow if anything is pending long startTime = System.currentTimeMillis(); if (cancelWorkflow) { _cancelWorkflow(site, path); } long duration = System.currentTimeMillis() - startTime; logger.debug("_cancelWorkflow Duration 111: {0}", duration); /* startTime = System.currentTimeMillis(); DmDependencyTO depItem = dmDependencyService.getDependencies(site, path, false, true); duration = System.currentTimeMillis() - startTime; logger.warn("getDependencies Duration 112: {0}", duration); if (depItem != null) { DependencyRules dependencyRules = new DependencyRules(site); dependencyRules.setObjectStateService(objectStateService); dependencyRules.setContentService(contentService); long startTime1 = System.currentTimeMillis(); Set<DmDependencyTO> submittedDeps = dependencyRules.applySubmitRule(depItem); duration = System.currentTimeMillis() - startTime1; logger.warn("applySubmitRule Duration 113: {0}", duration); List<String> transitionNodes = new ArrayList<String>(); for (DmDependencyTO dependencyTO : submittedDeps) { removeFromWorkflow(site, dependencyTO.getUri(), processedPaths, cancelWorkflow); ObjectState state = objectStateService.getObjectState(site, dependencyTO.getUri()); if (State.isScheduled(State.valueOf(state.getState())) || State.isSubmitted(State.valueOf(state.getState()))) { transitionNodes.add(dependencyTO.getUri()); } } if (!transitionNodes.isEmpty()) { objectStateService.transitionBulk(site, transitionNodes, org.craftercms.studio.api.v1.service.objectstate.TransitionEvent.SAVE, State.NEW_UNPUBLISHED_UNLOCKED); } } duration = System.currentTimeMillis() - startTime; logger.warn("removeFromWorkflow - dependencies Duration 114: {0}", duration);*/ //} } return false; } protected void _cancelWorkflow(String site, String path) { //if (contentService.contentExists(site, path)) { List<String> allItemsToCancel = getWorkflowAffectedPathsInternal(site, path); List<String> paths = new ArrayList<String>(); for (String affectedItem : allItemsToCancel) { try { deploymentService.cancelWorkflow(site, affectedItem); paths.add(affectedItem); } catch (DeploymentException e) { logger.error("Error occurred while trying to cancel workflow for path [" + affectedItem + "], site " + site, e); } } objectStateService.transitionBulk(site, paths, org.craftercms.studio.api.v1.service.objectstate.TransitionEvent.REJECT, State.NEW_UNPUBLISHED_UNLOCKED); if (objectStateService.isNew(site, path) && path.endsWith(DmConstants.INDEX_FILE)) { // TODO: process children for new parent /* NodeRef parentNodeRef = persistenceManagerService.getPrimaryParent(node).getParentRef(); FileInfo parentInfo = persistenceManagerService.getFileInfo(parentNodeRef); List<FileInfo> files = persistenceManagerService.listFiles(parentNodeRef); for (FileInfo file : files) { if (!file.getNodeRef().equals(node)) { ObjectStateService.State state = persistenceManagerService.getObjectState(file.getNodeRef()); if (ObjectStateService.State.isScheduled(state) || ObjectStateService.State.isSubmitted(state)) { _cancelWorkflow(site, file.getNodeRef()); persistenceManagerService.transition(file.getNodeRef(), ObjectStateService.TransitionEvent.SAVE); } } } List<FileInfo> folders = persistenceManagerService.listFolders(parentNodeRef); for (FileInfo folder : folders) { NodeRef indexNode = persistenceManagerService.getNodeRef(folder.getNodeRef(), DmConstants.INDEX_FILE); if (indexNode != null) { ObjectStateService.State state = persistenceManagerService.getObjectState(indexNode); if (ObjectStateService.State.isScheduled(state) || ObjectStateService.State.isSubmitted(state)) { _cancelWorkflow(site, indexNode); persistenceManagerService.transition(indexNode, ObjectStateService.TransitionEvent.SAVE); } } }*/ } //} } protected List<String> getWorkflowAffectedPathsInternal(String site, String path) { List<String> affectedPaths = new ArrayList<String>(); //List<ContentItemTO> affectedItems = new ArrayList<ContentItemTO>(); List<String> filteredPaths = new ArrayList<String>(); if (objectStateService.isInWorkflow(site, path)) { affectedPaths.add(path); boolean isNew = objectStateService.isNew(site, path); boolean isRenamed = objectMetadataManager.isRenamed(site, path); if (isNew || isRenamed) { getMandatoryChildren(site, path, affectedPaths); } List<String> dependencyPaths = getDependencyCandidates(site, affectedPaths); affectedPaths.addAll(dependencyPaths); List<String> candidates = new ArrayList<String>(); for (String p : affectedPaths) { if (!candidates.contains(p)) { candidates.add(p); } } for (String cp : candidates) { if (objectStateService.isInWorkflow(site, cp)) { filteredPaths.add(cp); } } //affectedItems = getWorkflowAffectedItems(site, filteredPaths); } return affectedPaths; } @Override public List<ContentItemTO> getWorkflowAffectedPaths(String site, String path) { List<String> affectedPaths = getWorkflowAffectedPathsInternal(site, path); return getWorkflowAffectedItems(site, affectedPaths); } private void getMandatoryChildren(String site, String path, List<String> affectedPaths) { // TODO: check folders and list children /* PersistenceManagerService persistenceManagerService = getService(PersistenceManagerService.class); String parentPath = fullPath.replace("/" + DmConstants.INDEX_FILE, ""); List<FileInfo> children = persistenceManagerService.list(parentPath); for (FileInfo child : children) { NodeRef childRef = child.getNodeRef(); String childPath = persistenceManagerService.getNodePath(childRef); DmPathTO dmPathTO = new DmPathTO(childPath); if (!affectedPaths.contains(dmPathTO.getRelativePath())) { affectedPaths.add(dmPathTO.getRelativePath()); getMandatoryChildren(childPath, affectedPaths); } }*/ } private List<String> getDependencyCandidates(String site, List<String> affectedPaths) { List<String> dependenciesPaths = new ArrayList<String>(); for (String path : affectedPaths) { getAllDependenciesRecursive(site, path, dependenciesPaths); } return dependenciesPaths; } protected void getAllDependenciesRecursive(String site, String path, List<String> dependecyPaths) { List<String> depPaths = dmDependencyService.getDependencyPaths(site, path); for (String depPath : depPaths) { if (!dependecyPaths.contains(depPath)) { dependecyPaths.add(depPath); getAllDependenciesRecursive(site, depPath, dependecyPaths); } } } protected List<ContentItemTO> getWorkflowAffectedItems(String site, List<String> paths) { List<ContentItemTO> items = new ArrayList<>(); for (String path : paths) { ContentItemTO item = contentService.getContentItem(site, path); items.add(item); } return items; } @Override public void updateWorkflowSandboxes(String site, String path) { // TODO: copy to live repo node /* PersistenceManagerService persistenceManagerService = getService(PersistenceManagerService.class); NodeRef node = persistenceManagerService.getNodeRef(fullPath); if (node != null) { NodeRef liveRepoNode = persistenceManagerService.getNodeRef(getPathFromLiveRepo(fullPath)); if (liveRepoNode != null) { persistenceManagerService.copy(node, liveRepoNode); } }*/ } /** * approve workflows and schedule them as specified in the request * * @param site * @param request * @return call result * @throws ServiceException */ @Override public ResultTO goDelete(String site, String request, String user) { String md5 = ContentUtils.getMd5ForFile(request); String id = site + ":" + user + ":" + md5; if (!generalLockService.tryLock(id)) { generalLockService.lock(id); generalLockService.unlock(id); return new ResultTO(); } try { Map<String, String> map = new HashMap<String, String>(); map.put(CStudioConstants.USER, user); //ThreadLocalContainer.set(map); return approve(site, request, Operation.DELETE); } finally { //ThreadLocalContainer.remove(); generalLockService.unlock(id); } } /** * approve workflows and schedule them as specified in the request * * @param site * @param request * @return call result * @throws ServiceException */ protected ResultTO approve(String site, String request, Operation operation) { String approver = securityService.getCurrentUser(); ResultTO result = new ResultTO(); try { JSONObject requestObject = JSONObject.fromObject(request); JSONArray items = requestObject.getJSONArray(JSON_KEY_ITEMS); String scheduledDate = null; if (requestObject.containsKey(JSON_KEY_SCHEDULED_DATE)) { scheduledDate = requestObject.getString(JSON_KEY_SCHEDULED_DATE); } boolean isNow = (requestObject.containsKey(JSON_KEY_IS_NOW)) ? requestObject.getBoolean(JSON_KEY_IS_NOW) : false; String publishChannelGroupName = (requestObject.containsKey(JSON_KEY_PUBLISH_CHANNEL)) ? requestObject.getString(JSON_KEY_PUBLISH_CHANNEL) : null; JSONObject jsonObjectStatus = requestObject.getJSONObject(JSON_KEY_STATUS_SET); String statusMessage = (jsonObjectStatus != null && jsonObjectStatus.containsKey(JSON_KEY_STATUS_MESSAGE)) ? jsonObjectStatus.getString(JSON_KEY_STATUS_MESSAGE) : null; String submissionComment = (requestObject != null && requestObject.containsKey(JSON_KEY_SUBMISSION_COMMENT)) ? requestObject.getString(JSON_KEY_SUBMISSION_COMMENT) : "Test Go Live"; MultiChannelPublishingContext mcpContext = new MultiChannelPublishingContext(publishChannelGroupName, statusMessage, submissionComment); if (operation != Operation.DELETE && !dmPublishService.hasChannelsConfigure(site, mcpContext)) { ResultTO toReturn = new ResultTO(); List<PublishingChannelConfigTO> channelsList = siteService.getPublishingChannelGroupConfigs(site) .get(mcpContext.getPublishingChannelGroup()).getChannels(); String channels = StringUtils.join(channelsList, " "); toReturn.setMessage(" Specified target '" + channels + "' was not found. Please check if an endpoint or channel with name '" + channels + "' exists in site configuration"); toReturn.setSuccess(false); toReturn.setInvalidateCache(false); return toReturn; } int length = items.size(); if (length == 0) { throw new ServiceException("No items provided to go live."); } String responseMessageKey = null; SimpleDateFormat format = new SimpleDateFormat(CStudioConstants.DATE_PATTERN_WORKFLOW); List<DmDependencyTO> submittedItems = new ArrayList<>(); for (int index = 0; index < length; index++) { String stringItem = items.optString(index); DmDependencyTO submittedItem = null; submittedItem = getSubmittedItem(site, stringItem, format, scheduledDate, null); List<DmDependencyTO> submitForDeleteChildren = removeSubmitToDeleteChildrenForGoLive(submittedItem, operation); if (submittedItem.isReference()) { submittedItem.setReference(false); } submittedItems.add(submittedItem); submittedItems.addAll(submitForDeleteChildren); } switch (operation) { case GO_LIVE: if (scheduledDate != null && isNow == false) { responseMessageKey = NotificationService.COMPLETE_SCHEDULE_GO_LIVE; } else { responseMessageKey = NotificationService.COMPLETE_GO_LIVE; } List<DmDependencyTO> submitToDeleteItems = new ArrayList<>(); List<DmDependencyTO> goLiveItems = new ArrayList<>(); List<DmDependencyTO> renameItems = new ArrayList<>(); for (DmDependencyTO item : submittedItems) { if (item.isSubmittedForDeletion()) { submitToDeleteItems.add(item); } else { if (!dmRenameService.isItemRenamed(site, item)) { goLiveItems.add(item); } else { renameItems.add(item); } } } if (!submitToDeleteItems.isEmpty()) { doDelete(site, submitToDeleteItems, approver); } if (!goLiveItems.isEmpty()) { List<DmDependencyTO> references = getRefAndChildOfDiffDateFromParent(site, goLiveItems, true); List<DmDependencyTO> children = getRefAndChildOfDiffDateFromParent(site, goLiveItems, false); goLiveItems.addAll(references); goLiveItems.addAll(children); List<String> goLivePaths = new ArrayList<>(); for (DmDependencyTO goLiveItem : goLiveItems) { resolveSubmittedPaths(site, goLiveItem, goLivePaths); } List<String> nodeRefs = new ArrayList<>(); for (String fullPath : goLivePaths) { String path = contentService.getRelativeSitePath(site, fullPath); String lockId = site + ":" + path; generalLockService.lock(lockId); } try { goLive(site, goLiveItems, approver, mcpContext); } finally { for (String fullPath : goLivePaths) { String path = contentService.getRelativeSitePath(site, fullPath); String lockId = site + ":" + path; generalLockService.unlock(lockId); } } } if (!renameItems.isEmpty()) { List<String> renamePaths = new ArrayList<>(); List<DmDependencyTO> renamedChildren = new ArrayList<>(); for (DmDependencyTO renameItem : renameItems) { renamedChildren.addAll(getChildrenForRenamedItem(site, renameItem)); String fullPath = contentService.expandRelativeSitePath(site, renameItem.getUri()); renamePaths.add(fullPath); objectStateService.setSystemProcessing(site, renameItem.getUri(), true); } for (DmDependencyTO renamedChild : renamedChildren) { String fullPath = contentService.expandRelativeSitePath(site, renamedChild.getUri()); renamePaths.add(fullPath); objectStateService.setSystemProcessing(site, renamedChild.getUri(), true); } renameItems.addAll(renamedChildren); //Set proper information of all renameItems before send them to GoLive for (int i = 0; i < renameItems.size(); i++) { DmDependencyTO renamedItem = renameItems.get(i); if (renamedItem.getScheduledDate() != null && renamedItem.getScheduledDate().after(new Date())) { renamedItem.setNow(false); } else { renamedItem.setNow(true); } renameItems.set(i, renamedItem); } dmRenameService.goLive(site, renameItems, approver, mcpContext); } break; case DELETE: responseMessageKey = NotificationService.COMPLETE_DELETE; List<String> deletePaths = new ArrayList<>(); List<String> nodeRefs = new ArrayList<String>(); for (DmDependencyTO deletedItem : submittedItems) { String fullPath = contentService.expandRelativeSitePath(site, deletedItem.getUri()); //deletedItem.setScheduledDate(getScheduledDate(site, format, scheduledDate)); deletePaths.add(fullPath); ContentItemTO contentItem = contentService.getContentItem(site, deletedItem.getUri()); if (contentItem != null) { //nodeRefs.add(nodeRef.getId()); } } doDelete(site, submittedItems, approver); } result.setSuccess(true); result.setStatus(200); result.setMessage(notificationService.getCompleteMessage(site, responseMessageKey)); } catch (JSONException e) { logger.error("error performing operation " + operation + " " + e); result.setSuccess(false); result.setMessage(e.getMessage()); } catch (ServiceException e) { logger.error("error performing operation " + operation + " " + e); result.setSuccess(false); result.setMessage(e.getMessage()); } return result; } /** * approve workflows and schedule them as specified in the request * * @param site * @param request * @return call result * @throws ServiceException */ protected ResultTO approve_new(String site, String request, Operation operation) { String approver = securityService.getCurrentUser(); ResultTO result = new ResultTO(); try { JSONObject requestObject = JSONObject.fromObject(request); JSONArray items = requestObject.getJSONArray(JSON_KEY_ITEMS); String scheduledDate = null; if (requestObject.containsKey(JSON_KEY_SCHEDULED_DATE)) { scheduledDate = requestObject.getString(JSON_KEY_SCHEDULED_DATE); } boolean isNow = (requestObject.containsKey(JSON_KEY_IS_NOW)) ? requestObject.getBoolean(JSON_KEY_IS_NOW) : false; String publishChannelGroupName = (requestObject.containsKey(JSON_KEY_PUBLISH_CHANNEL)) ? requestObject.getString(JSON_KEY_PUBLISH_CHANNEL) : null; JSONObject jsonObjectStatus = requestObject.getJSONObject(JSON_KEY_STATUS_SET); String statusMessage = (jsonObjectStatus != null && jsonObjectStatus.containsKey(JSON_KEY_STATUS_MESSAGE)) ? jsonObjectStatus.getString(JSON_KEY_STATUS_MESSAGE) : null; String submissionComment = (requestObject != null && requestObject.containsKey(JSON_KEY_SUBMISSION_COMMENT)) ? requestObject.getString(JSON_KEY_SUBMISSION_COMMENT) : "Test Go Live"; MultiChannelPublishingContext mcpContext = new MultiChannelPublishingContext(publishChannelGroupName, statusMessage, submissionComment); if (operation != Operation.DELETE && !dmPublishService.hasChannelsConfigure(site, mcpContext)) { ResultTO toReturn = new ResultTO(); List<PublishingChannelConfigTO> channelsList = siteService.getPublishingChannelGroupConfigs(site) .get(mcpContext.getPublishingChannelGroup()).getChannels(); String channels = StringUtils.join(channelsList, " "); toReturn.setMessage(" Specified target '" + channels + "' was not found. Please check if an endpoint or channel with name '" + channels + "' exists in site configuration"); toReturn.setSuccess(false); toReturn.setInvalidateCache(false); return toReturn; } int length = items.size(); if (length == 0) { throw new ServiceException("No items provided to go live."); } List<String> submittedPaths = new ArrayList<String>(); String responseMessageKey = null; SimpleDateFormat format = new SimpleDateFormat(CStudioConstants.DATE_PATTERN_WORKFLOW); List<DmDependencyTO> submittedItems = new ArrayList<>(); for (int index = 0; index < length; index++) { String stringItem = items.optString(index); submittedPaths.add(stringItem); DmDependencyTO submittedItem = null; submittedItem = getSubmittedItem_new(site, stringItem, format, scheduledDate); List<DmDependencyTO> submitForDeleteChildren = removeSubmitToDeleteChildrenForGoLive(submittedItem, operation); if (submittedItem.isReference()) { submittedItem.setReference(false); } submittedItems.add(submittedItem); submittedItems.addAll(submitForDeleteChildren); } switch (operation) { case GO_LIVE: if (scheduledDate != null && isNow == false) { responseMessageKey = NotificationService.COMPLETE_SCHEDULE_GO_LIVE; } else { responseMessageKey = NotificationService.COMPLETE_GO_LIVE; } List<DmDependencyTO> submitToDeleteItems = new ArrayList<>(); List<DmDependencyTO> goLiveItems = new ArrayList<>(); List<DmDependencyTO> renameItems = new ArrayList<>(); for (DmDependencyTO item : submittedItems) { if (item.isSubmittedForDeletion()) { submitToDeleteItems.add(item); } else { if (!dmRenameService.isItemRenamed(site, item)) { goLiveItems.add(item); } else { renameItems.add(item); } } } if (!submitToDeleteItems.isEmpty()) { doDelete(site, submitToDeleteItems, approver); } if (!goLiveItems.isEmpty()) { List<DmDependencyTO> references = getRefAndChildOfDiffDateFromParent_new(site, goLiveItems, true); List<DmDependencyTO> children = getRefAndChildOfDiffDateFromParent_new(site, goLiveItems, false); goLiveItems.addAll(references); goLiveItems.addAll(children); List<DmDependencyTO> dependencies = addDependenciesForSubmittedItems(site, submittedItems, format, scheduledDate); goLiveItems.addAll(dependencies); List<String> goLivePaths = new ArrayList<>(); for (DmDependencyTO goLiveItem : goLiveItems) { resolveSubmittedPaths(site, goLiveItem, goLivePaths); } for (String fullPath : goLivePaths) { String path = contentService.getRelativeSitePath(site, fullPath); String lockId = site + ":" + path; generalLockService.lock(lockId); } try { goLive(site, goLiveItems, approver, mcpContext); } finally { for (String fullPath : goLivePaths) { String path = contentService.getRelativeSitePath(site, fullPath); String lockId = site + ":" + path; generalLockService.unlock(lockId); } } } if (!renameItems.isEmpty()) { List<String> renamePaths = new ArrayList<>(); List<DmDependencyTO> renamedChildren = new ArrayList<>(); for (DmDependencyTO renameItem : renameItems) { renamedChildren.addAll(getChildrenForRenamedItem(site, renameItem)); String fullPath = contentService.expandRelativeSitePath(site, renameItem.getUri()); renamePaths.add(fullPath); objectStateService.setSystemProcessing(site, renameItem.getUri(), true); } for (DmDependencyTO renamedChild : renamedChildren) { String fullPath = contentService.expandRelativeSitePath(site, renamedChild.getUri()); renamePaths.add(fullPath); objectStateService.setSystemProcessing(site, renamedChild.getUri(), true); } renameItems.addAll(renamedChildren); //Set proper information of all renameItems before send them to GoLive for (int i = 0; i < renameItems.size(); i++) { DmDependencyTO renamedItem = renameItems.get(i); if (renamedItem.getScheduledDate() != null && renamedItem.getScheduledDate().after(new Date())) { renamedItem.setNow(false); } else { renamedItem.setNow(true); } renameItems.set(i, renamedItem); } dmRenameService.goLive(site, renameItems, approver, mcpContext); } break; case DELETE: responseMessageKey = NotificationService.COMPLETE_DELETE; List<String> deletePaths = new ArrayList<>(); List<String> nodeRefs = new ArrayList<String>(); for (DmDependencyTO deletedItem : submittedItems) { String fullPath = contentService.expandRelativeSitePath(site, deletedItem.getUri()); //deletedItem.setScheduledDate(getScheduledDate(site, format, scheduledDate)); deletePaths.add(fullPath); ContentItemTO contentItem = contentService.getContentItem(site, deletedItem.getUri()); if (contentItem != null) { //nodeRefs.add(nodeRef.getId()); } } doDelete(site, submittedItems, approver); } result.setSuccess(true); result.setStatus(200); result.setMessage(notificationService.getCompleteMessage(site, responseMessageKey)); } catch (JSONException e) { logger.error("error performing operation " + operation + " " + e); result.setSuccess(false); result.setMessage(e.getMessage()); } catch (ServiceException e) { logger.error("error performing operation " + operation + " " + e); result.setSuccess(false); result.setMessage(e.getMessage()); } return result; } /** * get a submitted item from a JSON item * * @param site * @param item * @param format * @return * @throws net.sf.json.JSONException */ protected DmDependencyTO getSubmittedItem(String site, JSONObject item, SimpleDateFormat format, String globalSchDate) throws JSONException { DmDependencyTO submittedItem = new DmDependencyTO(); String uri = item.getString(JSON_KEY_URI); submittedItem.setUri(uri); boolean deleted = (item.containsKey(JSON_KEY_DELETED)) ? item.getBoolean(JSON_KEY_DELETED) : false; submittedItem.setDeleted(deleted); boolean isNow = (item.containsKey(JSON_KEY_IS_NOW)) ? item.getBoolean(JSON_KEY_IS_NOW) : false; submittedItem.setNow(isNow); boolean submittedForDeletion = (item.containsKey(JSON_KEY_SUBMITTED_FOR_DELETION)) ? item.getBoolean(JSON_KEY_SUBMITTED_FOR_DELETION) : false; boolean submitted = (item.containsKey(JSON_KEY_SUBMITTED)) ? item.getBoolean(JSON_KEY_SUBMITTED) : false; boolean inProgress = (item.containsKey(JSON_KEY_IN_PROGRESS)) ? item.getBoolean(JSON_KEY_IN_PROGRESS) : false; boolean isReference = (item.containsKey(JSON_KEY_IN_REFERENCE)) ? item.getBoolean(JSON_KEY_IN_REFERENCE) : false; submittedItem.setReference(isReference); // boolean submittedForDeletion = // (item.containsKey(JSON_KEY_SUBMITTED_FOR_DELETION)) ? // item.getBoolean(JSON_KEY_SUBMITTED_FOR_DELETION) : false; submittedItem.setSubmittedForDeletion(submittedForDeletion); submittedItem.setSubmitted(submitted); submittedItem.setInProgress(inProgress); // TODO: check scheduled date to make sure it is not null when isNow = // true and also it is not past Date scheduledDate = null; if (globalSchDate != null && !StringUtils.isEmpty(globalSchDate)) { scheduledDate = getScheduledDate(site, format, globalSchDate); } else { if (item.containsKey(JSON_KEY_SCHEDULED_DATE)) { String dateStr = item.getString(JSON_KEY_SCHEDULED_DATE); if (!StringUtils.isEmpty(dateStr)) { scheduledDate = getScheduledDate(site, format, dateStr); } } } if (scheduledDate == null && isNow == false) { submittedItem.setNow(true); } submittedItem.setScheduledDate(scheduledDate); JSONArray components = (item.containsKey(JSON_KEY_COMPONENTS) && !item.getJSONObject(JSON_KEY_COMPONENTS).isNullObject()) ? item.getJSONArray(JSON_KEY_COMPONENTS) : null; List<DmDependencyTO> submittedComponents = getSubmittedItems(site, components, format, globalSchDate); submittedItem.setComponents(submittedComponents); JSONArray documents = (item.containsKey(JSON_KEY_DOCUMENTS) && !item.getJSONObject(JSON_KEY_DOCUMENTS).isNullObject()) ? item.getJSONArray(JSON_KEY_DOCUMENTS) : null; List<DmDependencyTO> submittedDocuments = getSubmittedItems(site, documents, format, globalSchDate); submittedItem.setDocuments(submittedDocuments); JSONArray assets = (item.containsKey(JSON_KEY_ASSETS) && !item.getJSONObject(JSON_KEY_ASSETS).isNullObject()) ? item.getJSONArray(JSON_KEY_ASSETS) : null; List<DmDependencyTO> submittedAssets = getSubmittedItems(site, assets, format, globalSchDate); submittedItem.setAssets(submittedAssets); JSONArray templates = (item.containsKey(JSON_KEY_RENDERING_TEMPLATES) && !item.getJSONObject(JSON_KEY_RENDERING_TEMPLATES).isNullObject()) ? item.getJSONArray(JSON_KEY_RENDERING_TEMPLATES) : null; List<DmDependencyTO> submittedTemplates = getSubmittedItems(site, templates, format, globalSchDate); submittedItem.setRenderingTemplates(submittedTemplates); JSONArray deletedItems = (item.containsKey(JSON_KEY_DELETED_ITEMS) && !item.getJSONObject(JSON_KEY_DELETED_ITEMS).isNullObject()) ? item.getJSONArray(JSON_KEY_DELETED_ITEMS) : null; List<DmDependencyTO> deletes = getSubmittedItems(site, deletedItems, format, globalSchDate); submittedItem.setDeletedItems(deletes); JSONArray children = (item.containsKey(JSON_KEY_CHILDREN)) ? item.getJSONArray(JSON_KEY_CHILDREN) : null; List<DmDependencyTO> submittedChidren = getSubmittedItems(site, children, format, globalSchDate); submittedItem.setChildren(submittedChidren); if (uri.endsWith(DmConstants.XML_PATTERN)) { /** * Get dependent pages */ DmDependencyTO dmDependencyTo = dmDependencyService.getDependenciesNoCalc(site, item.getString(JSON_KEY_URI), false, true, null); List<DmDependencyTO> dependentPages = new ArrayList<>(); if (dmDependencyTo != null) { dependentPages = dmDependencyTo.getPages(); } submittedItem.setPages(dependentPages); /** * Get Dependent Documents */ if (submittedItem.getDocuments() == null) { List<DmDependencyTO> dependentDocuments = new ArrayList<>(); if (dmDependencyTo != null) { dmDependencyTo.getDocuments(); } submittedItem.setDocuments(dependentDocuments); } /** * get sendEmail property if it is there */ /* TODO: implement send email try { String fullPath = contentService.expandRelativeSitePath(site, submittedItem.getUri()); Serializable sendEmailValue = persistenceManagerService.getProperty(persistenceManagerService.getNodeRef(fullPath), CStudioContentModel.PROP_WEB_WF_SEND_EMAIL); boolean sendEmail = (sendEmailValue != null) ? Boolean.parseBoolean(sendEmailValue.toString()) : false; submittedItem.setSendEmail(sendEmail); String user = item.getString(JSON_KEY_USER); submittedItem.setSubmittedBy(user); } catch (Exception e) { e.printStackTrace(); // To change body of catch statement use // File | Settings | File Templates. } */ } return submittedItem; } protected DmDependencyTO getSubmittedItem(String site, String itemPath, SimpleDateFormat format, String globalSchDate, Set<String> processedDependencies) throws JSONException { DmDependencyTO submittedItem = dmDependencyService.getDependenciesNoCalc(site, itemPath, false, true, processedDependencies); // TODO: check scheduled date to make sure it is not null when isNow = // true and also it is not past Date scheduledDate = null; if (globalSchDate != null && !StringUtils.isEmpty(globalSchDate)) { scheduledDate = getScheduledDate(site, format, globalSchDate); } else { if (submittedItem.getScheduledDate() != null) { scheduledDate = getScheduledDate(site, format, format.format(submittedItem.getScheduledDate())); } } if (scheduledDate == null) { submittedItem.setNow(true); } submittedItem.setScheduledDate(scheduledDate); if (processedDependencies == null) { processedDependencies = new HashSet<String>(); } if (CollectionUtils.isNotEmpty(submittedItem.getComponents())) { for (DmDependencyTO component : submittedItem.getComponents()) { if (!processedDependencies.contains(component.getUri())) { component = getSubmittedItem(site, component.getUri(), format, globalSchDate, processedDependencies); } } } if (CollectionUtils.isNotEmpty(submittedItem.getDocuments())) { for (DmDependencyTO document : submittedItem.getDocuments()) { if (!processedDependencies.contains(document.getUri())) { document = getSubmittedItem(site, document.getUri(), format, globalSchDate, processedDependencies); } } } if (CollectionUtils.isNotEmpty(submittedItem.getAssets())) { for (DmDependencyTO asset : submittedItem.getAssets()) { if (!processedDependencies.contains(asset.getUri())) { asset = getSubmittedItem(site, asset.getUri(), format, globalSchDate, processedDependencies); } } } if (CollectionUtils.isNotEmpty(submittedItem.getRenderingTemplates())) { for (DmDependencyTO template : submittedItem.getRenderingTemplates()) { if (!processedDependencies.contains(template.getUri())) { template = getSubmittedItem(site, template.getUri(), format, globalSchDate, processedDependencies); } } } if (CollectionUtils.isNotEmpty(submittedItem.getDeletedItems())) { for (DmDependencyTO deletedItem : submittedItem.getDeletedItems()) { if (!processedDependencies.contains(deletedItem.getUri())) { deletedItem = getSubmittedItem(site, deletedItem.getUri(), format, globalSchDate, processedDependencies); } } } if (CollectionUtils.isNotEmpty(submittedItem.getChildren())) { for (DmDependencyTO child : submittedItem.getChildren()) { if (!processedDependencies.contains(child.getUri())) { child = getSubmittedItem(site, child.getUri(), format, globalSchDate, processedDependencies); } } } return submittedItem; } protected DmDependencyTO getSubmittedItem_new(String site, String itemPath, SimpleDateFormat format, String globalSchDate) throws JSONException { DmDependencyTO submittedItem = dmDependencyService.getDependenciesNoCalc(site, itemPath, false, true, null); // TODO: check scheduled date to make sure it is not null when isNow = // true and also it is not past Date scheduledDate = null; if (globalSchDate != null && !StringUtils.isEmpty(globalSchDate)) { scheduledDate = getScheduledDate(site, format, globalSchDate); } else { if (submittedItem.getScheduledDate() != null) { scheduledDate = getScheduledDate(site, format, format.format(submittedItem.getScheduledDate())); } } if (scheduledDate == null) { submittedItem.setNow(true); } submittedItem.setScheduledDate(scheduledDate); return submittedItem; } /** * get submitted items from JSON request * * @param site * @param items * @param format * @return submitted items * @throws JSONException */ protected List<DmDependencyTO> getSubmittedItems(String site, JSONArray items, SimpleDateFormat format, String schDate) throws JSONException { if (items != null) { int length = items.size(); if (length > 0) { List<DmDependencyTO> submittedItems = new ArrayList<>(); for (int index = 0; index < length; index++) { JSONObject item = items.getJSONObject(index); DmDependencyTO submittedItem = getSubmittedItem(site, item, format, schDate); submittedItems.add(submittedItem); } return submittedItems; } } return null; } /** * removes the child items which are in submit to delete state from * submitted items as these have to be routed for deletion. it applies to * GoLive operation. * * @param dependencyTO * @param operation * @return */ protected List<DmDependencyTO> removeSubmitToDeleteChildrenForGoLive(DmDependencyTO dependencyTO, Operation operation) { List<DmDependencyTO> submitForDeleteChilds = new ArrayList<>(); if (operation == Operation.GO_LIVE && !dependencyTO.isSubmittedForDeletion()) { List<DmDependencyTO> children = dependencyTO.getChildren(); if (children != null) { for (DmDependencyTO child : children) { if (child.isSubmittedForDeletion()) { submitForDeleteChilds.add(child); } } for (DmDependencyTO submitForDeleteChild : submitForDeleteChilds) { children.remove(submitForDeleteChild); } } } return submitForDeleteChilds; } protected void doDelete(String site, List<DmDependencyTO> submittedItems, String approver) throws ServiceException { long start = System.currentTimeMillis(); String user = securityService.getCurrentUser(); // get web project information //String assignee = getAssignee(site, sub); // Don't make go live an item if it is new and to be deleted final Date now = new Date(); List<String> itemsToDelete = new ArrayList<>(); List<DmDependencyTO> deleteItems = new ArrayList<>(); List<DmDependencyTO> scheItems = new ArrayList<>(); for (DmDependencyTO submittedItem : submittedItems) { String uri = submittedItem.getUri(); Date schDate = submittedItem.getScheduledDate(); boolean isItemForSchedule = false; if (schDate == null || schDate.before(now)) { // Sending Notification if (StringUtils.isNotEmpty(approver)) { // immediate delete if (submittedItem.isSendEmail()) { sendDeleteApprovalNotification(site, submittedItem, approver);//TODO move it after delete actually happens } } if (submittedItem.getUri().endsWith(DmConstants.INDEX_FILE)) { submittedItem.setUri(submittedItem.getUri().replace("/" + DmConstants.INDEX_FILE, "")); } itemsToDelete.add(uri); } else { scheItems.add(submittedItem); isItemForSchedule = true; } submittedItem.setDeleted(true); // replace with the folder name boolean isNew = objectStateService.isNew(site, uri); if (!isNew || isItemForSchedule) { deleteItems.add(submittedItem); } ContentItemTO itemToDelete = contentService.getContentItem(site, uri); /* TODO: if item is renamed if(persistenceManagerService.hasAspect(itemToDelete, CStudioContentModel.ASPECT_RENAMED)){ String oldPath = (String) persistenceManagerService.getProperty(itemToDelete, CStudioContentModel.PROP_RENAMED_OLD_URL); if(oldPath!=null){ itemsToDelete.add(oldPath);//Make sure old path is going to be deleted } }*/ } //List<String> deletedItems = deleteInTransaction(site, itemsToDelete); GoLiveContext context = new GoLiveContext(approver, site); //final String pathPrefix = getSiteRoot(site, null); final String pathPrefix = "/wem-projects/" + site + "/" + site + "/work-area"; Map<Date, List<DmDependencyTO>> groupedPackages = groupByDate(deleteItems, now); if (groupedPackages.isEmpty()) { groupedPackages.put(now, Collections.<DmDependencyTO>emptyList()); } for (Date scheduledDate : groupedPackages.keySet()) { List<DmDependencyTO> deletePackage = groupedPackages.get(scheduledDate); SubmitPackage submitpackage = new SubmitPackage(pathPrefix); Set<String> rescheduledUris = new HashSet<String>(); if (deletePackage != null) { Date launchDate = scheduledDate.equals(now) ? null : scheduledDate; for (DmDependencyTO dmDependencyTO : deletePackage) { if (launchDate != null) { handleReferences(site, submitpackage, dmDependencyTO, true, null, "", rescheduledUris); } else { applyDeleteDependencyRule(site, submitpackage, dmDependencyTO); } } String label = submitpackage.getLabel(); //String workFlowName = _submitDirectWorkflowName; SubmitLifeCycleOperation deleteOperation = null; Set<String> liveDependencyItems = new HashSet<String>(); Set<String> allItems = new HashSet<String>(); for (String uri : itemsToDelete) {//$ToDO $ remove this case and keep the item in go live queue GoLiveDeleteCandidates deleteCandidate = contentService.getDeleteCandidates(context.getSite(), uri); allItems.addAll(deleteCandidate.getAllItems()); //get all dependencies that has to be removed as well liveDependencyItems.addAll(deleteCandidate.getLiveDependencyItems()); } List<String> submitPackPaths = submitpackage.getPaths(); if (launchDate != null) { deleteOperation = new PreScheduleDeleteOperation(this, submitpackage.getUris(), launchDate, context, rescheduledUris); label = DmConstants.DM_SCHEDULE_SUBMISSION_FLOW + ":" + label; //workFlowName = _reviewWorkflowName; /* for (String submitPackPath : submitpackage.getUris()) { String fullpath = dmContentService.getContentFullPath(site, submitPackPath); _cacheManager.invalidateAndRemoveFromQueue(fullpath, site); }*/ } else { //add dependencies to submitPackage for (String liveDependency : liveDependencyItems) { DmPathTO pathTO = new DmPathTO(liveDependency); submitpackage.addToPackage(pathTO.getRelativePath()); } submitPackPaths = submitpackage.getPaths(); deleteOperation = new PreSubmitDeleteOperation(this, new HashSet<String>(itemsToDelete), context, rescheduledUris); removeChildFromSubmitPackForDelete(submitPackPaths); for (String deleteCandidate : allItems) { //_cacheManager.invalidateAndRemoveFromQueue(deleteCandidate, site); } } Map<String, String> submittedBy = new HashMap<>(); /* TODO: add to submitted by mapping for (String longPath : submitPackPaths) { String uri = longPath.substring(pathPrefix.length()); //DmUtils.addToSubmittedByMapping(persistenceManagerService, dmContentService, searchService, site, uri, submittedBy, approver); }*/ workflowProcessor.addToWorkflow(site, new ArrayList<String>(), launchDate, label, deleteOperation, approver, null); } } long end = System.currentTimeMillis(); logger.debug("Submitted deleted items to queue time = " + (end - start)); } @Override public Map<Date, List<DmDependencyTO>> groupByDate(List<DmDependencyTO> submittedItems, Date now) { Map<Date, List<DmDependencyTO>> groupedPackages = new HashMap<>(); for (DmDependencyTO submittedItem : submittedItems) { Date scheduledDate = (submittedItem.isNow()) ? null : submittedItem.getScheduledDate(); if (scheduledDate == null || scheduledDate.before(now)) { scheduledDate = now; } List<DmDependencyTO> goLivePackage = groupedPackages.get(scheduledDate); if (goLivePackage == null) goLivePackage = new ArrayList<>(); goLivePackage.add(submittedItem); groupedPackages.put(scheduledDate, goLivePackage); } return groupedPackages; } protected void handleReferences(String site, SubmitPackage submitpackage, DmDependencyTO dmDependencyTO, boolean isNotScheduled, SubmitPackage dependencyPackage, String approver, Set<String> rescheduledUris) {//,boolean isReferencePage) { String path = contentService.expandRelativeSitePath(site, dmDependencyTO.getUri()); ObjectMetadata properties = objectMetadataManager.getProperties(site, dmDependencyTO.getUri()); Date scheduledDate = null; if (properties != null) { scheduledDate = properties.getLaunchDate(); } ObjectState state = objectStateService.getObjectState(site, dmDependencyTO.getUri()); if (state != null) { if (!State.isSubmitted(State.valueOf(state.getState())) && scheduledDate != null && scheduledDate.equals(dmDependencyTO.getScheduledDate())) { if (objectStateService.isScheduled(site, dmDependencyTO.getUri())) { return; } else { submitpackage.addToPackage(dmDependencyTO); } } } if (!dmDependencyTO.isReference()) { submitpackage.addToPackage(dmDependencyTO); } DependencyRules rule = new DependencyRules(site); rule.setObjectStateService(objectStateService); rule.setContentService(contentService); Set<DmDependencyTO> dependencyTOSet; if (dmDependencyTO.isSubmittedForDeletion() || dmDependencyTO.isDeleted()) { dependencyTOSet = rule.applyDeleteDependencyRule(dmDependencyTO); } else { long start = System.currentTimeMillis(); dependencyTOSet = rule.applySubmitRule(dmDependencyTO); long end = System.currentTimeMillis(); logger.debug("Time to get dependencies rule = " + (end - start)); } for (DmDependencyTO dependencyTO : dependencyTOSet) { submitpackage.addToPackage(dependencyTO); if (!isNotScheduled) { dependencyPackage.addToPackage(dependencyTO); } } if (isRescheduleRequest(dmDependencyTO, site)) { rescheduledUris.add(dmDependencyTO.getUri()); } } protected boolean areEqual(Date oldDate, Date newDate) { if (oldDate == null && newDate == null) { return true; } if (oldDate != null && newDate != null) { return oldDate.equals(newDate); } return false; } protected void applyDeleteDependencyRule(String site, SubmitPackage pack, DmDependencyTO dmDependencyTO) { pack.addToPackage(dmDependencyTO); DependencyRules rule = new DependencyRules(site); rule.setObjectStateService(objectStateService); rule.setContentService(contentService); Set<DmDependencyTO> dependencyTOSet = rule.applyDeleteDependencyRule(dmDependencyTO); for (DmDependencyTO dependencyTO : dependencyTOSet) { pack.addToPackage(dependencyTO); } } /** * parse the given date * * @param site * @param format * @param dateStr * @return date */ protected Date getScheduledDate(String site, SimpleDateFormat format, String dateStr) { return ContentFormatUtils.parseDate(format, dateStr, servicesConfig.getDefaultTimezone(site)); } protected void removeChildFromSubmitPackForDelete(List<String> paths) { Iterator<String> itr = paths.iterator(); while (itr.hasNext()) { String path = itr.next(); if (checkParentExistsInSubmitPackForDelete(paths, path)) { itr.remove(); } } } protected boolean checkParentExistsInSubmitPackForDelete(List<String> paths, String path) { String split[] = path.split("/"); for (int i = split.length - 1; i >= 0; i--) { int lastIndex = path.lastIndexOf(split[i]) - 1; if (lastIndex > 0) { path = path.substring(0, lastIndex); if (paths.contains(path)) { return true; } } } return false; } protected void sendDeleteApprovalNotification(String site, DmDependencyTO submittedItem, String approver) { try { if (submittedItem.isSendEmail()) { String uri = submittedItem.getUri(); ContentItemTO contentItem = contentService.getContentItem(site, uri); if (contentItem != null) { //Prepare to send notification /* Serializable submittedByValue = persistenceManagerService.getProperty(node, CStudioContentModel.PROP_WEB_WF_SUBMITTED_BY); String submittedBy = ""; if (submittedByValue != null) { submittedBy = (String) submittedByValue; notificationService.sendDeleteApprovalNotification(site, submittedBy, uri, approver); }*/ } } } catch (Exception e) { logger.error("Could not send delete approval notification for newly created item", e); } } protected List<DmDependencyTO> getRefAndChildOfDiffDateFromParent(String site, List<DmDependencyTO> submittedItems, boolean removeInPages) { List<DmDependencyTO> childAndReferences = new ArrayList<>(); for (DmDependencyTO submittedItem : submittedItems) { List<DmDependencyTO> children = submittedItem.getChildren(); Date date = submittedItem.getScheduledDate(); if (children != null) { Iterator<DmDependencyTO> childItr = children.iterator(); while (childItr.hasNext()) { DmDependencyTO child = childItr.next(); Date pageDate = child.getScheduledDate(); if ((date == null && pageDate != null) || (date != null && !date.equals(pageDate))) { if (!submittedItem.isNow()) { child.setNow(false); if (date != null && (pageDate != null && pageDate.before(date))) { child.setScheduledDate(date); } } childAndReferences.add(child); List<DmDependencyTO> childDeps = child.flattenChildren(); for (DmDependencyTO childDep : childDeps) { if (objectStateService.isUpdatedOrNew(site, childDep.getUri())) { childAndReferences.add(childDep); } } child.setReference(false); childItr.remove(); if (removeInPages) { String uri = child.getUri(); List<DmDependencyTO> pages = submittedItem.getPages(); if (pages != null) { Iterator<DmDependencyTO> pagesIter = pages.iterator(); while (pagesIter.hasNext()) { DmDependencyTO page = pagesIter.next(); if (page.getUri().equals(uri)) { pagesIter.remove(); } } } } } } } Set<String> dependenciesPaths = deploymentDependencyRule.applyRule(site, submittedItem.getUri()); for (String depPath : dependenciesPaths) { childAndReferences.add(dmDependencyService.getDependenciesNoCalc(site, depPath, false, true, null)); } } return childAndReferences; } protected List<DmDependencyTO> getRefAndChildOfDiffDateFromParent_new(String site, List<DmDependencyTO> submittedItems, boolean removeInPages) { List<DmDependencyTO> childAndReferences = new ArrayList<>(); for (DmDependencyTO submittedItem : submittedItems) { List<DmDependencyTO> children = submittedItem.getChildren(); Date date = submittedItem.getScheduledDate(); if (children != null) { Iterator<DmDependencyTO> childItr = children.iterator(); while (childItr.hasNext()) { DmDependencyTO child = childItr.next(); Date pageDate = child.getScheduledDate(); if ((date == null && pageDate != null) || (date != null && !date.equals(pageDate))) { if (!submittedItem.isNow()) { child.setNow(false); if (date != null && (pageDate != null && pageDate.before(date))) { child.setScheduledDate(date); } } childAndReferences.add(child); List<DmDependencyTO> childDeps = child.flattenChildren(); for (DmDependencyTO childDep : childDeps) { if (objectStateService.isUpdatedOrNew(site, childDep.getUri())) { childAndReferences.add(childDep); } } child.setReference(false); childItr.remove(); if (removeInPages) { String uri = child.getUri(); List<DmDependencyTO> pages = submittedItem.getPages(); if (pages != null) { Iterator<DmDependencyTO> pagesIter = pages.iterator(); while (pagesIter.hasNext()) { DmDependencyTO page = pagesIter.next(); if (page.getUri().equals(uri)) { pagesIter.remove(); } } } } } } } } return childAndReferences; } protected List<DmDependencyTO> addDependenciesForSubmittedItems(String site, List<DmDependencyTO> submittedItems, SimpleDateFormat format, String globalScheduledDate) { List<DmDependencyTO> dependencies = new ArrayList<DmDependencyTO>(); Set<String> dependenciesPaths = new HashSet<String>(); for (DmDependencyTO submittedItem : submittedItems) { dependenciesPaths.addAll(deploymentDependencyRule.applyRule(site, submittedItem.getUri())); } for (String depPath : dependenciesPaths) { dependencies.add(getSubmittedItem(site, depPath, format, globalScheduledDate, null)); } return dependencies; } protected void resolveSubmittedPaths(String site, DmDependencyTO item, List<String> submittedPaths) { String fullPath = contentService.expandRelativeSitePath(site, item.getUri()); if (!submittedPaths.contains(fullPath)) { submittedPaths.add(fullPath); } List<DmDependencyTO> children = item.getChildren(); if (children != null) { for (DmDependencyTO child : children) { String childPath = contentService.expandRelativeSitePath(site, child.getUri()); if (objectStateService.isUpdatedOrNew(site, child.getUri())) { if (!submittedPaths.contains(childPath)) { submittedPaths.add(childPath); } resolveSubmittedPaths(site, child, submittedPaths); } } } DependencyRules rule = new DependencyRules(site); rule.setObjectStateService(objectStateService); rule.setContentService(contentService); Set<DmDependencyTO> deps = rule.applySubmitRule(item); if (deps != null) { for (DmDependencyTO dep : deps) { String depPath = contentService.expandRelativeSitePath(site, dep.getUri()); if (objectStateService.isUpdatedOrNew(site, dep.getUri())) { if (!submittedPaths.contains(depPath)) { submittedPaths.add(depPath); } } resolveSubmittedPaths(site, dep, submittedPaths); } } } protected List<DmDependencyTO> getChildrenForRenamedItem(String site, DmDependencyTO renameItem) { List<DmDependencyTO> toRet = new ArrayList<>(); List<DmDependencyTO> children = renameItem.getChildren(); Date date = renameItem.getScheduledDate(); if (children != null) { Iterator<DmDependencyTO> childItr = children.iterator(); while (childItr.hasNext()) { DmDependencyTO child = childItr.next(); Date pageDate = child.getScheduledDate(); if ((date == null && pageDate != null) || (date != null && !date.equals(pageDate))) { if (!renameItem.isNow()) { child.setNow(false); if (date != null && (pageDate != null && pageDate.before(date))) { child.setScheduledDate(date); } } toRet.add(child); List<DmDependencyTO> childDeps = child.flattenChildren(); for (DmDependencyTO childDep : childDeps) { if (objectStateService.isUpdatedOrNew(site, childDep.getUri())) { toRet.add(childDep); } } child.setReference(false); childItr.remove(); } } } return toRet; } @Override public void preScheduleDelete(Set<String> urisToDelete, final Date scheduleDate, final GoLiveContext context, Set rescheduledUris) throws ServiceException { final String site = context.getSite(); final List<String> itemsToDelete = new ArrayList<String>(urisToDelete); dmPublishService.unpublish(site, itemsToDelete, context.getApprover(), scheduleDate); } @Override public List<String> preDelete(Set<String> urisToDelete, GoLiveContext context, Set<String> rescheduledUris) throws ServiceException { cleanUrisFromWorkflow(urisToDelete, context.getSite()); cleanUrisFromWorkflow(rescheduledUris, context.getSite()); List<String> deletedItems = deleteInTransaction(context.getSite(), new ArrayList<String>(urisToDelete), true, context.getApprover()); return deletedItems; } protected List<String> deleteInTransaction(final String site, final List<String> itemsToDelete, final boolean generateActivity, final String approver) throws ServiceException { dmPublishService.unpublish(site, itemsToDelete, approver); return null; //return contentService.deleteContents(site, itemsToDelete, generateActivity, approver); } protected void cleanUrisFromWorkflow(final Set<String> uris, final String site) { if (uris != null && !uris.isEmpty()) { for (String uri : uris) { cleanWorkflow(uri, site, Collections.<DmDependencyTO>emptySet()); } } } public boolean cleanWorkflow(final String url, final String site, final Set<DmDependencyTO> dependents) { _cancelWorkflow(site, url); return true; } /** * approve workflows and schedule them as specified in the request * * @param site * @param request * @return call result * @throws ServiceException */ @Override public ResultTO goLive(final String site, final String request) throws ServiceException { String lockKey = DmConstants.PUBLISHING_LOCK_KEY.replace("{SITE}", site.toUpperCase()); generalLockService.lock(lockKey); try { try { return approve_new(site, request, Operation.GO_LIVE); } catch (RuntimeException e) { logger.error("error making go live", e); throw e; } } catch (RuntimeException e) { throw e; } finally { generalLockService.unlock(lockKey); } } /** * approve workflows and schedule them as specified in the request * * @param site * @return call result * @throws ServiceException */ protected void goLive(final String site, final List<DmDependencyTO> submittedItems, String approver) throws ServiceException { goLive(site, submittedItems, approver, null); } /** * approve workflows and schedule them as specified in the request * * @param site * @return call result * @throws ServiceException */ protected void goLive(final String site, final List<DmDependencyTO> submittedItems, String approver, MultiChannelPublishingContext mcpContext) throws ServiceException { long start = System.currentTimeMillis(); // get web project information //final String assignee = getAssignee(site, sub); final String pathPrefix = "/wem-projects/" + site + "/" + site + "/work-area"; final Date now = new Date(); if (submittedItems != null) { // group submitted items into packages by their scheduled date Map<Date, List<DmDependencyTO>> groupedPackages = groupByDate(submittedItems, now); for (Date scheduledDate : groupedPackages.keySet()) { List<DmDependencyTO> goLivePackage = groupedPackages.get(scheduledDate); if (goLivePackage != null) { Date launchDate = scheduledDate.equals(now) ? null : scheduledDate; final boolean isNotScheduled = (launchDate == null); // for submit direct, package them together and submit them // together as direct submit final SubmitPackage submitpackage = new SubmitPackage(pathPrefix); /* dependencyPackage holds references of page. */ final Set<String> rescheduledUris = new HashSet<String>(); final SubmitPackage dependencyPackage = new SubmitPackage(""); for (final DmDependencyTO dmDependencyTO : goLivePackage) { goLivepackage(site, submitpackage, dmDependencyTO, isNotScheduled, dependencyPackage, approver, rescheduledUris); } List<String> stringList = submitpackage.getPaths(); String label = submitpackage.getLabel(); SubmitLifeCycleOperation operation = null; GoLiveContext context = new GoLiveContext(approver, site); if (!isNotScheduled) { Set<String> uris = new HashSet<String>(); uris.addAll(dependencyPackage.getUris()); uris.addAll(submitpackage.getUris()); label = getScheduleLabel(submitpackage, dependencyPackage); operation = new PreScheduleOperation(this, uris, launchDate, context, rescheduledUris); } else { operation = new PreGoLiveOperation(this, submitpackage.getUris(), context, rescheduledUris); } if (!stringList.isEmpty()) { // get the workflow initiator mapping Map<String, String> submittedBy = new HashMap<String, String>(); for (String longPath : stringList) { String uri = longPath.substring(pathPrefix.length()); //ContentUtils.addToSubmittedByMapping(getService(PersistenceManagerService.class), dmContentService, site, uri, submittedBy, approver); dmPublishService.cancelScheduledItem(site, uri); } workflowProcessor.addToWorkflow(site, stringList, launchDate, label, operation, approver, mcpContext); } Set<DmDependencyTO> dependencyTOSet = submitpackage.getItems(); for (DmDependencyTO dmDependencyTO : dependencyTOSet) { dmWorkflowListener.postGolive(site, dmDependencyTO); } dependencyTOSet = dependencyPackage.getItems(); for (DmDependencyTO dmDependencyTO : dependencyTOSet) { dmWorkflowListener.postGolive(site, dmDependencyTO); } } } } long end = System.currentTimeMillis(); logger.debug("Total go live time = " + (end - start)); } protected void goLivepackage(String site, SubmitPackage submitpackage, DmDependencyTO dmDependencyTO, boolean isNotScheduled, SubmitPackage dependencyPackage, String approver, Set<String> rescheduledUris) { handleReferences(site, submitpackage, dmDependencyTO, isNotScheduled, dependencyPackage, approver, rescheduledUris); List<DmDependencyTO> children = dmDependencyTO.getChildren(); if (children != null) { for (DmDependencyTO child : children) { handleReferences(site, submitpackage, child, isNotScheduled, dependencyPackage, approver, rescheduledUris); goLivepackage(site, submitpackage, child, isNotScheduled, dependencyPackage, approver, rescheduledUris); } } } protected String getScheduleLabel(SubmitPackage submitPackage, SubmitPackage dependencyPack) { StringBuilder builder = new StringBuilder("schedule_workflow:"); builder.append(submitPackage.getLabel()).append(",").append(dependencyPack.getLabel()); String label = builder.toString(); if (label.length() > 255) { label = label.substring(0, 252) + ".."; } return label; } /** * approve multiple packages by canceling pending workflows and submitting * them to one workflow instance. This should only be used for submit direct * case. (might change in future) * * @param site * @param user * @param scheduledDate * @param goLivePackage * @throws ServiceException */ protected void approveMultiplePackages(final String site, final String user, final Date scheduledDate, final List<DmDependencyTO> goLivePackage) throws ServiceException { // attach submitted aspect to all items within this package. Prepare workfow final StringBuffer buffer = new StringBuffer(); List<String> packagePaths = new ArrayList<>(); for (DmDependencyTO item : goLivePackage) { buffer.append(item.getUri() + ", "); List<String> paths = prepareWorkflowSubmission(site, user, item, scheduledDate, item.isSendEmail()); packagePaths.addAll(paths); } // submit to workflow String label = buffer.toString(); if (label.length() > 255) { label = label.substring(0, 252) + ".."; } submitToWorkflow(site, scheduledDate, label, packagePaths); } /** * approve single item by approving the existing workflow or submitting * direct * * @param site * @param user * @param scheduledDate * @throws ServiceException */ protected void approveSinglePackage(final String site, final String user, final Date scheduledDate, final DmDependencyTO submittedItem) throws ServiceException { List<String> tasks = submittedItem.getWorkflowTasks(); if (tasks == null || tasks.size() == 0) { // if no workflow started, submit items in the package // attach submitted aspect to items being submitted List<String> paths = prepareWorkflowSubmission(site, user, submittedItem, scheduledDate, submittedItem.isSendEmail()); String label = submittedItem.getUri(); if (label.length() > 255) { label = label.substring(0, 252) + ".."; } submitToWorkflow(site, scheduledDate, label, paths); } } protected List<String> prepareWorkflowSubmission(String site, String user, DmDependencyTO submittedItem, Date launchDate, boolean sendEmail) throws ServiceException { return prepareWorkflowSubmission(site, user, submittedItem, launchDate, sendEmail, false); } /** * prepare the content for workflow submission by attaching submitted aspect * * @param site * @param user * @param submittedItem * @param launchDate * @param sendEmail * @return * @throws ServiceException */ protected List<String> prepareWorkflowSubmission(String site, String user, DmDependencyTO submittedItem, Date launchDate, boolean sendEmail, boolean submittedForDeletion) throws ServiceException { List<String> paths = new ArrayList<>(); String fullPath = contentService.expandRelativeSitePath(site, submittedItem.getUri()); ContentItemTO contentItem = contentService.getContentItem(site, submittedItem.getUri()); if (contentItem != null) { if (!submittedItem.isDeleted()) { /* TODO: set properties persistenceManagerService.setProperty(node, CStudioContentModel.PROP_WEB_WF_SUBMITTED_BY, user); persistenceManagerService.setProperty(node, CStudioContentModel.PROP_WEB_WF_SEND_EMAIL, sendEmail); persistenceManagerService.setProperty(node, CStudioContentModel.PROP_WEB_WF_SUBMITTEDFORDELETION, submittedForDeletion); */ List<String> includedItems = new ArrayList<>(); addSubmittedAspect(site, user, null, submittedItem, launchDate, includedItems); for (String includedItem : includedItems) { paths.add(includedItem); } } else { // do nothing if deleted String topLevelItem = contentService.getRelativeSitePath(site, fullPath); paths.add(topLevelItem); } } else { logger.error(submittedItem.getUri() + " does not exist."); } return paths; } /** * add the submitted aspect to each item submitted and set properties * * @param site * @param user * @param parentUri * @param submittedItem * @param scheduledDate * @param includedItems * @throws ServiceException */ @SuppressWarnings("unchecked") protected void addSubmittedAspect(String site, String user, String parentUri, DmDependencyTO submittedItem, Date scheduledDate, List<String> includedItems) throws ServiceException { String fullPath = contentService.expandRelativeSitePath(site, submittedItem.getUri()); ContentItemTO node = contentService.getContentItem(site, submittedItem.getUri()); if (node != null) { // add submitted aspect /* TODO: Submitted aspectreplacement if (!persistenceManagerService.hasAspect(node, CStudioContentModel.ASPECT_WORKFLOW_SUBMITTED)) { // add submitted aspect persistenceManagerService.addAspect(node, CStudioContentModel.ASPECT_WORKFLOW_SUBMITTED, null); }*/ // set direct child items /* TODO: set properties List<String> childDependencies = getDependencies(site, user, submittedItem.getUri(), submittedItem, scheduledDate, includedItems); persistenceManagerService.setProperty(node, CStudioContentModel.PROP_WEB_WF_CHILDREN, (Serializable) childDependencies); // set a scheduled date persistenceManagerService.setProperty(node, WCMWorkflowModel.PROP_LAUNCH_DATE, scheduledDate); Map<QName, Serializable> properties = persistenceManagerService.getProperties(node); // add parent URI if not null if (!StringUtils.isEmpty(parentUri)) { Serializable parentValue = properties.get(CStudioContentModel.PROP_WEB_WF_PARENT_URI); List<String> parents = (parentValue == null) ? new ArrayList<String>(1) : (List<String>) parentValue; if (!parents.contains(parentUri)) { parents.add(parentUri); } persistenceManagerService.setProperty(node, CStudioContentModel.PROP_WEB_WF_PARENT_URI, (Serializable) parents); } */ includedItems.add(submittedItem.getUri()); } else { includedItems.add(submittedItem.getUri()); } } /** * submit the given list of paths to workflow * * @param site * @param launchDate * @param label * @param paths */ @SuppressWarnings("deprecation") protected void submitToWorkflow(final String site, final Date launchDate, final String label, final List<String> paths) throws ServiceException { submitToWorkflow(site, launchDate, label, paths, null); } /** * submit the given list of paths to workflow * * @param site * @param launchDate * @param label * @param paths */ @SuppressWarnings("deprecation") protected void submitToWorkflow(final String site, final Date launchDate, final String label, final List<String> paths, final MultiChannelPublishingContext mcpContext) throws ServiceException { _submit(site, launchDate, label, paths, mcpContext); } protected void _submit(String site, Date launchDate, String label, List<String> paths, MultiChannelPublishingContext mcpContext) { if (label.length() > 255) { label = label.substring(0, 252) + ".."; } // submit to workflow logger.debug("[WORKFLOW] w1,publish for " + label + ",start," + System.currentTimeMillis()); dmPublishService.publish(site, paths, launchDate, mcpContext); } protected void invokeListeners(List<DmDependencyTO> submittedItems, String site, Operation operation) { for (DmDependencyTO submittedItem : submittedItems) { List<DmDependencyTO> children = submittedItem.getChildren(); switch (operation) { case GO_LIVE: dmWorkflowListener.postGolive(site, submittedItem); break; case SUBMIT_TO_GO_LIVE: dmWorkflowListener.postSubmitToGolive(site, submittedItem); break; case REJECT: dmWorkflowListener.postReject(site, submittedItem); break; } if (null != children && !children.isEmpty()) { invokeListeners(children, site, operation); } } } @Override public boolean isRescheduleRequest(DmDependencyTO dependencyTO, String site) { if ((dependencyTO.isDeleted() || (!dependencyTO.isSubmitted() && !dependencyTO.isInProgress()))) { String path = contentService.expandRelativeSitePath(site, dependencyTO.getUri()); ContentItemTO to = contentService.getContentItem(site, dependencyTO.getUri()); Date newDate = dependencyTO.getScheduledDate(); Date oldDate = to.getScheduledDate(); return !areEqual(oldDate, newDate); } return false; } @Override public void preGoLive(Set<String> uris, GoLiveContext context, Set<String> rescheduledUris) { /* TODO: do we need this ? String approver = context.getApprover(); String site = context.getSite(); List<String> displayPatterns = servicesConfig.getDisplayInWidgetPathPatterns(site); for (String uri : uris) { if (ContentUtils.matchesPatterns(uri, displayPatterns) || customContentTypeNotification) { String path = dmContentService.getContentFullPath(site, uri); final NodeRef node = persistenceManagerService.getNodeRef(path); if (node != null && StringUtils.isNotEmpty(approver)) { persistenceManagerService.disableBehaviour(node, ContentModel.ASPECT_LOCKABLE); persistenceManagerService.setProperty(node, CStudioContentModel.PROP_WEB_APPROVED_BY, approver); persistenceManagerService.enableBehaviour(node, ContentModel.ASPECT_LOCKABLE); } } } */ } @Override public void preSchedule(Set<String> uris, final Date date, final GoLiveContext context, Set<String> rescheduledUris) { /* TODO: do we need this? preGoLive(uris, context, rescheduledUris); DmContentService dmContentService = getService(DmContentService.class); PersistenceManagerService persistenceManagerService = getService(PersistenceManagerService.class); for (String path : uris) { String fullPath = dmContentService.getContentFullPath(context.getSite(), path); NodeRef node = persistenceManagerService.getNodeRef(fullPath); if (node != null) { //dmStateManager.markScheduled(node, date, context.getSite()); Map<QName, Serializable> nodeProperties = persistenceManagerService.getProperties(node); nodeProperties.put(WCMWorkflowModel.PROP_LAUNCH_DATE, date); persistenceManagerService.setProperties(node, nodeProperties); } }*/ } public ResultTO submitToDelete(String site, String user, String requestBody) throws ServiceException { return submitForApproval(site, user, requestBody, true); } @Override public ResultTO reject(String site, String user, String request) throws ServiceException { ResultTO result = new ResultTO(); try { String approver = user; if (StringUtils.isEmpty(approver)) { approver = securityService.getCurrentUser(); } JSONObject requestObject = JSONObject.fromObject(request); String reason = (requestObject.containsKey(JSON_KEY_REASON)) ? requestObject.getString(JSON_KEY_REASON) : ""; JSONArray items = requestObject.getJSONArray(JSON_KEY_ITEMS); String scheduledDate = null; if (requestObject.containsKey(JSON_KEY_SCHEDULED_DATE)) { scheduledDate = requestObject.getString(JSON_KEY_SCHEDULED_DATE); } int length = items.size(); if (length > 0) { SimpleDateFormat format = new SimpleDateFormat(CStudioConstants.DATE_PATTERN_WORKFLOW); List<DmDependencyTO> submittedItems = new ArrayList<DmDependencyTO>(); for (int index = 0; index < length; index++) { String stringItem = items.optString(index); //JSONObject item = items.getJSONObject(index); DmDependencyTO submittedItem = null; //getSubmittedItem(site, item, format, scheduledDate); submittedItem = getSubmittedItem(site, stringItem, format, scheduledDate, null); submittedItems.add(submittedItem); } List<String> paths = new ArrayList<String>(); for (DmDependencyTO goLiveItem : submittedItems) { if (contentService.contentExists(site, goLiveItem.getUri())) { paths.add(goLiveItem.getUri()); } } objectStateService.setSystemProcessingBulk(site, paths, true); reject(site, submittedItems, reason, approver); objectStateService.setSystemProcessingBulk(site, paths, false); result.setSuccess(true); result.setStatus(200); result.setMessage( notificationService.getCompleteMessage(site, NotificationService.COMPLETE_REJECT)); } else { result.setSuccess(false); result.setMessage("No items provided for preparation."); } } catch (JSONException e) { result.setSuccess(false); result.setMessage(e.getMessage()); } return result; } protected void reject(String site, List<DmDependencyTO> submittedItems, String reason, String approver) { if (submittedItems != null) { // for each top level items submitted // add its children and dependencies that must go with the top level // item to the submitted aspect // and only submit the top level items to workflow for (DmDependencyTO dmDependencyTO : submittedItems) { DependencyRules rule = new DependencyRules(site); rejectThisAndReferences(site, dmDependencyTO, rule, approver, reason); List<DmDependencyTO> children = dmDependencyTO.getChildren(); if (children != null) { for (DmDependencyTO child : children) { rejectThisAndReferences(site, child, rule, approver, reason); } } } } // TODO: send the reason to the user } protected void rejectThisAndReferences(String site, DmDependencyTO dmDependencyTO, DependencyRules rule, String approver, String reason) { _reject(site, dmDependencyTO, approver, true, reason); Set<DmDependencyTO> dependencyTOSet = rule.applyRejectRule(dmDependencyTO); for (DmDependencyTO dependencyTO : dependencyTOSet) { boolean lsendEmail = true; try { String fullPath = contentService.expandRelativeSitePath(site, dependencyTO.getUri()); ContentItemTO contentItem = contentService.getContentItem(site, dependencyTO.getUri()); lsendEmail = !contentItem.isDocument() && !contentItem.isComponent() && !contentItem.isAsset(); } catch (Exception e) { logger.error("during rejection, content retrieve failed"); lsendEmail = false; } _reject(site, dependencyTO, approver, lsendEmail, reason); } } protected void _reject(String site, DmDependencyTO dmDependencyTO, String approver, boolean sendEmail, String reason) { String path = contentService.expandRelativeSitePath(site, dmDependencyTO.getUri()); boolean contentExists = contentService.contentExists(site, dmDependencyTO.getUri()); if (contentExists) { ObjectMetadata properties = null; if (!objectMetadataManager.metadataExist(site, dmDependencyTO.getUri())) { objectMetadataManager.insertNewObjectMetadata(site, dmDependencyTO.getUri()); } properties = objectMetadataManager.getProperties(site, dmDependencyTO.getUri()); String submittedBy = properties.getSubmittedBy(); if (sendEmail && StringUtils.isNotEmpty(submittedBy) && StringUtils.isNotEmpty(approver)) { boolean isPreviewable = true; try { ContentItemTO contentItem = contentService.getContentItem(site, dmDependencyTO.getUri()); isPreviewable = contentItem.isPreviewable(); } catch (Exception e) { logger.error("Item cannot be retrieved during rejection notification" + path); } notificationService.sendRejectionNotification(site, submittedBy, dmDependencyTO.getUri(), reason, approver, isPreviewable); } Map<String, Object> newProps = new HashMap<String, Object>(); newProps.put(ObjectMetadata.PROP_SUBMITTED_BY, ""); newProps.put(ObjectMetadata.PROP_SEND_EMAIL, 0); newProps.put(ObjectMetadata.PROP_SUBMITTED_FOR_DELETION, 0); newProps.put(ObjectMetadata.PROP_LAUNCH_DATE, null); objectMetadataManager.setObjectMetadata(site, dmDependencyTO.getUri(), newProps); ContentItemTO item = contentService.getContentItem(site, dmDependencyTO.getUri()); objectStateService.transition(site, item, TransitionEvent.REJECT); } dmWorkflowListener.postReject(site, dmDependencyTO); } public void setWorkflowJobDAL(WorkflowJobDAL dal) { _workflowJobDAL = dal; } // public void setDmWorkflowService(DmWorkflowService service) { _dmSimpleWfService = service; } // // @Override public NotificationService getNotificationService() { return notificationService; } public void setNotificationService(NotificationService service) { notificationService = service; } public ServicesConfig getServicesConfig() { return servicesConfig; } public void setServicesConfig(ServicesConfig servicesConfig) { this.servicesConfig = servicesConfig; } public void setDmDependencyService(DmDependencyService dmDependencyService) { this.dmDependencyService = dmDependencyService; } public void setDmFilterWrapper(DmFilterWrapper dmFilterWrapper) { this.dmFilterWrapper = dmFilterWrapper; } public void setContentService(ContentService contentService) { this.contentService = contentService; } public void setDeploymentService(DeploymentService deploymentService) { this.deploymentService = deploymentService; } public void setObjectStateService(ObjectStateService objectStateService) { this.objectStateService = objectStateService; } public DmPublishService getDmPublishService() { return dmPublishService; } public void setDmPublishService(DmPublishService dmPublishService) { this.dmPublishService = dmPublishService; } public GeneralLockService getGeneralLockService() { return generalLockService; } public void setGeneralLockService(GeneralLockService generalLockService) { this.generalLockService = generalLockService; } public SecurityService getSecurityService() { return securityService; } public void setSecurityService(SecurityService securityService) { this.securityService = securityService; } public SiteService getSiteService() { return siteService; } public void setSiteService(SiteService siteService) { this.siteService = siteService; } public DmRenameService getDmRenameService() { return dmRenameService; } public void setDmRenameService(DmRenameService dmRenameService) { this.dmRenameService = dmRenameService; } public WorkflowProcessor getWorkflowProcessor() { return workflowProcessor; } public void setWorkflowProcessor(WorkflowProcessor workflowProcessor) { this.workflowProcessor = workflowProcessor; } public DmWorkflowListener getDmWorkflowListener() { return dmWorkflowListener; } public void setDmWorkflowListener(DmWorkflowListener dmWorkflowListener) { this.dmWorkflowListener = dmWorkflowListener; } public String getCustomContentTypeNotificationPattern() { return customContentTypeNotificationPattern; } public void setCustomContentTypeNotificationPattern(String customContentTypeNotificationPattern) { this.customContentTypeNotificationPattern = customContentTypeNotificationPattern; } public boolean isCustomContentTypeNotification() { return customContentTypeNotification; } public void setCustomContentTypeNotification(boolean customContentTypeNotification) { this.customContentTypeNotification = customContentTypeNotification; } public ObjectMetadataManager getObjectMetadataManager() { return objectMetadataManager; } public void setObjectMetadataManager(ObjectMetadataManager objectMetadataManager) { this.objectMetadataManager = objectMetadataManager; } public DependencyRule getDeploymentDependencyRule() { return deploymentDependencyRule; } public void setDeploymentDependencyRule(DependencyRule deploymentDependencyRule) { this.deploymentDependencyRule = deploymentDependencyRule; } private WorkflowJobDAL _workflowJobDAL; private NotificationService notificationService; protected ServicesConfig servicesConfig; protected DeploymentService deploymentService; protected ContentService contentService; protected DmFilterWrapper dmFilterWrapper; protected DmDependencyService dmDependencyService; protected ObjectStateService objectStateService; protected DmPublishService dmPublishService; protected GeneralLockService generalLockService; protected SecurityService securityService; protected SiteService siteService; protected DmRenameService dmRenameService; protected WorkflowProcessor workflowProcessor; protected DmWorkflowListener dmWorkflowListener; protected String customContentTypeNotificationPattern; protected boolean customContentTypeNotification; protected ObjectMetadataManager objectMetadataManager; protected DependencyRule deploymentDependencyRule; public static class SubmitPackage { protected String pathPrefix; protected Set<String> paths = new HashSet<String>(); protected Set<DmDependencyTO> items = new HashSet<DmDependencyTO>(); protected Set<String> uris = new HashSet<String>(); protected StringBuilder builder = new StringBuilder(); public SubmitPackage(String pathPrefix) { this.pathPrefix = pathPrefix; } public void addToPackage(String relativePath) { paths.add(pathPrefix + relativePath); builder.append(relativePath).append(", "); uris.add(relativePath); } public void addToPackage(DmDependencyTO item) { paths.add(pathPrefix + item.getUri()); builder.append(item).append(", "); items.add(item); uris.add(item.getUri()); } public Set<String> getUris() { return uris; } public List<String> getPaths() { return new ArrayList<String>(paths); } public Set<DmDependencyTO> getItems() { return items; } public String getLabel() { String label = builder.toString(); if (label.length() > 255) { label = label.substring(0, 252) + ".."; } return label; } } }