001/*
002 * (C) Copyright 2015 Nuxeo SA (http://nuxeo.com/) and others.
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-2.1.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 <tdelprat@nuxeo.com>
016 */
017package org.nuxeo.automation.scripting.internals.operation;
018
019import java.util.ArrayList;
020import java.util.List;
021import java.util.Map;
022
023import javax.script.ScriptException;
024
025import jdk.nashorn.api.scripting.ScriptObjectMirror;
026import jdk.nashorn.internal.objects.NativeArray;
027
028import org.nuxeo.automation.scripting.api.AutomationScriptingService;
029import org.nuxeo.automation.scripting.internals.MarshalingHelper;
030import org.nuxeo.automation.scripting.internals.ScriptOperationContext;
031import org.nuxeo.ecm.automation.OperationException;
032import org.nuxeo.ecm.automation.core.Constants;
033import org.nuxeo.ecm.automation.core.scripting.DocumentWrapper;
034import org.nuxeo.ecm.automation.core.util.BlobList;
035import org.nuxeo.ecm.core.api.Blob;
036import org.nuxeo.ecm.core.api.DocumentModel;
037import org.nuxeo.ecm.core.api.DocumentModelList;
038import org.nuxeo.ecm.core.api.impl.DocumentModelListImpl;
039import org.nuxeo.runtime.api.Framework;
040
041/**
042 * @since 7.2
043 */
044public class ScriptingOperationImpl {
045
046    protected final ScriptOperationContext ctx;
047
048    protected final Map<String, Object> args;
049
050    protected final String source;
051
052    public ScriptingOperationImpl(String source, ScriptOperationContext ctx, Map<String, Object> args) throws ScriptException {
053        this.ctx = ctx;
054        this.args = args;
055        this.source = source;
056    }
057
058    public Object run(Object input) throws Exception {
059        try {
060            AutomationScriptingService scriptingService = Framework.getService(AutomationScriptingService.class);
061            scriptingService.setOperationContext(ctx);
062            ScriptingOperationInterface itf = scriptingService.getInterface(ScriptingOperationInterface.class, source,
063                    ctx.getCoreSession());
064            input = wrapArgsAndInput(input, args);
065            return unwrapResult(itf.run(input, args));
066        } catch (ScriptException e) {
067            throw new OperationException(e);
068        } finally {
069            if (ctx.get(Constants.VAR_IS_CHAIN) != null && !(Boolean) ctx.get(Constants.VAR_IS_CHAIN)) {
070                ctx.deferredDispose();
071            }
072        }
073    }
074
075    protected Object wrapArgsAndInput(Object input, Map<String, Object> args) {
076        for (String entryId : args.keySet()) {
077            Object entry = args.get(entryId);
078            if (entry instanceof DocumentModel) {
079                args.put(entryId, new DocumentWrapper(ctx.getCoreSession(), (DocumentModel) entry));
080            }
081            if (entry instanceof DocumentModelList) {
082                List<DocumentWrapper> docs = new ArrayList<>();
083                for (DocumentModel doc : (DocumentModelList) entry) {
084                    docs.add(new DocumentWrapper(ctx.getCoreSession(), doc));
085                }
086                args.put(entryId, docs);
087            }
088        }
089        if (input instanceof DocumentModel) {
090            return new DocumentWrapper(ctx.getCoreSession(), (DocumentModel) input);
091        } else if (input instanceof DocumentModelList) {
092            List<DocumentWrapper> docs = new ArrayList<>();
093            for (DocumentModel doc : (DocumentModelList) input) {
094                docs.add(new DocumentWrapper(ctx.getCoreSession(), doc));
095            }
096            return docs;
097        }
098        return input;
099    }
100
101    protected Object unwrapResult(Object res) {
102        // Unwrap Context
103        for (String entryId : ctx.keySet()) {
104            Object entry = ctx.get(entryId);
105            if (entry instanceof DocumentWrapper) {
106                ctx.put(entryId, ((DocumentWrapper) entry).getDoc());
107            } else if (ctx.get(entryId) instanceof List<?>) {
108                DocumentModelList docs = new DocumentModelListImpl();
109                List<?> l = (List<?>) entry;
110                for (Object item : l) {
111                    if (ctx.get(entryId) instanceof DocumentWrapper) {
112                        docs.add(((DocumentWrapper) item).getDoc());
113                    }
114                }
115                if (docs.size() == l.size() && docs.size() > 0) {
116                    ctx.put(entryId, ((DocumentWrapper) entry).getDoc());
117                }
118            }
119        }
120        // Unwrap Result
121        if (res == null) {
122            return null;
123        }
124        if (res instanceof ScriptObjectMirror) {
125            Object unwrapped = MarshalingHelper.unwrap(
126                    (ScriptObjectMirror) res);
127            if (unwrapped instanceof List<?>) {
128                DocumentModelList docs = new DocumentModelListImpl();
129                List<?> l = (List<?>) unwrapped;
130                for (Object item : l) {
131                    if (item instanceof DocumentWrapper) {
132                        docs.add(((DocumentWrapper) item).getDoc());
133                    }
134                }
135                if (docs.size() == l.size() && docs.size() > 0) {
136                    return docs;
137                }
138            } else if (unwrapped instanceof DocumentWrapper) {
139                return ((DocumentWrapper) unwrapped).getDoc();
140            }
141            return unwrapped;
142        } else if (res instanceof NativeArray) {
143            Object[] resList = ((NativeArray) res).asObjectArray();
144            DocumentModelList documentModelList = new DocumentModelListImpl();
145            BlobList blobList = new BlobList();
146            for (Object entry : resList) {
147                if (entry instanceof DocumentModel) {
148                    documentModelList.add((DocumentModel) entry);
149                } else if (entry instanceof Blob) {
150                    blobList.add((Blob) entry);
151                } else if (entry instanceof DocumentWrapper) {
152                    documentModelList.add(((DocumentWrapper) entry).getDoc());
153                }
154            }
155            return documentModelList.isEmpty() ? blobList : documentModelList;
156        } else if (res instanceof DocumentWrapper) {
157            return ((DocumentWrapper) res).getDoc();
158        } else if (res instanceof List<?>) {
159            DocumentModelList docs = new DocumentModelListImpl();
160            List<?> l = (List<?>) res;
161            for (Object item : l) {
162                if (item instanceof DocumentWrapper) {
163                    docs.add(((DocumentWrapper) item).getDoc());
164                }
165            }
166            if (docs.size() == l.size() && docs.size() > 0) {
167                return docs;
168            }
169        }
170        return res;
171    }
172
173}