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