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.net.URL; 020import java.util.Arrays; 021import java.util.Calendar; 022import java.util.List; 023import java.util.Map; 024 025import javax.script.ScriptException; 026 027import org.nuxeo.ecm.automation.AutomationService; 028import org.nuxeo.ecm.automation.OperationContext; 029import org.nuxeo.ecm.automation.OperationDocumentation; 030import org.nuxeo.ecm.automation.OperationException; 031import org.nuxeo.ecm.automation.core.Constants; 032import org.nuxeo.ecm.automation.core.impl.InvokableMethod; 033import org.nuxeo.ecm.automation.core.impl.OperationTypeImpl; 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.DocumentRef; 039import org.nuxeo.ecm.core.api.DocumentRefList; 040import org.nuxeo.ecm.core.api.NuxeoException; 041 042/** 043 * @since 7.2 044 */ 045public class ScriptingOperationTypeImpl extends OperationTypeImpl { 046 047 protected final AutomationService service; 048 049 protected final ScriptingOperationDescriptor desc; 050 051 protected final InvokableMethod[] methods; 052 053 public ScriptingOperationTypeImpl(AutomationService service, 054 ScriptingOperationDescriptor desc) { 055 this.service = service; 056 this.desc = desc; 057 this.inputType = desc.getInputType(); 058 this.methods = new InvokableMethod[] { runMethod() }; 059 } 060 061 062 @Override 063 public String getContributingComponent() { 064 return null; 065 } 066 067 @Override 068 public OperationDocumentation getDocumentation() { 069 OperationDocumentation doc = new OperationDocumentation(getId()); 070 doc.label = getId(); 071 doc.category = desc.getCategory(); 072 doc.description = desc.getDescription(); 073 doc.params = desc.getParams(); 074 doc.signature = new String[] { desc.getInputType(), desc.getOutputType() }; 075 doc.aliases = desc.getAliases(); 076 return doc; 077 } 078 079 @Override 080 public String getId() { 081 return desc.getId(); 082 } 083 084 @Override 085 public String[] getAliases() { 086 return desc.getAliases(); 087 } 088 089 @Override 090 public List<InvokableMethod> getMethods() { 091 return Arrays.asList(methods); 092 } 093 094 @Override 095 public InvokableMethod[] getMethodsMatchingInput(Class<?> in) { 096 return methods; 097 } 098 099 @Override 100 public AutomationService getService() { 101 return service; 102 } 103 104 @Override 105 public Class<?> getType() { 106 return ScriptingOperationImpl.class; 107 } 108 109 @SuppressWarnings("unchecked") 110 @Override 111 public Object newInstance(OperationContext ctx, Map<String, Object> args) throws OperationException { 112 // As org.nuxeo.ecm.automation.core.impl.OperationTypeImpl.inject() is not called in this OperationTypeImpl, 113 // we have to inject into arguments all context variables to play the fallback on chains variables. 114 if (ctx.getVars().containsKey(Constants.VAR_RUNTIME_CHAIN)) { 115 args.putAll((Map<String, Object>) ctx.getVars().get(Constants.VAR_RUNTIME_CHAIN)); 116 } 117 ScriptingOperationImpl impl; 118 try { 119 impl = new ScriptingOperationImpl(desc.getScript(), ctx, args); 120 } catch (ScriptException e) { 121 throw new NuxeoException(e); 122 } 123 return impl; 124 } 125 126 protected String getParamDocumentationType(Class<?> type, boolean isIterable) { 127 String t; 128 if (DocumentModel.class.isAssignableFrom(type) || DocumentRef.class.isAssignableFrom(type)) { 129 t = isIterable ? Constants.T_DOCUMENTS : Constants.T_DOCUMENT; 130 } else if (DocumentModelList.class.isAssignableFrom(type) || DocumentRefList.class.isAssignableFrom(type)) { 131 t = Constants.T_DOCUMENTS; 132 } else if (BlobList.class.isAssignableFrom(type)) { 133 t = Constants.T_BLOBS; 134 } else if (Blob.class.isAssignableFrom(type)) { 135 t = isIterable ? Constants.T_BLOBS : Constants.T_BLOB; 136 } else if (URL.class.isAssignableFrom(type)) { 137 t = Constants.T_RESOURCE; 138 } else if (Calendar.class.isAssignableFrom(type)) { 139 t = Constants.T_DATE; 140 } else { 141 t = type.getSimpleName().toLowerCase(); 142 } 143 return t; 144 } 145 146 protected InvokableMethod runMethod() { 147 try { 148 return new InvokableMethod(this, ScriptingOperationImpl.class.getMethod("run", Object.class)); 149 } catch (NoSuchMethodException | SecurityException e) { 150 throw new UnsupportedOperationException("Cannot use reflection for run method", e); 151 } 152 } 153 154}