summaryrefslogtreecommitdiffstats
path: root/sandbox/ant/container.easy/src/main/java/org
diff options
context:
space:
mode:
Diffstat (limited to 'sandbox/ant/container.easy/src/main/java/org')
-rw-r--r--sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/AsyncInvoker.java210
-rw-r--r--sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/AsyncMonitor.java31
-rw-r--r--sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyComponent.java117
-rw-r--r--sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyComponentBuilder.java83
-rw-r--r--sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyComponentType.java62
-rw-r--r--sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyComponentTypeLoader.java71
-rw-r--r--sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyImplementation.java47
-rw-r--r--sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyImplementationLoader.java85
-rw-r--r--sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyInstance.java31
-rw-r--r--sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyInstanceFactory.java71
-rw-r--r--sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyInvoker.java53
11 files changed, 861 insertions, 0 deletions
diff --git a/sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/AsyncInvoker.java b/sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/AsyncInvoker.java
new file mode 100644
index 0000000000..e5786e8a51
--- /dev/null
+++ b/sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/AsyncInvoker.java
@@ -0,0 +1,210 @@
+/*
+ * 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.easy;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.apache.tuscany.spi.component.TargetException;
+import org.apache.tuscany.spi.component.WorkContext;
+import org.apache.tuscany.spi.services.work.WorkScheduler;
+import org.apache.tuscany.spi.wire.InboundWire;
+import org.apache.tuscany.spi.wire.InvocationRuntimeException;
+import org.apache.tuscany.spi.wire.Message;
+import org.apache.tuscany.spi.wire.TargetInvoker;
+import org.osoa.sca.CompositeContext;
+import org.osoa.sca.CurrentCompositeContext;
+import org.osoa.sca.SCA;
+import org.osoa.sca.ServiceRuntimeException;
+
+/**
+ * Responsible for performing a non-blocking dispatch on a component implementation instance
+ *
+ * TODO: Pretty much a direct copy of what the groovy container does for async
+ */
+public class AsyncInvoker extends EasyInvoker {
+
+ private static final ContextBinder BINDER = new ContextBinder();
+ private static final Message RESPONSE = new AsyncInvoker.ImmutableMessage();
+
+ private InboundWire wire;
+ private WorkScheduler workScheduler;
+ private AsyncMonitor monitor;
+ private WorkContext workContext;
+ private Object target;
+ private Object messageId;
+
+ /**
+ * Creates a new invoker
+ *
+ * @param operation the operation the invoker is associated with
+ * @param wire
+ * @param component the target component
+ * @param workScheduler the work scheduler to run the invocation
+ * @param monitor the monitor to pass events to
+ * @param workContext
+ */
+ public AsyncInvoker(String operation,
+ InboundWire wire,
+ EasyComponent component,
+ WorkScheduler workScheduler,
+ AsyncMonitor monitor,
+ WorkContext workContext) {
+ super(operation, component);
+ this.wire = wire;
+ this.workScheduler = workScheduler;
+ this.monitor = monitor;
+ this.workContext = workContext;
+ }
+
+ // Override invocation methods to defer invocation to work item
+ // Both methods return null to indicate asynchrony; result will
+ // be conveyed by callback
+ @Override
+ public Object invokeTarget(final Object payload) throws InvocationTargetException {
+ final CompositeContext currentContext = CurrentCompositeContext.getContext();
+ // Schedule the invocation of the next interceptor in a new Work instance
+ try {
+ workScheduler.scheduleWork(new Runnable() {
+ private Object currentMessageId = messageId;
+
+ public void run() {
+ workContext.setCurrentMessageId(null);
+ workContext.setCurrentCorrelationId(currentMessageId);
+ CompositeContext oldContext = CurrentCompositeContext.getContext();
+ try {
+ BINDER.setContext(currentContext);
+ // REVIEW response must be null for one-way and non-null for callback
+ AsyncInvoker.super.invokeTarget(payload);
+ } catch (Exception e) {
+ // REVIEW uncomment when it is available
+ // monitor.executionError(e);
+ e.printStackTrace();
+ } finally {
+ BINDER.setContext(oldContext);
+ }
+ }
+ });
+ } catch (Exception e) {
+ throw new ServiceRuntimeException(e);
+ }
+ return RESPONSE;
+ }
+
+ public Message invoke(Message msg) throws InvocationRuntimeException {
+ // can't just call overriden invoke because it would bypass async
+ try {
+ messageId = msg.getMessageId();
+ wire.addMapping(messageId, msg.getFromAddress());
+ return (Message) invokeTarget(msg.getBody());
+ } catch (Throwable e) {
+ // FIXME need to log exceptions
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public AsyncInvoker clone() {
+ AsyncInvoker invoker = (AsyncInvoker) super.clone();
+ invoker.workScheduler = this.workScheduler;
+ invoker.monitor = this.monitor;
+ return invoker;
+ }
+
+ /**
+ * Resolves the target service instance or returns a cached one
+ */
+ protected Object getInstance() throws TargetException {
+ if (!isCacheable()) {
+ return component.getTargetInstance();
+ } else {
+ if (target == null) {
+ target = component.getTargetInstance();
+ }
+ return target;
+ }
+ }
+
+ protected static class ContextBinder extends SCA {
+ public void setContext(CompositeContext context) {
+ setCompositeContext(context);
+ }
+
+ public void start() {
+ throw new AssertionError();
+ }
+
+ public void stop() {
+ throw new AssertionError();
+ }
+ }
+
+ /**
+ * A dummy message passed back on an invocation
+ */
+ protected static class ImmutableMessage implements Message {
+
+ public Object getBody() {
+ return null;
+ }
+
+ public void setBody(Object body) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setTargetInvoker(TargetInvoker invoker) {
+ throw new UnsupportedOperationException();
+ }
+
+ public TargetInvoker getTargetInvoker() {
+ return null;
+ }
+
+ public Object getFromAddress() {
+ return null;
+ }
+
+ public void setFromAddress(Object fromAddress) {
+ throw new UnsupportedOperationException();
+ }
+
+ public Object getMessageId() {
+ return null;
+ }
+
+ public void setMessageId(Object messageId) {
+ throw new UnsupportedOperationException();
+ }
+
+ public Object getCorrelationId() {
+ return null;
+ }
+
+ public void setCorrelationId(Object correlationId) {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isFault() {
+ return false;
+ }
+
+ public void setBodyWithFault(Object fault) {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
diff --git a/sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/AsyncMonitor.java b/sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/AsyncMonitor.java
new file mode 100644
index 0000000000..ce39877dff
--- /dev/null
+++ b/sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/AsyncMonitor.java
@@ -0,0 +1,31 @@
+/*
+ * 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.easy;
+
+/**
+ * A monitor used to log events during non-blocking invocations
+ */
+public interface AsyncMonitor {
+
+ /**
+ * Logs an exception thrown during an invocation
+ */
+ void executionError(Exception e);
+
+}
diff --git a/sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyComponent.java b/sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyComponent.java
new file mode 100644
index 0000000000..62e812a782
--- /dev/null
+++ b/sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyComponent.java
@@ -0,0 +1,117 @@
+/*
+ * 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.easy;
+
+import static org.apache.tuscany.spi.idl.java.JavaIDLUtils.findMethod;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+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.services.work.WorkScheduler;
+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;
+
+/**
+ * A component implementation for script languages.
+ */
+public class EasyComponent extends AtomicComponentExtension {
+
+ private final List<Class<?>> services;
+
+ private final Map<String, Object> properties;
+
+ protected EasyInstanceFactory instanceFactory;
+
+ public EasyComponent(String name, EasyInstanceFactory instanceFactory, Map<String, Object> properties, List<Class<?>> services, CompositeComponent parent, ScopeContainer scopeContainer,
+ WireService wireService, WorkContext workContext, WorkScheduler workScheduler) {
+
+ super(name, parent, scopeContainer, wireService, workContext, workScheduler, 0);
+
+ this.instanceFactory = instanceFactory;
+ this.services = services;
+ this.scope = scopeContainer.getScope();
+ this.properties = properties;
+ }
+
+ @SuppressWarnings("unchecked")
+ 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);
+ context.put(wire.getReferenceName(), wireProxy);
+ }
+ }
+
+ return instanceFactory.createInstance(services, context);
+ }
+
+ public TargetInvoker createTargetInvoker(String targetName, Operation operation) {
+ Method[] methods = operation.getServiceContract().getInterfaceClass().getMethods();
+ Method method = findMethod(operation, methods);
+ return new EasyInvoker(method.getName(), this);
+ }
+
+ public TargetInvoker createAsyncTargetInvoker(InboundWire wire, Operation operation) {
+ return new AsyncInvoker(operation.getName(), wire, this, workScheduler, null, workContext);
+ }
+
+ // TODO: move all the following up to AtomicComponentExtension?
+
+ public List<Class<?>> getServiceInterfaces() {
+ return services;
+ }
+
+ public Map<String, Object> getProperties() {
+ return properties;
+ }
+
+ public Object getTargetInstance() throws TargetException {
+ return 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/sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyComponentBuilder.java b/sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyComponentBuilder.java
new file mode 100644
index 0000000000..fd46c77934
--- /dev/null
+++ b/sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyComponentBuilder.java
@@ -0,0 +1,83 @@
+/*
+ * 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.easy;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+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.PropertyValue;
+import org.apache.tuscany.spi.model.Scope;
+import org.apache.tuscany.spi.model.ServiceDefinition;
+
+/**
+ * Extension point for creating {@link ScriptComponent}s from an assembly configuration
+ */
+public class EasyComponentBuilder extends ComponentBuilderExtension<EasyImplementation> {
+
+ public EasyComponentBuilder() {
+ }
+
+ protected Class<EasyImplementation> getImplementationType() {
+ return EasyImplementation.class;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Component build(CompositeComponent parent, ComponentDefinition<EasyImplementation> componentDefinition,
+ DeploymentContext deploymentContext) throws BuilderConfigException {
+
+ String name = componentDefinition.getName();
+ EasyImplementation implementation = componentDefinition.getImplementation();
+ EasyComponentType 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());
+ }
+
+ // get the properties for the component
+ Map<String, Object> properties = new HashMap<String, Object>();
+ for (PropertyValue propertyValue : componentDefinition.getPropertyValues().values()) {
+ properties.put(propertyValue.getName(), propertyValue.getValueFactory().getInstance());
+ }
+
+ // 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 EasyComponent(name, implementation.getScriptInstanceFactory(), properties, services, parent, scopeContainer, wireService, workContext, workScheduler);
+ }
+
+}
diff --git a/sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyComponentType.java b/sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyComponentType.java
new file mode 100644
index 0000000000..aa3882a0aa
--- /dev/null
+++ b/sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyComponentType.java
@@ -0,0 +1,62 @@
+/*
+ * 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.easy;
+
+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;
+
+/**
+ * A componentType for script components
+ * TODO: need lifecycle methods init/destroy
+ * TODO: really need a generic componentType that supports scope and lifecycle
+ */
+public class EasyComponentType extends ComponentType<ServiceDefinition, ReferenceDefinition, Property<?>> {
+
+ private Scope lifecycleScope = Scope.MODULE;
+
+ public EasyComponentType() {
+ }
+
+ @SuppressWarnings("unchecked")
+ public EasyComponentType(ComponentType ct) {
+ // TODO: A bit hacky but this is so the generic .componentType XML 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/sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyComponentTypeLoader.java b/sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyComponentTypeLoader.java
new file mode 100644
index 0000000000..ada889e0a1
--- /dev/null
+++ b/sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyComponentTypeLoader.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.easy;
+
+import java.net.URL;
+
+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.loader.LoaderException;
+import org.apache.tuscany.spi.model.ComponentType;
+
+/**
+ * ComponentType loader for script components
+ */
+public class EasyComponentTypeLoader extends ComponentTypeLoaderExtension<EasyImplementation> {
+
+ public EasyComponentTypeLoader() {
+ }
+
+ @Override
+ protected Class<EasyImplementation> getImplementationClass() {
+ return EasyImplementation.class;
+ }
+
+ // TODO: must be possible to move all the following up in to ComponentTypeLoaderExtension
+
+ public void load(CompositeComponent parent, EasyImplementation implementation, DeploymentContext deploymentContext) throws LoaderException {
+ String sideFile = getSideFileName(implementation.getResourceName());
+ URL resource = implementation.getScriptInstanceFactory().getClassLoader().getResource(sideFile);
+ EasyComponentType componentType;
+ if (resource == null) {
+ throw new IllegalArgumentException("missing .componentType side file: " + sideFile);
+ // TODO: or else implement introspection
+ } else {
+ componentType = loadFromSidefile(resource, deploymentContext);
+ }
+ implementation.setComponentType(componentType);
+ }
+
+ protected EasyComponentType loadFromSidefile(URL url, DeploymentContext deploymentContext) throws LoaderException {
+ ComponentType ct = loaderRegistry.load(null, null, url, ComponentType.class, deploymentContext);
+ EasyComponentType scriptComponentType = new EasyComponentType(ct);
+ return scriptComponentType;
+ }
+
+ protected String getSideFileName(String resourceName) {
+ int lastDot = resourceName.lastIndexOf('.');
+ if (lastDot != -1) {
+ resourceName = resourceName.substring(0, lastDot);
+ }
+ return resourceName + ".componentType";
+ }
+
+}
diff --git a/sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyImplementation.java b/sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyImplementation.java
new file mode 100644
index 0000000000..891838d1c6
--- /dev/null
+++ b/sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyImplementation.java
@@ -0,0 +1,47 @@
+/*
+ * 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.easy;
+
+import org.apache.tuscany.spi.model.AtomicImplementation;
+
+/**
+ * Model object for a script implementation.
+ */
+public class EasyImplementation extends AtomicImplementation<EasyComponentType> {
+
+ private String resourceName;
+
+ private EasyInstanceFactory scriptInstanceFactory;
+
+ public String getResourceName() {
+ return resourceName;
+ }
+
+ public void setResourceName(String resourceName) {
+ this.resourceName = resourceName;
+ }
+
+ public EasyInstanceFactory getScriptInstanceFactory() {
+ return scriptInstanceFactory;
+ }
+
+ public void setScriptInstanceFactory(EasyInstanceFactory scriptInstanceFactory) {
+ this.scriptInstanceFactory = scriptInstanceFactory;
+ }
+}
diff --git a/sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyImplementationLoader.java b/sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyImplementationLoader.java
new file mode 100644
index 0000000000..79d38f1f35
--- /dev/null
+++ b/sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyImplementationLoader.java
@@ -0,0 +1,85 @@
+/*
+ * 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.easy;
+
+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 org.apache.tuscany.spi.annotation.Autowire;
+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.MissingResourceException;
+import org.osoa.sca.annotations.Constructor;
+
+/**
+ * Loader for handling implementation.script elements.
+ *
+ * <implementation.script script="path/foo.py" class="myclass">
+ *
+ */
+public abstract class EasyImplementationLoader extends LoaderExtension<EasyImplementation> {
+
+ @Constructor( { "registry" })
+ public EasyImplementationLoader(@Autowire LoaderRegistry registry) {
+ super(registry);
+ }
+
+ public abstract QName getXMLType();
+
+ 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/sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyInstance.java b/sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyInstance.java
new file mode 100644
index 0000000000..8e80103f04
--- /dev/null
+++ b/sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyInstance.java
@@ -0,0 +1,31 @@
+/*
+ * 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.easy;
+
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * An invokable instance of a script
+ *
+ * Basically just a wrapper around a BSF engine with an optional script class object.
+ */
+public interface EasyInstance {
+
+ public Object invokeTarget(String operationName, Object[] args) throws InvocationTargetException;
+}
diff --git a/sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyInstanceFactory.java b/sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyInstanceFactory.java
new file mode 100644
index 0000000000..403eeb6daf
--- /dev/null
+++ b/sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyInstanceFactory.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.easy;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * ScriptInstanceFactory creates ScriptInstances for a script
+ */
+public abstract class EasyInstanceFactory<T extends EasyInstance> {
+
+ protected String resourceName;
+
+ protected ClassLoader classLoader;
+
+ public EasyInstanceFactory(String resourceName, ClassLoader classLoader) {
+ this.resourceName = resourceName;
+ this.classLoader = classLoader;
+ }
+
+ /**
+ * Create a new invokeable instance of the script
+ * @param services
+ *
+ * @param context
+ * objects to add to scope of the script instance
+ * @return a RhinoScriptInstance
+ * TODO: services should be on the constructor not on this method
+ */
+ public abstract T createInstance(List<Class> services, Map<String, Object> context);
+
+ public String getResourceName() {
+ return resourceName;
+ }
+
+ public ClassLoader getClassLoader() {
+ return classLoader;
+ }
+
+ protected Map<String, Class> getResponseClasses(List<Class> services) {
+ Map<String, Class> responseClasses = new HashMap<String, Class>();
+ if (services != null) {
+ for (Class s : services) {
+ for (Method m : s.getMethods()) {
+ responseClasses.put(m.getName(), m.getReturnType());
+ }
+ }
+ }
+ return responseClasses;
+ }
+
+}
diff --git a/sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyInvoker.java b/sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyInvoker.java
new file mode 100644
index 0000000000..37ba4c5c2d
--- /dev/null
+++ b/sandbox/ant/container.easy/src/main/java/org/apache/tuscany/container/easy/EasyInvoker.java
@@ -0,0 +1,53 @@
+/*
+ * 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.easy;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.apache.tuscany.spi.extension.TargetInvokerExtension;
+
+/**
+ * TargetInvoker that calls a function on a ScriptInstance
+ */
+public class EasyInvoker extends TargetInvokerExtension {
+
+ protected EasyComponent component;
+
+ protected String functionName;
+
+ public EasyInvoker(String functionName, EasyComponent component) {
+ this.functionName = functionName;
+ this.component = component;
+ }
+
+ /**
+ * Invoke the function
+ */
+ public Object invokeTarget(final Object payload) throws InvocationTargetException {
+ EasyInstance target = (EasyInstance) component.getTargetInstance();
+ try {
+
+ return target.invokeTarget(functionName, (Object[]) payload);
+
+ } catch (Exception e) {
+ throw new InvocationTargetException(e);
+ }
+ }
+
+}