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.automation.OperationException; 030import org.nuxeo.ecm.core.api.CoreSession; 031import org.nuxeo.ecm.core.api.DocumentModel; 032import org.nuxeo.ecm.core.api.IdRef; 033import org.nuxeo.ecm.core.api.IterableQueryResult; 034import org.nuxeo.ecm.core.api.NuxeoException; 035import org.nuxeo.ecm.core.api.UnrestrictedSessionRunner; 036import org.nuxeo.ecm.core.work.AbstractWork; 037import org.nuxeo.ecm.core.work.api.WorkManager; 038import org.nuxeo.ecm.platform.routing.core.api.DocumentRoutingEscalationService; 039import org.nuxeo.ecm.platform.routing.core.impl.GraphNode.EscalationRule; 040import org.nuxeo.runtime.api.Framework; 041 042/** 043 * @since 5.7.2 044 */ 045public class DocumentRoutingEscalationServiceImpl implements DocumentRoutingEscalationService { 046 047 private static Log log = LogFactory.getLog(DocumentRoutingEscalationServiceImpl.class); 048 049 public static final String queryForSuspendedNodesWithEscalation = "Select DISTINCT ecm:uuid from RouteNode WHERE ecm:currentLifeCycleState = 'suspended' " 050 + "AND ( rnode:escalationRules/*1/executed = 0 OR rnode:escalationRules/*1/multipleExecution = 1 )"; 051 052 @Override 053 public List<String> queryForSuspendedNodesWithEscalation(CoreSession session) { 054 final List<String> nodesDocIds = new ArrayList<String>(); 055 new UnrestrictedSessionRunner(session) { 056 @Override 057 public void run() { 058 IterableQueryResult results = session.queryAndFetch(queryForSuspendedNodesWithEscalation, "NXQL"); 059 for (Map<String, Serializable> result : results) { 060 nodesDocIds.add(result.get("ecm:uuid").toString()); 061 log.trace("Inspecting node for escalation rules:" + result.get("ecm:uuid").toString()); 062 } 063 results.close(); 064 } 065 }.runUnrestricted(); 066 return nodesDocIds; 067 } 068 069 @Override 070 public List<EscalationRule> computeEscalationRulesToExecute(GraphNode node) { 071 return node.evaluateEscalationRules(); 072 } 073 074 @Override 075 public void scheduleExecution(EscalationRule rule, CoreSession session) { 076 WorkManager manager = Framework.getLocalService(WorkManager.class); 077 manager.schedule( 078 new EscalationRuleWork(rule.getId(), rule.getNode().getDocument().getId(), session.getRepositoryName()), 079 WorkManager.Scheduling.IF_NOT_SCHEDULED); 080 } 081 082 public static class EscalationRuleWork extends AbstractWork { 083 084 private static final long serialVersionUID = 1L; 085 086 protected String escalationRuleId; 087 088 protected String nodeDocId; 089 090 public static final String CATEGORY = "routingEscalation"; 091 092 public EscalationRuleWork(String escalationRuleId, String nodeDocId, String repositoryName) { 093 super(repositoryName + ":" + nodeDocId + ":escalationRule:" + escalationRuleId); 094 this.repositoryName = repositoryName; 095 this.escalationRuleId = escalationRuleId; 096 this.nodeDocId = nodeDocId; 097 } 098 099 @Override 100 public String getTitle() { 101 return getId(); 102 } 103 104 @Override 105 public String getCategory() { 106 return CATEGORY; 107 } 108 109 @Override 110 public void work() { 111 openSystemSession(); 112 DocumentModel nodeDoc = session.getDocument(new IdRef(nodeDocId)); 113 GraphNode node = nodeDoc.getAdapter(GraphNode.class); 114 if (node == null) { 115 throw new NuxeoException("Can't execute worker '" + getId() + "' : the document '" + nodeDocId 116 + "' can not be adapted to a GraphNode"); 117 } 118 List<EscalationRule> rules = node.getEscalationRules(); 119 EscalationRule rule = null; 120 for (EscalationRule escalationRule : rules) { 121 if (escalationRuleId.equals(escalationRule.getId())) { 122 rule = escalationRule; 123 break; 124 } 125 } 126 if (rule == null) { 127 throw new NuxeoException("Can't execute worker '" + getId() + "' : the rule '" + escalationRuleId 128 + "' was not found on the node '" + nodeDocId + "'"); 129 } 130 try (OperationContext context = new OperationContext(session)) { 131 context.putAll(node.getWorkflowContextualInfo(session, true)); 132 context.setInput(context.get("documents")); 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 } catch (OperationException e) { 146 throw new NuxeoException("Error when executing worker: " + getTitle(), e); 147 } 148 } 149 150 /** 151 * Used to check the executed status when the escalationRule is run by a worker in a work queue 152 * 153 * @param session 154 */ 155 public boolean getExecutionStatus(EscalationRule rule, CoreSession session) { 156 DocumentModel nodeDoc = session.getDocument(new IdRef(rule.getNode().getDocument().getId())); 157 GraphNode node = nodeDoc.getAdapter(GraphNode.class); 158 List<EscalationRule> rules = node.getEscalationRules(); 159 for (EscalationRule escalationRule : rules) { 160 if (rule.compareTo(escalationRule) == 0) { 161 return escalationRule.isExecuted(); 162 } 163 } 164 return false; 165 } 166 167 } 168 169 private static void markRuleAsExecuted(String nodeDocId, String escalationRuleId, CoreSession session) 170 { 171 DocumentModel nodeDoc = session.getDocument(new IdRef(nodeDocId)); 172 GraphNode node = nodeDoc.getAdapter(GraphNode.class); 173 List<EscalationRule> rules = node.getEscalationRules(); 174 EscalationRule rule = null; 175 for (EscalationRule escalationRule : rules) { 176 if (escalationRuleId.equals(escalationRule.getId())) { 177 rule = escalationRule; 178 break; 179 } 180 } 181 rule.setExecuted(true); 182 session.saveDocument(nodeDoc); 183 } 184}