Java tutorial
/* * Copyright (C) 2003-2007 eXo Platform SAS. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Affero 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.exoplatform.services.cms.actions.impl; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.Date; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import javax.jcr.Node; import javax.jcr.Property; import javax.jcr.PropertyType; import javax.jcr.Session; import javax.jcr.Value; import javax.jcr.nodetype.NodeType; import javax.jcr.nodetype.NodeTypeManager; import javax.jcr.nodetype.PropertyDefinition; import javax.jcr.observation.ObservationManager; import org.apache.commons.lang.StringUtils; import org.exoplatform.services.cms.JcrInputProperty; import org.exoplatform.services.cms.actions.ActionPlugin; import org.exoplatform.services.cms.actions.ActionServiceContainer; import org.exoplatform.services.cms.actions.DMSEvent; import org.exoplatform.services.jcr.RepositoryService; import org.exoplatform.services.jcr.core.ManageableRepository; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; import org.exoplatform.services.scheduler.JobInfo; import org.exoplatform.services.scheduler.JobSchedulerService; import org.exoplatform.services.scheduler.PeriodInfo; import org.exoplatform.services.wcm.utils.WCMCoreUtils; import org.quartz.JobDataMap; abstract public class BaseActionPlugin implements ActionPlugin { final static String JOB_NAME_PREFIX = "activate_"; final static String PERIOD_JOB = "period"; final static String CRON_JOB = "cron"; final static String SCHEDULABLE_INFO_MIXIN = "exo:schedulableInfo"; final static String SCHEDULED_INITIATOR = "exo:scheduledInitiator"; final static String JOB_NAME_PROP = "exo:jobName"; final static String JOB_GROUP_PROP = "exo:jobGroup"; final static String JOB_DESCRIPTION_PROP = "exo:jobDescription"; final static String JOB_CLASS_PROP = "exo:jobClass"; final static String SCHEDULE_TYPE_PROP = "exo:scheduleType"; final static String START_TIME_PROP = "exo:startTime"; final static String END_TIME_PROP = "exo:endTime"; final static String REPEAT_COUNT_PROP = "exo:repeatCount"; final static String TIME_INTERVAL_PROP = "exo:timeInterval"; final static String CRON_EXPRESSION_PROP = "exo:cronExpression"; final static String LIFECYCLE_PHASE_PROP = "exo:lifecyclePhase"; final static String NODE_NAME_PROP = "exo:name"; final static String COUNTER_PROP = "exo:counter"; final static String EXO_ACTIONS = "exo:actions"; final static String ACTION_STORAGE = "exo:actionStorage"; final static long BUFFER_TIME = 500 * 1000; final static String actionNameVar = "actionName"; final static String srcRepository = "repository"; final static String srcWorkspaceVar = "srcWorkspace"; final static String initiatorVar = "initiator"; final static String srcPathVar = "srcPath"; final static String nodePath = "nodePath"; final static String executableVar = "executable"; final static String MIX_AFFECTED_NODETYPE = "mix:affectedNodeTypes"; final static String AFFECTED_NODETYPE = "exo:affectedNodeTypeNames"; final static String ALL_DOCUMENT_TYPES = "ALL_DOCUMENT_TYPES"; protected Map<String, ECMEventListener> listeners_ = new HashMap<String, ECMEventListener>(); private static final Log LOG = ExoLogger.getLogger(BaseActionPlugin.class.getName()); abstract protected String getWorkspaceName(); abstract protected ManageableRepository getRepository() throws Exception; abstract protected String getActionType(); abstract protected List getActions(); abstract protected ECMEventListener createEventListener(String actionName, String actionExecutable, String repository, String srcWorkspace, String srcPath, Map variables, String actiontype) throws Exception; abstract protected Class createActivationJob() throws Exception; /** * {@inheritDoc} */ public void addAction(String actionType, String srcWorkspace, String srcPath, Map mappings) throws Exception { addAction(actionType, srcWorkspace, srcPath, true, null, null, mappings); } /** * {@inheritDoc} */ public void addAction(String actionType, String srcWorkspace, String srcPath, boolean isDeep, String[] uuid, String[] nodeTypeNames, Map mappings) throws Exception { String repoName = WCMCoreUtils.getRepository().getConfiguration().getName(); String actionName = (String) ((JcrInputProperty) mappings.get("/node/exo:name")).getValue(); mappings.remove("/node/exo:name"); Object typeObj = ((JcrInputProperty) mappings.get("/node/exo:lifecyclePhase")).getValue(); String[] type = (typeObj instanceof String) ? new String[] { (String) typeObj } : (String[]) typeObj; String actionExecutable = getActionExecutable(actionType); if (DMSEvent.getEventTypes(type) == DMSEvent.READ) return; if ((DMSEvent.getEventTypes(type) & DMSEvent.SCHEDULE) > 0) { scheduleActionActivationJob(srcWorkspace, srcPath, actionName, actionType, actionExecutable, mappings); } if (DMSEvent.getEventTypes(type) == DMSEvent.SCHEDULE) return; Map<String, Object> variables = getExecutionVariables(mappings); ECMEventListener listener = createEventListener(actionName, actionExecutable, repoName, srcWorkspace, srcPath, variables, actionType); Session session = getSystemSession(srcWorkspace); ObservationManager obsManager = session.getWorkspace().getObservationManager(); String listenerKey = repoName + ":" + srcPath + "/exo:actions/" + actionName; if (listeners_.containsKey(listenerKey)) { obsManager.removeEventListener(listeners_.get(listenerKey)); listeners_.remove(listenerKey); } obsManager.addEventListener(listener, DMSEvent.getEventTypes(type), srcPath, isDeep, uuid, nodeTypeNames, false); session.logout(); listeners_.put(listenerKey, listener); } /** * {@inheritDoc} */ public void initiateActionObservation(Node storedActionNode) throws Exception { RepositoryService repositoryService = WCMCoreUtils.getService(RepositoryService.class); String repository = repositoryService.getCurrentRepository().getConfiguration().getName(); String actionName = storedActionNode.getProperty("exo:name").getString(); String[] lifecyclePhase = storedActionNode.hasProperty("exo:lifecyclePhase") ? parseValuesToArray(storedActionNode.getProperty("exo:lifecyclePhase").getValues()) : null; if (DMSEvent.getEventTypes(lifecyclePhase) == DMSEvent.READ) return; String[] uuid = storedActionNode.hasProperty("exo:uuid") ? parseValuesToArray(storedActionNode.getProperty("exo:uuid").getValues()) : null; boolean isDeep = storedActionNode.hasProperty("exo:isDeep") ? storedActionNode.getProperty("exo:isDeep").getBoolean() : true; String[] nodeTypeNames = storedActionNode.hasProperty("exo:nodeTypeName") ? parseValuesToArray(storedActionNode.getProperty("exo:nodeTypeName").getValues()) : null; String actionType = storedActionNode.getPrimaryNodeType().getName(); String srcWorkspace = storedActionNode.getSession().getWorkspace().getName(); String srcPath = storedActionNode.getParent().getParent().getPath(); Map<String, Object> variables = new HashMap<String, Object>(); NodeType nodeType = storedActionNode.getPrimaryNodeType(); PropertyDefinition[] defs = nodeType.getPropertyDefinitions(); for (PropertyDefinition propDef : defs) { if (!propDef.isMultiple()) { String key = propDef.getName(); try { Object value = getPropertyValue(storedActionNode.getProperty(key)); variables.put(key, value); } catch (Exception e) { variables.put(key, null); } } } String actionExecutable = getActionExecutable(actionType); ECMEventListener listener = createEventListener(actionName, actionExecutable, repository, srcWorkspace, srcPath, variables, actionType); Session session = getSystemSession(srcWorkspace); String listenerKey = repository + ":" + srcPath + "/exo:actions/" + actionName; ObservationManager obsManager = session.getWorkspace().getObservationManager(); if (listeners_.containsKey(listenerKey)) { obsManager.removeEventListener(listeners_.get(listenerKey)); listeners_.remove(listenerKey); } obsManager.addEventListener(listener, DMSEvent.getEventTypes(lifecyclePhase), srcPath, isDeep, uuid, nodeTypeNames, false); session.logout(); listeners_.put(listenerKey, listener); } public void reScheduleActivations(Node storedActionNode) throws Exception { String jobClassName = storedActionNode.getProperty(JOB_CLASS_PROP).getString(); Class activationJobClass = null; try { activationJobClass = Class.forName(jobClassName); } catch (Exception e) { if (LOG.isErrorEnabled()) { LOG.error("Unexpected error", e); } return; } String actionName = storedActionNode.getProperty(NODE_NAME_PROP).getString(); String actionType = storedActionNode.getPrimaryNodeType().getName(); String srcWorkspace = storedActionNode.getSession().getWorkspace().getName(); String scheduleType = storedActionNode.getProperty(SCHEDULE_TYPE_PROP).getString(); String initiator = storedActionNode.getProperty(SCHEDULED_INITIATOR).getString(); String srcPath = storedActionNode.getParent().getParent().getPath(); String jobName = storedActionNode.getProperty(JOB_NAME_PROP).getString(); String jobGroup = storedActionNode.getProperty(JOB_GROUP_PROP).getString(); JobSchedulerService schedulerService = WCMCoreUtils.getService(JobSchedulerService.class); Map<String, Object> variables = new HashMap<String, Object>(); NodeType nodeType = storedActionNode.getPrimaryNodeType(); PropertyDefinition[] defs = nodeType.getPropertyDefinitions(); for (PropertyDefinition propDef : defs) { if (!propDef.isMultiple()) { String key = propDef.getName(); try { Object value = getPropertyValue(storedActionNode.getProperty(key)); variables.put(key, value); } catch (Exception e) { variables.put(key, null); } } } String actionExecutable = getActionExecutable(actionType); variables.put(initiatorVar, initiator); variables.put(actionNameVar, actionName); variables.put(executableVar, actionExecutable); variables.put(srcWorkspaceVar, srcWorkspace); variables.put(srcPathVar, srcPath); JobDataMap jdatamap = new JobDataMap(); JobInfo jinfo = new JobInfo(jobName, jobGroup, activationJobClass); jdatamap.putAll(variables); if (CRON_JOB.equals(scheduleType)) { String cronExpression = storedActionNode.getProperty(CRON_EXPRESSION_PROP).getString(); schedulerService.addCronJob(jinfo, cronExpression, jdatamap); } else { Calendar endTime = null; Date endDate = null; if (storedActionNode.hasProperty(END_TIME_PROP)) { endTime = storedActionNode.getProperty(END_TIME_PROP).getDate(); } if (endTime != null) endDate = endTime.getTime(); long timeInterval = storedActionNode.getProperty(TIME_INTERVAL_PROP).getLong(); Date startDate = new Date(System.currentTimeMillis() + BUFFER_TIME); int repeatCount = (int) storedActionNode.getProperty(REPEAT_COUNT_PROP).getLong(); int counter = (int) storedActionNode.getProperty(COUNTER_PROP).getLong(); PeriodInfo pinfo = new PeriodInfo(startDate, endDate, repeatCount - counter, timeInterval); schedulerService.addPeriodJob(jinfo, pinfo, jdatamap); } } protected Session getSystemSession(String workspace) throws Exception { ManageableRepository jcrRepository = getRepository(); return jcrRepository.getSystemSession(workspace); } public String getActionExecutable(String actionTypeName) throws Exception { NodeTypeManager ntManager = getRepository().getNodeTypeManager(); NodeType nt = ntManager.getNodeType(actionTypeName); PropertyDefinition[] propDefs = nt.getDeclaredPropertyDefinitions(); for (int i = 0; i < propDefs.length; i++) { PropertyDefinition definition = propDefs[i]; if (definition.getName().equals(getExecutableDefinitionName()) && definition.getDefaultValues() != null) { return definition.getDefaultValues()[0].getString(); } } return null; } public boolean isActionTypeSupported(String actionType) { try { NodeTypeManager ntmanager = getRepository().getNodeTypeManager(); for (NodeType type : ntmanager.getNodeType(actionType).getSupertypes()) { if (getActionType().equals(type.getName())) { return true; } } } catch (Exception re) { if (LOG.isWarnEnabled()) { LOG.warn(re.getMessage()); } } return false; } public void removeObservation(String repository, String actionPath) throws Exception { ECMEventListener eventListener = listeners_.get(repository + ":" + actionPath); if (eventListener != null) { String srcWorkspace = eventListener.getSrcWorkspace(); Session session = getSystemSession(srcWorkspace); ObservationManager obsManager = session.getWorkspace().getObservationManager(); obsManager.removeEventListener(eventListener); session.logout(); } listeners_.remove(repository + ":" + actionPath); } public void removeActivationJob(String jobName, String jobGroup, String jobClass) throws Exception { JobSchedulerService schedulerService = WCMCoreUtils.getService(JobSchedulerService.class); Class activationJob = null; try { activationJob = Class.forName(jobClass); } catch (Exception e) { if (LOG.isErrorEnabled()) { LOG.error("Unexpected error", e); } } if (activationJob == null) return; JobInfo jinfo = new JobInfo(jobName, jobGroup, activationJob); schedulerService.removeJob(jinfo); } public boolean isVariable(String variable) throws Exception { NodeTypeManager ntManager = getRepository().getNodeTypeManager(); NodeType nt = ntManager.getNodeType(getActionType()); PropertyDefinition[] propDefs = nt.getDeclaredPropertyDefinitions(); for (int i = 0; i < propDefs.length; i++) { PropertyDefinition definition = propDefs[i]; if (definition.getName().equals(variable)) { return false; } } return true; } public Collection<String> getVariableNames(String actionTypeName) throws Exception { Collection<String> variableNames = new ArrayList<String>(); NodeTypeManager ntManager = getRepository().getNodeTypeManager(); NodeType nt = ntManager.getNodeType(actionTypeName); PropertyDefinition[] propDefs = nt.getDeclaredPropertyDefinitions(); for (int i = 0; i < propDefs.length; i++) { PropertyDefinition definition = propDefs[i]; if (isVariable(definition.getName())) { variableNames.add(definition.getName()); } } return variableNames; } protected void importPredefinedActionsInJcr() throws Exception { List actions = getActions(); if (actions.isEmpty()) return; Session session = null; for (Iterator iter = actions.iterator(); iter.hasNext();) { ActionConfig.Action action = (ActionConfig.Action) iter.next(); try { session = getSystemSession(action.getSrcWorkspace()); importAction(action, session); session.logout(); } catch (Exception e) { if (session != null) session.logout(); if (LOG.isWarnEnabled()) { LOG.warn(" ==> Can not init action '" + action.getName() + "' and workspace '" + action.getSrcWorkspace() + "'"); } } } } protected void reImportPredefinedActionsInJcr() throws Exception { List actions = getActions(); if (actions.isEmpty()) return; Session session = null; for (Iterator iter = actions.iterator(); iter.hasNext();) { ActionConfig.Action action = (ActionConfig.Action) iter.next(); try { session = getSystemSession(action.getSrcWorkspace()); importAction(action, session); } catch (Exception e) { if (session != null) session.logout(); if (LOG.isWarnEnabled()) { LOG.warn(" ==> Can not init action '" + action.getName() + "' in current repository and workspace '" + action.getSrcWorkspace() + "'"); } } } } @SuppressWarnings("unchecked") private void importAction(ActionConfig.Action action, Session session) throws Exception { Node srcNode = (Node) session.getItem(action.getSrcPath()); Node actionNode = null; boolean firstImport = false; ActionServiceContainer actionContainer = WCMCoreUtils.getService(ActionServiceContainer.class); RepositoryService repositoryService = WCMCoreUtils.getService(RepositoryService.class); ManageableRepository manageRepo = repositoryService.getCurrentRepository(); Node actionNodeName = null; try { actionNodeName = actionContainer.getAction(srcNode, action.getName()); } catch (Exception e) { if (LOG.isWarnEnabled()) { LOG.warn(e.getMessage()); } } Node actionsNode = null; if (actionNodeName == null) { firstImport = true; if (!srcNode.isNodeType("exo:actionable")) { srcNode.addMixin("exo:actionable"); } try { actionsNode = srcNode.getNodes(EXO_ACTIONS).nextNode(); } catch (Exception e) { actionsNode = srcNode.addNode(EXO_ACTIONS, ACTION_STORAGE); srcNode.save(); } actionNode = actionsNode.addNode(action.getName(), action.getType()); actionNode.setProperty("exo:name", action.getName()); actionNode.setProperty("exo:description", action.getDescription()); actionNode.setProperty("exo:isDeep", action.isDeep()); if (action.getUuid() != null) actionNode.setProperty("exo:uuid", action.getUuid().toArray(new String[0])); if (action.getNodeTypeName() != null) actionNode.setProperty("exo:nodeTypeName", action.getNodeTypeName().toArray(new String[0])); if (action.getLifecyclePhase() != null) actionNode.setProperty("exo:lifecyclePhase", action.getLifecyclePhase().toArray(new String[0])); if (action.getRoles() != null) { String[] roles = StringUtils.split(action.getRoles(), ";"); actionNode.setProperty("exo:roles", roles); } Iterator mixins = action.getMixins().iterator(); NodeType nodeType; String value; while (mixins.hasNext()) { ActionConfig.Mixin mixin = (ActionConfig.Mixin) mixins.next(); actionNode.addMixin(mixin.getName()); Map<String, String> props = mixin.getParsedProperties(); Set keys = props.keySet(); nodeType = manageRepo.getNodeTypeManager().getNodeType(mixin.getName()); for (Iterator iterator = keys.iterator(); iterator.hasNext();) { String key = (String) iterator.next(); for (PropertyDefinition pro : nodeType.getPropertyDefinitions()) { if (pro.getName().equals(key)) { if (pro.isMultiple()) { value = props.get(key); if (value != null) { actionNode.setProperty(key, value.split(",")); } } else { actionNode.setProperty(key, props.get(key)); } break; } } } } } else { actionNodeName = actionContainer.getAction(srcNode, action.getName()); } String unparsedVariables = action.getVariables(); Map variablesMap = new HashMap(); if (unparsedVariables != null && !"".equals(unparsedVariables)) { String[] variables = StringUtils.split(unparsedVariables, ";"); for (int i = 0; i < variables.length; i++) { String variable = variables[i]; String[] keyValue = StringUtils.split(variable, "="); String variableKey = keyValue[0]; String variableValue = keyValue[1]; variablesMap.put(variableKey, variableValue); if (firstImport) actionNode.setProperty(variableKey, variableValue); } } if (firstImport) srcNode.save(); } private void scheduleActionActivationJob(String srcWorkspace, String srcPath, String actionName, String actionType, String actionExecutable, Map mappings) throws Exception { JobSchedulerService schedulerService = WCMCoreUtils.getService(JobSchedulerService.class); ActionServiceContainer actionContainer = WCMCoreUtils.getService(ActionServiceContainer.class); Session session = getSystemSession(srcWorkspace); Node srcNode = (Node) session.getItem(srcPath); Node actionNode = actionContainer.getAction(srcNode, actionName); if (!actionNode.isNodeType(SCHEDULABLE_INFO_MIXIN)) { actionNode.addMixin(SCHEDULABLE_INFO_MIXIN); } Class activationJob = createActivationJob(); String jobName = JOB_NAME_PREFIX.concat(actionName); String jobGroup = actionType; String userId = session.getUserID(); String scheduleType = null, repeatCount = null, timeInterval = null, cronExpress = null; GregorianCalendar startTime = new GregorianCalendar(); GregorianCalendar endTime = null; if (mappings.containsKey("/node/exo:scheduleType")) { scheduleType = (String) ((JcrInputProperty) mappings.get("/node/exo:scheduleType")).getValue(); mappings.remove("/node/exo:scheduleType"); } if (mappings.containsKey("/node/exo:startTime")) { startTime = (GregorianCalendar) ((JcrInputProperty) mappings.get("/node/exo:startTime")).getValue(); mappings.remove("/node/exo:startTime"); } if (mappings.containsKey("/node/exo:endTime")) { endTime = (GregorianCalendar) ((JcrInputProperty) mappings.get("/node/exo:endTime")).getValue(); mappings.remove("/node/exo:endTime"); } if (mappings.containsKey("/node/exo:repeatCount")) { repeatCount = (String) ((JcrInputProperty) mappings.get("/node/exo:repeatCount")).getValue(); mappings.remove("/node/exo:repeatCount"); } if (mappings.containsKey("/node/exo:timeInterval")) { timeInterval = (String) ((JcrInputProperty) mappings.get("/node/exo:timeInterval")).getValue(); mappings.remove("/node/exo:timeInterval"); } if (mappings.containsKey("/node/exo:cronExpression")) { cronExpress = (String) ((JcrInputProperty) mappings.get("/node/exo:cronExpression")).getValue(); mappings.remove("/node/exo:cronExpression"); } actionNode.setProperty(JOB_NAME_PROP, jobName); actionNode.setProperty(JOB_GROUP_PROP, jobGroup); actionNode.setProperty(JOB_CLASS_PROP, activationJob.getName()); actionNode.setProperty(SCHEDULED_INITIATOR, userId); actionNode.setProperty(SCHEDULE_TYPE_PROP, scheduleType); actionNode.save(); Map<String, Object> variables = new HashMap<String, Object>(); variables.put(initiatorVar, userId); variables.put(actionNameVar, actionName); variables.put(executableVar, actionExecutable); variables.put(srcWorkspaceVar, srcWorkspace); variables.put(srcPathVar, srcPath); variables.put(nodePath, srcPath); Map<String, Object> executionVariables = getExecutionVariables(mappings); JobDataMap jdatamap = new JobDataMap(); jdatamap.putAll(variables); jdatamap.putAll(executionVariables); JobInfo jinfo = new JobInfo(jobName, jobGroup, activationJob); if (scheduleType.equals(CRON_JOB)) { actionNode.setProperty(CRON_EXPRESSION_PROP, cronExpress); actionNode.save(); schedulerService.addCronJob(jinfo, cronExpress, jdatamap); } else { int repeatNum = Integer.parseInt(repeatCount); long period = Long.parseLong(timeInterval); actionNode.setProperty(START_TIME_PROP, startTime); if (endTime != null) { actionNode.setProperty(END_TIME_PROP, endTime); } actionNode.setProperty(TIME_INTERVAL_PROP, period); actionNode.setProperty(REPEAT_COUNT_PROP, repeatNum); actionNode.save(); PeriodInfo pinfo; if (endTime != null) { pinfo = new PeriodInfo(startTime.getTime(), endTime.getTime(), repeatNum, period); } else { pinfo = new PeriodInfo(repeatNum, period); } schedulerService.addPeriodJob(jinfo, pinfo, jdatamap); } session.save(); session.logout(); } private Map<String, Object> getExecutionVariables(Map mappings) { Map<String, Object> variables = new HashMap<String, Object>(); Set keys = mappings.keySet(); for (Iterator iter = keys.iterator(); iter.hasNext();) { String key = (String) iter.next(); Object value = ((JcrInputProperty) mappings.get(key)).getValue(); key = key.substring(key.lastIndexOf("/") + 1); variables.put(key, value); } return variables; } private Object getPropertyValue(Property property) throws Exception { int propertyType = property.getType(); switch (propertyType) { case PropertyType.STRING: return property.getValue().getString(); case PropertyType.BOOLEAN: return property.getValue().getBoolean(); case PropertyType.DATE: return property.getValue().getDate(); case PropertyType.DOUBLE: return property.getValue().getDouble(); case PropertyType.LONG: return property.getValue().getLong(); case PropertyType.NAME: return property.getValue().getString(); case PropertyType.UNDEFINED: return property.getValue(); } return null; } private String[] parseValuesToArray(Value[] values) throws Exception { String[] valueToString = new String[values.length]; int i = 0; for (Value value : values) { valueToString[i++] = value.getString(); } return valueToString; } }