Java tutorial
/* * This library is part of OpenCms - * the Open Source Content Management System * * Copyright (C) Alkacon Software (http://www.alkacon.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * For further information about Alkacon Software, please see the * company website: http://www.alkacon.com * * For further information about OpenCms, please see the * project website: http://www.opencms.org * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.opencms.workflow; import org.opencms.ade.publish.CmsCurrentPageProject; import org.opencms.ade.publish.CmsDirectPublishProject; import org.opencms.ade.publish.CmsMyChangesProject; import org.opencms.ade.publish.CmsPublish; import org.opencms.ade.publish.CmsRealProjectVirtualWrapper; import org.opencms.ade.publish.I_CmsVirtualProject; import org.opencms.ade.publish.shared.CmsProjectBean; import org.opencms.ade.publish.shared.CmsPublishListToken; import org.opencms.ade.publish.shared.CmsPublishOptions; import org.opencms.ade.publish.shared.CmsPublishResource; import org.opencms.ade.publish.shared.CmsWorkflow; import org.opencms.ade.publish.shared.CmsWorkflowAction; import org.opencms.ade.publish.shared.CmsWorkflowResponse; import org.opencms.file.CmsObject; import org.opencms.file.CmsProject; import org.opencms.file.CmsResource; import org.opencms.i18n.CmsMessages; import org.opencms.main.CmsException; import org.opencms.main.CmsLog; import org.opencms.main.OpenCms; import org.opencms.security.CmsOrganizationalUnit; import org.opencms.security.CmsRole; import org.opencms.util.CmsUUID; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import org.apache.commons.logging.Log; import com.google.common.collect.Maps; /** * The default implementation of the workflow manager interface, which offers only publish functionality.<p> */ public class CmsDefaultWorkflowManager extends A_CmsWorkflowManager { /** The forced publish workflow action. */ public static final String ACTION_FORCE_PUBLISH = "forcepublish"; /** The publish workflow action. */ public static final String ACTION_PUBLISH = "publish"; /** Default value for the maximum number of resources in the initial publish list. */ public static int DEFAULT_RESOURCE_LIMIT = 1000; /** The parameter name for the resource limit. */ public static final String PARAM_RESOURCE_LIMIT = "resourceLimit"; /** The name for the publish action. */ public static final String WORKFLOW_PUBLISH = "WORKFLOW_PUBLISH"; /** The log instance for this class. */ private static final Log LOG = CmsLog.getLog(CmsDefaultWorkflowManager.class); /** The map of registered virtual projects. */ protected Map<CmsUUID, I_CmsVirtualProject> m_virtualProjects = Maps.newHashMap(); /** The number of resources in the initial publish list above which the resources are not being displayed to the user. */ private int m_resourceLimit = DEFAULT_RESOURCE_LIMIT; /** * Constructor.<p> */ public CmsDefaultWorkflowManager() { m_virtualProjects.put(CmsCurrentPageProject.ID, new CmsCurrentPageProject()); m_virtualProjects.put(CmsMyChangesProject.ID, new CmsMyChangesProject()); m_virtualProjects.put(CmsDirectPublishProject.ID, new CmsDirectPublishProject()); } /** * Creates a project bean from a real project.<p> * * @param cms the CMS context * @param project the project * * @return the bean containing the project information */ public static CmsProjectBean createProjectBeanFromProject(CmsObject cms, CmsProject project) { CmsProjectBean manProj = new CmsProjectBean(project.getUuid(), project.getType().getMode(), org.opencms.ade.publish.Messages.get() .getBundle(OpenCms.getWorkplaceManager().getWorkplaceLocale(cms)) .key(org.opencms.ade.publish.Messages.GUI_NORMAL_PROJECT_1, getOuAwareName(cms, project.getName())), project.getDescription()); return manProj; } /** * Returns the simple name if the ou is the same as the current user's ou.<p> * * @param cms the CMS context * @param name the fully qualified name to check * * @return the simple name if the ou is the same as the current user's ou */ protected static String getOuAwareName(CmsObject cms, String name) { String ou = CmsOrganizationalUnit.getParentFqn(name); if (ou.equals(cms.getRequestContext().getCurrentUser().getOuFqn())) { return CmsOrganizationalUnit.getSimpleName(name); } return CmsOrganizationalUnit.SEPARATOR + name; } /** * @see org.opencms.workflow.I_CmsWorkflowManager#createFormatter(org.opencms.file.CmsObject, org.opencms.ade.publish.shared.CmsWorkflow, org.opencms.ade.publish.shared.CmsPublishOptions) */ public I_CmsPublishResourceFormatter createFormatter(CmsObject cms, CmsWorkflow workflow, CmsPublishOptions options) { CmsDefaultPublishResourceFormatter formatter = new CmsDefaultPublishResourceFormatter(cms); return formatter; } /** * @see org.opencms.workflow.I_CmsWorkflowManager#executeAction(org.opencms.file.CmsObject, org.opencms.ade.publish.shared.CmsWorkflowAction, org.opencms.ade.publish.shared.CmsPublishListToken) */ public CmsWorkflowResponse executeAction(CmsObject cms, CmsWorkflowAction action, CmsPublishListToken token) throws CmsException { if (action.getAction().equals(CmsWorkflowAction.ACTION_CANCEL)) { // Don't need to get the resource list for canceling return new CmsWorkflowResponse(true, action.getAction(), null, null, null); } List<CmsResource> resources = getWorkflowResources(cms, token.getWorkflow(), token.getOptions(), false) .getWorkflowResources(); return executeAction(cms, action, token.getOptions(), resources); } /** * @see org.opencms.workflow.I_CmsWorkflowManager#executeAction(org.opencms.file.CmsObject, org.opencms.ade.publish.shared.CmsWorkflowAction, org.opencms.ade.publish.shared.CmsPublishOptions, java.util.List) */ @Override public CmsWorkflowResponse executeAction(CmsObject userCms, CmsWorkflowAction action, CmsPublishOptions options, List<CmsResource> resources) throws CmsException { String actionKey = action.getAction(); if (CmsWorkflowAction.ACTION_CANCEL.equals(actionKey)) { return new CmsWorkflowResponse(true, actionKey, null, null, null); } else if (ACTION_PUBLISH.equals(actionKey)) { return actionPublish(userCms, options, resources); } else if (ACTION_FORCE_PUBLISH.equals(actionKey)) { return actionForcePublish(userCms, options, resources); } throw new CmsInvalidActionException(actionKey); } /** * Gets the localized label for a given CMS context and key.<p> * * @param cms the CMS context * @param key the localization key * * @return the localized label */ public String getLabel(CmsObject cms, String key) { CmsMessages messages = Messages.get().getBundle(getLocale(cms)); return messages.key(key); } /** * @see org.opencms.workflow.I_CmsWorkflowManager#getManageableProjects(org.opencms.file.CmsObject, java.util.Map) */ public List<CmsProjectBean> getManageableProjects(CmsObject cms, Map<String, String> params) { List<CmsProjectBean> manProjs = new ArrayList<CmsProjectBean>(); List<CmsProject> projects; try { projects = OpenCms.getOrgUnitManager().getAllManageableProjects(cms, "", true); } catch (CmsException e) { // should never happen LOG.error(e.getLocalizedMessage(), e); return manProjs; } for (CmsProject project : projects) { CmsProjectBean manProj = createProjectBeanFromProject(cms, project); manProjs.add(manProj); } for (I_CmsVirtualProject handler : m_virtualProjects.values()) { CmsProjectBean projectBean = handler.getProjectBean(cms, params); if (projectBean != null) { manProjs.add(projectBean); } } return manProjs; } /** * @see org.opencms.workflow.I_CmsWorkflowManager#getPublishListToken(org.opencms.file.CmsObject, org.opencms.ade.publish.shared.CmsWorkflow, org.opencms.ade.publish.shared.CmsPublishOptions) */ public CmsPublishListToken getPublishListToken(CmsObject cms, CmsWorkflow workflow, CmsPublishOptions options) { return new CmsPublishListToken(workflow, options); } /** * @see org.opencms.workflow.I_CmsWorkflowManager#getRealOrVirtualProject(org.opencms.util.CmsUUID) */ public I_CmsVirtualProject getRealOrVirtualProject(CmsUUID projectId) { I_CmsVirtualProject project = m_virtualProjects.get(projectId); if (project == null) { project = new CmsRealProjectVirtualWrapper(projectId); } return project; } /** * @see org.opencms.workflow.I_CmsWorkflowManager#getResourceLimit() */ public int getResourceLimit() { return m_resourceLimit; } /** * @see org.opencms.workflow.I_CmsWorkflowManager#getWorkflowForWorkflowProject(org.opencms.util.CmsUUID) */ public String getWorkflowForWorkflowProject(CmsUUID projectId) { return WORKFLOW_PUBLISH; } /** * @see org.opencms.workflow.I_CmsWorkflowManager#getWorkflowResources(org.opencms.file.CmsObject, org.opencms.ade.publish.shared.CmsWorkflow, org.opencms.ade.publish.shared.CmsPublishOptions, boolean) */ @Override public CmsWorkflowResources getWorkflowResources(CmsObject cms, CmsWorkflow workflow, CmsPublishOptions options, boolean canOverride) { try { List<CmsResource> rawResourceList = new ArrayList<CmsResource>(); I_CmsVirtualProject projectHandler = null; projectHandler = getRealOrVirtualProject(options.getProjectId()); if (projectHandler != null) { rawResourceList = projectHandler.getResources(cms, options.getParameters(), workflow.getId()); return new CmsWorkflowResources(rawResourceList); } return new CmsWorkflowResources(rawResourceList); } catch (Exception e) { LOG.error(e.getLocalizedMessage(), e); return new CmsWorkflowResources(Collections.<CmsResource>emptyList()); } } /** * @see org.opencms.workflow.I_CmsWorkflowManager#getWorkflows(org.opencms.file.CmsObject) */ public Map<String, CmsWorkflow> getWorkflows(CmsObject cms) { Map<String, CmsWorkflow> result = new LinkedHashMap<String, CmsWorkflow>(); List<CmsWorkflowAction> actions = new ArrayList<CmsWorkflowAction>(); String publishLabel = getLabel(cms, Messages.GUI_WORKFLOW_ACTION_PUBLISH_0); CmsWorkflowAction publishAction = new CmsWorkflowAction(ACTION_PUBLISH, publishLabel, true, true); actions.add(publishAction); String workflowLabel = getLabel(cms, Messages.GUI_WORKFLOW_PUBLISH_0); CmsWorkflow publishWorkflow = new CmsWorkflow(WORKFLOW_PUBLISH, workflowLabel, actions); result.put(WORKFLOW_PUBLISH, publishWorkflow); return result; } /** * @see org.opencms.workflow.A_CmsWorkflowManager#initialize(org.opencms.file.CmsObject) */ @Override public void initialize(CmsObject adminCms) { super.initialize(adminCms); String resourceLimitStr = getParameter(PARAM_RESOURCE_LIMIT, "invalid").trim(); try { m_resourceLimit = Integer.parseInt(resourceLimitStr); } catch (NumberFormatException e) { // ignore, resource limit will remain at the default setting } } /** * The implementation of the "forcepublish" workflow action.<p> * * @param userCms the user CMS context * @param resources the resources which the action should process * @param options the publish options to use * @return the workflow response * * @throws CmsException if something goes wrong */ protected CmsWorkflowResponse actionForcePublish(CmsObject userCms, CmsPublishOptions options, List<CmsResource> resources) throws CmsException { CmsPublish publish = new CmsPublish(userCms, options.getParameters()); publish.publishResources(resources); CmsWorkflowResponse response = new CmsWorkflowResponse(true, "", new ArrayList<CmsPublishResource>(), new ArrayList<CmsWorkflowAction>(), null); return response; } /** * The implementation of the "publish" workflow action.<p> * * @param userCms the user CMS context * @param options the publish options * @param resources the resources which the action should process * * @return the workflow response * @throws CmsException if something goes wrong */ protected CmsWorkflowResponse actionPublish(CmsObject userCms, CmsPublishOptions options, final List<CmsResource> resources) throws CmsException { final CmsPublish publish = new CmsPublish(userCms, options); // use FutureTask to get the broken links, because we can then use a different thread if it takes too long final FutureTask<List<CmsPublishResource>> brokenResourcesGetter = new FutureTask<List<CmsPublishResource>>( new Callable<List<CmsPublishResource>>() { public List<CmsPublishResource> call() throws Exception { return publish.getBrokenResources(resources); } }); Thread brokenResourcesThread = new Thread(brokenResourcesGetter); brokenResourcesThread.start(); try { List<CmsPublishResource> brokenResources = brokenResourcesGetter.get(10, TimeUnit.SECONDS); if (brokenResources.size() == 0) { publish.publishResources(resources); CmsWorkflowResponse response = new CmsWorkflowResponse(true, "", new ArrayList<CmsPublishResource>(), new ArrayList<CmsWorkflowAction>(), null); return response; } else { String brokenResourcesLabel = getLabel(userCms, Messages.GUI_BROKEN_LINKS_0); boolean canForcePublish = OpenCms.getWorkplaceManager().getDefaultUserSettings() .isAllowBrokenRelations() || OpenCms.getRoleManager().hasRole(userCms, CmsRole.VFS_MANAGER); List<CmsWorkflowAction> actions = new ArrayList<CmsWorkflowAction>(); if (canForcePublish) { String forceLabel = getLabel(userCms, Messages.GUI_WORKFLOW_ACTION_FORCE_PUBLISH_0); actions.add(new CmsWorkflowAction(ACTION_FORCE_PUBLISH, forceLabel, true, true)); } CmsWorkflowResponse response = new CmsWorkflowResponse(false, brokenResourcesLabel, brokenResources, actions, null); return response; } } catch (TimeoutException e) { // Things are taking too long, do them in a different thread and just return "OK" to the client Thread thread = new Thread() { @SuppressWarnings("synthetic-access") @Override public void run() { LOG.info( "Checking broken relations is taking too long, using a different thread for checking and publishing now."); try { // Make sure the computation is finished by calling get() without a timeout parameter // We don't need the actual result of the get(), though; we just get the set of resource paths from the validator object brokenResourcesGetter.get(); List<CmsResource> resourcesToPublish = new ArrayList<CmsResource>(resources); Iterator<CmsResource> resIter = resourcesToPublish.iterator(); while (resIter.hasNext()) { CmsResource currentRes = resIter.next(); if (publish.getRelationValidator().keySet().contains(currentRes.getRootPath())) { resIter.remove(); LOG.info("Excluding resource from publish list because relations would be broken: " + currentRes.getRootPath()); } } publish.publishResources(resourcesToPublish); } catch (Exception ex) { LOG.error(ex.getLocalizedMessage(), ex); } } }; thread.start(); CmsWorkflowResponse response = new CmsWorkflowResponse(true, "", new ArrayList<CmsPublishResource>(), new ArrayList<CmsWorkflowAction>(), null); return response; } catch (InterruptedException e) { // shouldn't happen; log exception LOG.error(e.getLocalizedMessage()); return null; } catch (ExecutionException e) { // shouldn't happen; log exception LOG.error(e.getLocalizedMessage()); return null; } } }