diff options
author | jsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68> | 2008-09-22 05:44:18 +0000 |
---|---|---|
committer | jsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68> | 2008-09-22 05:44:18 +0000 |
commit | ad3556602a27b731bfeaebe306e5c0c3e15222ae (patch) | |
tree | 56f1767be588f1c3198595e3105f4a08ba308f17 /branches/sca-equinox/modules/implementation-script/src/main/java/org/apache | |
parent | 5575cb865ad5f7c4f4f6126aadef6c428ee7609d (diff) |
Another fix for TUSCANY-2396. Split implementation-script into two modules, model and runtime. Got the script implementations that use componentTypes working.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@697664 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'branches/sca-equinox/modules/implementation-script/src/main/java/org/apache')
6 files changed, 233 insertions, 1056 deletions
diff --git a/branches/sca-equinox/modules/implementation-script/src/main/java/org/apache/tuscany/sca/implementation/script/ScriptImplementation.java b/branches/sca-equinox/modules/implementation-script/src/main/java/org/apache/tuscany/sca/implementation/script/ScriptImplementation.java index 87820c18ed..9dc8f2aeca 100644 --- a/branches/sca-equinox/modules/implementation-script/src/main/java/org/apache/tuscany/sca/implementation/script/ScriptImplementation.java +++ b/branches/sca-equinox/modules/implementation-script/src/main/java/org/apache/tuscany/sca/implementation/script/ScriptImplementation.java @@ -18,82 +18,96 @@ */ package org.apache.tuscany.sca.implementation.script; -import java.net.MalformedURLException; -import java.net.URL; +import java.util.ArrayList; +import java.util.List; -import org.apache.tuscany.sca.contribution.Artifact; -import org.apache.tuscany.sca.contribution.ContributionFactory; -import org.apache.tuscany.sca.contribution.DefaultContributionFactory; -import org.apache.tuscany.sca.contribution.resolver.ModelResolver; -import org.apache.tuscany.sca.extension.helper.utils.ResourceHelper; +import org.apache.tuscany.sca.assembly.ConstrainingType; +import org.apache.tuscany.sca.assembly.Implementation; +import org.apache.tuscany.sca.assembly.Property; +import org.apache.tuscany.sca.assembly.Reference; +import org.apache.tuscany.sca.assembly.Service; /** * Represents a Script implementation. * * @version $Rev$ $Date$ */ -public class ScriptImplementation { +public class ScriptImplementation implements Implementation { - protected String scriptName; - protected URL scriptURL; - protected String scriptSrc; - protected String scriptLanguage; + private String uri; + private String language; + private List<Property> properties = new ArrayList<Property>(); + private List<Reference> references = new ArrayList<Reference>(); + private List<Service> services = new ArrayList<Service>(); + private String location; + private boolean unresolved; + + public ScriptImplementation() { + } public String getScript() { - return scriptName; + return uri; } - public void setScript(String scriptName) { - this.scriptName = scriptName; + public void setScript(String uri) { + this.uri = uri; + } + + public String getLocation() { + return location; + } + + public void setLocation(String location) { + this.location = location; } public void setLanguage(String language) { - this.scriptLanguage = language; + this.language = language; } - public void setElementText(String elementText) { - scriptSrc = elementText; + public String getLanguage() { + return language; } - public String getScriptLanguage() { - if (scriptLanguage == null || scriptLanguage.length() < 1) { - int i = scriptName.lastIndexOf('.'); - if (i > 0) { - scriptLanguage = scriptName.substring(i + 1); - } - } - return scriptLanguage; + public ConstrainingType getConstrainingType() { + // The script implementation does not support constrainingTypes + return null; } - public String getScriptSrc() { - if (scriptSrc == null) { - if (scriptName == null) { - throw new IllegalArgumentException("script name is null and no inline source used"); - } - if (scriptURL == null) { - throw new RuntimeException("No script: " + scriptName); - } + public List<Property> getProperties() { + return properties; + } - scriptSrc = ResourceHelper.readResource(scriptURL); - } - return scriptSrc; + public List<Service> getServices() { + return services; } - public void resolve(ModelResolver resolver) { - - if (scriptName != null) { - //FIXME The contribution factory should be injected - ContributionFactory contributionFactory = new DefaultContributionFactory(); - Artifact artifact = contributionFactory.createArtifact(); - artifact.setURI(scriptName); - artifact = resolver.resolveModel(Artifact.class, artifact); - if (artifact.getLocation() != null) { - try { - scriptURL = new URL(artifact.getLocation()); - } catch (MalformedURLException e) { - throw new RuntimeException(e); - } - } - } + public List<Reference> getReferences() { + return references; + } + + public String getURI() { + return uri; + } + + public void setConstrainingType(ConstrainingType constrainingType) { + // The script implementation does not support constrainingTypes + } + + public void setURI(String uri) { + this.uri = uri; + } + + public boolean isUnresolved() { + return unresolved; + } + + public void setUnresolved(boolean unresolved) { + this.unresolved = unresolved; + } + + @Override + public String toString() { + return "Script : " + getURI(); } } diff --git a/branches/sca-equinox/modules/implementation-script/src/main/java/org/apache/tuscany/sca/implementation/script/ScriptImplementationActivator.java b/branches/sca-equinox/modules/implementation-script/src/main/java/org/apache/tuscany/sca/implementation/script/ScriptImplementationActivator.java deleted file mode 100644 index a7c4b9074f..0000000000 --- a/branches/sca-equinox/modules/implementation-script/src/main/java/org/apache/tuscany/sca/implementation/script/ScriptImplementationActivator.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.tuscany.sca.implementation.script; - -import org.apache.tuscany.sca.assembly.ComponentType; -import org.apache.tuscany.sca.extension.helper.ImplementationActivator; -import org.apache.tuscany.sca.extension.helper.InvokerFactory; -import org.apache.tuscany.sca.extension.helper.utils.PropertyValueObjectFactory; -import org.apache.tuscany.sca.runtime.RuntimeComponent; - -/** - * - * @version $Rev$ $Date$ - */ -public class ScriptImplementationActivator implements ImplementationActivator<ScriptImplementation> { - - // TODO: seems wrong to need PropertyValueObjectFactory, could it be on Property somehow? - protected PropertyValueObjectFactory propertyFactory; - - public ScriptImplementationActivator(PropertyValueObjectFactory propertyFactory) { - this.propertyFactory = propertyFactory; - } - - public Class<ScriptImplementation> getImplementationClass() { - return ScriptImplementation.class; - } - - public InvokerFactory createInvokerFactory(RuntimeComponent rc, ComponentType ct, ScriptImplementation implementation) { - return new ScriptInvokerFactory(rc, ct, implementation, propertyFactory); - } - -} diff --git a/branches/sca-equinox/modules/implementation-script/src/main/java/org/apache/tuscany/sca/implementation/script/ScriptImplementationProcessor.java b/branches/sca-equinox/modules/implementation-script/src/main/java/org/apache/tuscany/sca/implementation/script/ScriptImplementationProcessor.java new file mode 100644 index 0000000000..38ce384fe2 --- /dev/null +++ b/branches/sca-equinox/modules/implementation-script/src/main/java/org/apache/tuscany/sca/implementation/script/ScriptImplementationProcessor.java @@ -0,0 +1,166 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.implementation.script; + +import static javax.xml.stream.XMLStreamConstants.END_ELEMENT; + +import java.io.IOException; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.ComponentType; +import org.apache.tuscany.sca.assembly.builder.impl.ProblemImpl; +import org.apache.tuscany.sca.assembly.xml.Constants; +import org.apache.tuscany.sca.contribution.Artifact; +import org.apache.tuscany.sca.contribution.ContributionFactory; +import org.apache.tuscany.sca.contribution.ModelFactoryExtensionPoint; +import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor; +import org.apache.tuscany.sca.contribution.resolver.ModelResolver; +import org.apache.tuscany.sca.contribution.service.ContributionReadException; +import org.apache.tuscany.sca.contribution.service.ContributionResolveException; +import org.apache.tuscany.sca.contribution.service.ContributionWriteException; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.monitor.Problem; +import org.apache.tuscany.sca.monitor.Problem.Severity; + +/** + * ScriptImplementationProcessor + * + * @version $Rev: $ $Date: $ + */ +public class ScriptImplementationProcessor implements StAXArtifactProcessor<ScriptImplementation> { + private static final QName IMPLEMENTATION_SCRIPT = new QName(Constants.SCA10_TUSCANY_NS, "implementation.script"); + + private AssemblyFactory assemblyFactory; + private ContributionFactory contributionFactory; + private Monitor monitor; + + public ScriptImplementationProcessor(ModelFactoryExtensionPoint modelFactories, Monitor monitor) { + assemblyFactory = modelFactories.getFactory(AssemblyFactory.class); + contributionFactory = modelFactories.getFactory(ContributionFactory.class); + this.monitor = monitor; + } + + public QName getArtifactType() { + return IMPLEMENTATION_SCRIPT; + } + + public Class<ScriptImplementation> getModelType() { + return ScriptImplementation.class; + } + + public ScriptImplementation read(XMLStreamReader reader) throws ContributionReadException, XMLStreamException { + + // Read an <implementation.script> element + + // Create and initialize the script implementation model + ScriptImplementation implementation = new ScriptImplementation(); + implementation.setUnresolved(true); + + // Read the script attribute + String script = reader.getAttributeValue(null, "script"); + if (script != null) { + implementation.setScript(script); + } + + // Read the language attribute + String language = reader.getAttributeValue(null, "language"); + if (language != null) { + implementation.setLanguage(language); + } + + // Skip to end element + while (reader.hasNext()) { + if (reader.next() == END_ELEMENT && IMPLEMENTATION_SCRIPT.equals(reader.getName())) { + break; + } + } + + return implementation; + } + + public void resolve(ScriptImplementation implementation, ModelResolver resolver) throws ContributionResolveException { + + // Resolve the script location + if (implementation.getScript() != null) { + Artifact artifact = contributionFactory.createArtifact(); + artifact.setURI(implementation.getScript()); + Artifact resolved = resolver.resolveModel(Artifact.class, artifact); + if (resolved.getLocation() != null) { + implementation.setLocation(resolved.getLocation()); + } else { + error("CouldNotResolveScript", resolver, implementation.getScript()); + } + + // Resolve the componentType and add the declared properties, references + // and services to the implementation + String componentTypeURI = implementation.getScript(); + componentTypeURI = componentTypeURI.substring(0, componentTypeURI.lastIndexOf('.')); + componentTypeURI += ".componentType"; + ComponentType componentType = assemblyFactory.createComponentType(); + componentType.setUnresolved(true); + componentType.setURI(componentTypeURI); + componentType = resolver.resolveModel(ComponentType.class, componentType); + if (!componentType.isUnresolved()) { + implementation.getProperties().addAll(componentType.getProperties()); + implementation.getReferences().addAll(componentType.getReferences()); + implementation.getServices().addAll(componentType.getServices()); + } + } + + implementation.setUnresolved(false); + } + + public void write(ScriptImplementation implementation, XMLStreamWriter writer) throws ContributionWriteException, XMLStreamException { + + // Write <implementation.script> + writer.setPrefix("script", IMPLEMENTATION_SCRIPT.getNamespaceURI()); + writer.writeStartElement(IMPLEMENTATION_SCRIPT.getNamespaceURI(), IMPLEMENTATION_SCRIPT.getLocalPart()); + writer.writeNamespace("script", IMPLEMENTATION_SCRIPT.getNamespaceURI()); + + if (implementation.getScript() != null) { + writer.writeAttribute("script", implementation.getScript()); + } + if (implementation.getLanguage() != null) { + writer.writeAttribute("language", implementation.getLanguage()); + } + + writer.writeEndElement(); + } + + /** + * Report a error. + * + * @param problems + * @param message + * @param model + */ + private void error(String message, Object model, Object... messageParameters) { + if (monitor != null) { + Problem problem = new ProblemImpl(this.getClass().getName(), "impl-widget-validation-messages", Severity.ERROR, model, message, (Object[])messageParameters); + monitor.problem(problem); + } + } + +} diff --git a/branches/sca-equinox/modules/implementation-script/src/main/java/org/apache/tuscany/sca/implementation/script/ScriptInvoker.java b/branches/sca-equinox/modules/implementation-script/src/main/java/org/apache/tuscany/sca/implementation/script/ScriptInvoker.java deleted file mode 100644 index 2ccb414be8..0000000000 --- a/branches/sca-equinox/modules/implementation-script/src/main/java/org/apache/tuscany/sca/implementation/script/ScriptInvoker.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.tuscany.sca.implementation.script; - -import javax.script.Invocable; -import javax.script.ScriptEngine; -import javax.script.ScriptException; - -import org.apache.axiom.om.OMElement; -import org.apache.bsf.xml.XMLHelper; -import org.apache.tuscany.sca.interfacedef.Operation; -import org.apache.tuscany.sca.invocation.Invoker; -import org.apache.tuscany.sca.invocation.Message; - -/** - * Perform the actual script invocation - * - * @version $Rev$ $Date$ - */ -public class ScriptInvoker implements Invoker { - - protected ScriptEngine scriptEngine; - protected XMLHelper xmlHelper; - protected Operation operation; - - public ScriptInvoker(ScriptEngine scriptEngine, XMLHelper xmlHelper, Operation operation) { - this.scriptEngine = scriptEngine; - this.xmlHelper = xmlHelper; - this.operation = operation; - } - - protected Object doInvoke(Object[] objects, Operation op) throws ScriptException { - if (xmlHelper != null) { - objects[0] = xmlHelper.toScriptXML((OMElement)objects[0]); - } - - Operation oper = operation; // static setting - if (oper.getName() == null) { // if no static setting - oper = op; // use dynamic setting - } - Object response; - try { - response = ((Invocable)scriptEngine).invokeFunction(oper.getName(), objects); - } catch (ScriptException e) { - throw e; - } catch (Exception e) { - throw new ScriptException(e); - } - - if (xmlHelper != null) { - response = xmlHelper.toOMElement(response); - } - - return response; - } - - public Message invoke(Message msg) { - try { - Object resp = doInvoke((Object[])msg.getBody(), msg.getOperation()); - msg.setBody(resp); - } catch (ScriptException e) { - msg.setFaultBody(e.getCause()); - } - return msg; - } - -} diff --git a/branches/sca-equinox/modules/implementation-script/src/main/java/org/apache/tuscany/sca/implementation/script/ScriptInvokerFactory.java b/branches/sca-equinox/modules/implementation-script/src/main/java/org/apache/tuscany/sca/implementation/script/ScriptInvokerFactory.java deleted file mode 100644 index 9359590424..0000000000 --- a/branches/sca-equinox/modules/implementation-script/src/main/java/org/apache/tuscany/sca/implementation/script/ScriptInvokerFactory.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.tuscany.sca.implementation.script; - -import java.io.StringReader; -import java.security.AccessController; -import java.security.PrivilegedAction; - -import javax.script.Invocable; -import javax.script.ScriptEngine; -import javax.script.ScriptEngineManager; -import javax.script.ScriptException; - -import org.apache.axiom.om.OMElement; -import org.apache.bsf.xml.XMLHelper; -import org.apache.tuscany.sca.assembly.ComponentReference; -import org.apache.tuscany.sca.assembly.ComponentType; -import org.apache.tuscany.sca.assembly.Property; -import org.apache.tuscany.sca.assembly.Reference; -import org.apache.tuscany.sca.assembly.Service; -import org.apache.tuscany.sca.core.factory.ObjectCreationException; -import org.apache.tuscany.sca.core.factory.ObjectFactory; -import org.apache.tuscany.sca.extension.helper.InvokerFactory; -import org.apache.tuscany.sca.extension.helper.utils.PropertyValueObjectFactory; -import org.apache.tuscany.sca.implementation.script.engines.TuscanyJRubyScriptEngine; -import org.apache.tuscany.sca.interfacedef.InterfaceContract; -import org.apache.tuscany.sca.interfacedef.Operation; -import org.apache.tuscany.sca.interfacedef.java.JavaInterface; -import org.apache.tuscany.sca.interfacedef.wsdl.WSDLInterfaceContract; -import org.apache.tuscany.sca.invocation.Invoker; -import org.apache.tuscany.sca.runtime.RuntimeComponent; - -/** - * - * @version $Rev$ $Date$ - */ -public class ScriptInvokerFactory implements InvokerFactory { - - protected ScriptEngine scriptEngine; - protected XMLHelper xmlHelper; - - protected RuntimeComponent rc; - protected ComponentType ct; - protected ScriptImplementation implementation; - protected PropertyValueObjectFactory propertyFactory; - - - /** - * @param rc - * @param ct - * @param implementation - * @param propertyFactory - */ - public ScriptInvokerFactory(RuntimeComponent rc, - ComponentType ct, - ScriptImplementation implementation, - PropertyValueObjectFactory propertyFactory) { - super(); - this.rc = rc; - this.ct = ct; - this.implementation = implementation; - this.propertyFactory = propertyFactory; - } - - public Invoker createInvoker(Operation operation) { - init(rc, ct, implementation, propertyFactory); - return new ScriptInvoker(scriptEngine, xmlHelper, operation); - } - - protected synchronized void init(RuntimeComponent rc, ComponentType ct, ScriptImplementation implementation, PropertyValueObjectFactory propertyFactory) { - if(scriptEngine!=null) { - return; - } - try { - scriptEngine = getScriptEngineByExtension(implementation.getScriptLanguage()); - if (scriptEngine == null) { - throw new ObjectCreationException("no script engine found for language: " + implementation.getScriptLanguage()); - } - if (!(scriptEngine instanceof Invocable)) { - throw new ObjectCreationException("script engine does not support Invocable: " + scriptEngine); - } - - for (Reference reference : ct.getReferences()) { - scriptEngine.put(reference.getName(), createReferenceProxy(reference.getName(), rc)); - } - - for (Property property : ct.getProperties()) { - ObjectFactory<?> propertyValueFactory = propertyFactory.createValueFactory(property); - if ( propertyValueFactory != null) { - scriptEngine.put(property.getName(), propertyValueFactory.getInstance()); - } - } - - scriptEngine.eval(new StringReader(implementation.getScriptSrc())); - - } catch (ScriptException e) { - throw new ObjectCreationException(e); - } - - // set the databinding and XMLHelper for WSDL interfaces - for (Service service : rc.getServices()) { - InterfaceContract ic = service.getInterfaceContract(); - if (ic instanceof WSDLInterfaceContract) { - // Set to use the Axiom data binding - ic.getInterface().resetDataBinding(OMElement.class.getName()); - xmlHelper = XMLHelper.getArgHelper(scriptEngine); - } - } - } - - /** - * TODO: RuntimeComponent should provide a method like this - */ - @SuppressWarnings("unchecked") - protected Object createReferenceProxy(String name, RuntimeComponent component) { - for (ComponentReference reference : component.getReferences()) { - if (reference.getName().equals(name)) { - Class iface = ((JavaInterface)reference.getInterfaceContract().getInterface()).getJavaClass(); - return component.getComponentContext().getService(iface, name); - } - } - throw new IllegalArgumentException("reference " + name + " not found on component: " + component); - } - - /** - * Hack for now to work around a problem with the JRuby script engine - */ - protected ScriptEngine getScriptEngineByExtension(String scriptExtn) { - if ("rb".equals(scriptExtn)) { - return new TuscanyJRubyScriptEngine(); - } else { - if ("py".equals(scriptExtn)) { - pythonCachedir(); - } - // Allow privileged access to run access classes. Requires RuntimePermission - // for accessClassInPackage.sun.misc. - ScriptEngineManager scriptEngineManager = - AccessController.doPrivileged(new PrivilegedAction<ScriptEngineManager>() { - public ScriptEngineManager run() { - return new ScriptEngineManager(); - } - }); - return scriptEngineManager.getEngineByExtension(scriptExtn); - } - } - - /** - * If the Python home isn't set then let Tuscany suppress messages other than errors - * See TUSCANY-1950 - */ - protected void pythonCachedir() { - if (System.getProperty("python.home") == null) { - System.setProperty("python.verbose", "error"); - } - } -} diff --git a/branches/sca-equinox/modules/implementation-script/src/main/java/org/apache/tuscany/sca/implementation/script/engines/TuscanyJRubyScriptEngine.java b/branches/sca-equinox/modules/implementation-script/src/main/java/org/apache/tuscany/sca/implementation/script/engines/TuscanyJRubyScriptEngine.java deleted file mode 100644 index 324246c32b..0000000000 --- a/branches/sca-equinox/modules/implementation-script/src/main/java/org/apache/tuscany/sca/implementation/script/engines/TuscanyJRubyScriptEngine.java +++ /dev/null @@ -1,697 +0,0 @@ -/*
-* Copyright (c) 2006, Sun Microsystems, Inc.
-* All rights reserved.
-*
-* Redistribution and use in source and binary forms, with or without
-* modification, are permitted provided that the following conditions are met:
-*
-* - Redistributions of source code must retain the above copyright notice, this
-* list of conditions and the following disclaimer.
-*
-* - Redistributions in binary form must reproduce the above copyright notice,
-* this list of conditions and the following disclaimer in the documentation
-* and/or other materials provided with the distribution.
-*
-* - Neither the name of the Sun Microsystems, Inc. nor the names of
-* contributors may be used to endorse or promote products derived from this
-* software without specific prior written permission.
-*
-* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
-* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
-* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
-* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY
-* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
-* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
-* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
-* DAMAGE.
-*/
-package org.apache.tuscany.sca.implementation.script.engines;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PrintStream;
-import java.io.Reader;
-import java.io.StringWriter;
-import java.io.UnsupportedEncodingException;
-import java.io.Writer;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-import java.nio.charset.Charset;
-import java.nio.charset.CharsetDecoder;
-import java.nio.charset.CoderResult;
-import java.nio.charset.CodingErrorAction;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-
-import javax.script.AbstractScriptEngine;
-import javax.script.Bindings;
-import javax.script.Compilable;
-import javax.script.CompiledScript;
-import javax.script.Invocable;
-import javax.script.ScriptContext;
-import javax.script.ScriptEngine;
-import javax.script.ScriptEngineFactory;
-import javax.script.ScriptException;
-import javax.script.SimpleBindings;
-
-import org.jruby.Ruby;
-import org.jruby.RubyException;
-import org.jruby.RubyIO;
-import org.jruby.RubyObject;
-import org.jruby.ast.Node;
-import org.jruby.exceptions.RaiseException;
-import org.jruby.internal.runtime.GlobalVariable;
-import org.jruby.internal.runtime.GlobalVariables;
-import org.jruby.internal.runtime.ReadonlyAccessor;
-import org.jruby.internal.runtime.ValueAccessor;
-import org.jruby.javasupport.Java;
-import org.jruby.javasupport.JavaEmbedUtils;
-import org.jruby.javasupport.JavaObject;
-import org.jruby.javasupport.JavaUtil;
-import org.jruby.runtime.Block;
-import org.jruby.runtime.IAccessor;
-import org.jruby.runtime.builtin.IRubyObject;
-import org.jruby.util.KCode;
-
-import com.sun.script.jruby.JRubyScriptEngineFactory;
-
-/**
- * This class is a copy of the class com.sun.script.ruby.JRubyScriptEngine with some minor modifications
- * to work around problems with Tuscany setting SCA properties and references as global variable in JRuby
- * Should only need it temporarily till a new BSF release fixes it.
- *
- * @version $Rev$ $Date$
- */
-@SuppressWarnings("unchecked")
-public class TuscanyJRubyScriptEngine extends AbstractScriptEngine
- implements Compilable, Invocable {
-
- // my factory, may be null
- private ScriptEngineFactory factory;
- private Ruby runtime;
-
- public TuscanyJRubyScriptEngine() {
- // Allow privileged access to ready properties. Requires PropertyPermission in security
- // policy.
- String rubyPath = AccessController.doPrivileged(new PrivilegedAction<String>() {
- public String run() {
- return System.getProperty("com.sun.script.jruby.loadpath");
- }
- });
- init(rubyPath);
- }
-
- public TuscanyJRubyScriptEngine(String loadPath) {
- init(loadPath);
- }
-
- // my implementation for CompiledScript
- private class JRubyCompiledScript extends CompiledScript {
- // my compiled code
- private Node node;
-
- JRubyCompiledScript (Node node) {
- this.node = node;
- }
-
- public ScriptEngine getEngine() {
- return TuscanyJRubyScriptEngine.this;
- }
-
- public Object eval(ScriptContext ctx) throws ScriptException {
- return evalNode(node, ctx);
- }
- }
-
- // Compilable methods
- public CompiledScript compile(String script)
- throws ScriptException {
- Node node = compileScript(script, context);
- return new JRubyCompiledScript(node);
- }
-
- public CompiledScript compile (Reader reader)
- throws ScriptException {
- Node node = compileScript(reader, context);
- return new JRubyCompiledScript(node);
- }
-
- // Invocable methods
- public Object invokeFunction(String name, Object... args)
- throws ScriptException, NoSuchMethodException {
- return invokeImpl(null, name, args, Object.class);
- }
-
- public Object invokeMethod(Object obj, String name, Object... args)
- throws ScriptException, NoSuchMethodException {
- if (obj == null) {
- throw new IllegalArgumentException("script object is null");
- }
- return invokeImpl(obj, name, args, Object.class);
- }
-
- public Object getInterface(Object obj, Class clazz) {
- if (obj == null) {
- throw new IllegalArgumentException("script object is null");
- }
- return makeInterface(obj, clazz);
- }
-
- public Object getInterface(Class clazz) {
- return makeInterface(null, clazz);
- }
-
- private <T> T makeInterface(Object obj, Class<T> clazz) {
- if (clazz == null || !clazz.isInterface()) {
- throw new IllegalArgumentException("interface Class expected");
- }
- final Object thiz = obj;
- return (T) Proxy.newProxyInstance(
- clazz.getClassLoader(),
- new Class[] { clazz },
- new InvocationHandler() {
- public Object invoke(Object proxy, Method m, Object[] args)
- throws Throwable {
- return invokeImpl(thiz, m.getName(),
- args, m.getReturnType());
- }
- });
- }
-
- // ScriptEngine methods
- public synchronized Object eval(String str, ScriptContext ctx)
- throws ScriptException {
- Node node = compileScript(str, ctx);
- return evalNode(node, ctx);
- }
-
- public synchronized Object eval(Reader reader, ScriptContext ctx)
- throws ScriptException {
- Node node = compileScript(reader, ctx);
- return evalNode(node, ctx);
- }
-
- public ScriptEngineFactory getFactory() {
- synchronized (this) {
- if (factory == null) {
- factory = new JRubyScriptEngineFactory();
- }
- }
- return factory;
- }
-
- public Bindings createBindings() {
- return new SimpleBindings();
- }
-
- // package-private methods
- void setFactory(ScriptEngineFactory factory) {
- this.factory = factory;
- }
-
- // internals only below this point
-
- private Object rubyToJava(IRubyObject value) {
- return rubyToJava(value, Object.class);
- }
-
- private Object rubyToJava(IRubyObject value, Class type) {
- return JavaUtil.convertArgument(
- runtime,
- Java.ruby_to_java(value, value, Block.NULL_BLOCK),
- type);
- }
-
- private IRubyObject javaToRuby(Object value) {
- if (value instanceof IRubyObject) {
- return (IRubyObject) value;
- }
- IRubyObject result = JavaUtil.convertJavaToRuby(runtime, value);
- if (result instanceof JavaObject) {
- return runtime.getModule("JavaUtilities").callMethod(runtime.getCurrentContext(), "wrap", result);
- }
- return result;
- }
-
- private synchronized Node compileScript(String script, ScriptContext ctx)
- throws ScriptException {
- GlobalVariables oldGlobals = runtime.getGlobalVariables();
- try {
- setErrorWriter(ctx.getErrorWriter());
- setGlobalVariables(ctx);
- String filename = (String) ctx.getAttribute(ScriptEngine.FILENAME);
- if (filename == null) {
- filename = "<unknown>";
- }
- return runtime.parseEval(script, filename, null, 0);
- } catch (RaiseException e) {
- RubyException re = e.getException();
- runtime.printError(re);
- throw new ScriptException(e);
- } catch (Exception e) {
- throw new ScriptException(e);
- } finally {
- if (oldGlobals != null) {
- setGlobalVariables(oldGlobals);
- }
- }
- }
-
- private synchronized Node compileScript(Reader reader, ScriptContext ctx)
- throws ScriptException {
- GlobalVariables oldGlobals = runtime.getGlobalVariables();
- try {
- setErrorWriter(ctx.getErrorWriter());
- setGlobalVariables(ctx);
- String filename = (String) ctx.getAttribute(ScriptEngine.FILENAME);
- if (filename == null) {
- filename = "<unknown>";
- String script = getRubyScript(reader);
- return runtime.parseEval(script, filename, null, 0);
- }
- InputStream inputStream = getRubyReader(filename);
- return runtime.parseFile(inputStream, filename, null);
- } catch (RaiseException e) {
- RubyException re = e.getException();
- runtime.printError(re);
- throw new ScriptException(e);
- } catch (Exception exp) {
- throw new ScriptException(exp);
- } finally {
- if (oldGlobals != null) {
- setGlobalVariables(oldGlobals);
- }
- }
- }
-
- private String getRubyScript(Reader reader) throws IOException {
- StringBuffer sb = new StringBuffer();
- char[] cbuf;
- while (true) {
- cbuf = new char[8*1024];
- int chars = reader.read(cbuf, 0, cbuf.length);
- if (chars < 0) {
- break;
- }
- sb.append(cbuf, 0, chars);
- }
- cbuf = null;
- return (new String(sb)).trim();
- }
-
- private InputStream getRubyReader(String filename) throws FileNotFoundException {
- File file = new File(filename);
- return new FileInputStream(file);
- }
-
- private void setGlobalVariables(final ScriptContext ctx) {
- ctx.setAttribute("context", ctx, ScriptContext.ENGINE_SCOPE);
- setGlobalVariables(new GlobalVariables(runtime) {
- GlobalVariables parent = runtime.getGlobalVariables();
-
- @Override
- public void define(String name, IAccessor accessor) {
- assert name != null;
- assert accessor != null;
- assert name.startsWith("$");
- synchronized (ctx) {
- Bindings engineScope = ctx.getBindings(ScriptContext.ENGINE_SCOPE);
- engineScope.put(name, new GlobalVariable(accessor));
- }
- }
-
- @Override
- public void defineReadonly(String name, IAccessor accessor) {
- assert name != null;
- assert accessor != null;
- assert name.startsWith("$");
- synchronized (ctx) {
- Bindings engineScope = ctx.getBindings(ScriptContext.ENGINE_SCOPE);
- engineScope.put(name, new GlobalVariable(new
- ReadonlyAccessor(name, accessor)));
- }
- }
-
- @Override
- public boolean isDefined(String name) {
- assert name != null;
- assert name.startsWith("$");
- synchronized (ctx) {
- String modifiedName = name.substring(1);
- boolean defined = ctx.getAttributesScope(modifiedName) != -1;
- return defined ? true : parent.isDefined(name);
- }
- }
-
- @Override
- public void alias(String name, String oldName) {
- assert name != null;
- assert oldName != null;
- assert name.startsWith("$");
- assert oldName.startsWith("$");
-
- if (runtime.getSafeLevel() >= 4) {
- throw runtime.newSecurityError("Insecure: can't alias global variable");
- }
-
- synchronized (ctx) {
- int scope = ctx.getAttributesScope(name);
- if (scope == -1) {
- scope = ScriptContext.ENGINE_SCOPE;
- }
-
- IRubyObject value = get(oldName);
- ctx.setAttribute(name, rubyToJava(value), scope);
- }
- }
-
- @Override
- public IRubyObject get(String name) {
- assert name != null;
- assert name.startsWith("$");
-
- synchronized (ctx) {
- // skip '$' and try
- String modifiedName = name.substring(1);
- int scope = ctx.getAttributesScope(modifiedName);
- if (scope == -1) {
- return parent.get(name);
- }
-
- Object obj = ctx.getAttribute(modifiedName, scope);
- if (obj instanceof IAccessor) {
- return ((IAccessor)obj).getValue();
- } else {
- return javaToRuby(obj);
- }
- }
- }
-
- @Override
- public IRubyObject set(String name, IRubyObject value) {
- assert name != null;
- assert name.startsWith("$");
-
- if (runtime.getSafeLevel() >= 4) {
- throw runtime.newSecurityError("Insecure: can't change global variable value");
- }
-
- synchronized (ctx) {
- // skip '$' and try
- String modifiedName = name.substring(1);
- int scope = ctx.getAttributesScope(modifiedName);
- if (scope == -1) {
- scope = ScriptContext.ENGINE_SCOPE;
- }
- IRubyObject oldValue = get(name);
- Object obj = ctx.getAttribute(modifiedName, scope);
- if (obj instanceof IAccessor) {
- ((IAccessor)obj).setValue(value);
- } else {
- ctx.setAttribute(modifiedName, rubyToJava(value), scope);
- if ("KCODE".equals(modifiedName)) {
- setKCode((String)rubyToJava(value));
- } else if ("stdout".equals(modifiedName)) {
- equalOutputs((RubyObject)value);
- }
- }
- return oldValue;
- }
- }
-
- @Override
- public Set<String> getNames() {
- HashSet set = new HashSet();
- synchronized (ctx) {
- for (Object scope : ctx.getScopes()) {
- Bindings b = ctx.getBindings((Integer)scope);
- if (b != null) {
- for (Object key: b.keySet()) {
- set.add(key);
- }
- }
- }
- }
- for (Iterator<String> names = parent.getNames().iterator(); names.hasNext();) {
- set.add(names.next());
- }
- return Collections.unmodifiableSet(set);
- }
-
- @Override
- public IRubyObject getDefaultSeparator() {
- return parent.getDefaultSeparator();
- }
- });
- }
-
- private void setGlobalVariables(GlobalVariables globals) {
- runtime.setGlobalVariables(globals);
- }
-
- private synchronized Object evalNode(Node node, ScriptContext ctx)
- throws ScriptException {
- GlobalVariables oldGlobals = runtime.getGlobalVariables();
- try {
- setWriterOutputStream(ctx.getWriter());
- setErrorWriter(ctx.getErrorWriter());
- setGlobalVariables(ctx);
- return rubyToJava(runtime.runNormally(node, false));
- } catch (Exception exp) {
- throw new ScriptException(exp);
- } finally {
- try {
- JavaEmbedUtils.terminate(runtime);
- } catch (RaiseException e) {
- RubyException re = e.getException();
- runtime.printError(re);
- if (!runtime.fastGetClass("SystemExit").isInstance(re)) {
- throw new ScriptException(e);
- }
- } finally {
- if (oldGlobals != null) {
- setGlobalVariables(oldGlobals);
- }
- }
- }
- }
-
- private void init(final String loadPath) {
- AccessController.doPrivileged(new PrivilegedAction<Object>() {
- public Object run() {
- runtime = Ruby.newInstance();
- IAccessor d = new ValueAccessor(runtime.newString("<script>"));
- runtime.getGlobalVariables().define("$PROGRAM_NAME", d);
- runtime.getGlobalVariables().define("$0", d);
- String path = loadPath;
- if (path == null) {
- path = System.getProperty("java.class.path");
- }
- List list = Arrays.asList(path.split(File.pathSeparator));
- runtime.getLoadService().init(list);
- runtime.getLoadService().require("java");
- return null;
- }
- });
- }
-
- private synchronized Object invokeImpl(final Object obj, String method,
- Object[] args, Class returnType)
- throws ScriptException {
- if (method == null) {
- throw new NullPointerException("method name is null");
- }
- GlobalVariables oldGlobals = runtime.getGlobalVariables();
- try {
- setWriterOutputStream(context.getWriter());
- setErrorWriter(context.getErrorWriter());
- setGlobalVariables(context);
- IRubyObject rubyRecv = obj != null ?
- JavaUtil.convertJavaToRuby(runtime, obj) : runtime.getTopSelf();
-
- IRubyObject result;
- if (args != null && args.length > 0) {
- IRubyObject[] rubyArgs = JavaUtil.convertJavaArrayToRuby(runtime, args);
- // Create Ruby proxies for any input arguments that are not primitives.
- IRubyObject javaUtilities = runtime.getObject().getConstant("JavaUtilities");
- for (int i = 0; i < rubyArgs.length; i++) {
- IRubyObject tmp = rubyArgs[i];
- if (tmp instanceof JavaObject) {
- rubyArgs[i] = javaUtilities.callMethod(runtime.getCurrentContext(), "wrap", tmp);
- }
- }
- result = rubyRecv.callMethod(runtime.getCurrentContext(), method, rubyArgs);
- } else {
- result = rubyRecv.callMethod(runtime.getCurrentContext(), method);
- }
- return rubyToJava(result, returnType);
- } catch (Exception exp) {
- throw new ScriptException(exp);
- } finally {
- try {
- JavaEmbedUtils.terminate(runtime);
- } catch (RaiseException e) {
- RubyException re = e.getException();
- runtime.printError(re);
- if (!runtime.fastGetClass("SystemExit").isInstance(re)) {
- throw new ScriptException(e);
- }
- } finally {
- if (oldGlobals != null) {
- setGlobalVariables(oldGlobals);
- }
- }
- }
- }
-
- private void setKCode(String encoding) {
- KCode kcode = KCode.create(runtime, encoding);
- runtime.setKCode(kcode);
- }
-
- private void equalOutputs(RubyObject value) {
- runtime.getGlobalVariables().set("$>", value);
- runtime.getGlobalVariables().set("$defout", value);
- }
-
- private void setWriterOutputStream(Writer writer) {
- try {
- RubyIO dummy_io =
- new RubyIO(runtime, new PrintStream(new WriterOutputStream(new StringWriter())));
- runtime.getGlobalVariables().set("$stderr", dummy_io); //discard unwanted warnings
- RubyIO io =
- new RubyIO(runtime, new PrintStream(new WriterOutputStream(writer)));
- io.getOpenFile().getMainStream().setSync(true);
- runtime.defineGlobalConstant("STDOUT", io);
- runtime.getGlobalVariables().set("$>", io);
- runtime.getGlobalVariables().set("$stdout", io);
- runtime.getGlobalVariables().set("$defout", io);
- } catch (UnsupportedEncodingException exp) {
- throw new IllegalArgumentException(exp);
- }
- }
-
- private void setErrorWriter(Writer writer) {
- try {
- RubyIO dummy_io =
- new RubyIO(runtime, new PrintStream(new WriterOutputStream(new StringWriter())));
- runtime.getGlobalVariables().set("$stderr", dummy_io); //discard unwanted warnings
- RubyIO io =
- new RubyIO(runtime, new PrintStream(new WriterOutputStream(writer)));
- io.getOpenFile().getMainStream().setSync(true);
- runtime.defineGlobalConstant("STDERR", io);
- runtime.getGlobalVariables().set("$stderr", io);
- runtime.getGlobalVariables().set("$deferr", io);
- } catch (UnsupportedEncodingException exp) {
- throw new IllegalArgumentException(exp);
- }
- }
-
- private String getEncoding() {
- String enc = System.getProperty("sun.jnu.encoding");
- if (enc != null) {
- return enc;
- }
- return ((enc = System.getProperty("file.encoding")) == null) ? "UTF-8" : enc;
- }
-
- private class WriterOutputStream extends OutputStream {
-
- private Writer writer;
- private CharsetDecoder decoder;
-
- private WriterOutputStream(Writer writer) throws UnsupportedEncodingException {
- this(writer, getEncoding());
- }
-
- private WriterOutputStream(Writer writer, String enc) throws UnsupportedEncodingException {
- this.writer = writer;
- if (enc == null) {
- throw new UnsupportedEncodingException("encoding is " + enc);
- }
- try {
- decoder = Charset.forName(enc).newDecoder();
- } catch (Exception e) {
- throw new UnsupportedEncodingException("Unsupported: " + enc);
- }
- decoder.onMalformedInput(CodingErrorAction.REPLACE);
- decoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
- }
-
- @Override
- public void close() throws IOException {
- synchronized(writer) {
- decoder = null;
- writer.close();
- }
- }
-
- @Override
- public void flush() throws IOException {
- synchronized(writer) {
- writer.flush();
- }
- }
-
- @Override
- public void write(int b) throws IOException {
- byte[] buffer = new byte[1];
- write(buffer, 0, 1);
- }
-
- @Override
- public void write(byte[] buffer) throws IOException {
- write(buffer, 0, buffer.length);
- }
-
- @Override
- public void write(byte[] buffer, int offset, int length) throws IOException {
- synchronized(writer) {
- if (offset < 0 || offset > buffer.length - length || length < 0) {
- throw new IndexOutOfBoundsException();
- }
- if (length == 0) {
- return;
- }
- ByteBuffer bytes = ByteBuffer.wrap(buffer, offset, length);
- CharBuffer chars = CharBuffer.allocate(length);
- convert(bytes, chars);
- char[] cbuf = new char[chars.length()];
- chars.get(cbuf, 0, chars.length());
- writer.write(cbuf);
- writer.flush();
- }
- }
-
- private void convert(ByteBuffer bytes, CharBuffer chars) throws IOException {
- decoder.reset();
- chars.clear();
- CoderResult result = decoder.decode(bytes, chars, true);
- if (result.isError() || result.isOverflow()) {
- throw new IOException(result.toString());
- } else if (result.isUnderflow()) {
- chars.flip();
- }
- }
- }
-}
|