001/*
002 * (C) Copyright 2006-2014 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 *     Thierry Delprat
018 *     Florent Guillaume
019 */
020
021package org.nuxeo.ecm.automation.core.operations.execution;
022
023import java.util.Arrays;
024import java.util.Collection;
025import java.util.HashMap;
026import java.util.Map;
027
028import org.apache.commons.logging.Log;
029import org.apache.commons.logging.LogFactory;
030import org.nuxeo.ecm.automation.AutomationService;
031import org.nuxeo.ecm.automation.OperationContext;
032import org.nuxeo.ecm.automation.OperationException;
033import org.nuxeo.ecm.automation.core.Constants;
034import org.nuxeo.ecm.automation.core.annotations.Context;
035import org.nuxeo.ecm.automation.core.annotations.Operation;
036import org.nuxeo.ecm.automation.core.annotations.OperationMethod;
037import org.nuxeo.ecm.automation.core.annotations.Param;
038import org.nuxeo.ecm.core.api.CoreSession;
039import org.nuxeo.ecm.core.api.DocumentModel;
040import org.nuxeo.runtime.transaction.TransactionHelper;
041
042/**
043 * @deprecated since 6.0. Use instead {@link RunOperationOnList} with ID 'Context.RunOperationOnList'. Run an embedded
044 *             operation chain inside separated transactions using the current input. The output is undefined (Void)
045 * @since 5.7.2
046 */
047@Deprecated
048@Operation(id = RunOperationOnListInNewTransaction.ID, category = Constants.CAT_SUBCHAIN_EXECUTION, label = "Run For Each in new TX", description = "Run an operation/chain in a new Transaction for each element from the list defined by the 'list' parameter. The 'list' parameter is pointing to a context variable that represents the list which will be iterated. The 'itemName' parameter represents the name of the context variable which will point to the current element in the list at each iteration. You can use the 'isolate' parameter to specify whether or not the evalution context is the same as the parent context or a copy of it. If the 'isolate' parameter is 'true' then a copy of the current context is used and so that modifications in this context will not affect the parent context. Any input is accepted. The input is returned back as output when operation terminates.", deprecatedSince = "6.0", aliases = { "Context.RunOperationOnListInNewTx" })
049public class RunOperationOnListInNewTransaction {
050
051    protected static Log log = LogFactory.getLog(RunOperationOnListInNewTransaction.class);
052
053    public static final String ID = "RunOperationOnListInNewTx";
054
055    @Context
056    protected OperationContext ctx;
057
058    @Context
059    protected AutomationService service;
060
061    @Context
062    protected CoreSession session;
063
064    @Param(name = "id")
065    protected String chainId;
066
067    @Param(name = "list")
068    protected String listName;
069
070    @Param(name = "itemName", required = false, values = "item")
071    protected String itemName = "item";
072
073    @Param(name = "isolate", required = false, values = "true")
074    protected boolean isolate = true;
075
076    @OperationMethod
077    public void run() throws OperationException {
078        Map<String, Object> vars = isolate ? new HashMap<String, Object>(ctx.getVars()) : ctx.getVars();
079
080        Collection<?> list = null;
081        if (ctx.get(listName) instanceof Object[]) {
082            list = Arrays.asList((Object[]) ctx.get(listName));
083        } else if (ctx.get(listName) instanceof Collection<?>) {
084            list = (Collection<?>) ctx.get(listName);
085        } else {
086            throw new UnsupportedOperationException(ctx.get(listName).getClass() + " is not a Collection");
087        }
088
089        // commit the current transaction
090        TransactionHelper.commitOrRollbackTransaction();
091
092        // execute on list in separate transactions
093        for (Object value : list) {
094            TransactionHelper.startTransaction();
095            boolean completedAbruptly = true;
096            try {
097                OperationContext subctx = new OperationContext(session, vars);
098                subctx.setInput(ctx.getInput());
099                subctx.put(itemName, value);
100                service.run(subctx, chainId, null);
101                completedAbruptly = false;
102            } finally {
103                if (completedAbruptly) {
104                    TransactionHelper.setTransactionRollbackOnly();
105                }
106                TransactionHelper.commitOrRollbackTransaction();
107            }
108        }
109
110        TransactionHelper.startTransaction();
111
112        // reconnect documents in the context
113        if (!isolate) {
114            for (String varName : vars.keySet()) {
115                if (!ctx.getVars().containsKey(varName)) {
116                    ctx.put(varName, vars.get(varName));
117                } else {
118                    Object value = vars.get(varName);
119                    if (session != null && value != null && value instanceof DocumentModel) {
120                        ctx.getVars().put(varName, session.getDocument(((DocumentModel) value).getRef()));
121                    } else {
122                        ctx.getVars().put(varName, value);
123                    }
124                }
125            }
126        }
127    }
128
129}