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