/*
* 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.provider;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
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.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.implementation.script.ScriptImplementation;
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.provider.ImplementationProvider;
import org.apache.tuscany.sca.runtime.RuntimeComponent;
import org.apache.tuscany.sca.runtime.RuntimeComponentService;
/**
* An ImplementationProvider for Script implementations.
*
* @version $Rev$ $Date$
*/
public class ScriptImplementationProvider implements ImplementationProvider {
private RuntimeComponent component;
private ScriptImplementation implementation;
private ScriptPropertyFactory propertyFactory;
private ScriptEngine scriptEngine;
private XMLHelper xmlHelper;
public ScriptImplementationProvider(RuntimeComponent component, ScriptImplementation implementation, ScriptPropertyFactory propertyFactory) {
this.component = component;
this.implementation = implementation;
this.propertyFactory = propertyFactory;
// Set the databinding and XMLHelper for WSDL interfaces
for (Service service : component.getServices()) {
InterfaceContract ic = service.getInterfaceContract();
if (ic instanceof WSDLInterfaceContract) {
ic.getInterface().resetDataBinding(OMElement.class.getName());
xmlHelper = XMLHelper.getArgHelper(scriptEngine);
}
}
}
public void start() {
try {
String language = implementation.getLanguage();
if (language == null) {
language = implementation.getScript();
language = language.substring(language.lastIndexOf('.') +1);
}
scriptEngine = scriptEngine(language);
if (scriptEngine == null) {
throw new ObjectCreationException("no script engine found for language: " + implementation.getLanguage());
}
if (!(scriptEngine instanceof Invocable)) {
throw new ObjectCreationException("script engine does not support Invocable: " + scriptEngine);
}
for (Reference reference : implementation.getReferences()) {
scriptEngine.put(reference.getName(), getProxy(reference.getName()));
}
for (Property property : implementation.getProperties()) {
ObjectFactory<?> valueFactory = propertyFactory.createValueFactory(property);
if (valueFactory != null) {
scriptEngine.put(property.getName(), valueFactory.getInstance());
}
}
URL url = new URL(implementation.getLocation());
InputStreamReader reader = new InputStreamReader(url.openStream());
scriptEngine.eval(reader);
reader.close();
} catch (IOException e) {
throw new IllegalArgumentException(e);
} catch (ScriptException e) {
throw new IllegalArgumentException(e);
}
}
public void stop() {
}
public boolean supportsOneWayInvocation() {
return false;
}
public Invoker createInvoker(RuntimeComponentService service, Operation operation) {
return new ScriptInvoker(scriptEngine, xmlHelper, operation);
}
private Object getProxy(String name) {
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);
}
/**
* Returns the script engine for the given language.
*
* @param language
* @return
*/
private ScriptEngine scriptEngine(String language) {
if ("rb".equals(language)) {
// Hack for now to work around a problem with the JRuby script engine
// return new TuscanyJRubyScriptEngine();
} else {
if ("py".equals(language)) {
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(language);
}
/**
* If the Python home isn't set then let Tuscany suppress messages other than errors
* See TUSCANY-1950
*/
private static void pythonCachedir() {
if (System.getProperty("python.home") == null) {
System.setProperty("python.verbose", "error");
}
}
}