001/*
002 * (C) Copyright 2009-2012 Nuxeo SA (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Alexandre Russel
016 *     Florent Guillaume
017 */
018package org.nuxeo.ecm.platform.routing.api;
019
020import java.io.Serializable;
021import java.net.URL;
022import java.util.List;
023import java.util.Map;
024
025import org.nuxeo.ecm.core.api.CoreSession;
026import org.nuxeo.ecm.core.api.DocumentModel;
027import org.nuxeo.ecm.core.api.DocumentModelList;
028import org.nuxeo.ecm.core.api.DocumentRef;
029import org.nuxeo.ecm.core.api.NuxeoPrincipal;
030import org.nuxeo.ecm.platform.routing.api.exception.DocumentRouteAlredayLockedException;
031import org.nuxeo.ecm.platform.routing.api.exception.DocumentRouteException;
032import org.nuxeo.ecm.platform.routing.api.exception.DocumentRouteNotLockedException;
033import org.nuxeo.ecm.platform.task.Task;
034import org.nuxeo.runtime.model.RuntimeContext;
035
036/**
037 * The DocumentRoutingService allows manipulation of {@link DocumentRoute DocumentRoutes}.
038 */
039public interface DocumentRoutingService {
040
041    /**
042     * Creates a new route instance and optionally starts it.
043     * <p>
044     * If {@code startInstance = false}, then the route can be started later by calling {@link #startInstance}.
045     *
046     * @param routeModelId the route model id
047     * @param docIds the list of document bound to the instance
048     * @param map the values to pass as initial workflow variables
049     * @param session the session
050     * @param startInstance if the route is automatically started
051     * @return the created route instance id
052     */
053    String createNewInstance(String routeModelId, List<String> docIds, Map<String, Serializable> map,
054            CoreSession session, boolean startInstance);
055
056    /**
057     * Creates a new route instance and optionally starts it.
058     * <p>
059     * If {@code startInstance = false}, then the route can be started later by calling {@link #startInstance}.
060     *
061     * @param routeModelId the route model id
062     * @param docIds The list of document bound to the instance.
063     * @param session the session
064     * @param startInstance if the route is automatically started
065     * @return the created route instance id
066     */
067    String createNewInstance(String routeModelId, List<String> docIds, CoreSession session, boolean startInstance);
068
069    /**
070     * Create a new {@link DocumentRoute} instance from this {@link DocumentRoute} model.
071     *
072     * @param model The model used to create the instance.
073     * @param documentIds The list of document bound to the instance.
074     * @param startInstance if the {@link DocumentRoute} is automatically started.
075     * @return the created {@link DocumentRoute} instance.
076     */
077    DocumentRoute createNewInstance(DocumentRoute model, List<String> documentIds, CoreSession session,
078            boolean startInstance);
079
080    /**
081     * @deprecated since 5.6, use other APIs
082     */
083    @Deprecated
084    DocumentRoute createNewInstance(DocumentRoute model, String documentId, CoreSession session, boolean startInstance);
085
086    /**
087     * @deprecated since 5.6, use other APIs
088     */
089    @Deprecated
090    DocumentRoute createNewInstance(DocumentRoute model, List<String> documentIds, CoreSession session);
091
092    /**
093     * @deprecated since 5.6, use other APIs
094     */
095    @Deprecated
096    DocumentRoute createNewInstance(DocumentRoute model, String documentId, CoreSession session);
097
098    /**
099     * Starts an instance that was created with {@link #createNewInstance} but with {@code startInstance = false}.
100     *
101     * @param routeInstanceId the route instance id
102     * @param docIds the list of document bound to the instance
103     * @param map the values to pass as initial workflow variables
104     * @param session the session
105     * @since 5.7.2
106     */
107    void startInstance(String routeInstanceId, List<String> docIds, Map<String, Serializable> map, CoreSession session);
108
109    /**
110     * Resumes a route instance on a give node. Any remaining tasks on this node will be cancelled.
111     * <p/>
112     * Called by the UI action corresponding to a task button.
113     *
114     * @param routeId the id of the route instance
115     * @param nodeId the node id to resume on
116     * @param data the data coming from UI form
117     * @param status the status coming from UI form
118     * @param session the session
119     * @since 5.6
120     */
121    void resumeInstance(String routeId, String nodeId, Map<String, Object> data, String status, CoreSession session);
122
123    /**
124     * Completes a task on a give node. If this is the last task the workflow will continue.
125     * <p/>
126     * Called by the UI action corresponding to a task button.
127     *
128     * @param routeId the id of the route instance
129     * @param taskId the id of the task
130     * @param data the data coming from UI form
131     * @param status the status coming from UI form
132     * @param session the session
133     * @since 5.6
134     */
135    void completeTask(String routeId, String taskId, Map<String, Object> data, String status, CoreSession session);
136
137    /**
138     * Save a route instance as a new model of route.
139     * <p/>
140     * The place in which the new instance is persisted and its name depends on {@link DocumentRoutingPersister}. The
141     * route instance should be in either running, done or ready state. The new route model will be in draft state and
142     * won't have any attached documents.
143     *
144     * @param route the instance from which we create a new model.
145     * @return the new model in draft state.
146     */
147    DocumentRoute saveRouteAsNewModel(DocumentRoute route, CoreSession session);
148
149    /**
150     * Return the list of available {@link DocumentRoute} model the user can start.
151     *
152     * @param session The session of the user.
153     * @return A list of available {@link DocumentRoute}
154     */
155    List<DocumentRoute> getAvailableDocumentRouteModel(CoreSession session);
156
157    /**
158     * Return the list of available {@link DocumentRoute} document route.
159     *
160     * @param session The session of the user.
161     * @return A list of available {@link DocumentRoute}
162     * @since 7.2
163     */
164    List<DocumentRoute> getAvailableDocumentRoute(CoreSession session);
165
166    /**
167     * Return the operation chain to run for a documentType. The document type should extend the DocumentRouteStep. Use
168     * the <code>chainsToType</code> extension point to contribute new mapping.
169     *
170     * @deprecated since 5.9.2 - Use only routes of type 'graph'
171     * @param documentType The document type
172     * @return The operation chain id.
173     */
174    @Deprecated
175    String getOperationChainId(String documentType);
176
177    /**
178     * Return the operation chain to undo a step when the step is in running state. The document type should extend the
179     * DocumentRouteStep. Use the <code>chainsToType</code> extension point to contribute new mapping.
180     *
181     * @deprecated since 5.9.2 - Use only routes of type 'graph'
182     * @param documentType
183     * @return
184     */
185    @Deprecated
186    String getUndoFromRunningOperationChainId(String documentType);
187
188    /**
189     * Return the operation chain to undo a step when the step is in done state. The document type should extend the
190     * DocumentRouteStep. Use the <code>chainsToType</code> extension point to contribute new mapping.
191     *
192     * @param documentType
193     * @return
194     */
195    String getUndoFromDoneOperationChainId(String documentType);
196
197    /**
198     * Validates the given {@link DocumentRoute} model by changing its lifecycle state and setting it and all its
199     * children in ReadOnly.
200     *
201     * @return The validated route.
202     */
203    DocumentRoute validateRouteModel(DocumentRoute routeModel, CoreSession session)
204            throws DocumentRouteNotLockedException;
205
206    /**
207     * Unlock the given {@link DocumentRoute} model under unrestricted session.
208     *
209     * @param routeModel
210     * @param userSession
211     * @return The unlocked route.
212     * @since 1.9
213     */
214    public DocumentRoute unlockDocumentRouteUnrestrictedSession(final DocumentRoute routeModel, CoreSession userSession);
215
216    /**
217     * Computes the list of elements {@link DocumentRouteTableElement} for this {@link DocumentRoute}.
218     *
219     * @param routeDocument {@link DocumentRoute}.
220     * @param session The session used to query the {@link DocumentRoute}.
221     * @param A list of {@link DocumentRouteElement}
222     */
223    List<DocumentRouteTableElement> getRouteElements(DocumentRoute route, CoreSession session);
224
225    /**
226     * Return the list of related {@link DocumentRoute} in a state for a given attached document.
227     *
228     * @param session The session used to query the {@link DocumentRoute}.
229     * @param states the list of states.
230     * @return A list of available {@link DocumentRoute}
231     */
232    List<DocumentRoute> getDocumentRoutesForAttachedDocument(CoreSession session, String attachedDocId,
233            List<DocumentRouteElement.ElementLifeCycleState> states);
234
235    /**
236     * @param session
237     * @param attachedDocId
238     * @return
239     * @see #getDocumentRoutesForAttachedDocument(CoreSession, String, List) for route running or ready.
240     */
241    List<DocumentRoute> getDocumentRoutesForAttachedDocument(CoreSession session, String attachedDocId);
242
243    /**
244     * if the user can validate a route.
245     *
246     * @deprecated use {@link #canValidateRoute(DocumentModel, CoreSession)} instead.
247     */
248    @Deprecated
249    boolean canUserValidateRoute(NuxeoPrincipal currentUser);
250
251    /**
252     * Checks if the principal that created the client session can validate the route
253     *
254     * @param documentRoute
255     * @param coreSession
256     */
257    boolean canValidateRoute(DocumentModel documentRoute, CoreSession coreSession);
258
259    /**
260     * Add a route element in another route element.
261     *
262     * @deprecated since 5.9.2 - Use only routes of type 'graph'
263     * @param parentDocumentRef The DocumentRef of the parent document.
264     * @param idx The position of the document in its container.
265     * @param routeElement The document to add.
266     * @param session
267     */
268    @Deprecated
269    void addRouteElementToRoute(DocumentRef parentDocumentRef, int idx, DocumentRouteElement routeElement,
270            CoreSession session) throws DocumentRouteNotLockedException;
271
272    /**
273     * Add a route element in another route element.
274     * <p/>
275     * If the parent element is in draft state, the routeElement is kept in draft state. Otherwise, the element is set
276     * to 'ready' state.
277     *
278     * @deprecated since 5.9.2 - Use only routes of type 'graph'
279     * @param parentDocumentRef The DocumentRef of the parent document.
280     * @param sourceName the name of the previous document in the container.
281     * @param routeElement the document to add.
282     * @param session
283     */
284    @Deprecated
285    void addRouteElementToRoute(DocumentRef parentDocumentRef, String sourceName, DocumentRouteElement routeElement,
286            CoreSession session) throws DocumentRouteNotLockedException;
287
288    /**
289     * Remove the given route element
290     *
291     * @deprecated since 5.9.2 - Use only routes of type 'graph'
292     * @param The route element document.
293     * @param session
294     */
295    @Deprecated
296    void removeRouteElement(DocumentRouteElement routeElement, CoreSession session)
297            throws DocumentRouteNotLockedException;
298
299    /**
300     * Get the children of the given stepFolder ordered by the ecm:pos metadata.
301     *
302     * @deprecated since 5.9.2 - Use only routes of type 'graph'
303     * @param stepFolderId
304     * @param session
305     * @return
306     */
307    @Deprecated
308    DocumentModelList getOrderedRouteElement(String routeElementId, CoreSession session);
309
310    /**
311     * Locks this {@link DocumentRoute} if not already locked by the current user. If the document is already locked by
312     * another user and {@link DocumentRouteAlredayLockedException} is thrown
313     *
314     * @param routeDocument {@link DocumentRoute}.
315     * @param session The session used to lock the {@link DocumentRoute}.
316     * @throws {@link DocumentRouteAlredayLockedException}
317     */
318    void lockDocumentRoute(DocumentRoute routeModel, CoreSession session) throws DocumentRouteAlredayLockedException;
319
320    /**
321     * Unlocks this {@link DocumentRoute}.If the document is not locked throws a {@link DocumentRouteNotLockedException}
322     *
323     * @param routeDocument {@link DocumentRoute}.
324     * @param session The session used to lock the {@link DocumentRoute}.
325     */
326    void unlockDocumentRoute(DocumentRoute routeModel, CoreSession session) throws DocumentRouteNotLockedException;
327
328    /**
329     * Update the given route element
330     *
331     * @param The route element document.
332     * @param session
333     */
334    void updateRouteElement(DocumentRouteElement routeModel, CoreSession session)
335            throws DocumentRouteNotLockedException;
336
337    /**
338     * Verify is this {@link DocumentRoute} is already locked by the current user.
339     *
340     * @param routeDocument {@link DocumentRoute}.
341     * @param session
342     */
343    boolean isLockedByCurrentUser(DocumentRoute routeModel, CoreSession session);
344
345    /**
346     * Checks if the given document can be associated to a DocumentRoute.
347     *
348     * @param doc the document
349     * @return {@code true} if the document can be routed
350     */
351    boolean isRoutable(DocumentModel doc);
352
353    /**
354     * Imports all the route models resource templates.
355     *
356     * @param session the core session to use
357     *
358     * @since 7.3
359     */
360    void importAllRouteModels(CoreSession session);
361
362    /**
363     * Creates a route model in the root models folder defined by the current persister. The templateResource is a zip
364     * tree xml export of a route document and it is imported using the core-io importer.
365     *
366     * @param templateResource
367     * @param overwrite
368     * @param session
369     * @since 5.6
370     */
371    DocumentRoute importRouteModel(URL templateResource, boolean overwrite, CoreSession session);
372
373    /**
374     * Registers a new route model template to be imported at application startup.
375     *
376     * @param resource the resource
377     * @since 5.6
378     */
379    void registerRouteResource(RouteModelResourceType resource, RuntimeContext extensionContext);
380
381    /**
382     * Returns all the route models resource templates. Use the <code>routeModelImporter</code> extension point to
383     * contribute new resources.
384     *
385     * @since 5.6
386     */
387    List<URL> getRouteModelTemplateResources();
388
389    /**
390     * Returns the route models matching the {@code searchString}.
391     *
392     * @since 5.6
393     */
394    List<DocumentModel> searchRouteModels(CoreSession session, String searchString);
395
396    /**
397     * Returns the route model with the given id
398     *
399     * @since 5.6
400     */
401    DocumentRoute getRouteModelWithId(CoreSession session, String id);
402
403    // copied from the deprecated RoutingTaskService
404
405    /**
406     * Returns the doc id of the route model with the given id
407     *
408     * @since 5.7
409     */
410    String getRouteModelDocIdWithId(CoreSession session, String id);
411
412    /**
413     * Marks the tasks as Routing tasks.
414     * <p>
415     * This allows the related documents to be adapted to {@link RoutingTask}.
416     *
417     * @param session the session
418     * @param tasks the tasks
419     * @since 5.6, was on RoutingTaskService before
420     *
421     * @deprecated The facet RoutingTask is statically attached to the new
422     *             RoutingTask Document type since 7.1
423     */
424    @Deprecated
425    void makeRoutingTasks(CoreSession session, List<Task> tasks);
426
427    /**
428     * Ends a task. If this is the last task the workflow will continue.
429     *
430     * @param session
431     * @param task
432     * @param data
433     * @param status name of the button clicked to submit the task form
434     * @since 5.6, was on RoutingTaskService before
435     */
436    void endTask(CoreSession session, Task task, Map<String, Object> data, String status);
437
438    /**
439     * Grants on these documents the specified assignees permissions for this task.
440     *
441     * @param session the session
442     * @param permission the permission
443     * @param docs the documents
444     * @param task the task
445     * @since 5.6
446     */
447    void grantPermissionToTaskAssignees(CoreSession session, String permission, List<DocumentModel> docs, Task task);
448
449    /**
450     * Removes on these documents the specified assignees permissions for this task.
451     *
452     * @param session the session
453     * @param docs the documents
454     * @param task the task
455     * @since 5.6
456     */
457    void removePermissionFromTaskAssignees(CoreSession session, List<DocumentModel> docs, Task task);
458
459    /**
460     * Gets the documents following the workflow to which the given task belongs
461     *
462     * @param session
463     * @param task
464     * @return
465     * @since 5.6, was on RoutingTaskService before
466     */
467    List<DocumentModel> getWorkflowInputDocuments(CoreSession session, Task task);
468
469    /**
470     * Finishes an open task. All permissions granted to the tasks assignees on the document following the worklflow are
471     * removed. Doesn't resume the workflow as the <code>completeTask</code> method. Not executed using an unrestricted
472     * session.
473     *
474     * @param session
475     * @param route
476     * @param task
477     * @param delete
478     * @throws DocumentRouteException
479     * @since 5.7
480     * @deprecated // will be removed in 5.8, use completeTask instead
481     */
482    void finishTask(CoreSession session, DocumentRoute route, Task task, boolean delete) throws DocumentRouteException;
483
484    /**
485     * Cancels an open task. If the task was created by an workflow, all permissions granted to the tasks assignees on
486     * the document following the worklflow are removed. Doesn't resume the workflow as the <code>completeTask</code>
487     * method.
488     *
489     * @param session
490     * @param task
491     * @param delete
492     * @throws DocumentRouteException
493     * @since 5.7.3
494     */
495    void cancelTask(CoreSession session, String taskId) throws DocumentRouteException;
496
497    /**
498     * Reassigns the given task to the list of actors. Removes the permissions granted on the document following the
499     * workflow to the current task assignees and grants them to the new actors.
500     *
501     * @param session
502     * @param taskId
503     * @param actors
504     * @param comment
505     * @since 5.7.3
506     */
507    void reassignTask(CoreSession session, String taskId, List<String> actors, String comment)
508            throws DocumentRouteException;
509
510    /**
511     * Reassigns the given task to the list of actors. Grants to new delegated actors the same permissions as the task
512     * assignees on the document following the workflow .
513     *
514     * @param session
515     * @param taskId
516     * @param delegatedActors
517     * @param comment
518     * @since 5.8
519     */
520    void delegateTask(CoreSession session, String taskId, List<String> delegatedActors, String comment)
521            throws DocumentRouteException;
522
523    /**
524     * Grants on these documents the specified assignees permissions for this task to the tasks delegated actors.
525     *
526     * @param session the session
527     * @param permission the permission
528     * @param docs the documents
529     * @param task the task
530     * @since 5.8
531     */
532    void grantPermissionToTaskDelegatedActors(CoreSession session, String permission, List<DocumentModel> docs,
533            Task task);
534
535    /**
536     * Removes on these documents the specified assignees permissions for the task actors and also tasks delegated
537     * actors if this task was delegated
538     *
539     * @param session the session
540     * @param docs the documents
541     * @param task the task
542     * @since 5.8
543     */
544    void removePermissionsForTaskActors(CoreSession session, List<DocumentModel> docs, Task task);
545
546    /**
547     * Removes on these documents the specified assignees permissions for the task actors and also tasks delegated
548     * actors if this task was delegated
549     *
550     * @param session the session
551     * @param docs the documents
552     * @param taskId the taskId
553     * @since 7.4
554     */
555    void removePermissionsForTaskActors(CoreSession session, List<DocumentModel> docs, String taskId);
556
557    /**
558     * Query for the routes 'done' or 'canceled' and delete them. The max no of the routes that will be deleted is
559     * specified by the 'limit' parameter. When the limit is '0' all the completed routes are deleted. The routes to be
560     * deleted are ordered ascending by their creation date.
561     *
562     * @since 5.8
563     */
564    void cleanupDoneAndCanceledRouteInstances(String repositoryName, int limit);
565
566    /**
567     * @since 5.9.3
568     */
569    void invalidateRouteModelsCache();
570
571    /**
572     * Query for the routes 'done' or 'canceled' and delete them. The max no of the routes that will be deleted is
573     * specified by the 'limit' parameter. When the limit is '0' all the completed routes are deleted. The routes to be
574     * deleted are ordered ascending by their creation date.
575     *
576     * @return the number of cleaned up workflow instance
577     * @since 7.1
578     */
579    int doCleanupDoneAndCanceledRouteInstances(String reprositoryName, int limit);
580
581    /**
582     * @param userId
583     * @param workflowInstanceId
584     * @param session
585     * @return
586     * @since 7.2
587     */
588    List<Task> getTasks(final DocumentModel document, String actorId, String workflowInstanceId,
589            String workflowModelName, CoreSession session);
590
591    /**
592     * @param document
593     * @param session
594     * @return
595     * @since 7.2
596     */
597    List<DocumentRoute> getDocumentRelatedWorkflows(final DocumentModel document, final CoreSession session);
598
599    /**
600     * @since 7.2
601     */
602    List<DocumentRoute> getRunningWorkflowInstancesLaunchedByCurrentUser(final CoreSession session);
603
604    /**
605     * @since 7.2
606     */
607    List<DocumentRoute> getRunningWorkflowInstancesLaunchedByCurrentUser(CoreSession session, String worflowModelName);
608
609    /**
610     * Returns true id the document route is a model, false if it is just an instance i.e. a running workflow.
611     *
612     * @since 7.2
613     */
614    boolean isWorkflowModel(final DocumentRoute documentRoute);
615
616}