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