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