001/* 002 * (C) Copyright 2013 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Mariana Cedica 018 */ 019package org.nuxeo.ecm.platform.routing.core.impl; 020 021import java.io.Serializable; 022import java.util.ArrayList; 023import java.util.List; 024import java.util.Map; 025 026import org.apache.commons.logging.Log; 027import org.apache.commons.logging.LogFactory; 028import org.nuxeo.ecm.automation.OperationContext; 029import org.nuxeo.ecm.core.api.CoreSession; 030import org.nuxeo.ecm.core.api.DocumentModel; 031import org.nuxeo.ecm.core.api.IdRef; 032import org.nuxeo.ecm.core.api.IterableQueryResult; 033import org.nuxeo.ecm.core.api.NuxeoException; 034import org.nuxeo.ecm.core.api.UnrestrictedSessionRunner; 035import org.nuxeo.ecm.core.work.AbstractWork; 036import org.nuxeo.ecm.core.work.api.WorkManager; 037import org.nuxeo.ecm.platform.routing.core.api.DocumentRoutingEscalationService; 038import org.nuxeo.ecm.platform.routing.core.impl.GraphNode.EscalationRule; 039import org.nuxeo.runtime.api.Framework; 040 041/** 042 * @since 5.7.2 043 */ 044public class DocumentRoutingEscalationServiceImpl implements DocumentRoutingEscalationService { 045 046 private static Log log = LogFactory.getLog(DocumentRoutingEscalationServiceImpl.class); 047 048 public static final String queryForSuspendedNodesWithEscalation = "Select DISTINCT ecm:uuid from RouteNode WHERE ecm:currentLifeCycleState = 'suspended' " 049 + "AND ( rnode:escalationRules/*1/executed = 0 OR rnode:escalationRules/*1/multipleExecution = 1 )"; 050 051 @Override 052 public List<String> queryForSuspendedNodesWithEscalation(CoreSession session) { 053 final List<String> nodesDocIds = new ArrayList<String>(); 054 new UnrestrictedSessionRunner(session) { 055 @Override 056 public void run() { 057 IterableQueryResult results = session.queryAndFetch(queryForSuspendedNodesWithEscalation, "NXQL"); 058 for (Map<String, Serializable> result : results) { 059 nodesDocIds.add(result.get("ecm:uuid").toString()); 060 log.trace("Inspecting node for escalation rules:" + result.get("ecm:uuid").toString()); 061 } 062 results.close(); 063 } 064 }.runUnrestricted(); 065 return nodesDocIds; 066 } 067 068 @Override 069 public List<EscalationRule> computeEscalationRulesToExecute(GraphNode node) { 070 return node.evaluateEscalationRules(); 071 } 072 073 @Override 074 public void scheduleExecution(EscalationRule rule, CoreSession session) { 075 WorkManager manager = Framework.getLocalService(WorkManager.class); 076 manager.schedule( 077 new EscalationRuleWork(rule.getId(), rule.getNode().getDocument().getId(), session.getRepositoryName()), 078 WorkManager.Scheduling.IF_NOT_SCHEDULED); 079 } 080 081 public static class EscalationRuleWork extends AbstractWork { 082 083 private static final long serialVersionUID = 1L; 084 085 protected String escalationRuleId; 086 087 protected String nodeDocId; 088 089 public static final String CATEGORY = "routingEscalation"; 090 091 public EscalationRuleWork(String escalationRuleId, String nodeDocId, String repositoryName) { 092 super(repositoryName + ":" + nodeDocId + ":escalationRule:" + escalationRuleId); 093 this.repositoryName = repositoryName; 094 this.escalationRuleId = escalationRuleId; 095 this.nodeDocId = nodeDocId; 096 } 097 098 @Override 099 public String getTitle() { 100 return getId(); 101 } 102 103 @Override 104 public String getCategory() { 105 return CATEGORY; 106 } 107 108 @Override 109 public void work() { 110 openSystemSession(); 111 DocumentModel nodeDoc = session.getDocument(new IdRef(nodeDocId)); 112 GraphNode node = nodeDoc.getAdapter(GraphNode.class); 113 if (node == null) { 114 throw new NuxeoException("Can't execute worker '" + getId() + "' : the document '" + nodeDocId 115 + "' can not be adapted to a GraphNode"); 116 } 117 List<EscalationRule> rules = node.getEscalationRules(); 118 EscalationRule rule = null; 119 for (EscalationRule escalationRule : rules) { 120 if (escalationRuleId.equals(escalationRule.getId())) { 121 rule = escalationRule; 122 break; 123 } 124 } 125 if (rule == null) { 126 throw new NuxeoException("Can't execute worker '" + getId() + "' : the rule '" + escalationRuleId 127 + "' was not found on the node '" + nodeDocId + "'"); 128 } 129 OperationContext context = new OperationContext(session); 130 context.putAll(node.getWorkflowContextualInfo(session, true)); 131 context.setInput(context.get("documents")); 132 try { 133 // check to see if the rule wasn't executed meanwhile 134 boolean alreadyExecuted = getExecutionStatus(rule, session); 135 if (alreadyExecuted && !rule.isMultipleExecution()) { 136 log.trace("Rule " + rule.getId() + "on node " + node.getId() + " already executed"); 137 return; 138 } 139 node.executeChain(rule.getChain()); 140 // mark the rule as resolved 141 markRuleAsExecuted(nodeDocId, escalationRuleId, session); 142 } catch (NuxeoException e) { 143 e.addInfo("Error when executing worker: " + getTitle()); 144 throw e; 145 } 146 } 147 148 /** 149 * Used to check the executed status when the escalationRule is run by a worker in a work queue 150 * 151 * @param session 152 */ 153 public boolean getExecutionStatus(EscalationRule rule, CoreSession session) { 154 DocumentModel nodeDoc = session.getDocument(new IdRef(rule.getNode().getDocument().getId())); 155 GraphNode node = nodeDoc.getAdapter(GraphNode.class); 156 List<EscalationRule> rules = node.getEscalationRules(); 157 for (EscalationRule escalationRule : rules) { 158 if (rule.compareTo(escalationRule) == 0) { 159 return escalationRule.isExecuted(); 160 } 161 } 162 return false; 163 } 164 165 } 166 167 private static void markRuleAsExecuted(String nodeDocId, String escalationRuleId, CoreSession session) 168 { 169 DocumentModel nodeDoc = session.getDocument(new IdRef(nodeDocId)); 170 GraphNode node = nodeDoc.getAdapter(GraphNode.class); 171 List<EscalationRule> rules = node.getEscalationRules(); 172 EscalationRule rule = null; 173 for (EscalationRule escalationRule : rules) { 174 if (escalationRuleId.equals(escalationRule.getId())) { 175 rule = escalationRule; 176 break; 177 } 178 } 179 rule.setExecuted(true); 180 session.saveDocument(nodeDoc); 181 } 182}