diff options
author | dims <dims@13f79535-47bb-0310-9956-ffa450edef68> | 2008-06-17 00:23:01 +0000 |
---|---|---|
committer | dims <dims@13f79535-47bb-0310-9956-ffa450edef68> | 2008-06-17 00:23:01 +0000 |
commit | bdd0a41aed7edf21ec2a65cfa17a86af2ef8c48a (patch) | |
tree | 38a92061c0793434c4be189f1d70c3458b6bc41d /branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby |
Move Tuscany from Incubator to top level.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@668359 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to '')
14 files changed, 1473 insertions, 0 deletions
diff --git a/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/RubyComponent.java b/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/RubyComponent.java new file mode 100644 index 0000000000..7a244b828c --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/RubyComponent.java @@ -0,0 +1,134 @@ +/* + * 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.container.ruby; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.tuscany.container.ruby.rubyscript.RubyScript; +import org.apache.tuscany.container.ruby.rubyscript.RubyScriptInstance; +import org.apache.tuscany.spi.ObjectCreationException; +import org.apache.tuscany.spi.component.CompositeComponent; +import org.apache.tuscany.spi.component.ScopeContainer; +import org.apache.tuscany.spi.component.TargetException; +import org.apache.tuscany.spi.component.WorkContext; +import org.apache.tuscany.spi.extension.AtomicComponentExtension; +import org.apache.tuscany.spi.model.Operation; +import org.apache.tuscany.spi.wire.InboundWire; +import org.apache.tuscany.spi.wire.OutboundWire; +import org.apache.tuscany.spi.wire.TargetInvoker; +import org.apache.tuscany.spi.wire.WireService; + +/** + * The Ruby component implementation. + */ +public class RubyComponent extends AtomicComponentExtension { + + private final List<Class<?>> services; + + private final Map<String, Object> properties; + + private RubyScript rubyScript; + + private String rubyClassName; + + public RubyComponent(String name, + RubyScript rubyScript, + String rubyClassName, + List<Class<?>> services, + Map<String, Object> propValues, + CompositeComponent parent, + ScopeContainer scopeContainer, + WireService wireService, + WorkContext workContext) { + super(name, parent, scopeContainer, wireService, workContext, null, 0); + + this.rubyScript = rubyScript; + this.rubyClassName = rubyClassName; + this.services = services; + this.scope = scopeContainer.getScope(); + //this.properties = new HashMap<String, Object>(); + this.properties = propValues; + } + + public Object createInstance() throws ObjectCreationException { + + Map<String, Object> context = new HashMap<String, Object>(getProperties()); + + for (List<OutboundWire> referenceWires : getOutboundWires().values()) { + for (OutboundWire wire : referenceWires) { + Object wireProxy = wireService.createProxy(wire); + //since all types that may be used in the reference interface may not be known to Rhino + //using the wireProxy as is will fail result in type conversion exceptions in cases where + //Rhino does not know enough of the tpypes used. Hence introduce a interceptor proxy, + //with weak typing (java.lang.Object) so that Rhino's call to the proxy succeeds. Then + //within this interceptor proxy perform data mediations required to correctly call the + //referenced service. + Class<?> businessInterface = wire.getServiceContract().getInterfaceClass(); + RubyReferenceProxy interceptingProxy = new RubyReferenceProxy(businessInterface, + wireProxy, + rubyScript.getRubyEngine()); + context.put(wire.getReferenceName(), interceptingProxy.createProxy()); + } + } + + Object instance = rubyScript.createScriptInstance(context, rubyClassName); + + return instance; + } + + public TargetInvoker createTargetInvoker(String targetName, Operation operation) { + /*Method[] methods = operation.getServiceContract().getInterfaceClass().getMethods(); + Method method = findMethod(operation, + methods);*/ + return new RubyInvoker(operation.getName(), this, operation.getOutputType().getPhysical().getClass()); + } + + // TODO: move all the following up to AtomicComponentExtension? + + public List<Class<?>> getServiceInterfaces() { + return services; + } + + public Map<String, Object> getProperties() { + return properties; + } + + public RubyScriptInstance getTargetInstance() throws TargetException { + return (RubyScriptInstance) scopeContainer.getInstance(this); + } + + public Object getServiceInstance() throws TargetException { + return getServiceInstance(null); + } + + @SuppressWarnings("unchecked") + public Object getServiceInstance(String service) throws TargetException { + InboundWire wire = getInboundWire(service); + if (wire == null) { + TargetException e = new TargetException("ServiceDefinition not found"); // TODO better error message + e.setIdentifier(service); + throw e; + } + return wireService.createProxy(wire); + } + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/RubyComponentBuilder.java b/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/RubyComponentBuilder.java new file mode 100644 index 0000000000..bdbbd1871c --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/RubyComponentBuilder.java @@ -0,0 +1,94 @@ +/* + * 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.container.ruby; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.tuscany.container.ruby.rubyscript.RubyScript; +import org.apache.tuscany.spi.builder.BuilderConfigException; +import org.apache.tuscany.spi.component.Component; +import org.apache.tuscany.spi.component.CompositeComponent; +import org.apache.tuscany.spi.component.ScopeContainer; +import org.apache.tuscany.spi.deployer.DeploymentContext; +import org.apache.tuscany.spi.extension.ComponentBuilderExtension; +import org.apache.tuscany.spi.model.ComponentDefinition; +import org.apache.tuscany.spi.model.Property; +import org.apache.tuscany.spi.model.PropertyValue; +import org.apache.tuscany.spi.model.Scope; +import org.apache.tuscany.spi.model.ServiceDefinition; + +/** + * Extension point for creating {@link RubyComponent}s from an assembly configuration + */ +public class RubyComponentBuilder extends ComponentBuilderExtension<RubyImplementation> { + + protected Class<RubyImplementation> getImplementationType() { + return RubyImplementation.class; + } + + @SuppressWarnings("unchecked") + public Component build(CompositeComponent parent, + ComponentDefinition<RubyImplementation> componentDefinition, + DeploymentContext deploymentContext) throws BuilderConfigException { + + String name = componentDefinition.getName(); + RubyImplementation implementation = componentDefinition.getImplementation(); + RubyComponentType componentType = implementation.getComponentType(); + + // get list of services provided by this component + Collection<ServiceDefinition> collection = componentType.getServices().values(); + List<Class<?>> services = new ArrayList<Class<?>>(collection.size()); + for (ServiceDefinition serviceDefinition : collection) { + services.add(serviceDefinition.getServiceContract().getInterfaceClass()); + } + + Map<String, Object> propertyValues = new Hashtable<String, Object>(); + Collection<PropertyValue<?>> propValueSettings = componentDefinition.getPropertyValues().values(); + for (PropertyValue propertyValue : propValueSettings) { + propertyValues.put(propertyValue.getName(), + propertyValue.getValueFactory().getInstance()); + } + + RubyScript rubyScript = implementation.getRubyScript(); + + // TODO: have ComponentBuilderExtension pass ScopeContainer in on build method? + ScopeContainer scopeContainer; + Scope scope = componentType.getLifecycleScope(); + if (Scope.MODULE == scope) { + scopeContainer = deploymentContext.getModuleScope(); + } else { + scopeContainer = scopeRegistry.getScopeContainer(scope); + } + + return new RubyComponent(name, + rubyScript, + implementation.getRubyClassName(), + services, + propertyValues, + parent, + scopeContainer, + wireService, + workContext); + } +} diff --git a/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/RubyComponentType.java b/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/RubyComponentType.java new file mode 100644 index 0000000000..1b98cf86d6 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/RubyComponentType.java @@ -0,0 +1,58 @@ +/* + * 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.container.ruby; + +import org.apache.tuscany.spi.model.ComponentType; +import org.apache.tuscany.spi.model.Property; +import org.apache.tuscany.spi.model.ReferenceDefinition; +import org.apache.tuscany.spi.model.Scope; +import org.apache.tuscany.spi.model.ServiceDefinition; + +public class RubyComponentType extends + ComponentType<ServiceDefinition, ReferenceDefinition, Property<?>> { + + private Scope lifecycleScope = Scope.MODULE; + + public RubyComponentType() { + } + + @SuppressWarnings("unchecked") + public RubyComponentType(ComponentType ct) { + // TODO: A bit hacky but this is so the non-Ruby .componentType side file can be used for now + setInitLevel(ct.getInitLevel()); + for (Object property : ct.getProperties().values()) { + add((Property) property); + } + for (Object reference : ct.getReferences().values()) { + add((ReferenceDefinition) reference); + } + for (Object service : ct.getServices().values()) { + add((ServiceDefinition) service); + } + } + + public Scope getLifecycleScope() { + return lifecycleScope; + } + + public void setLifecycleScope(Scope lifecycleScope) { + this.lifecycleScope = lifecycleScope; + } + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/RubyComponentTypeLoader.java b/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/RubyComponentTypeLoader.java new file mode 100644 index 0000000000..6fc5f87c68 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/RubyComponentTypeLoader.java @@ -0,0 +1,118 @@ +/* + * 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.container.ruby; + +import java.net.URL; + +import org.apache.tuscany.container.ruby.rubyscript.RubySCAConfig; +import org.apache.tuscany.container.ruby.rubyscript.RubyScript; +import org.apache.tuscany.spi.annotation.Autowire; +import org.apache.tuscany.spi.component.CompositeComponent; +import org.apache.tuscany.spi.deployer.DeploymentContext; +import org.apache.tuscany.spi.extension.ComponentTypeLoaderExtension; +import org.apache.tuscany.spi.idl.InvalidServiceContractException; +import org.apache.tuscany.spi.idl.java.JavaInterfaceProcessorRegistry; +import org.apache.tuscany.spi.loader.LoaderException; +import org.apache.tuscany.spi.loader.MissingResourceException; +import org.apache.tuscany.spi.model.ComponentType; + +/** + * @version $Rev$ $Date$ + */ +public class RubyComponentTypeLoader extends ComponentTypeLoaderExtension<RubyImplementation> { + + private JavaInterfaceProcessorRegistry processorRegistry; + + public RubyComponentTypeLoader(@Autowire + JavaInterfaceProcessorRegistry processorRegistry) { + this.processorRegistry = processorRegistry; + } + + @Override + protected Class<RubyImplementation> getImplementationClass() { + return RubyImplementation.class; + } + + protected RubyComponentType loadByIntrospection(CompositeComponent parent, + RubyImplementation implementation, + DeploymentContext deploymentContext) throws + MissingResourceException, + InvalidServiceContractException { + + RubyScript rubyScript = implementation.getRubyScript(); + RubySCAConfig scaConfig = rubyScript.getSCAConfig(); + if (!scaConfig.hasSCAConfig()) { + throw new IllegalArgumentException( + "must use either .componentType side file or Ruby Global variable $SCA definition"); + } + + // FIXME this should be a system service, not instantiated here + RubyComponentType componentType = new RubyIntrospector(null, processorRegistry) + .introspectScript(scaConfig, rubyScript.getClassLoader()); + + return componentType; + } + + protected String getResourceName(RubyImplementation implementation) { + return implementation.getRubyScript().getScriptName(); + } + + // TODO: must be possible to move all the following up in to ComponentTypeLoaderExtension + + public void load(CompositeComponent parent, + RubyImplementation implementation, + DeploymentContext deploymentContext) throws LoaderException { + + URL resource = implementation.getRubyScript().getClassLoader().getResource(getSideFileName(implementation)); + RubyComponentType componentType; + if (resource == null) { + try { + componentType = loadByIntrospection(parent, implementation, deploymentContext); + } catch (InvalidServiceContractException e) { + throw new LoaderException("Invalid service contract", e); + } + } else { + componentType = loadFromSidefile(resource, deploymentContext); + } + + implementation.setComponentType(componentType); + + + } + + protected RubyComponentType loadFromSidefile(URL url, DeploymentContext deploymentContext) throws LoaderException { + ComponentType ct = loaderRegistry.load(null, + url, + ComponentType.class, + deploymentContext); + RubyComponentType jsct = new RubyComponentType(ct); + return jsct; + } + + private String getSideFileName(RubyImplementation implementation) { + String baseName = getResourceName(implementation); + int lastDot = baseName.lastIndexOf('.'); + if (lastDot != -1) { + baseName = baseName.substring(0, + lastDot); + } + return baseName + ".componentType"; + } + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/RubyImplementation.java b/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/RubyImplementation.java new file mode 100644 index 0000000000..6f07399d0a --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/RubyImplementation.java @@ -0,0 +1,48 @@ +/* + * 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.container.ruby; + +import org.apache.tuscany.container.ruby.rubyscript.RubyScript; +import org.apache.tuscany.spi.model.AtomicImplementation; + +/** + * Model object for a JavaScript implementation. + */ +public class RubyImplementation extends AtomicImplementation<RubyComponentType> { + + private RubyScript rubyScript; + + private String rubyClassName; + + public String getRubyClassName() { + return rubyClassName; + } + + public void setRubyClassName(String rubyClassName) { + this.rubyClassName = rubyClassName; + } + + public RubyScript getRubyScript() { + return rubyScript; + } + + public void setRubyScript(RubyScript rubyScript) { + this.rubyScript = rubyScript; + } +} diff --git a/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/RubyImplementationLoader.java b/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/RubyImplementationLoader.java new file mode 100644 index 0000000000..322e3d84e8 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/RubyImplementationLoader.java @@ -0,0 +1,123 @@ +/* + * 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.container.ruby; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.net.URL; +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import org.apache.tuscany.container.ruby.rubyscript.RubyScript; +import org.apache.tuscany.spi.annotation.Autowire; +import org.apache.tuscany.spi.component.CompositeComponent; +import org.apache.tuscany.spi.deployer.DeploymentContext; +import org.apache.tuscany.spi.extension.LoaderExtension; +import org.apache.tuscany.spi.loader.LoaderException; +import org.apache.tuscany.spi.loader.LoaderRegistry; +import org.apache.tuscany.spi.loader.LoaderUtil; +import org.apache.tuscany.spi.loader.MissingResourceException; +import org.osoa.sca.annotations.Constructor; + +/** + * Loader for handling JavaScript <js:implementation.js> elements. + */ +public class RubyImplementationLoader extends LoaderExtension<RubyImplementation> { + private static final QName IMPLEMENTATION_RUBY = new QName( + "http://incubator.apache.org/tuscany/xmlns/container/rb/1.0-incubator-M2", "implementation.rb"); + + @Constructor({"registry"}) + public RubyImplementationLoader(@Autowire + LoaderRegistry registry) { + super(registry); + } + + public QName getXMLType() { + return IMPLEMENTATION_RUBY; + } + + public RubyImplementation load(CompositeComponent parent, + XMLStreamReader reader, + DeploymentContext deploymentContext) throws XMLStreamException, + LoaderException { + + String script = reader.getAttributeValue(null, + "script"); + String rubyClassName = reader.getAttributeValue(null,"class"); + + if ( script == null ) { + throw new MissingResourceException("No script supplied"); + } + + ClassLoader cl = deploymentContext.getClassLoader(); + String source = loadSource(cl, + script); + + LoaderUtil.skipToEndElement(reader); + + RubyImplementation implementation = new RubyImplementation(); + RubyScript rubyScript = new RubyScript(script, source, null, cl); + implementation.setRubyScript(rubyScript); + implementation.setRubyClassName(rubyClassName); + registry.loadComponentType(parent, + implementation, + deploymentContext); + return implementation; + } + + protected String loadSource(ClassLoader cl, String resource) throws LoaderException { + URL url = cl.getResource(resource); + if (url == null) { + throw new MissingResourceException(resource); + } + InputStream is; + try { + is = url.openStream(); + } catch (IOException e) { + MissingResourceException mre = new MissingResourceException(resource, e); + mre.setIdentifier(resource); + throw mre; + } + try { + Reader reader = new InputStreamReader(is, "UTF-8"); + char[] buffer = new char[1024]; + StringBuilder source = new StringBuilder(); + int count; + while ((count = reader.read(buffer)) > 0) { + source.append(buffer, + 0, + count); + } + return source.toString(); + } catch (IOException e) { + LoaderException le = new LoaderException(e); + le.setIdentifier(resource); + throw le; + } finally { + try { + is.close(); + } catch (IOException e) { + // ignore + } + } + } +} diff --git a/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/RubyIntrospector.java b/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/RubyIntrospector.java new file mode 100644 index 0000000000..d5ef41d835 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/RubyIntrospector.java @@ -0,0 +1,173 @@ +/* + * 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.container.ruby; + +import java.util.Iterator; +import java.util.Map; + +import javax.wsdl.Definition; +import javax.wsdl.PortType; +import javax.wsdl.WSDLException; +import javax.wsdl.factory.WSDLFactory; +import javax.wsdl.xml.WSDLReader; +import javax.xml.namespace.QName; + +import org.apache.tuscany.container.ruby.rubyscript.RubySCAConfig; +import org.apache.tuscany.idl.wsdl.WSDLDefinitionRegistry; +import org.apache.tuscany.idl.wsdl.WSDLServiceContract; +import org.apache.tuscany.spi.annotation.Autowire; +import org.apache.tuscany.spi.idl.InvalidServiceContractException; +import org.apache.tuscany.spi.idl.java.JavaInterfaceProcessorRegistry; +import org.apache.tuscany.spi.loader.MissingResourceException; +import org.apache.tuscany.spi.model.ComponentType; +import org.apache.tuscany.spi.model.Scope; +import org.apache.tuscany.spi.model.ServiceContract; +import org.apache.tuscany.spi.model.ServiceDefinition; + +/** + * Introspects JavaScript files for SCA configuration + */ +public class RubyIntrospector { + + private WSDLDefinitionRegistry wsdlRegistry; + private JavaInterfaceProcessorRegistry processorRegistry; + + public RubyIntrospector(@Autowire WSDLDefinitionRegistry wsdlRegistry, + @Autowire JavaInterfaceProcessorRegistry processorRegistry) { + this.wsdlRegistry = wsdlRegistry; + this.processorRegistry = processorRegistry; + } + + public RubyComponentType introspectScript(RubySCAConfig scaConfig, ClassLoader cl) + throws MissingResourceException, InvalidServiceContractException { + RubyComponentType componentType = new RubyComponentType(); + introspectJavaInterface(componentType, cl, scaConfig.getJavaInterface()); + introspectWSDLInterface(componentType, cl, scaConfig.getWSDLNamespace(), scaConfig.getWSDLPortType(), + scaConfig.getWSDLLocation()); + introspectReferences(componentType, cl, scaConfig.getReferences()); + introspectProperties(componentType, cl, scaConfig.getProperties()); + introspectScope(componentType, scaConfig.getScope()); + return componentType; + } + + private void introspectScope(RubyComponentType componentType, Scope scope) { + if (scope != null) { + componentType.setLifecycleScope(scope); + } + } + + @SuppressWarnings("unchecked") + private void introspectJavaInterface(ComponentType componentType, ClassLoader cl, String serviceClass) + throws MissingResourceException, InvalidServiceContractException { + if (serviceClass != null) { + ServiceDefinition service = new ServiceDefinition(); + try { + ServiceContract<?> sc = processorRegistry.introspect(Class.forName(serviceClass)); + service.setServiceContract(sc); + componentType.add(service); + } catch (ClassNotFoundException e) { + throw new MissingResourceException("Interface not found", e); + } + } + } + + @SuppressWarnings("unchecked") + private void introspectWSDLInterface(ComponentType componentType, ClassLoader cl, String wsdlNamespace, + String wsdlPortType, String wsdlLocation) { + if (wsdlNamespace == null && wsdlPortType == null && wsdlLocation == null) { + return; + } + + PortType portType = null; + if (wsdlLocation != null) { + portType = readWSDLPortType(wsdlNamespace, wsdlPortType, wsdlLocation, portType); + } else { + portType = getPortType(wsdlNamespace, wsdlPortType); + } + + ServiceDefinition service = new ServiceDefinition(); + WSDLServiceContract wsdlSC = new WSDLServiceContract(); + wsdlSC.setPortType(portType); + service.setServiceContract(wsdlSC); + componentType.add(service); + } + + private PortType readWSDLPortType(String wsdlNamespace, String wsdlPortType, String wsdlLocation, + PortType portType) { + Definition wsdlDefinition; + try { + WSDLReader reader = WSDLFactory.newInstance().newWSDLReader(); + reader.setFeature("javax.wsdl.verbose", false); + wsdlDefinition = reader.readWSDL(wsdlLocation.toString()); + } catch (WSDLException e) { + throw new RuntimeException(e); + + } + Map portTypes = wsdlDefinition.getPortTypes(); + for (Iterator i = portTypes.keySet().iterator(); i.hasNext();) { + QName portTypeQN = (QName) i.next(); + if (wsdlNamespace != null) { + if (!portTypeQN.getNamespaceURI().equals(wsdlNamespace)) { + continue; + } + } + if (wsdlPortType != null) { + if (!portTypeQN.getLocalPart().equals(wsdlPortType)) { + continue; + } + } + if (portType != null) { + throw new RuntimeException("multiple matching portTypes in wsdl: " + wsdlLocation); + } + portType = (PortType) portTypes.get(portTypeQN); + } + if (portType == null) { + throw new RuntimeException("portType not found in wsdl: " + wsdlLocation); + } + return portType; + } + + private PortType getPortType(String wsdlNamespace, String wsdlPortType) { + if (wsdlPortType == null) { + throw new IllegalArgumentException("must specify the wsdlPortType in script SCA config"); + } + PortType portType = null; + if (wsdlNamespace != null) { + QName portTypeQN = new QName(wsdlNamespace.toString(), wsdlPortType.toString()); + portType = wsdlRegistry.getPortType(portTypeQN); + if (portType == null) { + throw new IllegalArgumentException("no WSDL registered for portType: " + portTypeQN); + } + } else { + // wsdlRegistry.getPortType(wsdlPortType.toString()); + if (portType == null) { + throw new IllegalArgumentException("no WSDL registered for portType:" + wsdlPortType); + } + } + return portType; + } + + + private void introspectProperties(ComponentType componentType, ClassLoader cl, Map properties) { + } + + private void introspectReferences(ComponentType componentType, ClassLoader cl, Map references) { + } + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/RubyInvoker.java b/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/RubyInvoker.java new file mode 100644 index 0000000000..a40f04612e --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/RubyInvoker.java @@ -0,0 +1,55 @@ +/* + * 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.container.ruby; + +import java.lang.reflect.InvocationTargetException; + +import org.apache.tuscany.container.ruby.rubyscript.RubyScriptInstance; +import org.apache.tuscany.spi.extension.TargetInvokerExtension; + +/** + * Dispatches to a JavaScript implementation instance + * + * @version $$Rev$$ $$Date$$ + */ +public class RubyInvoker extends TargetInvokerExtension { + + private RubyComponent context; + + private String functionName; + + private Class returnType; + + public RubyInvoker(String functionName, RubyComponent context, Class returnType) { + this.functionName = functionName; + this.context = context; + this.returnType = returnType; + } + + /** + * Invokes a function on a script instance + */ + public Object invokeTarget(final Object payload) throws InvocationTargetException { + RubyScriptInstance target = context.getTargetInstance(); + return target.invokeFunction(functionName, + (Object[]) payload, + returnType); + } + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/RubyRefInvocInterceptor.java b/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/RubyRefInvocInterceptor.java new file mode 100644 index 0000000000..bf62d1fcab --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/RubyRefInvocInterceptor.java @@ -0,0 +1,92 @@ +/*
+ * 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.container.ruby;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+
+import org.jruby.IRuby;
+import org.jruby.RubyObject;
+import org.jruby.javasupport.JavaUtil;
+
+/**
+ * This Interceptor encasulates the data mediation required by the JavaScriptReferenceProxy. The
+ * invocation handler of this class traps the javascript reference calls, performs data mediation
+ * and calls then calls the actual referred service. This classes implementation is subject to
+ * review and change when the DataMediation infrastructure of Tuscany is ready.
+ *
+ */
+public class RubyRefInvocInterceptor implements InvocationHandler {
+ private Object actualProxy;
+
+ private Class wireInterface;
+
+ private IRuby rubyEngine;
+
+ RubyRefInvocInterceptor(Object wireProxy, Class wireIfc, IRuby rubyEng) {
+ this.actualProxy = wireProxy;
+ this.wireInterface = wireIfc;
+ this.rubyEngine = rubyEng;
+ }
+
+ public Object invoke(Object arg0, Method method, Object[] args) throws Throwable {
+ if ( method.getName().equals("hashCode"))
+ return new Integer(1);
+
+ Method invokedMethod = getInvokedMethod(method.getName());
+ Object[] tranformedArgs = new Object[args.length];
+ for (int count = 0; count < args.length; ++count) {
+ tranformedArgs[count] = fromRubyToJava(invokedMethod.getParameterTypes()[count], args[count]);
+ }
+
+ Object response = invokedMethod.invoke(actualProxy, tranformedArgs);
+ response = fromJavaToRuby(response);
+ return response;
+ }
+
+ private Method getInvokedMethod(String methodName) {
+ Method[] methods = wireInterface.getMethods();
+
+ for (int count = 0; count < methods.length; ++count) {
+ if (methods[count].getName().equals(methodName)) {
+ return methods[count];
+ }
+ }
+ throw new RuntimeException("Unable to find invocation method");
+ }
+
+ protected Object fromRubyToJava(Class reqArgType, Object rubyArg) throws Exception {
+ Object javaArg = null;
+
+ //for known cases the JRuby runtime handles the conversion before calling the Java objects
+ //so nothing to do. When it cannot convert it simply passed the instance of RubyObject
+ if ( rubyArg instanceof RubyObject ) {
+ //need to deal with this
+ } else {
+ javaArg = rubyArg;
+ }
+
+ return javaArg;
+ }
+
+ protected Object fromJavaToRuby(Object retVal) throws RuntimeException {
+ Object rubyRetVal = JavaUtil.convertJavaToRuby(rubyEngine, retVal, retVal.getClass());
+ return rubyRetVal;
+ }
+}
diff --git a/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/RubyReferenceProxy.java b/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/RubyReferenceProxy.java new file mode 100644 index 0000000000..4d91194484 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/RubyReferenceProxy.java @@ -0,0 +1,127 @@ +/*
+ * 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.container.ruby;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+import org.jruby.IRuby;
+import org.jruby.RubyException;
+
+import net.sf.cglib.asm.ClassWriter;
+import net.sf.cglib.asm.CodeVisitor;
+import net.sf.cglib.asm.Constants;
+import net.sf.cglib.asm.Type;
+
+/**
+ * This is a proxy that will mediate reference calls from the JavaScript. The mediation code here will be reviewed when the DataMediation
+ * infrastructure is ready. This proxy assmes that there is no verloading of service methods on the reference interface i.e. there are no two service
+ * methods that have the same method name or operation name.
+ */
+public class RubyReferenceProxy {
+
+ private Class interfaze;
+
+ private Object wireProxy;
+
+ private IRuby rubyEngine;
+
+ public RubyReferenceProxy(Class interfaze, Object wireProxy, IRuby rubyEng) {
+ this.interfaze = interfaze;
+ this.wireProxy = wireProxy;
+ this.rubyEngine = rubyEng;
+ }
+
+ public Object createProxy() {
+ try {
+ GenericProxyClassLoader classloader = new GenericProxyClassLoader();
+ final byte[] byteCode = generateGenericInterface(interfaze);
+
+ Class genericInterface = classloader.defineClass(byteCode);
+ InvocationHandler proxyHandler = new RubyRefInvocInterceptor(wireProxy, interfaze, rubyEngine);
+ // return genericInterface.cast(Proxy.newProxyInstance(classloader, new Class[]{genericInterface}, proxyHandler));
+ return Proxy.newProxyInstance(classloader,
+ new Class[]{genericInterface},
+ proxyHandler);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ private static byte[] generateGenericInterface(Class serviceInterface) {
+ String interfazeName = serviceInterface.getCanonicalName();
+ ClassWriter cw = new ClassWriter(false);
+
+ cw.visit(Constants.V1_5,
+ Constants.ACC_PUBLIC + Constants.ACC_ABSTRACT + Constants.ACC_INTERFACE,
+ interfazeName.replace('.',
+ '/'),
+ "java/lang/Object",
+ null,
+ serviceInterface.getSimpleName() + ".java");
+
+ StringBuffer argsAndReturn = new StringBuffer("(");
+ Method[] methods = serviceInterface.getMethods();
+ for (int count = 0; count < methods.length; ++count) {
+ argsAndReturn = new StringBuffer("(");
+ Class[] paramTypes = methods[count].getParameterTypes();
+ Class returnType = methods[count].getReturnType();
+
+ for (int paramCount = 0; paramCount < paramTypes.length; ++paramCount) {
+ argsAndReturn.append(Type.getType(Object.class));
+ }
+ argsAndReturn.append(")");
+ argsAndReturn.append(Type.getType(Object.class));
+
+ Class[] exceptionTypes = methods[count].getExceptionTypes();
+ String[] exceptions = new String[exceptionTypes.length];
+ for (int excCount = 0; excCount < exceptionTypes.length; ++excCount) {
+ exceptions[excCount] = exceptionTypes[excCount].getName();
+ exceptions[excCount] = exceptions[excCount].replace('.',
+ '/');
+ }
+
+ CodeVisitor cv = cw.visitMethod(Constants.ACC_PUBLIC + Constants.ACC_ABSTRACT,
+ methods[count].getName(),
+ argsAndReturn.toString(),
+ exceptions,
+ null);
+ cw.visitEnd();
+ }
+
+ cw.visitEnd();
+
+ return cw.toByteArray();
+ }
+
+ private class GenericProxyClassLoader extends ClassLoader {
+ public Class defineClass(byte[] byteArray) {
+ try {
+ return defineClass(null,
+ byteArray,
+ 0,
+ byteArray.length);
+ } catch (Throwable e) {
+ return null;
+ }
+ }
+
+ }
+}
diff --git a/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/rubyscript/RubySCAConfig.java b/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/rubyscript/RubySCAConfig.java new file mode 100644 index 0000000000..4d14d8a56a --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/rubyscript/RubySCAConfig.java @@ -0,0 +1,159 @@ +/* + * 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.container.ruby.rubyscript; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.tuscany.spi.model.Scope; +import org.jruby.RubyHash; +import org.jruby.RubyObject; +import org.jruby.internal.runtime.GlobalVariables; +import org.jruby.runtime.builtin.IRubyObject; + +/** + * Represents the variable defining the SCA aspects of the script + * <code> + * SCA = { + * javaInterface : "my.pkg.ClassName", + * wsdlPortType : "wsdlPortTypeName", + * wsdlNameSpace : "http://my.namespace.com", + * wsdlLocation : "\wsdl\mywsdl.txt", + * properties : { "foo" : ["java.lang.String", "defaultValue"],}, + * references : {}, + * scope : 'stateless'|'request'|'conversational'|'composite', + * } + * </code> + * The config must define the service with either javaInterface or wsdl. When + * using wsdl the three parameters are optional. If wsdlLocation is used that is the + * WSDL document used, and the namespace and portType parameters are only required if + * the WSDL definition defines multiple portTypes. + */ +public class RubySCAConfig { + + private boolean hasSCAConfig; + + private String javaInterface; + + private String wsdlLocation; + + private String wsdlNamespace; + + private String wsdlPortType; + + private Map properties; + + private Map references; + + private Scope scope; + + public RubySCAConfig(GlobalVariables globalVariables) { + IRubyObject rubyObject = globalVariables.get("$SCA"); + if (rubyObject != null && !rubyObject.isNil()) { + hasSCAConfig = true; + RubyHash scaVar = (RubyHash) rubyObject; + Object o = scaVar.get("javaInterface"); + if ( o != null ) { + this.javaInterface = o.toString(); + } + o = scaVar.get("wsdlLocation"); + if (o != null ) { + this.wsdlLocation = o.toString(); + } + o = scaVar.get("wsdlPortType"); + if (o != null ) { + this.wsdlPortType = o.toString(); + } + o = scaVar.get("wsdlNamespace"); + if (o != null ) { + this.wsdlNamespace = o.toString(); + } + if (javaInterface != null) { + if (wsdlLocation != null || wsdlPortType != null || wsdlNamespace != null) { + throw new IllegalArgumentException("script SCA config defines both Java and WSDL service interface"); + } + } else { + if (wsdlLocation == null && wsdlPortType == null && wsdlNamespace == null) { + throw new IllegalArgumentException("script SCA config must define either Java or WSDL service interface"); + } + } + + this.properties = new HashMap(); + o = scaVar.get("properties"); + if (o != null ) { + // TODO parse properties + } + + this.references = new HashMap(); + o = scaVar.get("references"); + if (o != null ) { + // TODO parse references + } + + o = scaVar.get("scope"); + if (o != null ) { + if ("stateless".equalsIgnoreCase(String.valueOf(o))) { + this.scope = Scope.STATELESS; + } else if ("request".equalsIgnoreCase(String.valueOf(o))) { + this.scope = Scope.REQUEST; + } else if ("conversational".equalsIgnoreCase(String.valueOf(o))) { + this.scope = Scope.SESSION; // TODO: where's CONVERSATIONAL? + } else if ("composite".equalsIgnoreCase(String.valueOf(o))) { + this.scope = Scope.MODULE; // TODO: composite = MODULE for now? + } else { + throw new IllegalArgumentException("invalid scope value: " + o); + } + } + + } + } + + public boolean hasSCAConfig() { + return hasSCAConfig; + } + + public String getJavaInterface() { + return javaInterface; + } + + public Map getProperties() { + return properties; + } + + public Map getReferences() { + return references; + } + + public String getWSDLLocation() { + return wsdlLocation; + } + + public String getWSDLNamespace() { + return wsdlNamespace; + } + + public String getWSDLPortType() { + return wsdlPortType; + } + + public Scope getScope() { + return scope; + } + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/rubyscript/RubyScript.java b/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/rubyscript/RubyScript.java new file mode 100644 index 0000000000..87d995eabd --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/rubyscript/RubyScript.java @@ -0,0 +1,160 @@ +/* + * 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.container.ruby.rubyscript; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Vector; + +import org.jruby.IRuby; +import org.jruby.RubyString; +import org.jruby.javasupport.JavaEmbedUtils; +import org.jruby.javasupport.JavaUtil; +import org.jruby.runtime.builtin.IRubyObject; + +/** + * A RhinoScript represents a compiled JavaScript script + */ +public class RubyScript { + protected final String NEW = ".new"; + protected final String EQUAL = "="; + + protected String scriptName; + + protected String script; + + protected Map<String, Class> responseClasses; + + protected ClassLoader classLoader; + + private IRuby rubyEngine = JavaEmbedUtils.initialize(new Vector()); + + /** + * Create a new RubyScript. + * + * @param scriptName + * the name of the script. Can be anything, only used in messages to identify the script + * @param script + * the complete script + */ + public RubyScript(String scriptName, String script) { + this(scriptName, script, (Map) null, null); + } + + /** + * Create a new RubyScript. + * + * @param scriptName + * the name of the script. Can be anything, only used in messages to identify the script + * @param script + * the complete script + * @param context + * name-value pairs that are added in to the scope where the script is compiled. May be null. The value objects are made available to + * the script by using a variable with the name. + * @param classLoader + * the ClassLoader to be used to locate any user Java classes used in the script + */ + public RubyScript(String scriptName, String script, Map context, ClassLoader classLoader) { + this.scriptName = scriptName; + this.script = script; + this.responseClasses = new HashMap<String, Class>(); + this.classLoader = classLoader; + rubyEngine.loadScript((RubyString) JavaUtil.convertJavaToRuby(rubyEngine, + "MyScript.rb", + String.class), + (RubyString) JavaUtil.convertJavaToRuby(rubyEngine, + this.script, + String.class), + false); + } + + /** + * Create a new invokeable instance of the script + * + * @return a IRubyObject + */ +public RubyScriptInstance createScriptInstance(Map<String, Object> context, String rubyClassName) { + if ( rubyClassName == null ) { + return new RubyScriptInstance(rubyEngine.evalScript(script), responseClasses); + } + else { + IRubyObject rubyObject = rubyEngine.evalScript(rubyClassName + NEW); + + Iterator<String> keyIterator = context.keySet().iterator(); + String key = null; + Object value = null; + while ( keyIterator.hasNext()) { + key = keyIterator.next(); + value = JavaUtil.convertJavaToRuby(rubyEngine, + context.get(key), + context.get(key).getClass()); + + JavaEmbedUtils.invokeMethod(rubyEngine, + rubyObject, + key + EQUAL, + new Object[]{value}, null); + } + + return new RubyScriptInstance(rubyObject, responseClasses); + } + } + public String getScript() { + return script; + } + + public String getScriptName() { + return scriptName; + } + + public Map<String, Class> getResponseClasses() { + return responseClasses; + } + + public ClassLoader getClassLoader() { + return classLoader; + } + + /** + * Set the Java type of a response value. JavaScript is dynamically typed so Rhino cannot always work out what the intended Java type of a + * response should be, for example should the statement "return 42" be a Java int, or Integer or Double etc. When Rhino can't determine the type + * it will default to returning a String, using this method enables overriding the Rhino default to use a specific Java type. + */ + public void setResponseClass(String functionName, Class responseClasses) { + this.responseClasses.put(functionName, + responseClasses); + } + + public RubySCAConfig getSCAConfig() { + return new RubySCAConfig(rubyEngine.getGlobalVariables()); + } + + public void setScript(String script) { + this.script = script; + } + + public IRuby getRubyEngine() { + return rubyEngine; + } + + public void setRubyEngine(IRuby rubyEngine) { + this.rubyEngine = rubyEngine; + } + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/rubyscript/RubyScriptInstance.java b/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/rubyscript/RubyScriptInstance.java new file mode 100644 index 0000000000..2d93c57fc9 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/rubyscript/RubyScriptInstance.java @@ -0,0 +1,61 @@ +/* + * 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.container.ruby.rubyscript; + +import java.util.HashMap; +import java.util.Map; + +import org.jruby.javasupport.JavaEmbedUtils; +import org.jruby.runtime.builtin.IRubyObject; + +/** + * An invokeable instance of a JavaScript script. + */ +public class RubyScriptInstance { + + private IRubyObject rubyInstance; + + private Map<String, Class> responseClasses; + + public RubyScriptInstance(IRubyObject rubyInstance, Map<String, Class> responseClasses) { + this.rubyInstance = rubyInstance; + this.responseClasses = responseClasses; + if (this.responseClasses == null) { + this.responseClasses = new HashMap<String, Class>(); + } + } + + public Object invokeFunction(String functionName, Object[] args, Class returnType) { + Object[] rubyArgs = RubyUtils.fromJavaToRuby(rubyInstance.getRuntime(), args); + + Object rubyResponse = JavaEmbedUtils.invokeMethod(rubyInstance.getRuntime(), + rubyInstance, + functionName, + rubyArgs, + returnType); + Object response = RubyUtils.fromRubyToJava(rubyInstance.getRuntime(), + returnType, + rubyResponse); + return response; + } + + + + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/rubyscript/RubyUtils.java b/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/rubyscript/RubyUtils.java new file mode 100644 index 0000000000..c19f233b94 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.ruby/src/main/java/org/apache/tuscany/container/ruby/rubyscript/RubyUtils.java @@ -0,0 +1,71 @@ +/*
+ * 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.container.ruby.rubyscript;
+
+import java.io.ByteArrayInputStream;
+
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.axiom.om.OMAbstractFactory;
+import org.apache.axiom.om.OMElement;
+import org.apache.axiom.om.impl.builder.StAXOMBuilder;
+import org.apache.axiom.om.util.StAXUtils;
+import org.jruby.IRuby;
+import org.jruby.RubyObject;
+import org.jruby.javasupport.JavaUtil;
+
+/**
+ * @author administrator
+ *
+ */
+public class RubyUtils {
+ public static Object fromRubyToJava(IRuby rubyEngine, Class reqArgType, Object rubyArg) {
+ Object javaArg = null;
+
+ //for known cases the JRuby runtime handles the conversion before calling the Java objects
+ //so nothing to do. When it cannot convert it simply passed the instance of RubyObject
+ if ( rubyArg instanceof RubyObject ) {
+ //need to deal with this
+ } else {
+ javaArg = rubyArg;
+ }
+
+ return javaArg;
+ }
+
+ public static Object[] fromJavaToRuby(IRuby rubyEngine, Object[] arg) {
+ Object[] jsArgs;
+ if (arg == null) {
+ jsArgs = new Object[0];
+ } else {
+ jsArgs = new Object[arg.length];
+ for (int i = 0; i < jsArgs.length; i++) {
+ jsArgs[i] = fromJavaToRuby(rubyEngine, arg[i]);
+ }
+ }
+
+ return jsArgs;
+ }
+
+ public static Object fromJavaToRuby(IRuby rubyEngine, Object javaObj) {
+ Object rubyObj = JavaUtil.convertJavaToRuby(rubyEngine, javaObj, javaObj.getClass());
+ return rubyObj;
+ }
+
+}
|