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 /sandbox/rfeng/minicore/src/main/java/org |
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 'sandbox/rfeng/minicore/src/main/java/org')
116 files changed, 11535 insertions, 0 deletions
diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/binding/local/AbstractLocalTargetInvoker.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/binding/local/AbstractLocalTargetInvoker.java new file mode 100644 index 0000000000..4a06bc8c74 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/binding/local/AbstractLocalTargetInvoker.java @@ -0,0 +1,78 @@ +/* + * 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.core.binding.local; + +import java.lang.reflect.InvocationTargetException; + +import org.apache.tuscany.spi.wire.Interceptor; +import org.apache.tuscany.spi.wire.InvocationChain; +import org.apache.tuscany.spi.wire.InvocationRuntimeException; +import org.apache.tuscany.spi.wire.Message; +import org.apache.tuscany.spi.wire.TargetInvoker; +import org.apache.tuscany.spi.component.WorkContext; + +/** + * Base class for dispatching to a composite reference using the local binding + * + * @version $Rev$ $Date$ + */ +public abstract class AbstractLocalTargetInvoker implements TargetInvoker { + protected boolean cacheable; + + public boolean isCacheable() { + return cacheable; + } + + public void setCacheable(boolean cacheable) { + this.cacheable = cacheable; + } + + public boolean isOptimizable() { + return isCacheable(); // we only need to check if the scopes are correct + } + + public Object invokeTarget(final Object payload, short sequence, WorkContext workContext) throws InvocationTargetException { + throw new InvocationTargetException(new UnsupportedOperationException()); + } + + protected Message invoke(InvocationChain chain, TargetInvoker invoker, Message msg) throws Throwable { + Interceptor headInterceptor = chain.getHeadInterceptor(); + if (headInterceptor == null) { + try { + // short-circuit the dispatch and invoke the target directly + if (invoker == null) { + String name = chain.getOperation().getName(); + throw new AssertionError("No target invoker [" + name + "]"); + } + return invoker.invoke(msg); + } catch (InvocationRuntimeException e) { + // the cause was thrown by the target so throw it + throw e.getCause(); + } + } else { + msg.setTargetInvoker(invoker); + return headInterceptor.invoke(msg); + } + } + + @Override + public AbstractLocalTargetInvoker clone() throws CloneNotSupportedException { + return (AbstractLocalTargetInvoker) super.clone(); + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/binding/local/LocalBindingBuilder.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/binding/local/LocalBindingBuilder.java new file mode 100644 index 0000000000..63a9147b29 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/binding/local/LocalBindingBuilder.java @@ -0,0 +1,52 @@ +/* + * 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.core.binding.local; + +import org.apache.tuscany.spi.builder.BuilderException; +import org.apache.tuscany.spi.component.ReferenceBinding; +import org.apache.tuscany.spi.component.ServiceBinding; +import org.apache.tuscany.spi.deployer.DeploymentContext; +import org.apache.tuscany.spi.extension.BindingBuilderExtension; +import org.apache.tuscany.spi.model.ReferenceDefinition; +import org.apache.tuscany.spi.model.ServiceDefinition; + +/** + * Creates runtime artifacts for the local binding + * + * @version $Rev$ $Date$ + */ +public class LocalBindingBuilder extends BindingBuilderExtension<LocalBindingDefinition> { + + protected Class<LocalBindingDefinition> getBindingType() { + return LocalBindingDefinition.class; + } + + public ServiceBinding build(ServiceDefinition serviceDefinition, + LocalBindingDefinition bindingDefinition, + DeploymentContext context) throws BuilderException { + return new LocalServiceBinding(serviceDefinition.getUri()); + } + + + public ReferenceBinding build(ReferenceDefinition referenceDefinition, + LocalBindingDefinition bindingDefinition, + DeploymentContext context) throws BuilderException { + return new LocalReferenceBinding(referenceDefinition.getUri(), bindingDefinition.getTargetUri()); + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/binding/local/LocalBindingDefinition.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/binding/local/LocalBindingDefinition.java new file mode 100644 index 0000000000..9317a47457 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/binding/local/LocalBindingDefinition.java @@ -0,0 +1,39 @@ +/* + * 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.core.binding.local; + +import java.net.URI; + +import org.apache.tuscany.spi.model.BindingDefinition; + + +/** + * Represents the local by-reference binding + * + * @version $Rev$ $Date$ + */ +public class LocalBindingDefinition extends BindingDefinition { + + public LocalBindingDefinition() { + } + + public LocalBindingDefinition(URI targetUri) { + super(targetUri); + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/binding/local/LocalBindingLoader.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/binding/local/LocalBindingLoader.java new file mode 100644 index 0000000000..3442f1ca4c --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/binding/local/LocalBindingLoader.java @@ -0,0 +1,70 @@ +/* + * 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.core.binding.local; + +import java.net.URI; +import java.net.URISyntaxException; +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import org.osoa.sca.annotations.Reference; + +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.model.ModelObject; +import org.apache.tuscany.spi.wire.Wire; + +/** + * Loader responsible for handling the local binding + * + * @version $Rev$ $Date$ + */ +public class LocalBindingLoader extends LoaderExtension<LocalBindingDefinition> { + + /** + * Constructor specifies the registry to register with. + * + * @param registry the LoaderRegistry this loader should register with + */ + public LocalBindingLoader(@Reference LoaderRegistry registry) { + super(registry); + } + + public QName getXMLType() { + return Wire.LOCAL_BINDING; + } + + public LocalBindingDefinition load( + ModelObject object, + XMLStreamReader reader, + DeploymentContext deploymentContext) throws XMLStreamException, LoaderException { + String uri = reader.getAttributeValue(null, "uri"); + if (uri != null) { + try { + return new LocalBindingDefinition(new URI(uri)); + } catch (URISyntaxException e) { + throw new LoaderException(e); + } + } + return new LocalBindingDefinition(); + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/binding/local/LocalCallbackTargetInvoker.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/binding/local/LocalCallbackTargetInvoker.java new file mode 100644 index 0000000000..c505ee99ab --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/binding/local/LocalCallbackTargetInvoker.java @@ -0,0 +1,69 @@ +/* + * 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.core.binding.local; + +import java.util.Map; + +import org.apache.tuscany.spi.model.Operation; +import org.apache.tuscany.spi.wire.InvocationChain; +import org.apache.tuscany.spi.wire.InvocationRuntimeException; +import org.apache.tuscany.spi.wire.Message; +import org.apache.tuscany.spi.wire.MessageImpl; +import org.apache.tuscany.spi.wire.TargetInvoker; +import org.apache.tuscany.spi.wire.Wire; + +/** + * Dispatches a callback invocation to the callback instance + * + * @version $Rev$ $Date$ + */ +public class LocalCallbackTargetInvoker extends AbstractLocalTargetInvoker { + private Operation operation; + private Wire wire; + + public LocalCallbackTargetInvoker(Operation operation, Wire wire) { + assert operation != null : "Operation method cannot be null"; + this.operation = operation; + this.wire = wire; + } + + public Message invoke(Message msg) throws InvocationRuntimeException { + try { + return invoke(operation, msg); + } catch (Throwable e) { + Message faultMsg = new MessageImpl(); + faultMsg.setBodyWithFault(e); + return faultMsg; + } + } + + private Message invoke(Operation operation, Message msg) throws Throwable { + //TODO optimize as this is slow in local invocations + Map<Operation<?>, InvocationChain> chains = wire.getCallbackInvocationChains(); + InvocationChain chain = chains.get(operation); + TargetInvoker invoker = chain.getTargetInvoker(); + return invoke(chain, invoker, msg); + } + + @Override + public LocalCallbackTargetInvoker clone() throws CloneNotSupportedException { + return (LocalCallbackTargetInvoker) super.clone(); + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/binding/local/LocalReferenceBinding.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/binding/local/LocalReferenceBinding.java new file mode 100644 index 0000000000..b70df0e23a --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/binding/local/LocalReferenceBinding.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.core.binding.local; + +import java.net.URI; +import javax.xml.namespace.QName; + +import org.apache.tuscany.spi.CoreRuntimeException; +import org.apache.tuscany.spi.component.TargetInvokerCreationException; +import org.apache.tuscany.spi.extension.ReferenceBindingExtension; +import org.apache.tuscany.spi.model.Operation; +import org.apache.tuscany.spi.model.physical.PhysicalOperationDefinition; +import org.apache.tuscany.spi.wire.TargetInvoker; +import org.apache.tuscany.spi.wire.Wire; + +/** + * The runtime representaion of the local reference binding + * + * @version $Rev$ $Date$ + * @Deprecated + */ +public class LocalReferenceBinding extends ReferenceBindingExtension { + + public LocalReferenceBinding(URI name, URI targetUri) throws CoreRuntimeException { + super(name, targetUri); + } + + public QName getBindingType() { + return Wire.LOCAL_BINDING; + } + + public TargetInvoker createTargetInvoker(String name, Operation operation) + throws TargetInvokerCreationException { + if (operation.isCallback()) { + return new LocalCallbackTargetInvoker(operation, wire); + } else { + return new LocalTargetInvoker(operation, wire); + } + } + + public TargetInvoker createTargetInvoker(String targetName, PhysicalOperationDefinition operation) + throws TargetInvokerCreationException { + return null; + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/binding/local/LocalServiceBinding.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/binding/local/LocalServiceBinding.java new file mode 100644 index 0000000000..543a0f53b4 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/binding/local/LocalServiceBinding.java @@ -0,0 +1,60 @@ +/* + * 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.core.binding.local; + +import java.net.URI; +import javax.xml.namespace.QName; + +import org.apache.tuscany.spi.CoreRuntimeException; +import org.apache.tuscany.spi.component.TargetInvokerCreationException; +import org.apache.tuscany.spi.extension.ServiceBindingExtension; +import org.apache.tuscany.spi.model.Operation; +import org.apache.tuscany.spi.model.physical.PhysicalOperationDefinition; +import org.apache.tuscany.spi.wire.TargetInvoker; +import org.apache.tuscany.spi.wire.Wire; + +/** + * The runtime representaion of the local service binding + * + * @version $Rev$ $Date$ + */ +public class LocalServiceBinding extends ServiceBindingExtension { + + public LocalServiceBinding(URI name) throws CoreRuntimeException { + super(name); + } + + public QName getBindingType() { + return Wire.LOCAL_BINDING; + } + + public TargetInvoker createTargetInvoker(String name, Operation operation) + throws TargetInvokerCreationException { + if (operation.isCallback()) { + return new LocalCallbackTargetInvoker(operation, getWire()); + } else { + return new LocalTargetInvoker(operation, getWire()); + } + } + + public TargetInvoker createTargetInvoker(String targetName, PhysicalOperationDefinition operation) + throws TargetInvokerCreationException { + return null; + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/binding/local/LocalTargetInvoker.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/binding/local/LocalTargetInvoker.java new file mode 100644 index 0000000000..b89a70a9e0 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/binding/local/LocalTargetInvoker.java @@ -0,0 +1,79 @@ +/* + * 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.core.binding.local; + +import java.net.URI; + +import org.apache.tuscany.spi.model.Operation; +import org.apache.tuscany.spi.util.UriHelper; +import org.apache.tuscany.spi.wire.InvocationChain; +import org.apache.tuscany.spi.wire.InvocationRuntimeException; +import org.apache.tuscany.spi.wire.Message; +import org.apache.tuscany.spi.wire.MessageImpl; +import org.apache.tuscany.spi.wire.TargetInvoker; +import org.apache.tuscany.spi.wire.Wire; + +/** + * Dispatches an invocation through a composite service or reference using the local binding + * + * @version $Rev$ $Date$ + */ +public class LocalTargetInvoker extends AbstractLocalTargetInvoker { + private InvocationChain chain; + private URI fromAddress; + private boolean contractHasCallback; + + public LocalTargetInvoker(Operation operation, Wire wire) { + assert operation != null; + chain = wire.getInvocationChains().get(operation); + assert chain != null; + if (wire.getSourceUri() != null) { + fromAddress = URI.create(UriHelper.getBaseName(wire.getSourceUri())); + } + contractHasCallback = !wire.getCallbackInvocationChains().isEmpty(); + } + + @Override + public LocalTargetInvoker clone() throws CloneNotSupportedException { + return (LocalTargetInvoker) super.clone(); + } + + public Message invoke(Message msg) throws InvocationRuntimeException { + try { + TargetInvoker invoker = chain.getTargetInvoker(); + assert invoker != null; + // Pushing the from address only needs to happen in the outbound (forward) direction for callbacks + if (contractHasCallback) { + //JFM do we need this? + msg.pushCallbackUri(fromAddress); + } + + return invoke(chain, invoker, msg); + } catch (Throwable e) { + Message faultMsg = new MessageImpl(); + faultMsg.setBodyWithFault(e); + return faultMsg; + } + } + + + public boolean isOptimizable() { + return true; + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/bootstrap/Bootstrapper.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/bootstrap/Bootstrapper.java new file mode 100644 index 0000000000..a52e8e2f83 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/bootstrap/Bootstrapper.java @@ -0,0 +1,75 @@ +/* + * 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.core.bootstrap; + +import org.apache.tuscany.core.resolver.AutowireResolver; +import org.apache.tuscany.host.MonitorFactory; +import org.apache.tuscany.spi.builder.Connector; +import org.apache.tuscany.spi.component.ComponentManager; +import org.apache.tuscany.spi.component.ScopeRegistry; +import org.apache.tuscany.spi.deployer.Deployer; + +/** + * Interface that abstracts the process used to create a running Tuscany system. Implementation of this may provide + * different mechanisms for creating the primoridal system components used to boot the core to the level where it can + * support end-user applications. + * + * @version $Rev$ $Date$ + */ +public interface Bootstrapper { + /** + * Return the MonitorFactory being used by the implementation to provide monitor interfaces for the primordial + * components. + * + * @return the MonitorFactory being used by the bootstrapper + */ + MonitorFactory getMonitorFactory(); + + /** + * Create a Deployer that can be used to deploy the system definition. This will most likely only support a small + * subset of the available programming model. + * + * @return a new primordial Deployer + */ + Deployer createDeployer(); + + /** + * Create a ScopeRegistry that supports the Scopes supported for primordial components + * + * @return a new primordial ScopeRegistry + */ + ScopeRegistry getScopeRegistry(); + + /** + * Create a Connector that can wire together primordial components. + * + * @return a new primordial Connector + */ + Connector getConnector(); + + /** + * Returns the AutowireResolver that resolves autowire targets + * + * @return the AutowireResolver that resolves autowire targets + */ + AutowireResolver getAutowireResolver(); + + ComponentManager getComponentManager(); + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/bootstrap/DefaultBootstrapper.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/bootstrap/DefaultBootstrapper.java new file mode 100644 index 0000000000..db6cba72f9 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/bootstrap/DefaultBootstrapper.java @@ -0,0 +1,224 @@ +/* + * 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.core.bootstrap; + +import javax.xml.stream.XMLInputFactory; + +import org.apache.tuscany.core.binding.local.LocalBindingBuilder; +import org.apache.tuscany.core.binding.local.LocalBindingDefinition; +import org.apache.tuscany.core.binding.local.LocalBindingLoader; +import org.apache.tuscany.core.builder.BuilderRegistryImpl; +import org.apache.tuscany.core.component.scope.AbstractScopeContainer; +import org.apache.tuscany.core.component.scope.CompositeScopeContainer; +import org.apache.tuscany.core.component.scope.RequestScopeContainer; +import org.apache.tuscany.core.component.scope.ScopeRegistryImpl; +import org.apache.tuscany.core.component.scope.StatelessScopeContainer; +import org.apache.tuscany.core.deployer.DeployerImpl; +import org.apache.tuscany.core.implementation.composite.CompositeBuilder; +import org.apache.tuscany.core.implementation.composite.CompositeComponentTypeLoader; +import org.apache.tuscany.core.implementation.composite.CompositeLoader; +import org.apache.tuscany.core.loader.ComponentLoader; +import org.apache.tuscany.core.loader.ComponentTypeElementLoader; +import org.apache.tuscany.core.loader.IncludeLoader; +import org.apache.tuscany.core.loader.LoaderRegistryImpl; +import org.apache.tuscany.core.loader.PropertyLoader; +import org.apache.tuscany.core.loader.ReferenceLoader; +import org.apache.tuscany.core.loader.ServiceLoader; +import org.apache.tuscany.core.resolver.AutowireResolver; +import org.apache.tuscany.host.MonitorFactory; +import org.apache.tuscany.spi.builder.Builder; +import org.apache.tuscany.spi.builder.Connector; +import org.apache.tuscany.spi.component.ComponentManager; +import org.apache.tuscany.spi.component.ScopeContainerMonitor; +import org.apache.tuscany.spi.component.ScopeRegistry; +import org.apache.tuscany.spi.deployer.Deployer; +import org.apache.tuscany.spi.extension.LoaderExtension; +import org.apache.tuscany.spi.implementation.java.Introspector; +import org.apache.tuscany.spi.loader.Loader; +import org.apache.tuscany.spi.loader.LoaderRegistry; +import org.apache.tuscany.spi.loader.PropertyObjectFactory; +import org.apache.tuscany.spi.model.CompositeImplementation; + +/** + * A default implementation of a Bootstrapper. Please see the documentation on + * the individual methods for how the primordial components are created. + * + * @version $Rev$ $Date$ + */ +public class DefaultBootstrapper implements Bootstrapper { + private final MonitorFactory monitorFactory; + private final XMLInputFactory xmlFactory; + private final ComponentManager componentManager; + private final AutowireResolver resolver; + private final Connector connector; + private final ScopeRegistry scopeRegistry; + + /** + * Create a default bootstrapper. + * + * @param monitorFactory the MonitorFactory to be used to create monitors + * for the primordial components + * @param xmlFactory the XMLInputFactory to be used by the components to + * load XML artifacts + * @param componentManager the component manager for the runtime instance + * @param resolver the autowire resolver for the runtime instance + * @param connector the connector for the runtime instance + */ + public DefaultBootstrapper(MonitorFactory monitorFactory, + XMLInputFactory xmlFactory, + ComponentManager componentManager, + AutowireResolver resolver, + Connector connector) { + this.monitorFactory = monitorFactory; + this.xmlFactory = xmlFactory; + this.componentManager = componentManager; + this.resolver = resolver; + this.connector = connector; + this.scopeRegistry = createScopeRegistry(); + } + + /** + * Returns the MonitorFactory being used by this bootstrapper. + * + * @return the MonitorFactory being used by this bootstrapper + */ + public MonitorFactory getMonitorFactory() { + return monitorFactory; + } + + /** + * Create primordial deployer that can be used to load the system + * definition. + * + * @return the primordial deployer + */ + public Deployer createDeployer() { + ScopeRegistry scopeRegistry = getScopeRegistry(); + Builder builder = createBuilder(scopeRegistry); + Loader loader = createLoader(null, null); + DeployerImpl deployer = new DeployerImpl(xmlFactory, loader, builder, componentManager, resolver, connector); + deployer.setMonitor(getMonitorFactory().getMonitor(ScopeContainerMonitor.class)); + deployer.setScopeRegistry(getScopeRegistry()); + return deployer; + } + + /** + * Create a basic ScopeRegistry containing the ScopeContainers that are + * available to components in the system definition. The implementation + * returned only support COMPOSITE scope. + * + * @return a new ScopeRegistry + */ + private ScopeRegistry createScopeRegistry() { + ScopeRegistry scopeRegistry = new ScopeRegistryImpl(); + ScopeContainerMonitor monitor = monitorFactory.getMonitor(ScopeContainerMonitor.class); + AbstractScopeContainer[] containers = new AbstractScopeContainer[] {new CompositeScopeContainer(monitor), + new StatelessScopeContainer(monitor), + new RequestScopeContainer(monitor), + // new ConversationalScopeContainer(monitor), + // new HttpSessionScopeContainer(monitor) + }; + for (AbstractScopeContainer c : containers) { + c.start(); + scopeRegistry.register(c); + } + + return scopeRegistry; + } + + /** + * Create a new Connector that can be used to wire primordial components + * together. + * + * @return a new Connector + */ + public Connector getConnector() { + return connector; + } + + public AutowireResolver getAutowireResolver() { + return resolver; + } + + /** + * Helper method for registering a loader with the registry. The Loader is + * registered once for the QName returned by its + * {@link LoaderExtension#getXMLType()} method. + * + * @param registry the LoaderRegistry to register with + * @param loader the Loader to register + */ + protected void registerLoader(LoaderRegistry registry, LoaderExtension<?> loader) { + registry.registerLoader(loader.getXMLType(), loader); + } + + public LoaderRegistry createLoader(PropertyObjectFactory propertyFactory, Introspector introspector) { + LoaderRegistryImpl loaderRegistry = new LoaderRegistryImpl(monitorFactory + .getMonitor(LoaderRegistryImpl.Monitor.class)); + + // register element loaders + registerLoader(loaderRegistry, new ComponentLoader(loaderRegistry, propertyFactory)); + registerLoader(loaderRegistry, new ComponentTypeElementLoader(loaderRegistry)); + registerLoader(loaderRegistry, new CompositeLoader(loaderRegistry, null)); + registerLoader(loaderRegistry, new IncludeLoader(loaderRegistry)); + registerLoader(loaderRegistry, new PropertyLoader(loaderRegistry)); + registerLoader(loaderRegistry, new ReferenceLoader(loaderRegistry)); + registerLoader(loaderRegistry, new ServiceLoader(loaderRegistry)); + registerLoader(loaderRegistry, new LocalBindingLoader(loaderRegistry)); + + loaderRegistry.registerLoader(CompositeImplementation.class, new CompositeComponentTypeLoader(loaderRegistry)); + return loaderRegistry; + } + + /** + * Create a Builder that can be used to build the components in the system + * definition. The default implementation only supports implementations from + * the system programming model. + * + * @param scopeRegistry the ScopeRegistry defining the component scopes that + * will be supported + * @return a new Builder + */ + private Builder createBuilder(ScopeRegistry scopeRegistry) { + BuilderRegistryImpl builderRegistry = new BuilderRegistryImpl(scopeRegistry); + CompositeBuilder compositeBuilder = new CompositeBuilder(); + compositeBuilder.setBuilderRegistry(builderRegistry); + compositeBuilder.setScopeRegistry(scopeRegistry); + compositeBuilder.init(); + // builderRegistry.register(CompositeImplementation.class, + // compositeBuilder); + builderRegistry.register(LocalBindingDefinition.class, new LocalBindingBuilder()); + return builderRegistry; + } + + /** + * @return the componentManager + */ + public ComponentManager getComponentManager() { + return componentManager; + } + + /** + * @return the scopeRegistry + */ + public ScopeRegistry getScopeRegistry() { + return scopeRegistry; + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/bootstrap/ExtensionActivator.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/bootstrap/ExtensionActivator.java new file mode 100644 index 0000000000..92f526dd8b --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/bootstrap/ExtensionActivator.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.core.bootstrap; + +import org.apache.tuscany.spi.builder.BuilderRegistry; +import org.apache.tuscany.spi.loader.LoaderRegistry; + +/** + * @version $Rev$ $Date$ + */ +public interface ExtensionActivator { + void start(LoaderRegistry loaderRegistry, BuilderRegistry builderRegistry); + void stop(); +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/BuilderRegistryImpl.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/BuilderRegistryImpl.java new file mode 100644 index 0000000000..33dd2175f9 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/BuilderRegistryImpl.java @@ -0,0 +1,185 @@ +/* + * 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.core.builder; + +import java.net.URI; +import java.util.HashMap; +import java.util.Map; + +import org.osoa.sca.annotations.EagerInit; + +import org.apache.tuscany.spi.builder.BindingBuilder; +import org.apache.tuscany.spi.builder.BuilderException; +import org.apache.tuscany.spi.builder.BuilderRegistry; +import org.apache.tuscany.spi.builder.ComponentBuilder; +import org.apache.tuscany.spi.builder.ScopeNotFoundException; +import org.apache.tuscany.spi.component.Component; +import org.apache.tuscany.spi.component.Reference; +import org.apache.tuscany.spi.component.ReferenceBinding; +import org.apache.tuscany.spi.component.ScopeContainer; +import org.apache.tuscany.spi.component.ScopeRegistry; +import org.apache.tuscany.spi.component.Service; +import org.apache.tuscany.spi.component.ServiceBinding; +import org.apache.tuscany.spi.deployer.DeploymentContext; +import org.apache.tuscany.spi.model.BindingDefinition; +import org.apache.tuscany.spi.model.ComponentDefinition; +import org.apache.tuscany.spi.model.ComponentType; +import org.apache.tuscany.spi.model.Implementation; +import org.apache.tuscany.spi.model.ReferenceDefinition; +import org.apache.tuscany.spi.model.Scope; +import org.apache.tuscany.spi.model.ServiceContract; +import org.apache.tuscany.spi.model.ServiceDefinition; + +import org.apache.tuscany.core.binding.local.LocalBindingDefinition; +import org.apache.tuscany.core.implementation.composite.ReferenceImpl; +import org.apache.tuscany.core.implementation.composite.ServiceImpl; + +/** + * The default builder registry in the runtime + * + * @version $Rev$ $Date$ + */ +@EagerInit +public class BuilderRegistryImpl implements BuilderRegistry { + private ScopeRegistry scopeRegistry; + + private final Map<Class<? extends Implementation<?>>, ComponentBuilder<? extends Implementation<?>>> componentBuilders = + new HashMap<Class<? extends Implementation<?>>, ComponentBuilder<? extends Implementation<?>>>(); + private final Map<Class<? extends BindingDefinition>, BindingBuilder<? extends BindingDefinition>> bindingBuilders = + new HashMap<Class<? extends BindingDefinition>, BindingBuilder<? extends BindingDefinition>>(); + + public BuilderRegistryImpl(@org.osoa.sca.annotations.Reference ScopeRegistry scopeRegistry) { + this.scopeRegistry = scopeRegistry; + } + + public <I extends Implementation<?>> void register(Class<I> implClass, ComponentBuilder<I> builder) { + componentBuilders.put(implClass, builder); + } + + public <I extends Implementation<?>> void unregister(Class<I> implClass) { + componentBuilders.remove(implClass); + } + + public <B extends BindingDefinition> void register(Class<B> implClass, BindingBuilder<B> builder) { + bindingBuilders.put(implClass, builder); + } + + @SuppressWarnings("unchecked") + public <I extends Implementation<?>> Component build( + ComponentDefinition<I> componentDefinition, + DeploymentContext context) throws BuilderException { + Class<?> implClass = componentDefinition.getImplementation().getClass(); + // noinspection SuspiciousMethodCalls + ComponentBuilder<I> componentBuilder = (ComponentBuilder<I>) componentBuilders.get(implClass); + if (componentBuilder == null) { + String name = implClass.getName(); + throw new NoRegisteredBuilderException("No builder registered for implementation", name); + } + Component component = componentBuilder.build(componentDefinition, context); + assert component != null; + component.setDefaultPropertyValues(componentDefinition.getPropertyValues()); + Scope scope = componentDefinition.getImplementation().getComponentType().getImplementationScope(); + if (scope == Scope.SYSTEM || scope == Scope.COMPOSITE) { + component.setScopeContainer(context.getCompositeScope()); + } else { + // Check for conversational contract if conversational scope + if (scope == Scope.CONVERSATION) { + boolean hasConversationalContract = false; + ComponentType<ServiceDefinition, ReferenceDefinition, ?> componentType = + componentDefinition.getImplementation().getComponentType(); + Map<String, ServiceDefinition> services = componentType.getServices(); + for (ServiceDefinition serviceDef : services.values()) { + ServiceContract<?> contract = serviceDef.getServiceContract(); + if (contract.isConversational()) { + hasConversationalContract = true; + break; + } + } + if (!hasConversationalContract) { + String name = implClass.getName(); + throw new NoConversationalContractException( + "No conversational contract for conversational implementation", name); + } + } + // Now it's ok to set the scope container + ScopeContainer scopeContainer = scopeRegistry.getScopeContainer(scope); + if (scopeContainer == null) { + throw new ScopeNotFoundException(scope.toString()); + } + component.setScopeContainer(scopeContainer); + } + context.getComponents().put(component.getUri(), component); + ComponentType<?, ?, ?> componentType = componentDefinition.getImplementation().getComponentType(); + assert componentType != null : "Component type must be set"; + return component; + } + + @SuppressWarnings({"unchecked"}) + public Service build(ServiceDefinition serviceDefinition, DeploymentContext context) throws BuilderException { + URI uri = serviceDefinition.getUri(); + ServiceContract<?> serviceContract = serviceDefinition.getServiceContract(); + if (serviceDefinition.getBindings().isEmpty()) { + // if no bindings are configured, default to the local binding. + // this should be changed to allow runtime selection + if (serviceDefinition.getBindings().isEmpty()) { + // TODO JFM implement capability for the runtime to choose a binding + serviceDefinition.addBinding(new LocalBindingDefinition()); + } + } + URI targetUri = serviceDefinition.getTarget(); + Service service = new ServiceImpl(uri, serviceContract, targetUri); + for (BindingDefinition definition : serviceDefinition.getBindings()) { + Class<?> bindingClass = definition.getClass(); + // noinspection SuspiciousMethodCalls + BindingBuilder bindingBuilder = bindingBuilders.get(bindingClass); + if (bindingBuilder == null) { + throw new NoRegisteredBuilderException("No builder registered for type", bindingClass.getName()); + } + ServiceBinding binding = bindingBuilder.build(serviceDefinition, definition, context); + service.addServiceBinding(binding); + } + return service; + } + + @SuppressWarnings("unchecked") + public Reference build(ReferenceDefinition referenceDefinition, DeploymentContext context) throws BuilderException { + URI uri = referenceDefinition.getUri(); + ServiceContract<?> contract = referenceDefinition.getServiceContract(); + if (referenceDefinition.getBindings().isEmpty()) { + // if no bindings are configured, default to the local binding. + // this should be changed to allow runtime selection + if (referenceDefinition.getBindings().isEmpty()) { + // TODO JFM implement capability for the runtime to choose a binding + referenceDefinition.addBinding(new LocalBindingDefinition()); + } + } + + Reference reference = new ReferenceImpl(uri, contract); + for (BindingDefinition bindingDefinition : referenceDefinition.getBindings()) { + Class<?> bindingClass = bindingDefinition.getClass(); + // noinspection SuspiciousMethodCalls + BindingBuilder bindingBuilder = bindingBuilders.get(bindingClass); + ReferenceBinding binding = bindingBuilder.build(referenceDefinition, bindingDefinition, context); + reference.addReferenceBinding(binding); + + } + return reference; + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/ComponentNotFoundException.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/ComponentNotFoundException.java new file mode 100644 index 0000000000..a46e038cb9 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/ComponentNotFoundException.java @@ -0,0 +1,36 @@ +/* + * 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.core.builder; + +import java.net.URI; + +import org.apache.tuscany.spi.builder.WiringException; + +/** + * Indicates a component was not found during wiring + * + * @version $Rev$ $Date$ + */ +public class ComponentNotFoundException extends WiringException { + + public ComponentNotFoundException(String message, URI name) { + super(message, name, name); + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/ConnectorImpl.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/ConnectorImpl.java new file mode 100644 index 0000000000..6923fb6837 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/ConnectorImpl.java @@ -0,0 +1,385 @@ +/* + * 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.core.builder; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import javax.xml.namespace.QName; + +import org.osoa.sca.annotations.Constructor; + +import org.apache.tuscany.spi.builder.BuilderException; +import org.apache.tuscany.spi.builder.Connector; +import org.apache.tuscany.spi.builder.WiringException; +import org.apache.tuscany.spi.builder.interceptor.InterceptorBuilderRegistry; +import org.apache.tuscany.spi.builder.physical.WireAttacherRegistry; +import org.apache.tuscany.spi.component.AtomicComponent; +import org.apache.tuscany.spi.component.Component; +import org.apache.tuscany.spi.component.ComponentManager; +import org.apache.tuscany.spi.component.Invocable; +import org.apache.tuscany.spi.component.Reference; +import org.apache.tuscany.spi.component.ReferenceBinding; +import org.apache.tuscany.spi.component.Service; +import org.apache.tuscany.spi.component.ServiceBinding; +import org.apache.tuscany.spi.component.TargetInvokerCreationException; +import org.apache.tuscany.spi.component.WorkContext; +import org.apache.tuscany.spi.model.ComponentDefinition; +import org.apache.tuscany.spi.model.ComponentType; +import org.apache.tuscany.spi.model.CompositeComponentType; +import org.apache.tuscany.spi.model.Implementation; +import org.apache.tuscany.spi.model.Operation; +import org.apache.tuscany.spi.model.ReferenceDefinition; +import org.apache.tuscany.spi.model.ReferenceTarget; +import org.apache.tuscany.spi.model.Scope; +import org.apache.tuscany.spi.model.ServiceContract; +import org.apache.tuscany.spi.model.ServiceDefinition; +import org.apache.tuscany.spi.model.physical.PhysicalInterceptorDefinition; +import org.apache.tuscany.spi.model.physical.PhysicalOperationDefinition; +import org.apache.tuscany.spi.model.physical.PhysicalWireDefinition; +import org.apache.tuscany.spi.model.physical.PhysicalWireSourceDefinition; +import org.apache.tuscany.spi.model.physical.PhysicalWireTargetDefinition; +import org.apache.tuscany.spi.services.work.WorkScheduler; +import org.apache.tuscany.spi.util.UriHelper; +import org.apache.tuscany.spi.wire.Interceptor; +import org.apache.tuscany.spi.wire.InvocationChain; +import org.apache.tuscany.spi.wire.Wire; +import org.apache.tuscany.spi.wire.WirePostProcessorRegistry; + +import org.apache.tuscany.core.wire.InvocationChainImpl; +import org.apache.tuscany.core.wire.InvokerInterceptor; +import org.apache.tuscany.core.wire.NonBlockingInterceptor; +import org.apache.tuscany.core.wire.WireImpl; +import org.apache.tuscany.core.wire.WireUtils; + +/** + * The default connector implmentation + * + * @version $$Rev$$ $$Date$$ + */ +public class ConnectorImpl implements Connector { + private WirePostProcessorRegistry postProcessorRegistry; + private ComponentManager componentManager; + private WorkContext workContext; + private WorkScheduler scheduler; + private InterceptorBuilderRegistry interceptorBuilderRegistry; + private WireAttacherRegistry attacherRegistry; + + public ConnectorImpl(ComponentManager componentManager) { + this.componentManager = componentManager; + } + + @Constructor + public ConnectorImpl( + @org.osoa.sca.annotations.Reference InterceptorBuilderRegistry interceptorBuilderRegistry, + @org.osoa.sca.annotations.Reference WireAttacherRegistry attacherRegistry, + @org.osoa.sca.annotations.Reference WirePostProcessorRegistry processorRegistry, + @org.osoa.sca.annotations.Reference ComponentManager componentManager, + @org.osoa.sca.annotations.Reference WorkScheduler scheduler, + @org.osoa.sca.annotations.Reference WorkContext workContext) { + this.attacherRegistry = attacherRegistry; + this.interceptorBuilderRegistry = interceptorBuilderRegistry; + this.postProcessorRegistry = processorRegistry; + this.componentManager = componentManager; + this.scheduler = scheduler; + this.workContext = workContext; + } + + /** + * <strong>Note this method will not work yet</strong> + * <p/> + * Wires a source and target component based on a wire defintion + * + * @param definition the wire definition + * @throws WiringException + */ + public void connect(PhysicalWireDefinition definition) throws BuilderException { + URI sourceUri = definition.getSourceUri(); + assert sourceUri != null; + URI targetUri = definition.getTargetUri(); + assert targetUri != null; + URI baseSourceUri = UriHelper.getDefragmentedName(sourceUri); + URI baseTargetUri = UriHelper.getDefragmentedName(targetUri); + Component source = componentManager.getComponent(baseSourceUri); + if (source == null) { + throw new ComponentNotFoundException("Wire source component not found", baseSourceUri); + } + Wire wire = createWire(definition); + + PhysicalWireSourceDefinition sourceDefinition = definition.getSource(); + PhysicalWireTargetDefinition targetDefinition = definition.getTarget(); + Component target; + if (baseTargetUri != null) { + target = componentManager.getComponent(baseTargetUri); + if (target == null) { + throw new ComponentNotFoundException("Wire target component not found", baseTargetUri); + } + } else { + target = null; + } + attacherRegistry.attachToSource(source, sourceDefinition, target, targetDefinition, wire); + attacherRegistry.attachToTarget(source, sourceDefinition, target, targetDefinition, wire); + } + + public void connect(ComponentDefinition<? extends Implementation<?>> definition) throws WiringException { + URI sourceUri = definition.getUri(); + Component source = componentManager.getComponent(sourceUri); + if (source == null) { + throw new ComponentNotFoundException("Source not found", sourceUri); + } + ComponentType<?, ?, ?> type = definition.getImplementation().getComponentType(); + if (type instanceof CompositeComponentType) { + CompositeComponentType<?, ?, ?> compositeType = (CompositeComponentType<?, ?, ?>) type; + for (ComponentDefinition<? extends Implementation<?>> child : compositeType.getComponents().values()) { + connect(child); + } + for (ServiceDefinition child : compositeType.getServices().values()) { + connect(child); + } + for (ReferenceDefinition child : compositeType.getReferences().values()) { + connect(child); + } + } + Map<String, ReferenceTarget> targets = definition.getReferenceTargets(); + for (ReferenceTarget referenceTarget : targets.values()) { + List<Wire> wires = new ArrayList<Wire>(); + String refName = referenceTarget.getReferenceName().getFragment(); + ReferenceDefinition refDefinition = type.getReferences().get(refName); + assert refDefinition != null; + List<URI> uris = referenceTarget.getTargets(); + for (URI uri : uris) { + URI targetUri = UriHelper.getDefragmentedName(uri); + Component target = componentManager.getComponent(targetUri); + if (target == null && !refDefinition.isRequired()) { + // a non-required reference, just skip + continue; + } + if (target == null) { + throw new ComponentNotFoundException("Target not found", targetUri); + } + String fragment = uri.getFragment(); + URI sourceURI = refDefinition.getUri(); + Wire wire = createWire(sourceURI, uri, refDefinition.getServiceContract(), Wire.LOCAL_BINDING); + try { + attachInvokers(fragment, wire, source, target); + } catch (TargetInvokerCreationException e) { + throw new WireCreationException("Error creating invoker", sourceUri, targetUri, e); + } + if (postProcessorRegistry != null) { + postProcessorRegistry.process(wire); + } + optimize(source, target, wire); + wires.add(wire); + if (!wire.getCallbackInvocationChains().isEmpty()) { + target.attachCallbackWire(wire); + } + } + if (wires.size() > 1) { + // attach as a multiplicity + source.attachWires(wires); + } else if (wires.size() == 1) { + // attach as a single wire + Wire wire = wires.get(0); + source.attachWire(wire); + } + } + } + + /** + * @deprecated + */ + protected void connect(ServiceDefinition definition) throws WiringException { + URI uri = definition.getUri(); + URI sourceUri = UriHelper.getDefragmentedName(uri); + URI targetUri = definition.getTarget(); + URI baseTargetUri = UriHelper.getDefragmentedName(targetUri); + Component source = componentManager.getComponent(sourceUri); + if (source == null) { + throw new ComponentNotFoundException("Source not found", sourceUri); + } + Service service = source.getService(uri.getFragment()); + if (service == null) { + throw new SourceServiceNotFoundException("Service not found on composite", uri); + } + Component target = componentManager.getComponent(baseTargetUri); + if (target == null) { + throw new ComponentNotFoundException("Target not found", sourceUri); + } + ServiceContract<?> contract = definition.getServiceContract(); + // TODO if no binding, do local + for (ServiceBinding binding : service.getServiceBindings()) { + Wire wire = createWire(uri, targetUri, contract, binding.getBindingType()); + binding.setWire(wire); + if (postProcessorRegistry != null) { + postProcessorRegistry.process(wire); + } + try { + attachInvokers(definition.getTarget().getFragment(), wire, binding, target); + } catch (TargetInvokerCreationException e) { + throw new WireCreationException("Error creating invoker", sourceUri, baseTargetUri, e); + } + } + } + + /** + * @deprecated + */ + protected void connect(ReferenceDefinition definition) throws WiringException { + URI uri = definition.getUri(); + URI sourceUri = UriHelper.getDefragmentedName(uri); + Component source = componentManager.getComponent(sourceUri); + if (source == null) { + throw new ComponentNotFoundException("Source not found", sourceUri); + } + Reference reference = source.getReference(uri.getFragment()); + if (reference == null) { + throw new SourceServiceNotFoundException("Reference not found on composite", uri); + } + + for (ReferenceBinding binding : reference.getReferenceBindings()) { + // create wire + if (Wire.LOCAL_BINDING.equals(binding.getBindingType())) { + URI targetUri = binding.getTargetUri(); + ServiceContract<?> contract = binding.getBindingServiceContract(); + QName type = binding.getBindingType(); + Wire wire = createWire(sourceUri, targetUri, contract, type); + binding.setWire(wire); + // wire local bindings to their targets + Component target = componentManager.getComponent(UriHelper.getDefragmentedName(targetUri)); + if (target == null) { + throw new ComponentNotFoundException("Target not found", sourceUri); + } + try { + attachInvokers(targetUri.getFragment(), wire, binding, target); + } catch (TargetInvokerCreationException e) { + throw new WireCreationException("Error creating invoker", sourceUri, targetUri, e); + } + } else { + Wire wire = createWire(sourceUri, null, binding.getBindingServiceContract(), binding.getBindingType()); + if (postProcessorRegistry != null) { + postProcessorRegistry.process(wire); + } + binding.setWire(wire); + } + } + } + + protected Wire createWire(PhysicalWireDefinition definition) throws BuilderException { + URI sourceURI = definition.getSourceUri(); + URI targetUri = definition.getTargetUri(); + Wire wire = new WireImpl(); + wire.setSourceUri(sourceURI); + wire.setTargetUri(targetUri); + for (PhysicalOperationDefinition operation : definition.getOperations()) { + InvocationChain chain = new InvocationChainImpl(operation); + for (PhysicalInterceptorDefinition interceptorDefinition : operation.getInterceptors()) { + Interceptor interceptor = interceptorBuilderRegistry.build(interceptorDefinition); + chain.addInterceptor(interceptor); + } + wire.addInvocationChain(operation, chain); + } + return wire; + } + + protected Wire createWire(URI sourceURI, URI targetUri, ServiceContract<?> contract, QName bindingType) { + Wire wire = new WireImpl(bindingType); + wire.setSourceContract(contract); + wire.setTargetContract(contract); + wire.setSourceUri(sourceURI); + wire.setTargetUri(targetUri); + for (Operation<?> operation : contract.getOperations().values()) { + InvocationChain chain = new InvocationChainImpl(operation); + if (operation.isNonBlocking()) { + chain.addInterceptor(new NonBlockingInterceptor(scheduler, workContext)); + } + chain.addInterceptor(new InvokerInterceptor()); + wire.addInvocationChain(operation, chain); + + } + for (Operation<?> operation : contract.getCallbackOperations().values()) { + InvocationChain chain = new InvocationChainImpl(operation); + if (operation.isNonBlocking()) { + chain.addInterceptor(new NonBlockingInterceptor(scheduler, workContext)); + } + chain.addInterceptor(new InvokerInterceptor()); + wire.addCallbackInvocationChain(operation, chain); + } + return wire; + } + + /** + * @Deprecated + */ + private void attachInvokers(String name, Wire wire, Invocable source, Invocable target) + throws TargetInvokerCreationException { + // TODO section will deleted be replaced when we cut-over to the physical marshallers + for (InvocationChain chain : wire.getInvocationChains().values()) { + chain.setTargetInvoker(target.createTargetInvoker(name, chain.getOperation())); + } + for (InvocationChain chain : wire.getCallbackInvocationChains().values()) { + chain.setTargetInvoker(source.createTargetInvoker(null, chain.getOperation())); + } + } + + /** + * @Deprecated + */ + protected void optimize(Component source, Component target, Wire wire) { + boolean optimizableScopes = isOptimizable(source.getScope(), target.getScope()); + if (optimizableScopes && target.isOptimizable() && WireUtils.isOptimizable(wire)) { + wire.setOptimizable(true); + wire.setTarget((AtomicComponent) target); + } else { + wire.setOptimizable(false); + } + } + + protected boolean isOptimizable(Scope pReferrer, Scope pReferee) { + if (pReferrer == Scope.UNDEFINED + || pReferee == Scope.UNDEFINED + || pReferrer == Scope.CONVERSATION + || pReferee == Scope.CONVERSATION) { + return false; + } + if (pReferee == pReferrer) { + return true; + } else if (pReferrer == Scope.STATELESS) { + return true; + } else if (pReferee == Scope.STATELESS) { + return false; + } else if (pReferrer == Scope.REQUEST && pReferee == Scope.SESSION) { + return true; + } else if (pReferrer == Scope.REQUEST && pReferee == Scope.COMPOSITE) { + return true; + } else if (pReferrer == Scope.REQUEST && pReferee == Scope.SYSTEM) { + return true; + } else if (pReferrer == Scope.SESSION && pReferee == Scope.COMPOSITE) { + return true; + } else if (pReferrer == Scope.SESSION && pReferee == Scope.SYSTEM) { + return true; + } else //noinspection SimplifiableIfStatement + if (pReferrer == Scope.SYSTEM && pReferee == Scope.COMPOSITE) { + // case where a service context points to a composite scoped component + return true; + } else { + return pReferrer == Scope.COMPOSITE && pReferee == Scope.SYSTEM; + } + } +}
\ No newline at end of file diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/IllegalCallbackException.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/IllegalCallbackException.java new file mode 100644 index 0000000000..183ccea1b8 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/IllegalCallbackException.java @@ -0,0 +1,36 @@ +/* + * 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.core.builder; + +import java.net.URI; + +import org.apache.tuscany.spi.builder.WiringException; + +/** + * Denotes an illegal callback + * + * @version $Rev$ $Date$ + */ +public class IllegalCallbackException extends WiringException { + + public IllegalCallbackException(String message, String identifier, URI sourceUri, URI targetUri) { + super(message, identifier, sourceUri, targetUri); + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/IncompatibleInterfacesException.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/IncompatibleInterfacesException.java new file mode 100644 index 0000000000..1a9c74aa3b --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/IncompatibleInterfacesException.java @@ -0,0 +1,40 @@ +/* + * 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.core.builder; + +import java.net.URI; + +import org.apache.tuscany.spi.builder.WiringException; + +/** + * Denotes an attempt to wire incompatible interfaces + * + * @version $Rev$ $Date$ + */ +public class IncompatibleInterfacesException extends WiringException { + + public IncompatibleInterfacesException(URI source, URI target) { + super("Incompatible source and target interfaces", source, target); + } + + public IncompatibleInterfacesException(URI source, URI target, Throwable throwable) { + super("Incompatible source and target interfaces", source, target, throwable); + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/InvalidSourceTypeException.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/InvalidSourceTypeException.java new file mode 100644 index 0000000000..d9df445530 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/InvalidSourceTypeException.java @@ -0,0 +1,35 @@ +/* + * 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.core.builder; + +import java.net.URI; + +import org.apache.tuscany.spi.builder.WiringException; + +/** + * Denotes an invalid source type for a wire + * + * @version $Rev$ $Date$ + */ +public class InvalidSourceTypeException extends WiringException { + + public InvalidSourceTypeException(String message, URI sourceUri, URI targetUri) { + super(message, sourceUri, targetUri); + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/InvalidTargetTypeException.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/InvalidTargetTypeException.java new file mode 100644 index 0000000000..e3c26c75d2 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/InvalidTargetTypeException.java @@ -0,0 +1,35 @@ +/* + * 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.core.builder; + +import java.net.URI; + +import org.apache.tuscany.spi.builder.WiringException; + +/** + * Denotes an invalid target service for a wire + * + * @version $Rev$ $Date$ + */ +public class InvalidTargetTypeException extends WiringException { + + public InvalidTargetTypeException(String message, URI sourceUri, URI targetUri) { + super(message, sourceUri, targetUri); + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/NoBindingException.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/NoBindingException.java new file mode 100644 index 0000000000..c351013297 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/NoBindingException.java @@ -0,0 +1,35 @@ +/* + * 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.core.builder; + +import java.net.URI; + +import org.apache.tuscany.spi.builder.WiringException; + +/** + * Denotes no binding was specified for a wire + * + * @version $Rev$ $Date$ + */ +public class NoBindingException extends WiringException { + + public NoBindingException(String message, URI sourceUri, URI targetUri) { + super(message, sourceUri, targetUri); + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/NoCompatibleBindingsException.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/NoCompatibleBindingsException.java new file mode 100644 index 0000000000..3c49767333 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/NoCompatibleBindingsException.java @@ -0,0 +1,34 @@ +/* + * 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.core.builder; + +import java.net.URI; + +import org.apache.tuscany.spi.builder.WiringException; + +/** + * @version $Rev$ $Date$ + */ +public class NoCompatibleBindingsException extends WiringException { + + public NoCompatibleBindingsException(URI sourceName, URI targetName) { + super("No compatible bindings for source and target", sourceName, targetName); + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/NoConversationalContractException.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/NoConversationalContractException.java new file mode 100644 index 0000000000..71eb9ebd26 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/NoConversationalContractException.java @@ -0,0 +1,37 @@ +/*
+ * 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.core.builder;
+
+import org.apache.tuscany.spi.builder.BuilderException;
+
+/**
+ * Raised when a component has conversational scope but no conversational contract
+ *
+ * @version $Rev: 487877 $ $Date: 2006-12-16 15:32:16 -0500 (Sat, 16 Dec 2006) $
+ */
+public class NoConversationalContractException extends BuilderException {
+
+ public NoConversationalContractException(String message, String identifier) {
+ super(message, identifier);
+ }
+
+ public NoConversationalContractException(String message) {
+ super(message);
+ }
+}
diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/NoRegisteredBuilderException.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/NoRegisteredBuilderException.java new file mode 100644 index 0000000000..340a20f239 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/NoRegisteredBuilderException.java @@ -0,0 +1,38 @@ +/* + * 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.core.builder; + +import org.apache.tuscany.spi.builder.BuilderException; + +/** + * Raised when a builder cannot be found for a SCDL entry type + * + * @version $Rev$ $Date$ + */ +public class NoRegisteredBuilderException extends BuilderException { + + public NoRegisteredBuilderException(String message, String identifier) { + super(message, identifier); + } + + public NoRegisteredBuilderException(String message) { + super(message); + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/SourceServiceNotFoundException.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/SourceServiceNotFoundException.java new file mode 100644 index 0000000000..7d3d49b937 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/SourceServiceNotFoundException.java @@ -0,0 +1,36 @@ +/* + * 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.core.builder; + +import java.net.URI; + +import org.apache.tuscany.spi.builder.WiringException; + +/** + * Indicates the source service of a wire was not found + * + * @version $Rev$ $Date$ + */ +public class SourceServiceNotFoundException extends WiringException { + + public SourceServiceNotFoundException(String message, URI sourceName) { + super(message, sourceName, null); + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/TargetServiceNotFoundException.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/TargetServiceNotFoundException.java new file mode 100644 index 0000000000..f22b421aa7 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/TargetServiceNotFoundException.java @@ -0,0 +1,36 @@ +/* + * 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.core.builder; + +import java.net.URI; + +import org.apache.tuscany.spi.builder.WiringException; + +/** + * Indicates the target service of a reference was not found + * + * @version $Rev$ $Date$ + */ +public class TargetServiceNotFoundException extends WiringException { + + public TargetServiceNotFoundException(String message, URI sourceName, URI targetName) { + super(message, sourceName, targetName); + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/WireCreationException.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/WireCreationException.java new file mode 100644 index 0000000000..117bb23180 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/WireCreationException.java @@ -0,0 +1,39 @@ +/* + * 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.core.builder; + +import java.net.URI; + +import org.apache.tuscany.spi.builder.WiringException; + +/** + * Denotes an error creating a wire + * + * @version $Rev$ $Date$ + */ +public class WireCreationException extends WiringException { + + public WireCreationException(String message, URI sourceUri, Throwable e) { + super(message, sourceUri, null, e); + } + + public WireCreationException(String message, URI sourceUri, URI targetUri, Throwable e) { + super(message, sourceUri, targetUri, e); + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/WirePostProcessorRegistryImpl.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/WirePostProcessorRegistryImpl.java new file mode 100644 index 0000000000..6f611956be --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/WirePostProcessorRegistryImpl.java @@ -0,0 +1,50 @@ +/* + * 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.core.builder; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.tuscany.spi.wire.Wire; +import org.apache.tuscany.spi.wire.WirePostProcessor; +import org.apache.tuscany.spi.wire.WirePostProcessorRegistry; + +/** + * The default implementation of a <code>WirePostProcessor</code> + * + * @version $Rev$ $Date$ + */ +public class WirePostProcessorRegistryImpl implements WirePostProcessorRegistry { + + private final List<WirePostProcessor> processors = new ArrayList<WirePostProcessor>(); + + public void process(Wire wire) { + for (WirePostProcessor processor : processors) { + processor.process(wire); + } + } + + public void register(WirePostProcessor processor) { + processors.add(processor); + } + + public void unregister(WirePostProcessor processor) { + processors.remove(processor); + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/WiringExceptionFormatter.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/WiringExceptionFormatter.java new file mode 100644 index 0000000000..661dc8bfea --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/builder/WiringExceptionFormatter.java @@ -0,0 +1,67 @@ +/* + * 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.core.builder; + +import java.io.PrintWriter; + +import org.osoa.sca.annotations.Destroy; +import org.osoa.sca.annotations.EagerInit; +import org.osoa.sca.annotations.Reference; + +import org.apache.tuscany.spi.builder.WiringException; + +import org.apache.tuscany.host.monitor.ExceptionFormatter; +import org.apache.tuscany.host.monitor.FormatterRegistry; + +/** + * Formats {@link WiringException}s + * + * @version $Rev$ $Date$ + */ +@EagerInit +public class WiringExceptionFormatter implements ExceptionFormatter { + private FormatterRegistry factory; + + public WiringExceptionFormatter(@Reference FormatterRegistry factory) { + this.factory = factory; + factory.register(this); + } + + public boolean canFormat(Class<?> type) { + return WiringException.class.isAssignableFrom(type); + } + + @Destroy + public void destroy() { + factory.unregister(this); + } + + public PrintWriter write(PrintWriter writer, Throwable exception) { + assert exception instanceof WiringException; + WiringException e = (WiringException) exception; + e.appendBaseMessage(writer); + if (e.getSourceUri() != null) { + writer.write("\nSource : " + e.getSourceUri()); + } + if (e.getTargetUri() != null) { + writer.write("\nTarget : " + e.getTargetUri()); + } + return writer; + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/CallableReferenceImpl.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/CallableReferenceImpl.java new file mode 100644 index 0000000000..e674112a89 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/CallableReferenceImpl.java @@ -0,0 +1,60 @@ +/* + * 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.core.component; + +import org.osoa.sca.CallableReference; +import org.osoa.sca.Conversation; + +import org.apache.tuscany.spi.ObjectFactory; + +/** + * Base class for implementations of service and callback references. + * + * @version $Rev$ $Date$ + * @param <B> the type of the business interface + */ +public abstract class CallableReferenceImpl<B> implements CallableReference<B> { + private final Class<B> businessInterface; + private final ObjectFactory<B> factory; + + protected CallableReferenceImpl(Class<B> businessInterface, ObjectFactory<B> factory) { + this.businessInterface = businessInterface; + this.factory = factory; + } + + public B getService() { + return factory.getInstance(); + } + + public Class<B> getBusinessInterface() { + return businessInterface; + } + + public boolean isConversational() { + return false; + } + + public Conversation getConversation() { + return null; + } + + public Object getCallbackID() { + return null; + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/CallbackReferenceImpl.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/CallbackReferenceImpl.java new file mode 100644 index 0000000000..532a8b2bad --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/CallbackReferenceImpl.java @@ -0,0 +1,33 @@ +/* + * 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.core.component; + +import org.apache.tuscany.spi.ObjectFactory; + +/** + * Default implementation of a callback reference. + * + * @version $Rev$ $Date$ + * @param <CB> the type of the business interface + */ +public class CallbackReferenceImpl<CB> extends CallableReferenceImpl<CB> { + public CallbackReferenceImpl(Class<CB> businessInterface, ObjectFactory<CB> factory) { + super(businessInterface, factory); + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/ComponentContextImpl.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/ComponentContextImpl.java new file mode 100644 index 0000000000..c8047abdab --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/ComponentContextImpl.java @@ -0,0 +1,97 @@ +/* + * 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.core.component; + +import org.osoa.sca.CallableReference; +import org.osoa.sca.ComponentContext; +import org.osoa.sca.RequestContext; +import org.osoa.sca.ServiceReference; +import org.osoa.sca.ServiceRuntimeException; + +import org.apache.tuscany.api.TuscanyRuntimeException; +import org.apache.tuscany.spi.ObjectFactory; +import org.apache.tuscany.spi.component.AtomicComponent; +import org.apache.tuscany.spi.component.Component; + +/** + * Implementation of ComponentContext that delegates to a ComponentContextProvider. + * + * @version $Rev$ $Date$ + */ +public class ComponentContextImpl implements ComponentContext { + private final ComponentContextProvider component; + + public ComponentContextImpl(ComponentContextProvider component) { + this.component = component; + } + + public String getURI() { + try { + return component.getUri().toString(); + } catch (TuscanyRuntimeException e) { + throw new ServiceRuntimeException(e.getMessage(), e); + } + } + + public <B, R extends CallableReference<B>> R cast(B target) throws IllegalArgumentException { + try { + return (R) component.cast(target); + } catch (TuscanyRuntimeException e) { + throw new ServiceRuntimeException(e.getMessage(), e); + } + } + + public <B> B getService(Class<B> businessInterface, String referenceName) { + try { + return component.getService(businessInterface, referenceName); + } catch (TuscanyRuntimeException e) { + throw new ServiceRuntimeException(e.getMessage(), e); + } + } + + public <B> ServiceReference<B> getServiceReference(Class<B> businessInterface, String referenceName) { + try { + return component.getServiceReference(businessInterface, referenceName); + } catch (TuscanyRuntimeException e) { + throw new ServiceRuntimeException(e.getMessage(), e); + } + } + + public <B> B getProperty(Class<B> type, String propertyName) { + try { + return component.getProperty(type, propertyName); + } catch (TuscanyRuntimeException e) { + throw new ServiceRuntimeException(e.getMessage(), e); + } + } + + public <B> ServiceReference<B> createSelfReference(Class<B> businessInterface) { + // FIXME: How to get the ObjectFactory? + ObjectFactory<B> factory = ((AtomicComponent) component).createObjectFactory(); + return new ServiceReferenceImpl<B>(businessInterface, factory); + } + + public <B> ServiceReference<B> createSelfReference(Class<B> businessInterface, String serviceName) { + return null; + } + + public RequestContext getRequestContext() { + return null; + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/ComponentContextProvider.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/ComponentContextProvider.java new file mode 100644 index 0000000000..4237d8b09f --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/ComponentContextProvider.java @@ -0,0 +1,44 @@ +/* + * 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.core.component; + +import java.net.URI; + +import org.osoa.sca.ComponentContext; +import org.osoa.sca.ServiceReference; +import org.osoa.sca.CallableReference; + +/** + * Interface implemented by Component's that want to expose a ComponentContext. + * + * @version $Rev$ $Date$ + */ +public interface ComponentContextProvider { + ComponentContext getComponentContext(); + + URI getUri(); + + <B> B getService(Class<B> businessInterface, String referenceName); + + <B> ServiceReference<B> getServiceReference(Class<B> businessInterface, String referenceName); + + <B> B getProperty(Class<B> type, String propertyName); + + <B, R extends CallableReference<B>> R cast(B target); +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/ComponentManagerImpl.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/ComponentManagerImpl.java new file mode 100644 index 0000000000..76958c88ff --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/ComponentManagerImpl.java @@ -0,0 +1,109 @@ +/* + * 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.core.component; + +import java.net.URI; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.tuscany.spi.component.AtomicComponent; +import org.apache.tuscany.spi.component.Component; +import org.apache.tuscany.spi.component.ComponentManager; +import org.apache.tuscany.spi.component.DuplicateNameException; +import org.apache.tuscany.spi.component.RegistrationException; +import org.apache.tuscany.spi.event.Event; +import org.apache.tuscany.spi.model.ServiceContract; +import org.apache.tuscany.spi.services.management.TuscanyManagementService; +import org.apache.tuscany.spi.idl.java.JavaServiceContract; + +import org.apache.tuscany.core.resolver.AutowireResolver; + +/** + * Default implementation of the component manager + * + * @version $Rev$ $Date$ + */ +public class ComponentManagerImpl implements ComponentManager { + private TuscanyManagementService managementService; + private AutowireResolver resolver; + private Map<URI, Component> components; + + public ComponentManagerImpl() { + components = new ConcurrentHashMap<URI, Component>(); + } + + public ComponentManagerImpl(TuscanyManagementService managementService, AutowireResolver resolver) { + this(); + this.managementService = managementService; + this.resolver = resolver; + } + + public synchronized void register(Component component) throws RegistrationException { + URI uri = component.getUri(); + assert uri != null; + assert !uri.toString().endsWith("/"); + if (components.containsKey(uri)) { + throw new DuplicateNameException(uri.toString()); + } + components.put(uri, component); + + if (managementService != null && component instanceof AtomicComponent) { + // FIXME shouldn't it take the canonical name and also not distinguish atomic components? + managementService.registerComponent(component.getUri().toString(), component); + } + } + + public <S, I extends S> void registerJavaObject(URI uri, JavaServiceContract<S> service, I instance) + throws RegistrationException { + SystemSingletonAtomicComponent<S, I> component = + new SystemSingletonAtomicComponent<S, I>(uri, service, instance); + register(component); + if (resolver != null) { + for (ServiceContract contract : component.getServiceContracts()) { + resolver.addHostUri(contract, uri); + } + } + } + + public <S, I extends S> void registerJavaObject(URI uri, List<JavaServiceContract<?>> services, I instance) + throws RegistrationException { + SystemSingletonAtomicComponent<S, I> component = + new SystemSingletonAtomicComponent<S, I>(uri, services, instance); + register(component); + if (resolver != null) { + for (ServiceContract contract : component.getServiceContracts()) { + resolver.addHostUri(contract, uri); + } + } + } + + public synchronized void unregister(Component component) throws RegistrationException { + URI uri = component.getUri(); + components.remove(uri); + } + + public Component getComponent(URI name) { + return components.get(name); + } + + public void onEvent(Event event) { + throw new UnsupportedOperationException(); + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/ScopeIdentifier.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/ScopeIdentifier.java new file mode 100644 index 0000000000..35125b85ef --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/ScopeIdentifier.java @@ -0,0 +1,35 @@ +/* + * 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.core.component; + +/** + * Implementations enable lazy retrieval of a scope id associated with a request, i.e. an id (and presumably a context) + * do not have to be generated if the scope is never accessed. Identifiers are associated with the current request + * thread and keyed on scope type. + * + * @version $Rev$ $Date$ + * @see org.apache.tuscany.spi.component.WorkContext + */ +public interface ScopeIdentifier { + + /** + * Returns the scope id for the request. + */ + Object getIdentifier(); +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/ServiceReferenceImpl.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/ServiceReferenceImpl.java new file mode 100644 index 0000000000..4d57d3efe0 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/ServiceReferenceImpl.java @@ -0,0 +1,52 @@ +/* + * 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.core.component; + +import org.osoa.sca.ServiceReference; + +import org.apache.tuscany.spi.ObjectFactory; + +/** + * Default implementation of a ServiceReference. + * + * @version $Rev$ $Date$ + * @param <B> the type of the business interface + */ +public class ServiceReferenceImpl<B> extends CallableReferenceImpl<B> implements ServiceReference<B> { + public ServiceReferenceImpl(Class<B> businessInterface, ObjectFactory<B> factory) { + super(businessInterface, factory); + } + + public Object getConversationID() { + return null; + } + + public void setConversationID(Object conversationId) throws IllegalStateException { + } + + public void setCallbackID(Object callbackID) { + } + + public Object getCallback() { + return null; + } + + public void setCallback(Object callback) { + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/SimpleWorkContext.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/SimpleWorkContext.java new file mode 100644 index 0000000000..7e978f6f35 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/SimpleWorkContext.java @@ -0,0 +1,113 @@ +/* + * 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.core.component; + +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.LinkedList; +import java.util.ArrayList; +import java.net.URI; + +import org.apache.tuscany.spi.component.WorkContext; +import org.apache.tuscany.spi.component.AtomicComponent; +import org.apache.tuscany.spi.wire.Wire; + +/** + * A simple WorkContext implementation that provides basic thread-local support + * for storing work context information. The implementation is <em>not</em> + * thread safe. + * + * @version $Rev$ $Date$ + */ +public class SimpleWorkContext implements WorkContext { + private final Map<Object, Object> identifiers = new HashMap<Object, Object>(); + private final List<String> serviceNameStack = new ArrayList<String>(); + + private LinkedList<URI> callbackUris; + private LinkedList<Wire> callbackWires; + private Object correlationId; + private AtomicComponent currentAtomicComponent; + + public Object getIdentifier(Object type) { + return identifiers.get(type); + } + + public void setIdentifier(Object type, Object identifier) { + identifiers.put(type, identifier); + } + + public void clearIdentifier(Object type) { + identifiers.remove(type); + } + + public void clearIdentifiers() { + identifiers.clear(); + } + + public LinkedList<URI> getCallbackUris() { + return callbackUris; + } + + public void setCallbackUris(LinkedList<URI> uris) { + this.callbackUris = uris; + } + + public LinkedList<Wire> getCallbackWires() { + return callbackWires; + } + + public void setCallbackWires(LinkedList<Wire> wires) { + this.callbackWires = wires; + } + + public Object getCorrelationId() { + return correlationId; + } + + public void setCorrelationId(Object correlationId) { + this.correlationId = correlationId; + } + + public AtomicComponent getCurrentAtomicComponent() { + return currentAtomicComponent; + } + + public void setCurrentAtomicComponent(AtomicComponent currentAtomicComponent) { + this.currentAtomicComponent = currentAtomicComponent; + } + + public String getCurrentServiceName() { + assert !serviceNameStack.isEmpty(); + return serviceNameStack.get(serviceNameStack.size() - 1); + } + + public void pushServiceName(String name) { + serviceNameStack.add(name); + } + + public String popServiceName() { + assert !serviceNameStack.isEmpty(); + return serviceNameStack.remove(serviceNameStack.size() - 1); + } + + public void clearServiceNames() { + serviceNameStack.clear(); + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/SystemSingletonAtomicComponent.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/SystemSingletonAtomicComponent.java new file mode 100644 index 0000000000..872853506e --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/SystemSingletonAtomicComponent.java @@ -0,0 +1,138 @@ +/* + * 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.core.component; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +import org.apache.tuscany.core.injection.SingletonObjectFactory; +import org.apache.tuscany.spi.ObjectCreationException; +import org.apache.tuscany.spi.ObjectFactory; +import org.apache.tuscany.spi.component.AtomicComponent; +import org.apache.tuscany.spi.component.InstanceWrapper; +import org.apache.tuscany.spi.component.TargetInvokerCreationException; +import org.apache.tuscany.spi.component.TargetResolutionException; +import org.apache.tuscany.spi.extension.AbstractComponentExtension; +import org.apache.tuscany.spi.idl.java.JavaServiceContract; +import org.apache.tuscany.spi.model.Operation; +import org.apache.tuscany.spi.model.Scope; +import org.apache.tuscany.spi.model.ServiceContract; +import org.apache.tuscany.spi.model.physical.PhysicalOperationDefinition; +import org.apache.tuscany.spi.wire.TargetInvoker; +import org.apache.tuscany.spi.wire.Wire; + +/** + * An {@link org.apache.tuscany.spi.component.AtomicComponent} used when registering objects directly into a composite + * + * @version $$Rev$$ $$Date$$ + */ +public class SystemSingletonAtomicComponent<S, T extends S> extends AbstractComponentExtension + implements AtomicComponent<T> { + private T instance; + private List<ServiceContract> serviceContracts = new ArrayList<ServiceContract>(); + + public SystemSingletonAtomicComponent(URI name, JavaServiceContract<S> contract, T instance) { + super(name); + this.instance = instance; + this.serviceContracts.add(contract); + } + + public SystemSingletonAtomicComponent(URI name, List<JavaServiceContract<?>> services, T instance) { + super(name); + this.instance = instance; + for (ServiceContract<?> contract : services) { + serviceContracts.add(contract); + } + } + + public Scope getScope() { + return Scope.COMPOSITE; + } + + public boolean isEagerInit() { + return false; + } + + public int getInitLevel() { + return 0; + } + + public long getMaxIdleTime() { + return -1; + } + + public long getMaxAge() { + return -1; + } + + public T getTargetInstance() throws TargetResolutionException { + return instance; + } + + public Object createInstance() throws ObjectCreationException { + throw new UnsupportedOperationException(); + } + + public void removeInstance() { + throw new UnsupportedOperationException(); + } + + public InstanceWrapper<T> createInstanceWrapper() throws ObjectCreationException { + throw new UnsupportedOperationException(); + } + + public ObjectFactory<T> createObjectFactory() { + return new SingletonObjectFactory<T>(instance); + } + + public boolean isOptimizable() { + return true; + } + + public void attachWire(Wire wire) { + throw new UnsupportedOperationException(); + } + + public void attachWires(List<Wire> wires) { + throw new UnsupportedOperationException(); + } + + public List<Wire> getWires(String name) { + throw new UnsupportedOperationException(); + } + + public void attachCallbackWire(Wire wire) { + throw new UnsupportedOperationException(); + } + + public TargetInvoker createTargetInvoker(String targetName, Operation operation) { + return null; + } + + public TargetInvoker createTargetInvoker(String targetName, PhysicalOperationDefinition operation) + throws TargetInvokerCreationException { + return null; + } + + public List<ServiceContract> getServiceContracts() { + return serviceContracts; + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/WorkContextImpl.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/WorkContextImpl.java new file mode 100644 index 0000000000..3eb6e9d3eb --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/WorkContextImpl.java @@ -0,0 +1,214 @@ +/* + * 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.core.component; + +import java.net.URI; +import java.util.ArrayList; +import java.util.IdentityHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.apache.tuscany.spi.component.AtomicComponent; +import org.apache.tuscany.spi.component.WorkContext; +import org.apache.tuscany.spi.wire.Wire; + +/** + * An implementation of an {@link org.apache.tuscany.spi.component.WorkContext} that handles event-to-thread + * associations using an <code>InheritableThreadLocal</code> + * + * @version $Rev$ $Date$ + */ +public class WorkContextImpl implements WorkContext { + private static final Object CORRELATION_ID = new Object(); + private static final Object CALLBACK_URIS = new Object(); + private static final Object CURRENT_ATOMIC = new Object(); + private static final Object CURRENT_SERVICE_NAMES = new Object(); + private static final Object CALLBACK_WIRES = new Object(); + + // [rfeng] We cannot use InheritableThreadLocal for message ids here since it's shared by parent and children + private ThreadLocal<Map<Object, Object>> workContext = new ThreadLocal<Map<Object, Object>>(); + + // [rfeng] Session id requires InheritableThreadLocal + private ThreadLocal<Map<Object, Object>> inheritableContext = new InheritableThreadLocal<Map<Object, Object>>(); + + public WorkContextImpl() { + super(); + } + + public Object getCorrelationId() { + Map<Object, Object> map = workContext.get(); + if (map == null) { + return null; + } + return map.get(CORRELATION_ID); + } + + public void setCorrelationId(Object id) { + Map<Object, Object> map = getWorkContextMap(); + map.put(CORRELATION_ID, id); + } + + public AtomicComponent getCurrentAtomicComponent() { + Map<Object, Object> map = workContext.get(); + if (map == null) { + return null; + } + return (AtomicComponent) map.get(CURRENT_ATOMIC); + } + + public void setCurrentAtomicComponent(AtomicComponent component) { + Map<Object, Object> map = getWorkContextMap(); + map.put(CURRENT_ATOMIC, component); + } + + @SuppressWarnings("unchecked") + public LinkedList<URI> getCallbackUris() { + Map<Object, Object> map = workContext.get(); + if (map == null) { + return null; + } + return (LinkedList<URI>) map.get(CALLBACK_URIS); + } + + public void setCallbackUris(LinkedList<URI> uris) { + Map<Object, Object> map = getWorkContextMap(); + map.put(CALLBACK_URIS, uris); + } + + + @SuppressWarnings({"unchecked"}) + public LinkedList<Wire> getCallbackWires() { + Map<Object, Object> map = workContext.get(); + if (map == null) { + return null; + } + return (LinkedList<Wire>) map.get(CALLBACK_WIRES); + } + + public void setCallbackWires(LinkedList<Wire> wires) { + Map<Object, Object> map = getWorkContextMap(); + map.put(CALLBACK_WIRES, wires); + } + + + public Object getIdentifier(Object type) { + Map<Object, Object> map = inheritableContext.get(); + if (map == null) { + return null; + } + Object currentId = map.get(type); + if (currentId instanceof ScopeIdentifier) { + currentId = ((ScopeIdentifier) currentId).getIdentifier(); + // once we have accessed the id, replace the lazy wrapper + map.put(type, currentId); + } + return currentId; + } + + public void setIdentifier(Object type, Object identifier) { + Map<Object, Object> map = inheritableContext.get(); + if (map == null) { + map = new IdentityHashMap<Object, Object>(); + inheritableContext.set(map); + } + map.put(type, identifier); + } + + public void clearIdentifier(Object type) { + if (type == null) { + return; + } + Map map = inheritableContext.get(); + if (map != null) { + map.remove(type); + } + } + + public void clearIdentifiers() { + inheritableContext.remove(); + } + + @SuppressWarnings({"unchecked"}) + public String popServiceName() { + Map<Object, Object> map = inheritableContext.get(); + if (map == null) { + return null; + } + List<String> stack = (List) map.get(CURRENT_SERVICE_NAMES); + if (stack == null || stack.size() < 1) { + return null; + } + String name = stack.remove(stack.size() - 1); + if (stack.size() == 0) { + // cleanup to avoid leaks + map.remove(CURRENT_SERVICE_NAMES); + } + return name; + } + + @SuppressWarnings({"unchecked"}) + public String getCurrentServiceName() { + Map<Object, Object> map = inheritableContext.get(); + if (map == null) { + return null; + } + List<String> stack = (List) map.get(CURRENT_SERVICE_NAMES); + if (stack == null || stack.size() < 1) { + return null; + } + return stack.get(stack.size() - 1); + } + + @SuppressWarnings({"unchecked"}) + public void pushServiceName(String name) { + Map<Object, Object> map = inheritableContext.get(); + List<String> names; + if (map == null) { + map = new IdentityHashMap<Object, Object>(); + inheritableContext.set(map); + names = new ArrayList<String>(); + map.put(CURRENT_SERVICE_NAMES, names); + } else { + names = (List<String>) map.get(CURRENT_SERVICE_NAMES); + if (names == null) { + names = new ArrayList<String>(); + map.put(CURRENT_SERVICE_NAMES, names); + } + } + names.add(name); + } + + public void clearServiceNames() { + Map<Object, Object> map = inheritableContext.get(); + if (map == null) { + return; + } + map.remove(CURRENT_SERVICE_NAMES); + } + + private Map<Object, Object> getWorkContextMap() { + Map<Object, Object> map = workContext.get(); + if (map == null) { + map = new IdentityHashMap<Object, Object>(); + workContext.set(map); + } + return map; + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/AbstractEvent.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/AbstractEvent.java new file mode 100644 index 0000000000..6d026ca08c --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/AbstractEvent.java @@ -0,0 +1,39 @@ +/* + * 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.core.component.event; + +import org.apache.tuscany.spi.event.Event; + +/** + * A basic implementation of a runtime event + * + * @version $$Rev$$ $$Date$$ + */ +public abstract class AbstractEvent implements Event { + protected Object source; + + public AbstractEvent(Object source) { + assert source != null : "Source id was null"; + this.source = source; + } + + public Object getSource() { + return source; + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/AbstractRequestEvent.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/AbstractRequestEvent.java new file mode 100644 index 0000000000..762b917600 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/AbstractRequestEvent.java @@ -0,0 +1,38 @@ +/* + * 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.core.component.event; + +/** + * Base implementation of a request event + * + * @version $$Rev$$ $$Date$$ + */ +public abstract class AbstractRequestEvent extends AbstractEvent implements RequestEvent { + + /** + * Creates a new event + * + * @param source the source of the event + */ + public AbstractRequestEvent(Object source) { + super(source); + } + + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/ComponentEvent.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/ComponentEvent.java new file mode 100644 index 0000000000..7de32a56d0 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/ComponentEvent.java @@ -0,0 +1,34 @@ +/* + * 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.core.component.event; + +import java.net.URI; + +import org.apache.tuscany.spi.event.Event; + +/** + * Implemented by runtime events associated with a component, e.g. lifecycle events + * + * @version $$Rev$$ $$Date$$ + */ +public interface ComponentEvent extends Event { + + URI getComponentUri(); + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/ComponentStart.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/ComponentStart.java new file mode 100644 index 0000000000..6be1c88d3f --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/ComponentStart.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.core.component.event; + +import java.net.URI; + +/** + * Propagated when a component starts + * + * @version $$Rev$$ $$Date$$ + */ +public class ComponentStart extends AbstractEvent implements ComponentEvent { + + private URI uri; + + /** + * Creates a component start event + * + * @param source the source of the event + * @param componentURI the uri of the component being started + */ + public ComponentStart(Object source, URI componentURI) { + super(source); + this.uri = componentURI; + } + + public URI getComponentUri() { + return uri; + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/ComponentStop.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/ComponentStop.java new file mode 100644 index 0000000000..ac0a7fd5c0 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/ComponentStop.java @@ -0,0 +1,46 @@ +/* + * 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.core.component.event; + +import java.net.URI; + +/** + * Propagated when a component stops + * + * @version $$Rev$$ $$Date$$ + */ +public class ComponentStop extends AbstractEvent implements ComponentEvent { + + private URI uri; + + /** + * Creates a component stop event + * + * @param source the source of the event + * @param componentUri the composite component associated the component being stopped + */ + public ComponentStop(Object source, URI componentUri) { + super(source); + this.uri = componentUri; + } + + public URI getComponentUri() { + return uri; + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/ConversationEnd.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/ConversationEnd.java new file mode 100644 index 0000000000..4a51d970c3 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/ConversationEnd.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.core.component.event;
+
+/**
+ * Propagated when a conversation session is expired
+ *
+ * @version $$Rev: 430937 $$ $$Date: 2006-08-11 21:17:56 -0400 (Fri, 11 Aug 2006) $$
+ */
+public class ConversationEnd extends ConversationalEvent {
+
+ public ConversationEnd(Object source, Object id) {
+ super(source, id);
+ }
+}
diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/ConversationStart.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/ConversationStart.java new file mode 100644 index 0000000000..5725369bf6 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/ConversationStart.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.core.component.event;
+
+/**
+ * Propagated when a conversation session has started
+ *
+ * @version $$Rev: 430937 $$ $$Date: 2006-08-11 21:17:56 -0400 (Fri, 11 Aug 2006) $$
+ */
+public class ConversationStart extends ConversationalEvent {
+
+ public ConversationStart(Object source, Object id) {
+ super(source, id);
+ }
+}
diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/ConversationalEvent.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/ConversationalEvent.java new file mode 100644 index 0000000000..a75086e745 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/ConversationalEvent.java @@ -0,0 +1,39 @@ +/*
+ * 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.core.component.event;
+
+/**
+ * A base implementation of conversational session events in the runtime
+ *
+ * @version $$Rev: 430937 $$ $$Date: 2006-08-11 21:17:56 -0400 (Fri, 11 Aug 2006) $$
+ */
+public class ConversationalEvent extends AbstractEvent {
+
+ private Object id;
+
+ public ConversationalEvent(Object source, Object id) {
+ super(source);
+ assert id != null : "Conversation id was null";
+ this.id = id;
+ }
+
+ public Object getId() {
+ return id;
+ }
+}
diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/HttpRequestEnded.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/HttpRequestEnded.java new file mode 100644 index 0000000000..01bd769031 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/HttpRequestEnded.java @@ -0,0 +1,38 @@ +/*
+ * 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.core.component.event;
+
+/**
+ * Propagated when an HTTP-based request has ended.
+ *
+ * @version $$Rev: 430937 $$ $$Date: 2006-08-11 21:17:56 -0400 (Fri, 11 Aug 2006) $$
+ */
+public class HttpRequestEnded extends HttpSessionEvent {
+
+ /**
+ * Creates a new event
+ *
+ * @param source the source of the event
+ * @param id the id of the HTTP session being ended
+ */
+ public HttpRequestEnded(Object source, Object id) {
+ super(source, id);
+ }
+
+}
diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/HttpRequestStart.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/HttpRequestStart.java new file mode 100644 index 0000000000..9d0ff80dd7 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/HttpRequestStart.java @@ -0,0 +1,38 @@ +/*
+ * 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.core.component.event;
+
+/**
+ * Propagated when an HTTP-based request has started
+ *
+ * @version $$Rev: 430937 $$ $$Date: 2006-08-11 21:17:56 -0400 (Fri, 11 Aug 2006) $$
+ */
+public class HttpRequestStart extends HttpSessionEvent {
+
+ /**
+ * Creates a new event
+ *
+ * @param source the source of the event
+ * @param id the id of the HTTP session being ended
+ */
+ public HttpRequestStart(Object source, Object id) {
+ super(source, id);
+ }
+
+}
diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/HttpSessionEnd.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/HttpSessionEnd.java new file mode 100644 index 0000000000..7f2bebe94a --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/HttpSessionEnd.java @@ -0,0 +1,38 @@ +/* + * 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.core.component.event; + +/** + * Propagated when an HTTP-based session is expired + * + * @version $$Rev$$ $$Date$$ + */ +public class HttpSessionEnd extends HttpSessionEvent { + + /** + * Creates a new event + * + * @param source the source of the event + * @param id the id of the HTTP session being ended + */ + public HttpSessionEnd(Object source, Object id) { + super(source, id); + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/HttpSessionEvent.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/HttpSessionEvent.java new file mode 100644 index 0000000000..ed245d0930 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/HttpSessionEvent.java @@ -0,0 +1,45 @@ +/* + * 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.core.component.event; + +/** + * A base implementation of HTTP-based session events in the runtime + * + * @version $$Rev$$ $$Date$$ + */ +public abstract class HttpSessionEvent extends AbstractEvent { + + private Object id; + + public HttpSessionEvent(Object source, Object id) { + super(source); + assert id != null : "Session id was null"; + this.id = id; + } + + + public Object getSource() { + return source; + } + + public Object getId() { + return id; + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/HttpSessionStart.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/HttpSessionStart.java new file mode 100644 index 0000000000..7f9c0fadea --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/HttpSessionStart.java @@ -0,0 +1,38 @@ +/* + * 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.core.component.event; + +/** + * Propagated when an HTTP-based session has started + * + * @version $$Rev$$ $$Date$$ + */ +public class HttpSessionStart extends HttpSessionEvent { + + /** + * Creates a new event + * + * @param source the source of the event + * @param id the id of the HTTP session being ended + */ + public HttpSessionStart(Object source, Object id) { + super(source, id); + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/RequestEnd.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/RequestEnd.java new file mode 100644 index 0000000000..25856e86f8 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/RequestEnd.java @@ -0,0 +1,38 @@ +/* + * 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.core.component.event; + +/** + * Propagated when a request completes or is ended + * + * @version $$Rev$$ $$Date$$ + */ +public class RequestEnd extends AbstractRequestEvent { + + /** + * Creates a new event + * + * @param source the source of the event + */ + public RequestEnd(Object source) { + super(source); + } + + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/RequestEvent.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/RequestEvent.java new file mode 100644 index 0000000000..9a6d767236 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/RequestEvent.java @@ -0,0 +1,28 @@ +/* + * 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.core.component.event; + +/** + * Implemented by runtime events associated request + * + * @version $$Rev$$ $$Date$$ + */ +public interface RequestEvent { + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/RequestStart.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/RequestStart.java new file mode 100644 index 0000000000..466f52551a --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/event/RequestStart.java @@ -0,0 +1,37 @@ +/* + * 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.core.component.event; + +/** + * Propagated when a request is started in the runtime + * + * @version $$Rev$$ $$Date$$ + */ +public class RequestStart extends AbstractRequestEvent { + + /** + * Creates a new event + * + * @param source the source of the event + */ + public RequestStart(Object source) { + super(source); + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/scope/AbstractScopeContainer.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/scope/AbstractScopeContainer.java new file mode 100644 index 0000000000..7fa8765426 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/scope/AbstractScopeContainer.java @@ -0,0 +1,265 @@ +/* + * 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.core.component.scope; + + +import java.net.URI; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.osoa.sca.annotations.Destroy; +import org.osoa.sca.annotations.Init; +import org.osoa.sca.annotations.Reference; + +import org.apache.tuscany.spi.AbstractLifecycle; +import org.apache.tuscany.spi.component.AtomicComponent; +import org.apache.tuscany.spi.component.GroupInitializationException; +import org.apache.tuscany.spi.component.InstanceWrapper; +import org.apache.tuscany.spi.component.PersistenceException; +import org.apache.tuscany.spi.component.ScopeContainer; +import org.apache.tuscany.spi.component.ScopeContainerMonitor; +import org.apache.tuscany.spi.component.ScopeRegistry; +import org.apache.tuscany.spi.component.TargetDestructionException; +import org.apache.tuscany.spi.component.TargetResolutionException; +import org.apache.tuscany.spi.event.Event; +import org.apache.tuscany.spi.model.Scope; + +/** + * Implements functionality common to scope contexts. + * + * @version $Rev$ $Date$ + */ +public abstract class AbstractScopeContainer<KEY> extends AbstractLifecycle + implements ScopeContainer<KEY> { + + private static final Comparator<AtomicComponent<?>> COMPARATOR = new Comparator<AtomicComponent<?>>() { + public int compare(AtomicComponent<?> o1, AtomicComponent<?> o2) { + return o1.getInitLevel() - o2.getInitLevel(); + } + }; + + private final Scope scope; + protected final ScopeContainerMonitor monitor; + + protected final Map<AtomicComponent<?>, URI> componentGroups = + new ConcurrentHashMap<AtomicComponent<?>, URI>(); + + protected final Map<KEY, URI> contextGroups = new ConcurrentHashMap<KEY, URI>(); + + // the queue of components to eagerly initialize in each group + protected final Map<URI, List<AtomicComponent<?>>> initQueues = + new HashMap<URI, List<AtomicComponent<?>>>(); + + // the queue of instanceWrappers to destroy, in the order that their instances were created + protected final Map<KEY, List<InstanceWrapper<?>>> destroyQueues = + new ConcurrentHashMap<KEY, List<InstanceWrapper<?>>>(); + + public AbstractScopeContainer(Scope scope, ScopeContainerMonitor monitor) { + this.scope = scope; + this.monitor = monitor; + } + + public Scope getScope() { + return scope; + } + + @Reference + public void setScopeRegistry(ScopeRegistry scopeRegistry) { + scopeRegistry.register(this); + } + + @Init + public synchronized void start() { + int lifecycleState = getLifecycleState(); + if (lifecycleState != UNINITIALIZED && lifecycleState != STOPPED) { + throw new IllegalStateException("Scope must be in UNINITIALIZED or STOPPED state [" + lifecycleState + "]"); + } + setLifecycleState(RUNNING); + } + + @Destroy + public synchronized void stop() { + int lifecycleState = getLifecycleState(); + if (lifecycleState != RUNNING) { + throw new IllegalStateException("Scope in wrong state [" + lifecycleState + "]"); + } + setLifecycleState(STOPPED); + componentGroups.clear(); + contextGroups.clear(); + synchronized (initQueues) { + initQueues.clear(); + } + destroyQueues.clear(); + } + + protected void checkInit() { + if (getLifecycleState() != RUNNING) { + throw new IllegalStateException("Scope container not running [" + getLifecycleState() + "]"); + } + } + + public void onEvent(Event event) { + } + + public <T> void register(AtomicComponent<T> component, URI groupId) { + checkInit(); + if (component.isEagerInit()) { + componentGroups.put(component, groupId); + synchronized (initQueues) { + List<AtomicComponent<?>> initQueue = initQueues.get(groupId); + if (initQueue == null) { + initQueue = new ArrayList<AtomicComponent<?>>(); + initQueues.put(groupId, initQueue); + } + // FIXME it would be more efficient to binary search and then insert + initQueue.add(component); + Collections.sort(initQueue, COMPARATOR); + } + } + } + + public <T> void unregister(AtomicComponent<T> component) { + if (component.isEagerInit()) { + URI groupId = componentGroups.remove(component); + synchronized (initQueues) { + List<AtomicComponent<?>> initQueue = initQueues.get(groupId); + initQueue.remove(component); + if (initQueue.isEmpty()) { + initQueues.remove(groupId); + } + } + } + } + + public void startContext(KEY contextId, URI groupId) throws GroupInitializationException { + assert !contextGroups.containsKey(contextId); + contextGroups.put(contextId, groupId); + destroyQueues.put(contextId, new ArrayList<InstanceWrapper<?>>()); + + // get and clone initialization queue + List<AtomicComponent<?>> initQueue; + synchronized (initQueues) { + initQueue = initQueues.get(groupId); + if (initQueue != null) { + initQueue = new ArrayList<AtomicComponent<?>>(initQueue); + } + } + if (initQueue != null) { + initializeComponents(contextId, initQueue); + } + } + + public void stopContext(KEY contextId) { + assert contextGroups.containsKey(contextId); + shutdownComponents(destroyQueues.get(contextId)); + contextGroups.remove(contextId); + destroyQueues.remove(contextId); + } + + public <T> InstanceWrapper<T> getWrapper(AtomicComponent<T> component, KEY contextId) + throws TargetResolutionException { + return null; + } + + public <T> InstanceWrapper<T> getAssociatedWrapper(AtomicComponent<T> component, KEY contextId) + throws TargetResolutionException { + return null; + } + + public <T> void returnWrapper(AtomicComponent<T> component, InstanceWrapper<T> wrapper, KEY contextId) + throws TargetDestructionException { + } + + public <T> void remove(AtomicComponent<T> component) throws PersistenceException { + throw new UnsupportedOperationException("Scope does not support persistence"); + } + + /** + * Initialise an ordered list of components. + * The list is traversed in order and the getWrapper() method called for each to + * associate an instance with the supplied context. + * + * @param contextId the contextId to associated with the component instances + * @param components the components to be initialized + * @throws GroupInitializationException if one or more components threw an exception during initialization + */ + protected void initializeComponents(KEY contextId, List<AtomicComponent<?>> components) + throws GroupInitializationException { + List<Exception> causes = null; + for (AtomicComponent<?> component : components) { + try { + getWrapper(component, contextId); + + } catch (Exception e) { + if (causes == null) { + causes = new ArrayList<Exception>(); + } + causes.add(e); + } + } + if (causes != null) { + throw new GroupInitializationException(String.valueOf(contextId), causes); + } + } + + /** + * Shut down an ordered list of instances. + * The list passed to this method is treated as a live, mutable list + * so any instances added to this list as shutdown is occuring will also be shut down. + * + * @param instances the list of instances to shutdown + */ + protected void shutdownComponents(List<InstanceWrapper<?>> instances) { + while (true) { + InstanceWrapper<?> toDestroy; + synchronized (instances) { + if (instances.size() == 0) { + return; + } + toDestroy = instances.remove(instances.size() - 1); + } + try { + toDestroy.stop(); + } catch (TargetDestructionException e) { + // log the error from destroy but continue + monitor.destructionError(e); + } + } + } + + public String toString() { + return "In state [" + super.toString() + ']'; + } + + /** + * Creates a new physical instance of a component, wrapped in an InstanceWrapper. + * + * @param component the component whose instance should be created + * @return a wrapped instance that has been injected but not yet started + * @throws TargetResolutionException if there was a problem creating the instance + */ + protected <T> InstanceWrapper<T> createInstance(AtomicComponent<T> component) throws TargetResolutionException { + return component.createInstanceWrapper(); + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/scope/CompositeScopeContainer.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/scope/CompositeScopeContainer.java new file mode 100644 index 0000000000..1a5dbcdcd4 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/scope/CompositeScopeContainer.java @@ -0,0 +1,114 @@ +/* + * 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.core.component.scope; + +import java.net.URI; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.osoa.sca.annotations.EagerInit; +import org.osoa.sca.annotations.Service; + +import org.apache.tuscany.api.annotation.Monitor; +import org.apache.tuscany.spi.component.AtomicComponent; +import org.apache.tuscany.spi.component.InstanceWrapper; +import org.apache.tuscany.spi.component.ScopeContainerMonitor; +import org.apache.tuscany.spi.component.TargetDestructionException; +import org.apache.tuscany.spi.component.TargetInitializationException; +import org.apache.tuscany.spi.component.TargetNotFoundException; +import org.apache.tuscany.spi.component.TargetResolutionException; +import org.apache.tuscany.spi.component.ScopeContainer; +import org.apache.tuscany.spi.model.Scope; + +/** + * A scope context which manages atomic component instances keyed by composite + * + * @version $Rev$ $Date$ + */ +@EagerInit +@Service(ScopeContainer.class) +public class CompositeScopeContainer<KEY> extends AbstractScopeContainer<KEY> { + private static final InstanceWrapper<Object> EMPTY = new InstanceWrapper<Object>() { + public Object getInstance() { + return null; + } + + public boolean isStarted() { + return true; + } + + public void start() throws TargetInitializationException { + + } + + public void stop() throws TargetDestructionException { + + } + }; + + // there is one instance per component so we can index directly + private final Map<AtomicComponent<?>, InstanceWrapper<?>> instanceWrappers = + new ConcurrentHashMap<AtomicComponent<?>, InstanceWrapper<?>>(); + + public CompositeScopeContainer(@Monitor ScopeContainerMonitor monitor) { + super(Scope.COMPOSITE, monitor); + } + + public <T> void register(AtomicComponent<T> component, URI groupId) { + super.register(component, groupId); + instanceWrappers.put(component, EMPTY); + } + + public <T> void unregister(AtomicComponent<T> component) { + // FIXME should this component be destroyed already or do we need to stop it? + instanceWrappers.remove(component); + super.unregister(component); + } + + public synchronized void stop() { + super.stop(); + instanceWrappers.clear(); + } + + public <T> InstanceWrapper<T> getWrapper(AtomicComponent<T> component, KEY contextId) + throws TargetResolutionException { + assert instanceWrappers.containsKey(component); + @SuppressWarnings("unchecked") + InstanceWrapper<T> wrapper = (InstanceWrapper<T>) instanceWrappers.get(component); + if (wrapper == EMPTY) { + // FIXME is there a potential race condition here that may result in two instances being created + wrapper = createInstance(component); + instanceWrappers.put(component, wrapper); + wrapper.start(); + destroyQueues.get(contextId).add(wrapper); + } + return wrapper; + } + + public <T> InstanceWrapper<T> getAssociatedWrapper(AtomicComponent<T> component, KEY contextId) + throws TargetResolutionException { + assert instanceWrappers.containsKey(component); + @SuppressWarnings("unchecked") + InstanceWrapper<T> wrapper = (InstanceWrapper<T>) instanceWrappers.get(component); + if (wrapper == EMPTY) { + throw new TargetNotFoundException(component.getUri().toString()); + } + return wrapper; + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/scope/ConversationalScopeContainer.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/scope/ConversationalScopeContainer.java new file mode 100644 index 0000000000..2d9d3d938c --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/scope/ConversationalScopeContainer.java @@ -0,0 +1,190 @@ +/*
+ * 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.core.component.scope;
+
+import java.net.URI;
+
+import org.apache.tuscany.spi.component.AtomicComponent;
+import org.apache.tuscany.spi.component.InstanceWrapper;
+import org.apache.tuscany.spi.component.PersistenceException;
+import org.apache.tuscany.spi.component.ScopeContainer;
+import org.apache.tuscany.spi.component.ScopeContainerMonitor;
+import org.apache.tuscany.spi.component.TargetDestructionException;
+import org.apache.tuscany.spi.component.TargetResolutionException;
+import org.apache.tuscany.spi.component.WorkContext;
+import org.apache.tuscany.spi.event.Event;
+import org.apache.tuscany.spi.event.RuntimeEventListener;
+import org.apache.tuscany.spi.model.Scope;
+import org.apache.tuscany.spi.services.store.Store;
+import org.apache.tuscany.spi.services.store.StoreExpirationEvent;
+import org.apache.tuscany.spi.services.store.StoreReadException;
+import org.apache.tuscany.spi.services.store.StoreWriteException;
+
+/**
+ * A scope context which manages atomic component instances keyed on a conversation session
+ *
+ * @version $Rev: 452655 $ $Date: 2006-10-03 18:09:02 -0400 (Tue, 03 Oct 2006) $
+ */
+public class ConversationalScopeContainer extends AbstractScopeContainer implements ScopeContainer {
+ private final WorkContext workContext;
+ private final Store nonDurableStore;
+
+ public ConversationalScopeContainer(Store store, WorkContext workContext, final ScopeContainerMonitor monitor) {
+ super(Scope.CONVERSATION, monitor);
+ this.workContext = workContext;
+ this.nonDurableStore = store;
+ if (store != null) {
+ store.addListener(new ExpirationListener(monitor));
+ }
+ }
+
+ public void onEvent(Event event) {
+ checkInit();
+ }
+
+ public synchronized void start() {
+ if (lifecycleState != UNINITIALIZED && lifecycleState != STOPPED) {
+ throw new IllegalStateException("Scope must be in UNINITIALIZED or STOPPED state [" + lifecycleState + "]");
+ }
+ lifecycleState = RUNNING;
+ }
+
+ public synchronized void stop() {
+ lifecycleState = STOPPED;
+ }
+
+ public void register(AtomicComponent component, URI groupId) {
+ super.register(component, groupId);
+ component.addListener(this);
+ }
+
+ public void unregister(AtomicComponent component) {
+ // FIXME should all the instances associated with this component be remove already
+ component.removeListener(this);
+ super.unregister(component);
+ }
+
+ public void persistNew(AtomicComponent component, String id, Object instance, long expiration)
+ throws PersistenceException {
+ try {
+ nonDurableStore.insertRecord(component, id, instance, expiration);
+ } catch (StoreWriteException e) {
+ throw new PersistenceException(e);
+ }
+ }
+
+ public void persist(AtomicComponent component, String id, Object instance, long expiration)
+ throws PersistenceException {
+ try {
+ nonDurableStore.updateRecord(component, id, instance, expiration);
+ } catch (StoreWriteException e) {
+ throw new PersistenceException(e);
+ }
+ }
+
+ public void remove(AtomicComponent component) throws PersistenceException {
+ String conversationId = getConversationId();
+ try {
+ workContext.setCurrentAtomicComponent(component);
+ // FIXME this should be an InstanceWrapper and shouldn't we stop it?
+ Object instance = nonDurableStore.readRecord(component, conversationId);
+ if (instance != null) {
+ nonDurableStore.removeRecord(component, conversationId);
+ }
+ } catch (StoreReadException e) {
+ throw new PersistenceException(e);
+ } catch (StoreWriteException e) {
+ throw new PersistenceException(e);
+ }
+ }
+
+ protected InstanceWrapper getInstanceWrapper(AtomicComponent component, boolean create)
+ throws TargetResolutionException {
+ String conversationId = getConversationId();
+ try {
+ workContext.setCurrentAtomicComponent(component);
+ InstanceWrapper wrapper = (InstanceWrapper) nonDurableStore.readRecord(component, conversationId);
+ if (wrapper != null) {
+ if (component.getMaxIdleTime() > 0) {
+ // update expiration
+ long expire = System.currentTimeMillis() + component.getMaxIdleTime();
+ nonDurableStore.updateRecord(component, conversationId, wrapper, expire);
+ }
+ } else if (create) {
+ // FIXME should the store really be persisting the wrappers
+ wrapper = component.createInstanceWrapper();
+ wrapper.start();
+ long expire = calculateExpiration(component);
+ nonDurableStore.insertRecord(component, conversationId, wrapper, expire);
+ }
+ return wrapper;
+ } catch (StoreReadException e) {
+ throw new TargetResolutionException("Error retrieving target instance", e);
+ } catch (StoreWriteException e) {
+ throw new TargetResolutionException("Error persisting target instance", e);
+ } finally {
+ workContext.setCurrentAtomicComponent(null);
+ }
+ }
+
+ /**
+ * Returns the conversation id associated with the current invocation context
+ * @return the conversation id
+ */
+ private String getConversationId() {
+ String conversationId = (String) workContext.getIdentifier(Scope.CONVERSATION);
+ assert conversationId != null;
+ return conversationId;
+ }
+
+ private long calculateExpiration(AtomicComponent component) {
+ if (component.getMaxAge() > 0) {
+ long now = System.currentTimeMillis();
+ return now + component.getMaxAge();
+ } else if (component.getMaxIdleTime() > 0) {
+ long now = System.currentTimeMillis();
+ return now + component.getMaxIdleTime();
+ } else {
+ return Store.DEFAULT_EXPIRATION_OFFSET;
+ }
+ }
+
+ /**
+ * Receives expiration events from the store and notifies the corresponding atomic component
+ */
+ private static class ExpirationListener implements RuntimeEventListener {
+ private final ScopeContainerMonitor monitor;
+
+ public ExpirationListener(ScopeContainerMonitor monitor) {
+ this.monitor = monitor;
+ }
+
+ public void onEvent(Event event) {
+ if (event instanceof StoreExpirationEvent) {
+ StoreExpirationEvent expiration = (StoreExpirationEvent) event;
+ InstanceWrapper wrapper = (InstanceWrapper) expiration.getInstance();
+ try {
+ wrapper.stop();
+ } catch (TargetDestructionException e) {
+ monitor.destructionError(e);
+ }
+ }
+ }
+ }
+}
diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/scope/HttpSessionScopeContainer.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/scope/HttpSessionScopeContainer.java new file mode 100644 index 0000000000..5a398e921e --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/scope/HttpSessionScopeContainer.java @@ -0,0 +1,141 @@ +/* + * 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.core.component.scope; + +import java.util.ArrayList; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.tuscany.spi.component.AtomicComponent; +import org.apache.tuscany.spi.component.ScopeContainerMonitor; +import org.apache.tuscany.spi.component.TargetDestructionException; +import org.apache.tuscany.spi.component.TargetResolutionException; +import org.apache.tuscany.spi.component.WorkContext; +import org.apache.tuscany.spi.component.InstanceWrapper; +import org.apache.tuscany.spi.event.Event; +import org.apache.tuscany.spi.model.Scope; + +import org.apache.tuscany.core.component.event.HttpSessionEnd; + +/** + * A scope context which manages atomic component instances keyed on HTTP session + * + * @version $Rev$ $Date$ + */ +public class HttpSessionScopeContainer extends AbstractScopeContainer { + private final WorkContext workContext; + private final Map<AtomicComponent, Map<Object, InstanceWrapper>> contexts; + private final Map<Object, List<InstanceWrapper>> destroyQueues; + + public HttpSessionScopeContainer(WorkContext workContext, ScopeContainerMonitor monitor) { + super(Scope.SESSION, monitor); + this.workContext = workContext; + contexts = new ConcurrentHashMap<AtomicComponent, Map<Object, InstanceWrapper>>(); + destroyQueues = new ConcurrentHashMap<Object, List<InstanceWrapper>>(); + } + + public void onEvent(Event event) { + checkInit(); + if (event instanceof HttpSessionEnd) { + Object key = ((HttpSessionEnd) event).getId(); + shutdownInstances(key); + workContext.clearIdentifier(key); + } + } + + public synchronized void start() { + if (lifecycleState != UNINITIALIZED && lifecycleState != STOPPED) { + throw new IllegalStateException("Scope must be in UNINITIALIZED or STOPPED state [" + lifecycleState + "]"); + } + lifecycleState = RUNNING; + } + + public synchronized void stop() { + contexts.clear(); + synchronized (destroyQueues) { + destroyQueues.clear(); + } + lifecycleState = STOPPED; + } + + public void register(AtomicComponent component, Object groupId) { + contexts.put(component, new ConcurrentHashMap<Object, InstanceWrapper>()); + component.addListener(this); + } + + public void unregister(AtomicComponent component) { + // FIXME should all the instances associated with this component be destroyed already + contexts.remove(component); + component.removeListener(this); + super.unregister(component); + } + + protected InstanceWrapper getInstanceWrapper(AtomicComponent component, boolean create) + throws TargetResolutionException { + Object key = workContext.getIdentifier(Scope.SESSION); + assert key != null : "HTTP session key not bound in work context"; + return getInstance(component, key, create); + } + + private InstanceWrapper getInstance(AtomicComponent component, Object key, boolean create) + throws TargetResolutionException { + Map<Object, InstanceWrapper> wrappers = contexts.get(component); + InstanceWrapper ctx = wrappers.get(key); + if (ctx == null && !create) { + return null; + } + if (ctx == null) { + ctx = component.createInstanceWrapper(); + ctx.start(); + wrappers.put(key, ctx); + List<InstanceWrapper> destroyQueue = destroyQueues.get(key); + if (destroyQueue == null) { + destroyQueue = new ArrayList<InstanceWrapper>(); + destroyQueues.put(key, destroyQueue); + } + synchronized (destroyQueue) { + destroyQueue.add(ctx); + } + } + return ctx; + + } + + private void shutdownInstances(Object key) { + List<InstanceWrapper> destroyQueue = destroyQueues.remove(key); + if (destroyQueue != null) { + for (Map<Object, InstanceWrapper> map : contexts.values()) { + map.remove(key); + } + ListIterator<InstanceWrapper> iter = destroyQueue.listIterator(destroyQueue.size()); + synchronized (destroyQueue) { + while (iter.hasPrevious()) { + try { + iter.previous().stop(); + } catch (TargetDestructionException e) { + monitor.destructionError(e); + } + } + } + } + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/scope/InstanceWrapperBase.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/scope/InstanceWrapperBase.java new file mode 100644 index 0000000000..def862fa7c --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/scope/InstanceWrapperBase.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.core.component.scope; + +import org.apache.tuscany.spi.component.TargetDestructionException; +import org.apache.tuscany.spi.component.TargetInitializationException; +import org.apache.tuscany.spi.component.InstanceWrapper; + +/** + * @version $Rev$ $Date$ + */ +public class InstanceWrapperBase<T> implements InstanceWrapper<T> { + protected final T instance; + private boolean started; + + public InstanceWrapperBase(T instance) { + assert instance != null; + this.instance = instance; + } + + public T getInstance() { + assert started; + return instance; + } + + public boolean isStarted() { + return started; + } + + public void start() throws TargetInitializationException { + started = true; + } + + public void stop() throws TargetDestructionException { + started = false; + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/scope/RequestScopeContainer.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/scope/RequestScopeContainer.java new file mode 100644 index 0000000000..d40277dc23 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/scope/RequestScopeContainer.java @@ -0,0 +1,130 @@ +/* + * 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.core.component.scope; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.tuscany.spi.component.AtomicComponent; +import org.apache.tuscany.spi.component.ScopeContainerMonitor; +import org.apache.tuscany.spi.component.TargetDestructionException; +import org.apache.tuscany.spi.component.TargetResolutionException; +import org.apache.tuscany.spi.component.InstanceWrapper; +import org.apache.tuscany.spi.event.Event; +import org.apache.tuscany.spi.model.Scope; + +import org.apache.tuscany.core.component.event.RequestEnd; + +/** + * A scope context which manages atomic component instances keyed on the current request context + * + * @version $Rev$ $Date$ + */ +public class RequestScopeContainer extends AbstractScopeContainer { + private final Map<AtomicComponent, Map<Thread, InstanceWrapper>> contexts; + private final Map<Thread, List<InstanceWrapper>> destroyQueues; + + public RequestScopeContainer(ScopeContainerMonitor monitor) { + super(Scope.REQUEST, monitor); + contexts = new ConcurrentHashMap<AtomicComponent, Map<Thread, InstanceWrapper>>(); + destroyQueues = new ConcurrentHashMap<Thread, List<InstanceWrapper>>(); + } + + public void onEvent(Event event) { + checkInit(); + if (event instanceof RequestEnd) { + shutdownInstances(Thread.currentThread()); + } + } + + public synchronized void start() { + if (lifecycleState != UNINITIALIZED && lifecycleState != STOPPED) { + throw new IllegalStateException("Scope must be in UNINITIALIZED or STOPPED state [" + lifecycleState + "]"); + } + lifecycleState = RUNNING; + } + + public synchronized void stop() { + contexts.clear(); + synchronized (destroyQueues) { + destroyQueues.clear(); + } + lifecycleState = STOPPED; + } + + public void register(AtomicComponent component, URI groupId) { + super.register(component, groupId); + contexts.put(component, new ConcurrentHashMap<Thread, InstanceWrapper>()); + } + + public void unregister(AtomicComponent component) { + // FIXME should all the instances associated with this component be destroyed already + contexts.remove(component); + super.unregister(component); + } + + protected InstanceWrapper getInstanceWrapper(AtomicComponent component, boolean create) + throws TargetResolutionException { + Map<Thread, InstanceWrapper> instanceContextMap = contexts.get(component); + assert instanceContextMap != null : "Atomic component not registered"; + InstanceWrapper ctx = instanceContextMap.get(Thread.currentThread()); + if (ctx == null && !create) { + return null; + } + if (ctx == null) { + ctx = component.createInstanceWrapper(); + ctx.start(); + instanceContextMap.put(Thread.currentThread(), ctx); + List<InstanceWrapper> destroyQueue = destroyQueues.get(Thread.currentThread()); + if (destroyQueue == null) { + destroyQueue = new ArrayList<InstanceWrapper>(); + destroyQueues.put(Thread.currentThread(), destroyQueue); + } + synchronized (destroyQueue) { + destroyQueue.add(ctx); + } + } + return ctx; + } + + private void shutdownInstances(Thread key) { + List<InstanceWrapper> destroyQueue = destroyQueues.remove(key); + if (destroyQueue != null && destroyQueue.size() > 0) { + Thread thread = Thread.currentThread(); + for (Map<Thread, InstanceWrapper> map : contexts.values()) { + map.remove(thread); + } + ListIterator<InstanceWrapper> iter = destroyQueue.listIterator(destroyQueue.size()); + synchronized (destroyQueue) { + while (iter.hasPrevious()) { + try { + iter.previous().stop(); + } catch (TargetDestructionException e) { + monitor.destructionError(e); + } + } + } + } + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/scope/ScopeRegistryImpl.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/scope/ScopeRegistryImpl.java new file mode 100644 index 0000000000..bcf05982eb --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/scope/ScopeRegistryImpl.java @@ -0,0 +1,49 @@ +/* + * 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.core.component.scope; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.tuscany.spi.ObjectFactory; +import org.apache.tuscany.spi.component.ScopeContainer; +import org.apache.tuscany.spi.component.ScopeRegistry; +import org.apache.tuscany.spi.model.Scope; + +/** + * The default implementation of a scope registry + * + * @version $Rev$ $Date$ + */ +public class ScopeRegistryImpl implements ScopeRegistry { + private final Map<Scope, ScopeContainer> scopeCache = + new ConcurrentHashMap<Scope, ScopeContainer>(); + private final Map<Scope, ObjectFactory<? extends ScopeContainer>> factoryCache = + new ConcurrentHashMap<Scope, ObjectFactory<? extends ScopeContainer>>(); + + public void register(ScopeContainer container) { + scopeCache.put(container.getScope(), container); + } + + public ScopeContainer getScopeContainer(Scope scope) { + return scopeCache.get(scope); + } + + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/scope/StatelessScopeContainer.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/scope/StatelessScopeContainer.java new file mode 100644 index 0000000000..0e1d5cab6a --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/component/scope/StatelessScopeContainer.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.core.component.scope; + +import org.osoa.sca.annotations.EagerInit; +import org.osoa.sca.annotations.Service; + +import org.apache.tuscany.spi.component.AtomicComponent; +import org.apache.tuscany.spi.component.InstanceWrapper; +import org.apache.tuscany.spi.component.ScopeContainerMonitor; +import org.apache.tuscany.spi.component.TargetDestructionException; +import org.apache.tuscany.spi.component.TargetResolutionException; +import org.apache.tuscany.spi.component.ScopeContainer; +import org.apache.tuscany.spi.model.Scope; +import org.apache.tuscany.api.annotation.Monitor; + +/** + * A scope context which manages stateless atomic component instances in a non-pooled fashion. + * + * @version $Rev$ $Date$ + */ +@EagerInit +@Service(ScopeContainer.class) +public class StatelessScopeContainer<KEY> extends AbstractScopeContainer<KEY> { + + public StatelessScopeContainer(@Monitor ScopeContainerMonitor monitor) { + super(Scope.STATELESS, monitor); + } + + public <T> InstanceWrapper<T> getWrapper(AtomicComponent<T> component, KEY contextId) + throws TargetResolutionException { + InstanceWrapper<T> ctx = createInstance(component); + ctx.start(); + return ctx; + } + + public <T> InstanceWrapper<T> getAssociatedWrapper(AtomicComponent<T> component, KEY contextId) + throws TargetResolutionException { + throw new UnsupportedOperationException(); + } + + public <T> void returnWrapper(AtomicComponent<T> component, InstanceWrapper<T> wrapper, KEY contextId) + throws TargetDestructionException { + wrapper.stop(); + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/deployer/AbstractDeploymentContext.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/deployer/AbstractDeploymentContext.java new file mode 100644 index 0000000000..8d24047781 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/deployer/AbstractDeploymentContext.java @@ -0,0 +1,80 @@ +/* + * 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.core.deployer; + +import java.net.URI; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; + +import org.apache.tuscany.spi.component.Component; +import org.apache.tuscany.spi.deployer.DeploymentContext; + +/** + * Base class for DeploymentContext implementations. + * + * @version $Rev$ $Date$ + */ +public abstract class AbstractDeploymentContext implements DeploymentContext { + private final URI componentId; + private boolean autowire; + private final ClassLoader classLoader; + private final URL scdlLocation; + private final Map<URI, Component> components = new HashMap<URI, Component>(); + + /** + * Constructor defining properties of this context. + * + * @param classLoader the classloader for loading application resources + * @param scdlLocation the location of the SCDL defining this composite + * @param componentId the id of the component being deployed + * @param autowire if autowire is enabled + */ + protected AbstractDeploymentContext(ClassLoader classLoader, URL scdlLocation, URI componentId, boolean autowire) { + this.classLoader = classLoader; + this.scdlLocation = scdlLocation; + this.componentId = componentId; + this.autowire = autowire; + } + + public ClassLoader getClassLoader() { + return classLoader; + } + + public URL getScdlLocation() { + return scdlLocation; + } + + public URI getComponentId() { + return componentId; + } + + public boolean isAutowire() { + return autowire; + } + + public void setAutowire(boolean autowire) { + this.autowire = autowire; + } + + @Deprecated + public Map<URI, Component> getComponents() { + return components; + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/deployer/ChildDeploymentContext.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/deployer/ChildDeploymentContext.java new file mode 100644 index 0000000000..c2f8ae07fc --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/deployer/ChildDeploymentContext.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.core.deployer; + +import java.net.URI; +import java.net.URL; +import javax.xml.stream.XMLInputFactory; + +import org.apache.tuscany.spi.component.ScopeContainer; +import org.apache.tuscany.spi.deployer.DeploymentContext; + +/** + * An holder that can be used during the load process to store information that is not part of the logical assembly + * model. This should be regarded as transient and references to this context should not be stored inside the model. + * + * @version $Rev$ $Date$ + */ +public class ChildDeploymentContext extends AbstractDeploymentContext { + private final DeploymentContext parent; + + /** + * Constructor defining properties of this context. + * + * @param parent the parent of this context + * @param classLoader the classloader for loading application resources + * @param scdlLocation the location of the SCDL defining this composite + * @param componentId the id of the component being deployed + * @param autowire if autowire is enabled + */ + public ChildDeploymentContext(DeploymentContext parent, + ClassLoader classLoader, + URL scdlLocation, + URI componentId, + boolean autowire) { + super(classLoader, scdlLocation, componentId, autowire); + assert parent != null; + this.parent = parent; + } + + public DeploymentContext getParent() { + return parent; + } + + public XMLInputFactory getXmlFactory() { + return parent.getXmlFactory(); + } + + public ScopeContainer getCompositeScope() { + return parent.getCompositeScope(); + } + + public URI getGroupId() { + return parent.getGroupId(); + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/deployer/DeployerImpl.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/deployer/DeployerImpl.java new file mode 100644 index 0000000000..18f078e4f6 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/deployer/DeployerImpl.java @@ -0,0 +1,197 @@ +/* + * 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.core.deployer; + +import java.net.URI; +import java.util.Collection; +import javax.xml.stream.XMLInputFactory; + +import org.osoa.sca.annotations.Reference; + +import org.apache.tuscany.api.annotation.Monitor; +import org.apache.tuscany.core.resolver.AutowireResolver; +import org.apache.tuscany.spi.builder.Builder; +import org.apache.tuscany.spi.builder.BuilderException; +import org.apache.tuscany.spi.builder.BuilderInstantiationException; +import org.apache.tuscany.spi.builder.BuilderRegistry; +import org.apache.tuscany.spi.builder.Connector; +import org.apache.tuscany.spi.component.Component; +import org.apache.tuscany.spi.component.ComponentManager; +import org.apache.tuscany.spi.component.RegistrationException; +import org.apache.tuscany.spi.component.SCAObject; +import org.apache.tuscany.spi.component.ScopeContainer; +import org.apache.tuscany.spi.component.ScopeContainerMonitor; +import org.apache.tuscany.spi.component.ScopeRegistry; +import org.apache.tuscany.spi.deployer.Deployer; +import org.apache.tuscany.spi.deployer.DeploymentContext; +import org.apache.tuscany.spi.loader.Loader; +import org.apache.tuscany.spi.loader.LoaderException; +import org.apache.tuscany.spi.loader.LoaderRegistry; +import org.apache.tuscany.spi.model.ComponentDefinition; +import org.apache.tuscany.spi.model.Implementation; +import org.apache.tuscany.spi.model.Scope; +import org.apache.tuscany.spi.resolver.ResolutionException; + +/** + * Default implementation of Deployer. + * + * @version $Rev$ $Date$ + */ +public class DeployerImpl implements Deployer { + private XMLInputFactory xmlFactory; + private Loader loader; + private Builder builder; + private ScopeContainerMonitor monitor; + private AutowireResolver resolver; + private Connector connector; + private ComponentManager componentManager; + private ScopeRegistry scopeRegistry; + + + public DeployerImpl(XMLInputFactory xmlFactory, + Loader loader, + Builder builder, + ComponentManager componentManager, + AutowireResolver resolver, + Connector connector) { + this.xmlFactory = xmlFactory; + this.builder = builder; + this.loader = loader; + this.componentManager = componentManager; + this.resolver = resolver; + this.connector = connector; + } + + public DeployerImpl() { + xmlFactory = XMLInputFactory.newInstance("javax.xml.stream.XMLInputFactory", getClass().getClassLoader()); + } + + @Reference + public void setBuilder(BuilderRegistry builder) { + this.builder = builder; + } + + @Monitor + public void setMonitor(ScopeContainerMonitor monitor) { + this.monitor = monitor; + } + + @Reference + public void setResolver(AutowireResolver resolver) { + this.resolver = resolver; + } + + @Reference + public void setConnector(Connector connector) { + this.connector = connector; + } + + @Reference + public void setComponentManager(ComponentManager componentManager) { + this.componentManager = componentManager; + } + + @Reference + public void setScopeRegistry(ScopeRegistry scopeRegistry) { + this.scopeRegistry = scopeRegistry; + } + + public <I extends Implementation<?>> Collection<Component> deploy(Component parent, + ComponentDefinition<I> componentDefinition) + throws LoaderException, BuilderException, ResolutionException { + @SuppressWarnings("unchecked") + ScopeContainer<URI> scopeContainer = scopeRegistry.getScopeContainer(Scope.COMPOSITE); + URI groupId = componentDefinition.getUri(); + DeploymentContext deploymentContext = + new RootDeploymentContext(null, null, groupId, xmlFactory, scopeContainer, false); + // load the model + load(parent, componentDefinition, deploymentContext); + // resolve autowires + resolver.resolve(null, componentDefinition); + // build runtime artifacts + build(parent, componentDefinition, deploymentContext); +/* + // create a listener so the scope container is shutdown when the top-level composite stops + RuntimeEventListener listener = new RuntimeEventListener() { + public void onEvent(Event event) { + scopeContainer.onEvent(event); + if (event instanceof ComponentStop) { + scopeContainer.stop(); + } + } + }; + component.addListener(listener); +*/ + + Collection<Component> components = deploymentContext.getComponents().values(); + for (Component toRegister : components) { + try { + componentManager.register(toRegister); + } catch (RegistrationException e) { + throw new BuilderInstantiationException("Error registering component", e); + } + } + connector.connect(componentDefinition); + return components; + } + + /** + * Load the componentDefinition type information for the componentDefinition being deployed. For a typical + * deployment this will result in the SCDL definition being loaded. + * + * @param componentDefinition the componentDefinition being deployed + * @param deploymentContext the current deployment context + */ + protected <I extends Implementation<?>> void load(Component parent, + ComponentDefinition<I> componentDefinition, + DeploymentContext deploymentContext) throws LoaderException { + loader.loadComponentType(componentDefinition.getImplementation(), deploymentContext); + } + + + /** + * Build the runtime context for a loaded componentDefinition. + * + * @param parent the context that will be the parent of the new sub-context + * @param componentDefinition the componentDefinition being deployed + * @param deploymentContext the current deployment context + * @return the new runtime context + */ + protected <I extends Implementation<?>> SCAObject build(Component parent, + ComponentDefinition<I> componentDefinition, + DeploymentContext deploymentContext) + throws BuilderException { + return builder.build(componentDefinition, deploymentContext); + } + + /** + * @return the builder + */ + public Builder getBuilder() { + return builder; + } + + /** + * @return the loader + */ + public Loader getLoader() { + return loader; + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/deployer/RootDeploymentContext.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/deployer/RootDeploymentContext.java new file mode 100644 index 0000000000..a523dadbf4 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/deployer/RootDeploymentContext.java @@ -0,0 +1,74 @@ +/* + * 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.core.deployer; + +import java.net.URI; +import java.net.URL; +import javax.xml.stream.XMLInputFactory; + +import org.apache.tuscany.spi.component.ScopeContainer; +import org.apache.tuscany.spi.deployer.DeploymentContext; + +/** + * A holder that can be used during the load process to store information that is not part of the logical assembly + * model. This should be regarded as transient and references to this context should not be stored inside the model. + * + * @version $Rev$ $Date$ + */ +public class RootDeploymentContext extends AbstractDeploymentContext { + private final XMLInputFactory xmlFactory; + private final ScopeContainer scopeContainer; + + /** + * Constructor defining properties of this context. + * + * @param classLoader the classloader for loading application resources + * @param scdlLocation the location of the SCDL defining this composite + * @param componentId the id of the component being deployed + * @param xmlFactory a factory that can be used to obtain an StAX XMLStreamReader + * @param scopeContainer the scope context representing this deployment's COMPOSITE scope + * @param autowire if autowire is enabled + */ + public RootDeploymentContext(ClassLoader classLoader, + URL scdlLocation, + URI componentId, + XMLInputFactory xmlFactory, + ScopeContainer scopeContainer, + boolean autowire) { + super(classLoader, scdlLocation, componentId, autowire); + this.xmlFactory = xmlFactory; + this.scopeContainer = scopeContainer; + } + + public DeploymentContext getParent() { + return null; + } + + public XMLInputFactory getXmlFactory() { + return xmlFactory; + } + + public ScopeContainer getCompositeScope() { + return scopeContainer; + } + + public URI getGroupId() { + return getComponentId(); + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/implementation/PojoWorkContextTunnel.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/implementation/PojoWorkContextTunnel.java new file mode 100644 index 0000000000..cef6675f05 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/implementation/PojoWorkContextTunnel.java @@ -0,0 +1,63 @@ +/* + * 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.core.implementation; + +import org.apache.tuscany.spi.component.WorkContext; + +/** + * Class for tunneling a WorkContext through the invocation of a user class. + * + * @version $Rev$ $Date$ + */ +public final class PojoWorkContextTunnel { + private PojoWorkContextTunnel() { + } + + private static final ThreadLocal<WorkContext> CONTEXT = new ThreadLocal<WorkContext>(); + + /** + * Set the WorkContext for the current thread. + * The current work context is returned and must be restored after the invocation is complete. + * Typical usage would be: + * <pre> + * WorkContext old = PojoWorkContextTunnel.setThreadWorkContext(newContext); + * try { + * ... invoke user code ... + * } finally { + * PojoWorkContextTunnel.setThreadWorkContext(old); + * } + * </pre> + * @param context + * @return the current work context for the thread; this must be restored after the invocation is made + */ + public static WorkContext setThreadWorkContext(WorkContext context) { + WorkContext old = CONTEXT.get(); + CONTEXT.set(context); + return old; + } + + /** + * Returns the WorkContext for the current thread. + * + * @return the WorkContext for the current thread + */ + public static WorkContext getThreadWorkContext() { + return CONTEXT.get(); + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/implementation/composite/AbstractCompositeBuilder.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/implementation/composite/AbstractCompositeBuilder.java new file mode 100644 index 0000000000..d12b407ea7 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/implementation/composite/AbstractCompositeBuilder.java @@ -0,0 +1,69 @@ +/* + * 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.core.implementation.composite; + +import org.apache.tuscany.spi.builder.BuilderException; +import org.apache.tuscany.spi.builder.BuilderInstantiationException; +import org.apache.tuscany.spi.component.Component; +import org.apache.tuscany.spi.component.Reference; +import org.apache.tuscany.spi.component.RegistrationException; +import org.apache.tuscany.spi.component.Service; +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.CompositeComponentType; +import org.apache.tuscany.spi.model.Implementation; +import org.apache.tuscany.spi.model.ReferenceDefinition; +import org.apache.tuscany.spi.model.ServiceDefinition; + +/** + * Abstract builder for composites + * + * @version $Rev$ $Date$ + */ +public abstract class AbstractCompositeBuilder<T extends Implementation<CompositeComponentType>> + extends ComponentBuilderExtension<T> { + + public Component build( + Component component, + CompositeComponentType<?, ?, ?> componentType, + DeploymentContext deploymentContext) throws BuilderException { + for (ComponentDefinition<? extends Implementation<?>> definition : componentType.getComponents().values()) { + builderRegistry.build(definition, deploymentContext); + } + for (ServiceDefinition definition : componentType.getServices().values()) { + try { + Service service = builderRegistry.build(definition, deploymentContext); + component.register(service); + } catch (RegistrationException e) { + throw new BuilderInstantiationException("Error registering service", e); + } + } + for (ReferenceDefinition definition : componentType.getReferences().values()) { + try { + Reference reference = builderRegistry.build(definition, deploymentContext); + component.register(reference); + } catch (RegistrationException e) { + throw new BuilderInstantiationException("Error registering reference", e); + } + } + return component; + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/implementation/composite/ComponentTimeoutException.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/implementation/composite/ComponentTimeoutException.java new file mode 100644 index 0000000000..ed64cb1236 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/implementation/composite/ComponentTimeoutException.java @@ -0,0 +1,33 @@ +/* + * 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.core.implementation.composite; + +import org.apache.tuscany.spi.component.ComponentRuntimeException; + +/** + * Denotes a condition where a component times out waiting to perform an operation + * + * @version $Rev$ $Date$ + */ +public class ComponentTimeoutException extends ComponentRuntimeException { + + public ComponentTimeoutException(String message) { + super(message); + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/implementation/composite/CompositeBuilder.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/implementation/composite/CompositeBuilder.java new file mode 100644 index 0000000000..51d360ec39 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/implementation/composite/CompositeBuilder.java @@ -0,0 +1,51 @@ +/* + * 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.core.implementation.composite; + +import java.net.URI; + +import org.apache.tuscany.spi.builder.BuilderException; +import org.apache.tuscany.spi.component.Component; +import org.apache.tuscany.spi.deployer.DeploymentContext; +import org.apache.tuscany.spi.model.ComponentDefinition; +import org.apache.tuscany.spi.model.CompositeComponentType; +import org.apache.tuscany.spi.model.CompositeImplementation; + +/** + * Instantiates a composite component from an assembly definition + * + * @version $Rev$ $Date$ + */ +public class CompositeBuilder extends AbstractCompositeBuilder<CompositeImplementation> { + + public Component build(ComponentDefinition<CompositeImplementation> componentDefinition, + DeploymentContext deploymentContext) throws BuilderException { + + CompositeImplementation implementation = componentDefinition.getImplementation(); + CompositeComponentType<?, ?, ?> componentType = implementation.getComponentType(); + URI name = componentDefinition.getUri(); + CompositeComponentImpl component = new CompositeComponentImpl(name); + + return build(component, componentType, deploymentContext); + } + + protected Class<CompositeImplementation> getImplementationType() { + return CompositeImplementation.class; + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/implementation/composite/CompositeComponentImpl.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/implementation/composite/CompositeComponentImpl.java new file mode 100644 index 0000000000..8df05048c8 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/implementation/composite/CompositeComponentImpl.java @@ -0,0 +1,121 @@ +/* + * 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.core.implementation.composite; + +import java.net.URI; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.apache.tuscany.spi.event.Event; +import org.apache.tuscany.spi.extension.CompositeComponentExtension; +import org.apache.tuscany.spi.wire.Wire; + +import org.apache.tuscany.core.component.event.ComponentStop; + +/** + * The standard implementation of a composite component. Autowiring is performed by delegating to the parent composite. + * + * @version $Rev$ $Date$ + */ +public class CompositeComponentImpl extends CompositeComponentExtension { + public static final int DEFAULT_WAIT = 1000 * 60; + // Blocking latch to ensure the composite is initialized exactly once prior to servicing requests + protected CountDownLatch initializeLatch = new CountDownLatch(1); + protected final Object lock = new Object(); + // Indicates whether the composite context has been initialized + protected boolean initialized; + + /** + * Constructor + * + * @param name the name of this Component + */ + public CompositeComponentImpl(URI name) { + super(name); + } + + public void attachWire(Wire wire) { + throw new UnsupportedOperationException(); + } + + public void attachWires(List<Wire> wires) { + throw new UnsupportedOperationException(); + } + + public List<Wire> getWires(String name) { + throw new UnsupportedOperationException(); + } + + public void attachCallbackWire(Wire wire) { + throw new UnsupportedOperationException(); + } + + public void start() { + synchronized (lock) { + if (lifecycleState != UNINITIALIZED && lifecycleState != STOPPED) { + throw new IllegalStateException("Composite not in UNINITIALIZED state"); + } + initializeLatch.countDown(); + initialized = true; + lifecycleState = INITIALIZED; + } + } + + public void stop() { + if (lifecycleState == STOPPED) { + return; + } + + publish(new ComponentStop(this, getUri())); + // need to block a start until reset is complete + initializeLatch = new CountDownLatch(2); + lifecycleState = STOPPING; + initialized = false; + // allow initialized to be called + initializeLatch.countDown(); + lifecycleState = STOPPED; + } + + public void publish(Event event) { + if (lifecycleState == STOPPED) { + return; + } + checkInit(); + super.publish(event); + } + + /** + * Blocks until the composite context has been initialized + */ + protected void checkInit() throws ComponentTimeoutException { + if (!initialized) { + try { + /* block until the composite has initialized */ + boolean success = initializeLatch.await(DEFAULT_WAIT, TimeUnit.MILLISECONDS); + if (!success) { + throw new ComponentTimeoutException("Timeout waiting for context to initialize"); + } + } catch (InterruptedException e) { // should not happen + } + } + + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/implementation/composite/CompositeComponentTypeLoader.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/implementation/composite/CompositeComponentTypeLoader.java new file mode 100644 index 0000000000..6cb31a8e20 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/implementation/composite/CompositeComponentTypeLoader.java @@ -0,0 +1,65 @@ +/* + * 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.core.implementation.composite; + +import java.net.URI; +import java.net.URL; + +import org.apache.tuscany.spi.deployer.CompositeClassLoader; +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.loader.LoaderRegistry; +import org.apache.tuscany.spi.model.CompositeComponentType; +import org.apache.tuscany.spi.model.CompositeImplementation; + +import org.apache.tuscany.core.deployer.ChildDeploymentContext; + +/** + * Loads a composite component type + * + * @version $Rev$ $Date$ + */ +public class CompositeComponentTypeLoader extends ComponentTypeLoaderExtension<CompositeImplementation> { + public CompositeComponentTypeLoader() { + } + + public CompositeComponentTypeLoader(LoaderRegistry loaderRegistry) { + super(loaderRegistry); + } + + protected Class<CompositeImplementation> getImplementationClass() { + return CompositeImplementation.class; + } + + public void load(CompositeImplementation implementation, DeploymentContext context) throws LoaderException { + URL scdlLocation = implementation.getScdlLocation(); + ClassLoader cl = new CompositeClassLoader(null, implementation.getClassLoader()); + URI componentId = URI.create(context.getComponentId().toString() + '/'); + DeploymentContext childContext = + new ChildDeploymentContext(context, cl, scdlLocation, componentId, context.isAutowire()); + CompositeComponentType componentType = loadFromSidefile(scdlLocation, childContext); + implementation.setComponentType(componentType); + } + + protected CompositeComponentType loadFromSidefile(URL url, DeploymentContext deploymentContext) + throws LoaderException { + return loaderRegistry.load(null, url, CompositeComponentType.class, deploymentContext); + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/implementation/composite/CompositeLoader.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/implementation/composite/CompositeLoader.java new file mode 100644 index 0000000000..008ee59de8 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/implementation/composite/CompositeLoader.java @@ -0,0 +1,224 @@ +/* + * 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.core.implementation.composite; + +import static javax.xml.stream.XMLStreamConstants.END_ELEMENT; +import static javax.xml.stream.XMLStreamConstants.START_ELEMENT; +import static org.osoa.sca.Constants.SCA_NS; + +import java.net.URI; +import java.util.List; +import java.util.Map; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import org.apache.tuscany.spi.deployer.DeploymentContext; +import org.apache.tuscany.spi.extension.LoaderExtension; +import org.apache.tuscany.spi.loader.InvalidServiceException; +import org.apache.tuscany.spi.loader.InvalidWireException; +import org.apache.tuscany.spi.loader.LoaderException; +import org.apache.tuscany.spi.loader.LoaderRegistry; +import org.apache.tuscany.spi.model.ComponentDefinition; +import org.apache.tuscany.spi.model.ComponentType; +import org.apache.tuscany.spi.model.CompositeComponentType; +import org.apache.tuscany.spi.model.Implementation; +import org.apache.tuscany.spi.model.Include; +import org.apache.tuscany.spi.model.ModelObject; +import org.apache.tuscany.spi.model.Property; +import org.apache.tuscany.spi.model.ReferenceDefinition; +import org.apache.tuscany.spi.model.ReferenceTarget; +import org.apache.tuscany.spi.model.ServiceDefinition; +import org.apache.tuscany.spi.model.WireDefinition; +import org.apache.tuscany.spi.services.artifact.ArtifactRepository; +import org.osoa.sca.annotations.Reference; + +/** + * Loads a composite component definition from an XML-based assembly file + * + * @version $Rev$ $Date$ + */ +public class CompositeLoader extends LoaderExtension<CompositeComponentType> { + public static final QName COMPOSITE = new QName(SCA_NS, "composite"); + public static final String URI_DELIMITER = "/"; + + private final ArtifactRepository artifactRepository; + + public CompositeLoader(@Reference + LoaderRegistry registry, @Reference + ArtifactRepository artifactRepository) { + super(registry); + this.artifactRepository = artifactRepository; + } + + public QName getXMLType() { + return COMPOSITE; + } + + public CompositeComponentType load(ModelObject object, XMLStreamReader reader, DeploymentContext deploymentContext) + throws XMLStreamException, LoaderException { + + String name = reader.getAttributeValue(null, "name"); + String targetNamespace = reader.getAttributeValue(null, "targetNamespace"); + boolean autowire = Boolean.parseBoolean(reader.getAttributeValue(null, "autowire")); + + CompositeComponentType<ServiceDefinition, ReferenceDefinition, Property<?>> type = new CompositeComponentType<ServiceDefinition, ReferenceDefinition, Property<?>>( + new QName( + targetNamespace, + name)); + type.setAutowire(autowire); + boolean done = false; + while (!done) { + switch (reader.next()) { + case START_ELEMENT: + boolean oldAutowire = deploymentContext.isAutowire(); + deploymentContext.setAutowire(autowire); + ModelObject o = registry.load(type, reader, deploymentContext); + deploymentContext.setAutowire(oldAutowire); + if (o instanceof ServiceDefinition) { + type.add((ServiceDefinition)o); + } else if (o instanceof ReferenceDefinition) { + type.add((ReferenceDefinition)o); + } else if (o instanceof Property<?>) { + type.add((Property<?>)o); + } else if (o instanceof ComponentDefinition<?>) { + type.add((ComponentDefinition<?>)o); + } else if (o instanceof Include) { + type.add((Include)o); + } else if (o instanceof WireDefinition) { + type.add((WireDefinition)o); + } else { + // add as an unknown model extension + if (o != null) { + type.getExtensions().put(o.getClass(), o); + } + } + reader.next(); + break; + case END_ELEMENT: + if (COMPOSITE.equals(reader.getName())) { + // if there are wire defintions then link them up to the + // relevant components + resolveWires(type); + verifyCompositeCompleteness(type); + done = true; + break; + } + } + } + for (ComponentDefinition<? extends Implementation<?>> c : type.getComponents().values()) { + // PropertyHelper.processProperties(type, c, deploymentContext); + } + return type; + } + + protected void resolveWires(CompositeComponentType<ServiceDefinition, ReferenceDefinition, Property<?>> composite) + throws InvalidWireException { + ComponentDefinition componentDefinition; + ServiceDefinition serviceDefinition; + List<WireDefinition> wireDefns = composite.getDeclaredWires(); + for (WireDefinition wire : wireDefns) { + URI targetUri = wire.getTarget(); + // validate the target before finding the source + validateTarget(targetUri, composite); + + String sourceName = wire.getSource().getPath(); // new + // QualifiedName(wire.getSource().getPath()); + serviceDefinition = composite.getDeclaredServices().get(sourceName); + if (serviceDefinition != null) { + serviceDefinition.setTarget(wire.getTarget()); + } else { + componentDefinition = composite.getDeclaredComponents().get(sourceName); + if (componentDefinition != null) { + if (wire.getSource().getFragment() == null) { + throw new InvalidWireException("Source reference not specified", sourceName); + } + URI referenceName = URI.create(wire.getSource().getFragment()); + ReferenceTarget referenceTarget = createReferenceTarget(referenceName, + targetUri, + componentDefinition); + componentDefinition.add(referenceTarget); + } else { + throw new InvalidWireException("Source not found", sourceName); + } + } + } + } + + private ReferenceTarget createReferenceTarget(URI componentReferenceName, + URI target, + ComponentDefinition componentDefn) throws InvalidWireException { + ComponentType componentType = componentDefn.getImplementation().getComponentType(); + if (componentReferenceName == null) { + // if there is ambiguity in determining the source of the wire or + // there is no reference to be wired + if (componentType.getReferences().size() > 1 || componentType.getReferences().isEmpty()) { + throw new InvalidWireException("Unable to determine unique source reference"); + } else { + Map references = componentType.getReferences(); + ReferenceDefinition definition = (ReferenceDefinition)references.values().iterator().next(); + componentReferenceName = definition.getUri(); + } + } + + ReferenceTarget referenceTarget = new ReferenceTarget(); + referenceTarget.setReferenceName(componentReferenceName); + referenceTarget.addTarget(target); + return referenceTarget; + } + + protected void verifyCompositeCompleteness(CompositeComponentType<ServiceDefinition, ReferenceDefinition, Property<?>> composite) + throws InvalidServiceException { + // check if all of the composite services have been wired + for (ServiceDefinition svcDefn : composite.getDeclaredServices().values()) { + if (svcDefn.getTarget() == null) { + String identifier = svcDefn.getUri().toString(); + throw new InvalidServiceException("Composite service not wired to a target", identifier); + } + } + } + + private void validateTarget(URI target, + CompositeComponentType<ServiceDefinition, ReferenceDefinition, Property<?>> composite) + throws InvalidWireException { + // if target is not a reference of the composite + String targetName = target.getPath(); + if (composite.getReferences().get(targetName) == null) { + ComponentDefinition<?> targetDefinition = composite.getDeclaredComponents().get(targetName); + // if a target component exists in this composite + if (targetDefinition != null) { + Implementation<?> implementation = targetDefinition.getImplementation(); + ComponentType<?, ?, ?> componentType = implementation.getComponentType(); + Map<String, ? extends ServiceDefinition> services = componentType.getServices(); + if (target.getFragment() == null) { + if (services.size() > 1 || services.isEmpty()) { + throw new InvalidWireException("Ambiguous target", target.toString()); + } + } else { + if (services.get(target.getFragment()) == null) { + throw new InvalidWireException("Invalid target service", target.toString()); + } + } + } else { + throw new InvalidWireException("Target not found", target.toString()); + } + } + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/implementation/composite/ManagedRequestContext.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/implementation/composite/ManagedRequestContext.java new file mode 100644 index 0000000000..f2a8109ee3 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/implementation/composite/ManagedRequestContext.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.core.implementation.composite; + +import javax.security.auth.Subject; + +import org.osoa.sca.RequestContext; +import org.osoa.sca.ServiceReference; +import org.osoa.sca.CallableReference; + +import org.apache.tuscany.spi.component.WorkContext; + +/** + * @version $Rev$ $Date$ + */ +public class ManagedRequestContext implements RequestContext { + private WorkContext workContext; + + public ManagedRequestContext(WorkContext workContext) { + this.workContext = workContext; + } + + public Subject getSecuritySubject() { + throw new UnsupportedOperationException(); + } + + public String getServiceName() { + return workContext.getCurrentServiceName(); + } + + public <B> ServiceReference<B> getServiceReference() { + throw new UnsupportedOperationException(); + } + + public <CB> CB getCallback() { + throw new UnsupportedOperationException(); + } + + public <CB> CallableReference<CB> getCallbackReference() { + throw new UnsupportedOperationException(); + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/implementation/composite/ReferenceImpl.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/implementation/composite/ReferenceImpl.java new file mode 100644 index 0000000000..f824980f29 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/implementation/composite/ReferenceImpl.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.core.implementation.composite; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.apache.tuscany.spi.component.AbstractSCAObject; +import org.apache.tuscany.spi.component.Reference; +import org.apache.tuscany.spi.component.ReferenceBinding; +import org.apache.tuscany.spi.model.ServiceContract; + +/** + * The default implementation of a {@link org.apache.tuscany.spi.component.Reference} + * + * @version $Rev$ $Date$ + */ +public class ReferenceImpl extends AbstractSCAObject implements Reference { + private ServiceContract<?> serviceContract; + private List<ReferenceBinding> bindings = new ArrayList<ReferenceBinding>(); + + public ReferenceImpl(URI name, ServiceContract<?> contract) { + super(name); + this.serviceContract = contract; + } + + public ServiceContract<?> getServiceContract() { + return serviceContract; + } + + public List<ReferenceBinding> getReferenceBindings() { + return Collections.unmodifiableList(bindings); + } + + public void addReferenceBinding(ReferenceBinding binding) { + bindings.add(binding); + } + + public void start() { + super.start(); + for (ReferenceBinding binding : bindings) { + binding.start(); + } + } + + public void stop() { + super.stop(); + for (ReferenceBinding binding : bindings) { + binding.stop(); + } + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/implementation/composite/ServiceImpl.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/implementation/composite/ServiceImpl.java new file mode 100644 index 0000000000..b8b9b00b49 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/implementation/composite/ServiceImpl.java @@ -0,0 +1,81 @@ +/* + * 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.core.implementation.composite; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.apache.tuscany.spi.component.AbstractSCAObject; +import org.apache.tuscany.spi.component.Service; +import org.apache.tuscany.spi.component.ServiceBinding; +import org.apache.tuscany.spi.model.ServiceContract; + +/** + * The default implementation of a {@link Service} + * + * @version $Rev$ $Date$ + */ +public class ServiceImpl extends AbstractSCAObject implements Service { + private ServiceContract<?> serviceContract; + private List<ServiceBinding> bindings = new ArrayList<ServiceBinding>(); + private URI targetUri; + + public ServiceImpl(URI name, ServiceContract<?> contract) { + this(name, contract, null); + } + + public ServiceImpl(URI name, ServiceContract<?> contract, URI targetUri) { + super(name); + this.serviceContract = contract; + this.targetUri = targetUri; + } + + public ServiceContract<?> getServiceContract() { + return serviceContract; + } + + public URI getTargetUri() { + return targetUri; + } + + public List<ServiceBinding> getServiceBindings() { + return Collections.unmodifiableList(bindings); + } + + public void addServiceBinding(ServiceBinding binding) { + bindings.add(binding); + } + + public void start() { + super.start(); + for (ServiceBinding binding : bindings) { + binding.start(); + } + } + + public void stop() { + super.stop(); + for (ServiceBinding binding : bindings) { + binding.stop(); + } + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/injection/SingletonObjectFactory.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/injection/SingletonObjectFactory.java new file mode 100644 index 0000000000..713c1ae54f --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/injection/SingletonObjectFactory.java @@ -0,0 +1,39 @@ +/* + * 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.core.injection; + +import org.apache.tuscany.spi.ObjectFactory; + +/** + * Implementation of ObjectFactory that returns a single instance, typically an immutable type. + * + * @version $Rev$ $Date$ + */ +public class SingletonObjectFactory<T> implements ObjectFactory<T> { + private final T instance; + + public SingletonObjectFactory(T instance) { + this.instance = instance; + } + + public T getInstance() { + return instance; + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/ComponentLoader.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/ComponentLoader.java new file mode 100644 index 0000000000..b289e74a9b --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/ComponentLoader.java @@ -0,0 +1,360 @@ +/* + * 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.core.loader; + +import static javax.xml.stream.XMLStreamConstants.END_ELEMENT; +import static javax.xml.stream.XMLStreamConstants.START_ELEMENT; +import static org.osoa.sca.Constants.SCA_NS; + +import java.lang.reflect.Type; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import org.apache.tuscany.core.binding.local.LocalBindingDefinition; +import org.apache.tuscany.core.deployer.ChildDeploymentContext; +import org.apache.tuscany.spi.ObjectFactory; +import org.apache.tuscany.spi.QualifiedName; +import org.apache.tuscany.spi.deployer.DeploymentContext; +import org.apache.tuscany.spi.extension.LoaderExtension; +import org.apache.tuscany.spi.loader.InvalidReferenceException; +import org.apache.tuscany.spi.loader.InvalidValueException; +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.MissingImplementationException; +import org.apache.tuscany.spi.loader.MissingReferenceException; +import org.apache.tuscany.spi.loader.MissingRequiredPropertyException; +import org.apache.tuscany.spi.loader.PropertyObjectFactory; +import org.apache.tuscany.spi.loader.ReferenceMultiplicityViolationException; +import org.apache.tuscany.spi.loader.UndefinedPropertyException; +import org.apache.tuscany.spi.loader.UndefinedReferenceException; +import org.apache.tuscany.spi.loader.UnrecognizedElementException; +import org.apache.tuscany.spi.model.BindingDefinition; +import org.apache.tuscany.spi.model.ComponentDefinition; +import org.apache.tuscany.spi.model.ComponentType; +import org.apache.tuscany.spi.model.CompositeComponentType; +import org.apache.tuscany.spi.model.Implementation; +import org.apache.tuscany.spi.model.ModelObject; +import org.apache.tuscany.spi.model.Multiplicity; +import org.apache.tuscany.spi.model.Property; +import org.apache.tuscany.spi.model.PropertyValue; +import org.apache.tuscany.spi.model.ReferenceDefinition; +import org.apache.tuscany.spi.model.ReferenceTarget; +import org.apache.tuscany.spi.model.ServiceDefinition; +import org.osoa.sca.annotations.Constructor; +import org.osoa.sca.annotations.Reference; +import org.w3c.dom.Document; + +/** + * Loads a component definition from an XML-based assembly file + * + * @version $Rev$ $Date$ + */ +public class ComponentLoader extends LoaderExtension<ComponentDefinition<?>> { + private static final QName COMPONENT = new QName(SCA_NS, "component"); + private static final QName PROPERTY = new QName(SCA_NS, "property"); + private static final QName REFERENCE = new QName(SCA_NS, "reference"); + + private static final String PROPERTY_FILE_ATTR = "file"; + private static final String PROPERTY_NAME_ATTR = "name"; + private static final String PROPERTY_SOURCE_ATTR = "source"; + + private PropertyObjectFactory propertyFactory; + + @Constructor + public ComponentLoader(@Reference LoaderRegistry registry, @Reference PropertyObjectFactory propertyFactory) { + super(registry); + this.propertyFactory = propertyFactory; + } + + public QName getXMLType() { + return COMPONENT; + } + + @SuppressWarnings("unchecked") + public ComponentDefinition<?> load(ModelObject object, XMLStreamReader reader, DeploymentContext context) + throws XMLStreamException, LoaderException { + assert COMPONENT.equals(reader.getName()); + String name = reader.getAttributeValue(null, "name"); + String initLevel = reader.getAttributeValue(null, "initLevel"); + String autowireAttr = reader.getAttributeValue(null, "autowire"); + boolean autowire; + if (autowireAttr == null) { + autowire = context.isAutowire(); + } else { + autowire = Boolean.parseBoolean(autowireAttr); + } + String runtimeAttr = reader.getAttributeValue(null, "runtimeId"); + URI runtimeId; + if (runtimeAttr != null) { + try { + runtimeId = new URI(runtimeAttr); + } catch (URISyntaxException e) { + throw new InvalidValueException(runtimeAttr, "runtimeId", e); + } + } else { + runtimeId = null; + } + + URI componentId = URI.create(context.getComponentId() + "/").resolve(name); + ClassLoader loader = context.getClassLoader(); + URL location = context.getScdlLocation(); + // xcv test + DeploymentContext childContext = new ChildDeploymentContext(context, loader, location, componentId, autowire); + Implementation<?> impl = loadImplementation(reader, childContext); + registry.loadComponentType(impl, childContext); + + ComponentDefinition<Implementation<?>> componentDefinition = + new ComponentDefinition<Implementation<?>>(componentId, impl); + componentDefinition.setAutowire(autowire); + componentDefinition.setRuntimeId(runtimeId); + if (initLevel != null) { + if (initLevel.length() == 0) { + componentDefinition.setInitLevel(0); + } else { + try { + componentDefinition.setInitLevel(Integer.valueOf(initLevel)); + } catch (NumberFormatException e) { + throw new InvalidValueException(initLevel, "initValue", e); + } + } + } + + while (true) { + switch (reader.next()) { + case START_ELEMENT: + QName qname = reader.getName(); + if (PROPERTY.equals(qname)) { + loadProperty(reader, componentDefinition, childContext); + } else if (REFERENCE.equals(qname)) { + loadReference(reader, componentDefinition, childContext); + } else { + throw new UnrecognizedElementException(qname); + } + reader.next(); + break; + case END_ELEMENT: + if (reader.getName().equals(COMPONENT)) { + populatePropertyValues(componentDefinition); + ComponentType<ServiceDefinition, ReferenceDefinition, Property<?>> type = + (ComponentType<ServiceDefinition, ReferenceDefinition, Property<?>>) componentDefinition + .getImplementation().getComponentType(); + + for (ReferenceDefinition ref : type.getReferences().values()) { + // add reference target definitions if autowire is enabled for references that are not + // explicitly configured with autowire by the component + if (!componentDefinition.getReferenceTargets().containsKey(ref.getUri().getFragment())) { + if (autowire) { + ReferenceTarget referenceTarget = new ReferenceTarget(); + String compName = componentDefinition.getUri().toString(); + URI refName = URI.create(compName + ref.getUri().toString()); + referenceTarget.setReferenceName(refName); + referenceTarget.setAutowire(autowire); + componentDefinition.add(referenceTarget); + } + } + } + validate(componentDefinition); + return componentDefinition; + } + break; + } + } + } + + protected Implementation<?> loadImplementation(XMLStreamReader reader, DeploymentContext context) + throws XMLStreamException, LoaderException { + reader.nextTag(); + ModelObject o = registry.load(null, reader, context); + if (!(o instanceof Implementation)) { + throw new MissingImplementationException(); + } + return (Implementation<?>) o; + } + + @SuppressWarnings("unchecked") + protected void loadProperty(XMLStreamReader reader, ComponentDefinition<?> definition, DeploymentContext context) + throws XMLStreamException, LoaderException { + String name = reader.getAttributeValue(null, PROPERTY_NAME_ATTR); + Implementation<?> implementation = definition.getImplementation(); + ComponentType<?, ?, ?> componentType = implementation.getComponentType(); + Property<Type> property = (Property<Type>) componentType.getProperties().get(name); + if (property == null) { + throw new UndefinedPropertyException(name); + } + PropertyValue<Type> propertyValue; + String source = reader.getAttributeValue(null, PROPERTY_SOURCE_ATTR); + String file = reader.getAttributeValue(null, PROPERTY_FILE_ATTR); + if (source != null || file != null) { + propertyValue = new PropertyValue<Type>(name, source, file); + propertyValue.setValue(property.getDefaultValue()); + LoaderUtil.skipToEndElement(reader); + } else { + try { + DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + Document value = PropertyUtils.createPropertyValue(reader, property.getXmlType(), documentBuilder); + propertyValue = new PropertyValue<Type>(name, value); + } catch (ParserConfigurationException e) { + throw new LoaderException(e); + } + } + ObjectFactory<Type> objectFactory = propertyFactory.createObjectFactory(property, propertyValue); + propertyValue.setValueFactory(objectFactory); + definition.add(propertyValue); + } + + protected void loadReference(XMLStreamReader reader, + ComponentDefinition<?> componentDefinition, + DeploymentContext context) throws XMLStreamException, LoaderException { + String name = reader.getAttributeValue(null, "name"); + if (name == null) { + throw new InvalidReferenceException("No name specified"); + } + String target = reader.getAttributeValue(null, "target"); + boolean autowire = Boolean.parseBoolean(reader.getAttributeValue(null, "autowire")); + URI componentId = context.getComponentId(); + List<URI> uris = new ArrayList<URI>(); + if (target != null) { + StringTokenizer tokenizer = new StringTokenizer(target); + while (tokenizer.hasMoreTokens()) { + String token = tokenizer.nextToken(); + QualifiedName qName = new QualifiedName(token); + uris.add(componentId.resolve(qName.getFragment())); + } + } + + Implementation<?> impl = componentDefinition.getImplementation(); + ComponentType<?, ?, ?> componentType = impl.getComponentType(); + if (!componentType.getReferences().containsKey(name)) { + throw new UndefinedReferenceException(name); + } + if (componentType instanceof CompositeComponentType) { + if (uris.size() != 1) { + // FIXME not yet implemented + throw new UnsupportedOperationException(); + } + ReferenceDefinition definition = componentType.getReferences().get(name); + if (definition.getBindings().isEmpty()) { + // TODO JFM allow selection of a default binding + LocalBindingDefinition binding = new LocalBindingDefinition(uris.get(0)); + definition.addBinding(binding); + } else { + for (BindingDefinition binding : definition.getBindings()) { + binding.setTargetUri(uris.get(0)); + } + } + } else { + ReferenceTarget referenceTarget = componentDefinition.getReferenceTargets().get(name); + if (referenceTarget == null) { + referenceTarget = new ReferenceTarget(); + referenceTarget.setReferenceName(componentId.resolve('#' + name)); + referenceTarget.setAutowire(autowire); + componentDefinition.add(referenceTarget); + } + for (URI uri : uris) { + referenceTarget.addTarget(uri); + } + } + } + + @SuppressWarnings("unchecked") + protected void populatePropertyValues(ComponentDefinition<Implementation<?>> componentDefinition) + throws MissingRequiredPropertyException { + ComponentType componentType = componentDefinition.getImplementation().getComponentType(); + if (componentType != null) { + Map<String, Property<?>> properties = componentType.getProperties(); + Map<String, PropertyValue<?>> propertyValues = componentDefinition.getPropertyValues(); + + for (Property<?> aProperty : properties.values()) { + if (propertyValues.get(aProperty.getName()) == null) { + if (aProperty.isRequired()) { + throw new MissingRequiredPropertyException(aProperty.getName()); + } else if (aProperty.getDefaultValue() != null) { + PropertyValue propertyValue = new PropertyValue(); + propertyValue.setName(aProperty.getName()); + propertyValue.setValue(aProperty.getDefaultValue()); +// propertyValue.setValueFactory(new SimplePropertyObjectFactory(aProperty, +// propertyValue.getValue())); + propertyValues.put(aProperty.getName(), propertyValue); + } + } + } + } + } + + /** + * Validates a component definition, ensuring all component type configuration elements are satisfied + */ + protected void validate(ComponentDefinition<Implementation<?>> definition) throws LoaderException { + // validate refererences + Implementation<?> implementation = definition.getImplementation(); + ComponentType<?, ?, ?> type = implementation.getComponentType(); + if (type == null) { + return; + } + for (ReferenceDefinition referenceDef : type.getReferences().values()) { + if (!referenceDef.isRequired()) { + continue; + } + String name = referenceDef.getUri().getFragment(); + ReferenceTarget target = definition.getReferenceTargets().get(name); + if (target == null) { + throw new MissingReferenceException(name); + } + if (target.isAutowire()) { + // autowire targets are not set yet + continue; + } + int count = target.getTargets().size(); + Multiplicity multiplicity = referenceDef.getMultiplicity(); + switch (multiplicity) { + case ZERO_N: + break; + case ZERO_ONE: + if (count > 1) { + throw new ReferenceMultiplicityViolationException(name, multiplicity, count); + } + break; + case ONE_ONE: + if (count != 1) { + throw new ReferenceMultiplicityViolationException(name, multiplicity, count); + } + break; + case ONE_N: + if (count < 1) { + throw new ReferenceMultiplicityViolationException(name, multiplicity, count); + } + break; + } + + } + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/ComponentTypeElementLoader.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/ComponentTypeElementLoader.java new file mode 100644 index 0000000000..beb0bc2731 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/ComponentTypeElementLoader.java @@ -0,0 +1,86 @@ +/* + * 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.core.loader; + +import javax.xml.namespace.QName; +import static javax.xml.stream.XMLStreamConstants.END_ELEMENT; +import static javax.xml.stream.XMLStreamConstants.START_ELEMENT; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import static org.osoa.sca.Constants.SCA_NS; +import org.osoa.sca.annotations.Constructor; +import org.osoa.sca.annotations.Reference; + +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.model.ComponentType; +import org.apache.tuscany.spi.model.ModelObject; +import org.apache.tuscany.spi.model.Property; +import org.apache.tuscany.spi.model.ReferenceDefinition; +import org.apache.tuscany.spi.model.ServiceDefinition; + +/** + * @version $Rev$ $Date$ + */ +public class ComponentTypeElementLoader extends LoaderExtension<ComponentType> { + public static final QName COMPONENT_TYPE = new QName(SCA_NS, "componentType"); + + @Constructor + public ComponentTypeElementLoader(@Reference LoaderRegistry registry) { + super(registry); + } + + public QName getXMLType() { + return COMPONENT_TYPE; + } + + @SuppressWarnings("unchecked") + public ComponentType load(ModelObject object, XMLStreamReader reader, DeploymentContext context) + throws XMLStreamException, LoaderException { + assert COMPONENT_TYPE.equals(reader.getName()); + ComponentType<ServiceDefinition, ReferenceDefinition, Property<?>> componentType; + if (object != null) { + assert object instanceof ComponentType; + // a specialized component type was passed in + componentType = (ComponentType<ServiceDefinition, ReferenceDefinition, Property<?>>) object; + } else { + componentType = new ComponentType<ServiceDefinition, ReferenceDefinition, Property<?>>(); + } + + while (true) { + switch (reader.next()) { + case START_ELEMENT: + ModelObject o = registry.load(componentType, reader, context); + if (o instanceof ServiceDefinition) { + componentType.add((ServiceDefinition) o); + } else if (o instanceof ReferenceDefinition) { + componentType.add((ReferenceDefinition) o); + } else if (o instanceof Property) { + componentType.add((Property<?>) o); + } + break; + case END_ELEMENT: + return componentType; + } + } + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/IncludeLoader.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/IncludeLoader.java new file mode 100644 index 0000000000..e10a93bbc0 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/IncludeLoader.java @@ -0,0 +1,105 @@ +/* + * 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.core.loader; + +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import static org.osoa.sca.Constants.SCA_NS; +import org.osoa.sca.annotations.Constructor; +import org.osoa.sca.annotations.Reference; + +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.MissingIncludeException; +import org.apache.tuscany.spi.loader.MissingResourceException; +import org.apache.tuscany.spi.model.CompositeComponentType; +import org.apache.tuscany.spi.model.Include; +import org.apache.tuscany.spi.model.ModelObject; + +import org.apache.tuscany.core.deployer.ChildDeploymentContext; + +/** + * Loader that handles <include> elements. + * + * @version $Rev$ $Date$ + */ +public class IncludeLoader extends LoaderExtension<Include> { + private static final QName INCLUDE = new QName(SCA_NS, "include"); + + @Constructor + public IncludeLoader(@Reference LoaderRegistry registry) { + super(registry); + } + + public QName getXMLType() { + return INCLUDE; + } + + public Include load(ModelObject object, XMLStreamReader reader, DeploymentContext deploymentContext) + throws XMLStreamException, LoaderException { + + assert INCLUDE.equals(reader.getName()); + String name = reader.getAttributeValue(null, "name"); + String scdlLocation = reader.getAttributeValue(null, "scdlLocation"); + String scdlResource = reader.getAttributeValue(null, "scdlResource"); + LoaderUtil.skipToEndElement(reader); + + ClassLoader cl = deploymentContext.getClassLoader(); + URL url; + if (scdlLocation != null) { + try { + url = new URL(deploymentContext.getScdlLocation(), scdlLocation); + } catch (MalformedURLException e) { + throw new MissingResourceException(scdlLocation, name, e); + } + } else if (scdlResource != null) { + url = cl.getResource(scdlResource); + if (url == null) { + throw new MissingResourceException(scdlResource, name); + } + } else { + throw new MissingIncludeException("No SCDL location or resource specified", name); + } + + // when we include, the componentId remains that of the parent + URI componentId = deploymentContext.getComponentId(); + boolean autowire = deploymentContext.isAutowire(); + DeploymentContext childContext = new ChildDeploymentContext(deploymentContext, cl, url, componentId, autowire); + CompositeComponentType composite; + composite = loadFromSidefile(url, childContext); + + Include include = new Include(); + include.setName(name); + include.setScdlLocation(url); + include.setIncluded(composite); + return include; + } + + protected CompositeComponentType loadFromSidefile(URL url, DeploymentContext context) throws LoaderException { + return registry.load(null, url, CompositeComponentType.class, context); + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/LoaderExceptionFormatter.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/LoaderExceptionFormatter.java new file mode 100644 index 0000000000..26ec72ecb6 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/LoaderExceptionFormatter.java @@ -0,0 +1,67 @@ +/* + * 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.core.loader; + +import java.io.PrintWriter; + +import org.osoa.sca.annotations.Destroy; +import org.osoa.sca.annotations.EagerInit; +import org.osoa.sca.annotations.Reference; + +import org.apache.tuscany.spi.loader.LoaderException; + +import org.apache.tuscany.host.monitor.ExceptionFormatter; +import org.apache.tuscany.host.monitor.FormatterRegistry; + +/** + * Formats {@link org.apache.tuscany.spi.loader.LoaderException} events + * + * @version $Rev$ $Date$ + */ +@EagerInit +public class LoaderExceptionFormatter implements ExceptionFormatter { + private FormatterRegistry factory; + + public LoaderExceptionFormatter(@Reference FormatterRegistry factory) { + this.factory = factory; + factory.register(this); + } + + public boolean canFormat(Class<?> type) { + return LoaderException.class.isAssignableFrom(type); + } + + @Destroy + public void destroy() { + factory.unregister(this); + } + + public PrintWriter write(PrintWriter writer, Throwable exception) { + assert exception instanceof LoaderException; + LoaderException e = (LoaderException) exception; + e.appendBaseMessage(writer); + if (e.getLine() != LoaderException.UNDEFINED) { + writer.write("\nLine: " + e.getLine() + "\n"); + writer.write("Column: " + e.getColumn() + "\n"); + } else { + writer.write("\n"); + } + return writer; + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/LoaderRegistryImpl.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/LoaderRegistryImpl.java new file mode 100644 index 0000000000..57fd1da870 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/LoaderRegistryImpl.java @@ -0,0 +1,179 @@ +/* + * 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.core.loader; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import javax.xml.namespace.QName; +import javax.xml.stream.Location; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import org.osoa.sca.annotations.EagerInit; + +import org.apache.tuscany.spi.deployer.DeploymentContext; +import org.apache.tuscany.spi.loader.ComponentTypeLoader; +import org.apache.tuscany.spi.loader.InvalidConfigurationException; +import org.apache.tuscany.spi.loader.LoaderException; +import org.apache.tuscany.spi.loader.LoaderRegistry; +import org.apache.tuscany.spi.loader.StAXElementLoader; +import org.apache.tuscany.spi.loader.UnrecognizedComponentTypeException; +import org.apache.tuscany.spi.loader.UnrecognizedElementException; +import org.apache.tuscany.spi.model.Implementation; +import org.apache.tuscany.spi.model.ModelObject; + +/** + * The default implementation of a loader registry + * + * @version $Rev$ $Date$ + */ +@EagerInit +public class LoaderRegistryImpl implements LoaderRegistry { + private Monitor monitor; + private final Map<QName, StAXElementLoader<? extends ModelObject>> loaders = + new HashMap<QName, StAXElementLoader<? extends ModelObject>>(); + private final Map<Class<? extends Implementation<?>>, + ComponentTypeLoader<? extends Implementation<?>>> componentTypeLoaders = + new HashMap<Class<? extends Implementation<?>>, ComponentTypeLoader<? extends Implementation<?>>>(); + + public LoaderRegistryImpl(@org.apache.tuscany.api.annotation.Monitor Monitor monitor) { + this.monitor = monitor; + } + + public <T extends ModelObject> void registerLoader(QName element, StAXElementLoader<T> loader) { + monitor.registeringLoader(element); + loaders.put(element, loader); + } + + public <T extends ModelObject> void unregisterLoader(QName element, StAXElementLoader<T> loader) { + monitor.unregisteringLoader(element); + loaders.remove(element); + } + + public ModelObject load( + ModelObject object, + XMLStreamReader reader, + DeploymentContext deploymentContext) throws XMLStreamException, LoaderException { + QName name = reader.getName(); + monitor.elementLoad(name); + StAXElementLoader<? extends ModelObject> loader = loaders.get(name); + if (loader == null) { + throw new UnrecognizedElementException(name); + } + return loader.load(object, reader, deploymentContext); + } + + public <MO extends ModelObject> MO load( + ModelObject object, + URL url, + Class<MO> type, + DeploymentContext ctx) throws LoaderException { + try { + XMLStreamReader reader; + InputStream is; + is = url.openStream(); + try { + XMLInputFactory factory = ctx.getXmlFactory(); + reader = factory.createXMLStreamReader(is); + try { + reader.nextTag(); + QName name = reader.getName(); + ModelObject mo = load(object, reader, ctx); + if (type.isInstance(mo)) { + return type.cast(mo); + } else { + UnrecognizedElementException e = new UnrecognizedElementException(name); + e.setResourceURI(url.toString()); + throw e; + } + } catch (LoaderException e) { + Location location = reader.getLocation(); + e.setLine(location.getLineNumber()); + e.setColumn(location.getColumnNumber()); + throw e; + } finally { + try { + reader.close(); + } catch (XMLStreamException e) { + // ignore + } + } + } finally { + try { + is.close(); + } catch (IOException e) { + // ignore + } + } + } catch (IOException e) { + LoaderException sfe = new LoaderException(e); + sfe.setResourceURI(url.toString()); + throw sfe; + } catch (XMLStreamException e) { + throw new InvalidConfigurationException("Invalid or missing resource", url.toString(), e); + } + } + + public <I extends Implementation<?>> void registerLoader(Class<I> key, ComponentTypeLoader<I> loader) { + componentTypeLoaders.put(key, loader); + } + + public <I extends Implementation<?>> void unregisterLoader(Class<I> key) { + componentTypeLoaders.remove(key); + } + + @SuppressWarnings("unchecked") + public <I extends Implementation<?>> void loadComponentType(I implementation, + DeploymentContext deploymentContext) + throws LoaderException { + Class<I> key = (Class<I>) implementation.getClass(); + ComponentTypeLoader<I> loader = (ComponentTypeLoader<I>) componentTypeLoaders.get(key); + if (loader == null) { + throw new UnrecognizedComponentTypeException(key); + } + loader.load(implementation, deploymentContext); + } + + public static interface Monitor { + /** + * Event emitted when a StAX element loader is registered. + * + * @param xmlType the QName of the element the loader will handle + */ + void registeringLoader(QName xmlType); + + /** + * Event emitted when a StAX element loader is unregistered. + * + * @param xmlType the QName of the element the loader will handle + */ + void unregisteringLoader(QName xmlType); + + /** + * Event emitted when a request is made to load an element. + * + * @param xmlType the QName of the element that should be loaded + */ + void elementLoad(QName xmlType); + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/PolicySetLoader.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/PolicySetLoader.java new file mode 100644 index 0000000000..66d2a87593 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/PolicySetLoader.java @@ -0,0 +1,195 @@ +/* + * 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.core.loader; + +import java.util.ArrayList; +import java.util.List; +import javax.xml.namespace.QName; +import static javax.xml.stream.XMLStreamConstants.END_ELEMENT; +import static javax.xml.stream.XMLStreamConstants.START_ELEMENT; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import static org.osoa.sca.Constants.SCA_NS; +import org.osoa.sca.annotations.Constructor; +import org.osoa.sca.annotations.Reference; + +import org.apache.tuscany.spi.deployer.DeploymentContext; +import org.apache.tuscany.spi.extension.LoaderExtension; +import org.apache.tuscany.spi.loader.LoaderRegistry; +import org.apache.tuscany.spi.loader.LoaderUtil; +import org.apache.tuscany.spi.model.IntentMap; +import org.apache.tuscany.spi.model.IntentName; +import org.apache.tuscany.spi.model.ModelObject; +import org.apache.tuscany.spi.model.PolicySet; +import org.apache.tuscany.spi.model.PolicySetReference; +import org.apache.tuscany.spi.model.Qualifier; +import org.apache.tuscany.spi.model.WSPolicyAttachment; + +/** + * Loads a PolicySet definition from an SCDL file. + * + * @version $Rev$ $Date$ + */ +public class PolicySetLoader extends LoaderExtension<PolicySet> { + + private static final String WSPOLICY_NAMESPACE = "http://schemas.xmlsoap.org/ws/2004/09/policy"; + + private static final QName POLICYSET = new QName(SCA_NS, "policySet"); + + private static final QName INTENTMAP = new QName(SCA_NS, "intentMap"); + + private static final QName QUALIFIER = new QName(SCA_NS, "qualifier"); + + private static final QName POLICYSETREFERENCE = new QName(SCA_NS, "policySetReference"); + + private static final QName WSPOLICYATTACHMENT = new QName(WSPOLICY_NAMESPACE, "PolicyAttachment"); + + @Constructor + public PolicySetLoader(@Reference LoaderRegistry registry) { + super(registry); + + } + + @Override + public QName getXMLType() { + return POLICYSET; + } + + public PolicySet load(ModelObject object, XMLStreamReader reader, + DeploymentContext deploymentContext) + throws XMLStreamException { + assert POLICYSET.equals(reader.getName()); + String name = reader.getAttributeValue(null, "name"); + String provides = reader.getAttributeValue(null, "provides"); + String appliesTo = reader.getAttributeValue(null, "appliesTo"); + PolicySet policySet = new PolicySet(new QName(SCA_NS, name), parseIntentName(provides)); + String[] appliesToArtifact = split(appliesTo); + for (String artifact : appliesToArtifact) { + policySet.addAppliedArtifacts(new QName(SCA_NS, artifact)); + } + while (true) { + switch (reader.next()) { + case START_ELEMENT: + QName qname = reader.getName(); + if (INTENTMAP.equals(qname)) { + policySet.addIntentMap(loadIntentMap(reader, deploymentContext)); + } else if (POLICYSETREFERENCE.equals(qname)) { + policySet.addPolicySetReference(loadPolicyReference(reader, deploymentContext)); + } else if (WSPOLICYATTACHMENT.equals(qname)) { + policySet.addWsPolicyAttachment(loadWSPolicyAttachment(reader, deploymentContext)); + } + + reader.next(); + break; + case END_ELEMENT: + if (reader.getName().equals(POLICYSET)) { + return policySet; + } + break; + } + } + + } + + private PolicySetReference loadPolicyReference(XMLStreamReader reader, DeploymentContext deploymentContext) + throws XMLStreamException { + assert POLICYSETREFERENCE.equals(reader.getName()); + String name = reader.getAttributeValue(null, "name"); + LoaderUtil.skipToEndElement(reader); + return new PolicySetReference(new QName(SCA_NS, name)); + } + + private IntentMap loadIntentMap(XMLStreamReader reader, DeploymentContext deploymentContext) + throws XMLStreamException { + assert INTENTMAP.equals(reader.getName()); + String defaultIntentAttr = reader.getAttributeValue(null, "default"); + String provides = reader.getAttributeValue(null, "provides"); + IntentMap intentMap = new IntentMap(defaultIntentAttr, java.util.Arrays.asList(split(provides))); + //parentPolicySet.addIntentMap(intentMap); + + while (true) { + switch (reader.next()) { + case START_ELEMENT: + QName qname = reader.getName(); + if (QUALIFIER.equals(qname)) { + intentMap.addQualifier(loadQualifier(reader, deploymentContext)); + } + reader.next(); + break; + case END_ELEMENT: + if (reader.getName().equals(INTENTMAP)) { + return intentMap; + } + } + } + + } + + private Qualifier loadQualifier(XMLStreamReader reader, DeploymentContext deploymentContext) + throws XMLStreamException { + assert QUALIFIER.equals(reader.getName()); + String name = reader.getAttributeValue(null, "name"); + Qualifier qualifier = new Qualifier(name); + while (true) { + switch (reader.next()) { + case START_ELEMENT: + QName qname = reader.getName(); + if (INTENTMAP.equals(qname)) { + qualifier.setIntentMap(loadIntentMap(reader, deploymentContext)); + } else if (WSPOLICYATTACHMENT.equals(qname)) { + qualifier.addWsPolicyAttachment(loadWSPolicyAttachment(reader, deploymentContext)); + } + reader.next(); + break; + case END_ELEMENT: + if (reader.getName().equals(QUALIFIER)) { + return qualifier; + } + } + } + + } + + private WSPolicyAttachment loadWSPolicyAttachment(XMLStreamReader reader, DeploymentContext deploymentContext) + throws XMLStreamException { + return new WSPolicyAttachment(); + } + + /** + * Split a string to string array separated by " " + */ + private static String[] split(String string) { + if (string == null) { + return new String[0]; + } + String[] intents = string.split("[ ]+"); + return intents; + } + + private static List<IntentName> parseIntentName(String attributes) { + String[] intents = split(attributes); + List<IntentName> result = new ArrayList<IntentName>(intents.length); + for (String intent : intents) { + result.add(new IntentName(intent)); + } + return result; + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/PropertyLoader.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/PropertyLoader.java new file mode 100644 index 0000000000..ac39c135d9 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/PropertyLoader.java @@ -0,0 +1,98 @@ +/* + * 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.core.loader; + +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import org.w3c.dom.Document; +import static org.osoa.sca.Constants.SCA_NS; +import org.osoa.sca.annotations.Constructor; +import org.osoa.sca.annotations.Reference; + +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.model.ModelObject; +import org.apache.tuscany.spi.model.Property; + +/** + * Loads a property from an XML-based assembly file + * + * @version $Rev$ $Date$ + */ +public class PropertyLoader extends LoaderExtension<Property> { + public static final String PROPERTY_NAME_ATTR = "name"; + public static final String PROPERTY_TYPE_ATTR = "type"; + public static final String PROPERTY_MANY_ATTR = "many"; + public static final String REQUIRED_ATTR = "override"; + + public static final QName PROPERTY = new QName(SCA_NS, "property"); + private final DocumentBuilder documentBuilder; + + @Constructor + public PropertyLoader(@Reference LoaderRegistry registry) { + super(registry); + try { + documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + } catch (ParserConfigurationException e) { + // we should be able to construct the default DocumentBuilder + throw new AssertionError(e); + } + } + + public QName getXMLType() { + return PROPERTY; + } + + public Property<?> load(ModelObject object, XMLStreamReader reader, + DeploymentContext ctx) + throws XMLStreamException, LoaderException { + assert PROPERTY.equals(reader.getName()); + String name = reader.getAttributeValue(null, PROPERTY_NAME_ATTR); + String typeName = reader.getAttributeValue(null, PROPERTY_TYPE_ATTR); + QName xmlType = null; + if (typeName != null) { + int index = typeName.indexOf(':'); + if (index != -1) { + String prefix = typeName.substring(0, index); + String localName = typeName.substring(index + 1); + String ns = reader.getNamespaceURI(prefix); + xmlType = new QName(ns, localName, prefix); + } + } + boolean many = Boolean.parseBoolean(reader.getAttributeValue(null, PROPERTY_MANY_ATTR)); + String required = reader.getAttributeValue(null, REQUIRED_ATTR); + Document value = PropertyUtils.createPropertyValue(reader, xmlType, documentBuilder); + + Property<?> property = new Property(); + property.setRequired(Boolean.parseBoolean(required)); + property.setName(name); + property.setXmlType(xmlType); + property.setMany(many); + + property.setDefaultValue(value); + return property; + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/PropertyUtils.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/PropertyUtils.java new file mode 100644 index 0000000000..57c1e1b5f4 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/PropertyUtils.java @@ -0,0 +1,119 @@ +/* + * 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.core.loader; + +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +/** + * @version $Rev$ $Date$ + */ +public final class PropertyUtils { + + private PropertyUtils() { + } + + public static Document createPropertyValue(XMLStreamReader reader, QName type, DocumentBuilder builder) + throws XMLStreamException { + Document doc = builder.newDocument(); + + // root element has no namespace and local name "value" + Element root = doc.createElementNS(null, "value"); + if (type != null) { + Attr xsi = doc.createAttributeNS(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, "xmlns:xsi"); + xsi.setValue(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI); + root.setAttributeNodeNS(xsi); + + String prefix = type.getPrefix(); + if (prefix == null || prefix.length() == 0) { + prefix = "ns"; + } + Attr typeXmlns = doc.createAttributeNS(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, "xmlns:" + prefix); + typeXmlns.setValue(type.getNamespaceURI()); + root.setAttributeNodeNS(typeXmlns); + + Attr xsiType = doc.createAttributeNS(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "xsi:type"); + xsiType.setValue(prefix + ":" + type.getLocalPart()); + root.setAttributeNodeNS(xsiType); + } + doc.appendChild(root); + + loadPropertyValue(reader, root); + return doc; + } + + /** + * Load a property value specification from an StAX stream into a DOM Document. Only elements, text and attributes + * are processed; all comments and other whitespace are ignored. + * + * @param reader the stream to read from + * @param root the DOM node to load + * @throws javax.xml.stream.XMLStreamException + * + */ + public static void loadPropertyValue(XMLStreamReader reader, Node root) throws XMLStreamException { + Document document = root.getOwnerDocument(); + Node current = root; + while (true) { + switch (reader.next()) { + case XMLStreamConstants.START_ELEMENT: + QName name = reader.getName(); + Element child = document.createElementNS(name.getNamespaceURI(), name.getLocalPart()); + + // add the attributes for this element + int count = reader.getAttributeCount(); + for (int i = 0; i < count; i++) { + String ns = reader.getAttributeNamespace(i); + String localPart = reader.getAttributeLocalName(i); + String value = reader.getAttributeValue(i); + child.setAttributeNS(ns, localPart, value); + } + + // push the new element and make it the current one + current.appendChild(child); + current = child; + break; + case XMLStreamConstants.CDATA: + current.appendChild(document.createCDATASection(reader.getText())); + break; + case XMLStreamConstants.CHARACTERS: + current.appendChild(document.createTextNode(reader.getText())); + break; + case XMLStreamConstants.END_ELEMENT: + // if we are back at the root then we are done + if (current == root) { + return; + } + + // pop the element off the stack + current = current.getParentNode(); + } + } + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/ReferenceLoader.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/ReferenceLoader.java new file mode 100644 index 0000000000..54183d1c72 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/ReferenceLoader.java @@ -0,0 +1,107 @@ +/* + * 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.core.loader; + +import java.util.HashMap; +import java.util.Map; +import javax.xml.namespace.QName; +import static javax.xml.stream.XMLStreamConstants.END_ELEMENT; +import static javax.xml.stream.XMLStreamConstants.START_ELEMENT; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import static org.osoa.sca.Constants.SCA_NS; +import org.osoa.sca.annotations.Constructor; +import org.osoa.sca.annotations.Reference; + +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.UnrecognizedElementException; +import org.apache.tuscany.spi.model.BindingDefinition; +import org.apache.tuscany.spi.model.ModelObject; +import org.apache.tuscany.spi.model.Multiplicity; +import org.apache.tuscany.spi.model.ReferenceDefinition; +import org.apache.tuscany.spi.model.ServiceContract; + +/** + * Loads a reference from an XML-based assembly file + * + * @version $Rev$ $Date$ + */ +public class ReferenceLoader extends LoaderExtension<ReferenceDefinition> { + public static final QName REFERENCE = new QName(SCA_NS, "reference"); + private static final Map<String, Multiplicity> MULTIPLICITY = new HashMap<String, Multiplicity>(4); + + static { + MULTIPLICITY.put("0..1", Multiplicity.ZERO_ONE); + MULTIPLICITY.put("1..1", Multiplicity.ONE_ONE); + MULTIPLICITY.put("0..n", Multiplicity.ZERO_N); + MULTIPLICITY.put("1..n", Multiplicity.ONE_N); + } + + @Constructor + public ReferenceLoader(@Reference LoaderRegistry registry) { + super(registry); + } + + public QName getXMLType() { + return REFERENCE; + } + + public ReferenceDefinition load(ModelObject object, XMLStreamReader reader, DeploymentContext context) + throws XMLStreamException, LoaderException { + assert REFERENCE.equals(reader.getName()); + String name = reader.getAttributeValue(null, "name"); + String multiplicityVal = reader.getAttributeValue(null, "multiplicity"); + Multiplicity multiplicity = multiplicity(multiplicityVal, Multiplicity.ONE_ONE); + ReferenceDefinition referenceDefinition = new ReferenceDefinition(); + referenceDefinition.setMultiplicity(multiplicity); + referenceDefinition.setUri(context.getComponentId().resolve('#' + name)); + while (true) { + switch (reader.next()) { + case START_ELEMENT: + ModelObject o = registry.load(null, reader, context); + if (o instanceof ServiceContract) { + referenceDefinition.setServiceContract((ServiceContract) o); + } else if (o instanceof BindingDefinition) { + referenceDefinition.addBinding((BindingDefinition) o); + } else { + throw new UnrecognizedElementException(reader.getName()); + } + break; + case END_ELEMENT: + return referenceDefinition; + } + } + } + + /** + * Convert a "multiplicity" attribute to the equivalent enum value. + * + * @param multiplicity the attribute to convert + * @param def the default value + * @return the enum equivalent + */ + private static Multiplicity multiplicity(String multiplicity, Multiplicity def) { + return multiplicity == null ? def : MULTIPLICITY.get(multiplicity); + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/ServiceLoader.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/ServiceLoader.java new file mode 100644 index 0000000000..c5be797cda --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/ServiceLoader.java @@ -0,0 +1,99 @@ +/* + * 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.core.loader; + +import java.net.URI; +import javax.xml.namespace.QName; +import static javax.xml.stream.XMLStreamConstants.END_ELEMENT; +import static javax.xml.stream.XMLStreamConstants.START_ELEMENT; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import static org.osoa.sca.Constants.SCA_NS; +import org.osoa.sca.annotations.Constructor; +import org.osoa.sca.annotations.Reference; + +import org.apache.tuscany.spi.QualifiedName; +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.UnrecognizedElementException; +import org.apache.tuscany.spi.model.BindingDefinition; +import org.apache.tuscany.spi.model.ModelObject; +import org.apache.tuscany.spi.model.ServiceContract; +import org.apache.tuscany.spi.model.ServiceDefinition; + +/** + * Loads a service definition from an XML-based assembly file + * + * @version $Rev$ $Date$ + */ +public class ServiceLoader extends LoaderExtension<ServiceDefinition> { + private static final QName SERVICE = new QName(SCA_NS, "service"); + + @Constructor + public ServiceLoader(@Reference LoaderRegistry registry) { + super(registry); + } + + public QName getXMLType() { + return SERVICE; + } + + public ServiceDefinition load(ModelObject object, XMLStreamReader reader, DeploymentContext context) + throws XMLStreamException, LoaderException { + assert SERVICE.equals(reader.getName()); + String name = reader.getAttributeValue(null, "name"); + URI compositeId = context.getComponentId(); + URI componentBase = URI.create(compositeId + "/"); + ServiceDefinition def = new ServiceDefinition(); + def.setUri(compositeId.resolve('#' + name)); + + URI targetUri = null; + String promote = reader.getAttributeValue(null, "promote"); + if (promote != null) { + QualifiedName qName = new QualifiedName(promote); + targetUri = componentBase.resolve(qName.getFragment()); + } + while (true) { + int i = reader.next(); + switch (i) { + case START_ELEMENT: + ModelObject o = registry.load(null, reader, context); + if (o instanceof ServiceContract) { + def.setServiceContract((ServiceContract) o); + } else if (o instanceof BindingDefinition) { + def.addBinding((BindingDefinition) o); + } else { + throw new UnrecognizedElementException(reader.getName()); + } + break; + case END_ELEMENT: + if (SERVICE.equals(reader.getName())) { + if (targetUri != null) { + def.setTarget(targetUri); + } + return def; + } + break; + } + } + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/StringParserPropertyFactory.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/StringParserPropertyFactory.java new file mode 100644 index 0000000000..eda09d6f11 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/StringParserPropertyFactory.java @@ -0,0 +1,191 @@ +/* + * 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.core.loader; + +import java.beans.PropertyEditor; +import java.beans.PropertyEditorManager; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import javax.xml.stream.XMLStreamException; + +import org.apache.tuscany.spi.ObjectFactory; +import org.apache.tuscany.spi.loader.LoaderException; +import org.apache.tuscany.spi.loader.PropertyObjectFactory; +import org.apache.tuscany.spi.model.Property; +import org.apache.tuscany.spi.model.PropertyValue; + +import org.apache.tuscany.core.injection.SingletonObjectFactory; + +/** + * Implementation of StAXPropertyFactory that interprets the XML as + * + * @version $Rev$ $Date$ + */ +public class StringParserPropertyFactory implements PropertyObjectFactory { + + public <T> ObjectFactory<T> createObjectFactory(Property<T> property, PropertyValue<T> value) + throws LoaderException { + String text = value.getValue().getDocumentElement().getTextContent(); + return new SingletonObjectFactory<T>(createInstance(text, property.getJavaType())); + } + + @SuppressWarnings("unchecked") + public <T> T createInstance(String text, Class<T> type) throws LoaderException { + // Class<T> type = property.getJavaType(); + assert type != null : "property type is null"; + + // degenerate case where property type is a String + if (String.class.equals(type)) { + return type.cast(text); + } + + // special handler to convert hexBinary to a byte[] + if (byte[].class.equals(type)) { + byte[] instance = new byte[text.length() >> 1]; + for (int i = 0; i < instance.length; i++) { + instance[i] = + (byte) (Character.digit(text.charAt(i << 1), 16) << 4 | Character.digit(text + .charAt((i << 1) + 1), 16)); + } + return type.cast(instance); + } + + // does this type have a static valueOf(String) method? + try { + Method valueOf = type.getMethod("valueOf", String.class); + if (Modifier.isStatic(valueOf.getModifiers())) { + try { + return type.cast(valueOf.invoke(null, text)); + } catch (IllegalAccessException e) { + throw new AssertionError("getMethod returned an inaccessible method"); + } catch (InvocationTargetException e) { + // FIXME we should throw something better + throw new LoaderException(e.getCause()); + } + } + } catch (NoSuchMethodException e) { + // try something else + } + + // does this type have a constructor that takes a String? + try { + Constructor<T> ctr = type.getConstructor(String.class); + return ctr.newInstance(text); + } catch (NoSuchMethodException e) { + // try something else + } catch (IllegalAccessException e) { + throw new AssertionError("getConstructor returned an inaccessible method"); + } catch (InstantiationException e) { + throw new LoaderException("Property type cannot be instantiated: " + type.getName()); + } catch (InvocationTargetException e) { + // FIXME we should throw something better + throw new LoaderException(e.getCause()); + } + + // do we have a property editor for it? + PropertyEditor editor = PropertyEditorManager.findEditor(type); + if (editor != null) { + try { + editor.setAsText(text); + return (T) editor.getValue(); + } catch (IllegalArgumentException e) { + // FIXME we should throw something better + throw new LoaderException(e); + + } + } + + // FIXME we should throw something better + throw new LoaderException("Do not have a way to parse a String into a " + type.getName()); + + } + + @SuppressWarnings("unchecked") + public <T> ObjectFactory<T> createObjectFactory(String text, Property<T> property) + throws XMLStreamException, LoaderException { + Class<T> type = property.getJavaType(); + assert type != null : "property type is null"; + + // degenerate case where property type is a String + if (String.class.equals(type)) { + return new SingletonObjectFactory<T>(type.cast(text)); + } + + // special handler to convert hexBinary to a byte[] + if (byte[].class.equals(type)) { + byte[] instance = new byte[text.length() >> 1]; + for (int i = 0; i < instance.length; i++) { + instance[i] = + (byte) (Character.digit(text.charAt(i << 1), 16) << 4 | Character.digit(text + .charAt((i << 1) + 1), 16)); + } + return new SingletonObjectFactory<T>(type.cast(instance)); + } + + // does this type have a static valueOf(String) method? + try { + Method valueOf = type.getMethod("valueOf", String.class); + if (Modifier.isStatic(valueOf.getModifiers())) { + try { + return new SingletonObjectFactory<T>(type.cast(valueOf.invoke(null, text))); + } catch (IllegalAccessException e) { + throw new AssertionError("getMethod returned an inaccessible method"); + } catch (InvocationTargetException e) { + // FIXME we should throw something better + throw new LoaderException(e.getCause()); + } + } + } catch (NoSuchMethodException e) { + // try something else + } + + // does this type have a constructor that takes a String? + try { + Constructor<T> ctr = type.getConstructor(String.class); + return new SingletonObjectFactory<T>(ctr.newInstance(text)); + } catch (NoSuchMethodException e) { + // try something else + } catch (IllegalAccessException e) { + throw new AssertionError("getConstructor returned an inaccessible method"); + } catch (InstantiationException e) { + throw new LoaderException("Property type cannot be instantiated: " + type.getName()); + } catch (InvocationTargetException e) { + // FIXME we should throw something better + throw new LoaderException(e.getCause()); + } + + // do we have a property editor for it? + PropertyEditor editor = PropertyEditorManager.findEditor(type); + if (editor != null) { + try { + editor.setAsText(text); + return new SingletonObjectFactory<T>((T) editor.getValue()); + } catch (IllegalArgumentException e) { + // FIXME we should throw something better + throw new LoaderException(e); + + } + } + + // FIXME we should throw something better + throw new LoaderException("Do not have a way to parse a String into a " + type.getName()); + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/WireLoader.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/WireLoader.java new file mode 100644 index 0000000000..9c60790111 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/loader/WireLoader.java @@ -0,0 +1,122 @@ +/*
+ * 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.core.loader;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import javax.xml.namespace.QName;
+import static javax.xml.stream.XMLStreamConstants.END_ELEMENT;
+import static javax.xml.stream.XMLStreamConstants.START_ELEMENT;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import static org.osoa.sca.Constants.SCA_NS;
+import org.osoa.sca.annotations.Constructor;
+import org.osoa.sca.annotations.Reference;
+
+import org.apache.tuscany.spi.QualifiedName;
+import org.apache.tuscany.spi.deployer.DeploymentContext;
+import org.apache.tuscany.spi.extension.LoaderExtension;
+import org.apache.tuscany.spi.loader.InvalidWireException;
+import org.apache.tuscany.spi.loader.LoaderException;
+import org.apache.tuscany.spi.loader.LoaderRegistry;
+import org.apache.tuscany.spi.model.ModelObject;
+import org.apache.tuscany.spi.model.WireDefinition;
+
+/**
+ * Loads a wire from an XML-based assembly file
+ *
+ * @version $Rev: 465084 $ $Date: 2006-10-18 04:00:49 +0530 (Wed, 18 Oct 2006) $
+ */
+public class WireLoader extends LoaderExtension<WireDefinition> {
+ private static final QName WIRE = new QName(SCA_NS, "wire");
+ private static final QName SOURCE_URI = new QName(SCA_NS, "source.uri");
+ private static final QName TARGET_URI = new QName(SCA_NS, "target.uri");
+
+ @Constructor
+ public WireLoader(@Reference LoaderRegistry registry) {
+ super(registry);
+ }
+
+ public QName getXMLType() {
+ return WIRE;
+ }
+
+ public WireDefinition load(
+ ModelObject object,
+ XMLStreamReader reader,
+ DeploymentContext deploymentContext) throws XMLStreamException, LoaderException {
+ assert WIRE.equals(reader.getName());
+ WireDefinition wireDefn;
+ URI sourceURI = null;
+ URI targetURI = null;
+ String uriString;
+ while (true) {
+ switch (reader.next()) {
+ case START_ELEMENT:
+ try {
+ if (reader.getName().equals(SOURCE_URI)) {
+ uriString = reader.getElementText();
+ if (uriString != null && uriString.trim().length() > 0) {
+ QualifiedName name = new QualifiedName(uriString);
+ if (name.getPortName() == null) {
+ sourceURI = new URI(uriString);
+ } else {
+ sourceURI = new URI(name.getPartName() + "#" + name.getPortName());
+ }
+ } else {
+ throw new InvalidWireException("Wire source not defined");
+ }
+ } else if (reader.getName().equals(TARGET_URI)) {
+ uriString = reader.getElementText();
+ if (uriString != null && uriString.trim().length() > 0) {
+ QualifiedName name = new QualifiedName(uriString);
+ if (name.getPortName() == null) {
+ targetURI = new URI(uriString);
+ } else {
+ targetURI = new URI(name.getPartName() + "#" + name.getPortName());
+ }
+ } else {
+ throw new InvalidWireException("Wire target not defined");
+ }
+ } else {
+ QName name = reader.getName();
+ throw new InvalidWireException("Unrecognized element in wire ", name.toString());
+ }
+ } catch (URISyntaxException e) {
+ throw new InvalidWireException("Invalid wire uri", e);
+ }
+
+ reader.next();
+ break;
+ case END_ELEMENT:
+ if (reader.getName().equals(WIRE)) {
+ if (sourceURI != null && targetURI != null) {
+ wireDefn = new WireDefinition();
+ wireDefn.setSource(sourceURI);
+ wireDefn.setTarget(targetURI);
+ } else {
+ throw new InvalidWireException("Incomplete wire definition");
+ }
+ return wireDefn;
+ }
+ }
+ }
+ }
+}
diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/monitor/DefaultExceptionFormatter.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/monitor/DefaultExceptionFormatter.java new file mode 100644 index 0000000000..14468061e3 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/monitor/DefaultExceptionFormatter.java @@ -0,0 +1,54 @@ +/* + * 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.core.monitor; + +import java.io.PrintWriter; + +import org.apache.tuscany.api.TuscanyException; +import org.apache.tuscany.api.TuscanyRuntimeException; +import org.apache.tuscany.host.monitor.ExceptionFormatter; + +/** + * Performs basics formatting of exceptions for JDK logging + * + * @version $Rev$ $Date$ + */ +public class DefaultExceptionFormatter implements ExceptionFormatter { + + public DefaultExceptionFormatter() { + } + + public boolean canFormat(Class<?> type) { + return Throwable.class.isAssignableFrom(type); + } + + public PrintWriter write(PrintWriter writer, Throwable exception) { + if (exception instanceof TuscanyException) { + TuscanyException e = (TuscanyException) exception; + e.appendBaseMessage(writer); + } else if (exception instanceof TuscanyRuntimeException) { + TuscanyRuntimeException e = (TuscanyRuntimeException) exception; + e.appendBaseMessage(writer); + } + writer.append("\n"); + return writer; + } + + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/monitor/InvalidLevelException.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/monitor/InvalidLevelException.java new file mode 100644 index 0000000000..cf07b0f914 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/monitor/InvalidLevelException.java @@ -0,0 +1,64 @@ +/* + * 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.core.monitor; + +/** + * Exception indicating an invalid log level has been passed. + * + * @version $Rev$ $Date$ + */ +public class InvalidLevelException extends IllegalArgumentException { + private static final long serialVersionUID = 7767234706427841915L; + private final String method; + private final String level; + + /** + * Constructor specifying the method name and the level affected. + * + * @param method the name of the method being monitored + * @param level the invalid log level value + */ + public InvalidLevelException(String method, String level) { + super(); + this.method = method; + this.level = level; + } + + /** + * Returns the name of the method being monitored. + * + * @return the name of the method being monitored + */ + public String getMethod() { + return method; + } + + /** + * Returns the invalid log level specified. + * + * @return the invalid log level that was specified + */ + public String getLevel() { + return level; + } + + public String getMessage() { + return "Invalid level for method " + method + " : " + level; + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/monitor/JavaLoggingMonitorFactory.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/monitor/JavaLoggingMonitorFactory.java new file mode 100644 index 0000000000..4adff1b0db --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/monitor/JavaLoggingMonitorFactory.java @@ -0,0 +1,120 @@ +/* + * 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.core.monitor; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.ResourceBundle; +import java.util.logging.Level; +import java.util.logging.LogRecord; +import java.util.logging.Logger; + +import org.osoa.sca.annotations.Service; + +import org.apache.tuscany.host.MonitorFactory; +import org.apache.tuscany.host.monitor.FormatterRegistry; + +/** + * A factory for monitors that forwards events to a {@link java.util.logging.Logger Java Logging (JSR47) Logger}. + * + * @version $Rev$ $Date$ + * @see java.util.logging + */ +@Service(interfaces = {MonitorFactory.class, FormatterRegistry.class}) +public class JavaLoggingMonitorFactory extends ProxyMonitorFactory { + + /** + * Construct a MonitorFactory that will monitor the specified methods at the specified levels and generate messages + * using java.util.logging. + * <p/> + * The supplied Properties can be used to specify custom log levels for specific monitor methods. The key should be + * the method name in form returned by <code>Class.getName() + '#' + Method.getName()</code> and the value the log + * level to use as defined by {@link java.util.logging.Level}. + * + * @param levels definition of custom levels for specific monitored methods, may be null or empty. + * @param defaultLevel the default log level to use + * @param bundleName the name of a resource bundle that will be passed to the logger + * @see java.util.logging.Logger + */ + public JavaLoggingMonitorFactory(Properties levels, Level defaultLevel, String bundleName) { + Map<String, Object> configProperties = new HashMap<String, Object>(); + configProperties.put("levels", levels); + configProperties.put("defaultLevel", defaultLevel); + configProperties.put("bundleName", bundleName); + initInternal(configProperties); + } + + /** + * Constructs a MonitorFactory that needs to be subsequently configured via a call to {@link #initialize}. + */ + public JavaLoggingMonitorFactory() { + } + + protected <T> InvocationHandler createInvocationHandler(Class<T> monitorInterface, + Map<String, Level> levels) { + ResourceBundle bundle = locateBundle(monitorInterface, bundleName); + Logger logger = Logger.getLogger(monitorInterface.getName()); + return new LoggingHandler(logger, levels, bundle); + } + + private class LoggingHandler implements InvocationHandler { + private final Logger logger; + private final Map<String, Level> methodLevels; + private final ResourceBundle bundle; + + public LoggingHandler(Logger logger, + Map<String, Level> methodLevels, + ResourceBundle bundle + ) { + this.logger = logger; + this.methodLevels = methodLevels; + this.bundle = bundle; + } + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + String sourceMethod = method.getName(); + Level level = methodLevels.get(sourceMethod); + if (level != null && logger.isLoggable(level)) { + // construct the key for the resource bundle + String className = logger.getName(); + String key = className + '#' + sourceMethod; + + LogRecord logRecord = new LogRecord(level, key); + logRecord.setLoggerName(className); + logRecord.setSourceClassName(className); + logRecord.setSourceMethodName(sourceMethod); + logRecord.setParameters(args); + if (args != null) { + for (Object o : args) { + if (o instanceof Throwable) { + logRecord.setMessage(formatException((Throwable) o)); + break; + } + } + } + logRecord.setResourceBundle(bundle); + logger.log(logRecord); + } + return null; + } + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/monitor/MonitorFactoryUtil.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/monitor/MonitorFactoryUtil.java new file mode 100644 index 0000000000..92224d469f --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/monitor/MonitorFactoryUtil.java @@ -0,0 +1,78 @@ +/* + * 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.core.monitor; + +import org.apache.tuscany.host.MonitorFactory; + +import java.util.Map; + +/** + * Helper for creating MonitorFactory instances. + * + * @version $$Rev$$ $$Date$$ + */ + +public final class MonitorFactoryUtil { + /** + * Hide the constructor + */ + private MonitorFactoryUtil() { + } + + /** + * Creates a MonitorFactory instance of the specified type. + * @param name fully qualified classname of the desired MonitorFactory type + * @param props collection of initialization properties + * @return a configured MonitorFactory instance, or null if the factory could not be instantiated. + */ + @SuppressWarnings("unchecked") + public static MonitorFactory createMonitorFactory(String name, Map<String, Object> props) { + Class<? extends MonitorFactory> clazz; + try { + clazz = (Class<? extends MonitorFactory>) Class.forName(name); + } catch (ClassNotFoundException cnfe) { + return null; + } catch (ClassCastException cce) { + return null; + } + + return createMonitorFactory(clazz, props); + } + + /** + * Creates a MonitorFactory instance of the specified type. + * @param mfc class of the desired MonitorFactory type + * @param props collection of initialization properties + * @return a configured MonitorFactory instance, or null if the factory could not be instantiated. + */ + public static MonitorFactory createMonitorFactory(Class<? extends MonitorFactory> mfc, Map<String, Object> props) { + MonitorFactory mf; + try { + mf = mfc.newInstance(); + mf.initialize(props); + } catch (InstantiationException e) { + throw new AssertionError(e); + } catch (IllegalAccessException e) { + throw new AssertionError(e); + } + // allow IllegalArgumentException to propogate out + + return mf; + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/monitor/NullMonitorFactory.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/monitor/NullMonitorFactory.java new file mode 100644 index 0000000000..46c52e38f6 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/monitor/NullMonitorFactory.java @@ -0,0 +1,68 @@ +/* + * 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.core.monitor; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.Map; + +import org.osoa.sca.annotations.EagerInit; + +import org.apache.tuscany.host.MonitorFactory; +import org.apache.tuscany.host.monitor.ExceptionFormatter; + +/** + * Implementation of a {@link MonitorFactory} that produces implementations that simply return. + * + * @version $Rev$ $Date$ + */ +@EagerInit +public class NullMonitorFactory implements MonitorFactory { + + /** + * Singleton hander that does nothing. + */ + private static final InvocationHandler NULL_MONITOR = new InvocationHandler() { + public Object invoke(Object proxy, Method method, Object[] args) { + return null; + } + }; + + public void initialize(Map<String, Object> configProperties) { + } + + public <T> T getMonitor(Class<T> monitorInterface) { + /* + * This uses a reflection proxy to implement the monitor interface which + * is a simple but perhaps not very performant solution. Performance + * might be improved by code generating an implementation with empty methods. + */ + return monitorInterface.cast( + Proxy.newProxyInstance(monitorInterface.getClassLoader(), new Class<?>[]{monitorInterface}, NULL_MONITOR)); + } + + public void register(ExceptionFormatter formatter) { + + } + + public void unregister(ExceptionFormatter formatter) { + + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/monitor/ProxyMonitorFactory.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/monitor/ProxyMonitorFactory.java new file mode 100644 index 0000000000..d9ca9e6cfc --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/monitor/ProxyMonitorFactory.java @@ -0,0 +1,234 @@ +/* + * 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.core.monitor; + +import java.util.Map; +import java.util.Properties; +import java.util.HashMap; +import java.util.ResourceBundle; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.List; +import java.util.ArrayList; +import java.util.WeakHashMap; +import java.util.logging.Level; +import java.lang.ref.WeakReference; +import java.lang.reflect.Method; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; +import java.io.PrintWriter; +import java.io.StringWriter; + +import org.apache.tuscany.host.MonitorFactory; +import org.apache.tuscany.host.monitor.FormatterRegistry; +import org.apache.tuscany.host.monitor.ExceptionFormatter; +import org.apache.tuscany.api.annotation.LogLevel; + +/** + * @version $Rev$ $Date$ + */ +public abstract class ProxyMonitorFactory implements MonitorFactory, FormatterRegistry { + protected String bundleName; + protected final List<ExceptionFormatter> formatters = new ArrayList<ExceptionFormatter>(); + protected final ExceptionFormatter defaultFormatter = new DefaultExceptionFormatter(); + protected Level defaultLevel; + protected Map<String, Level> levels; + private final Map<Class<?>, WeakReference<?>> proxies = new WeakHashMap<Class<?>, WeakReference<?>>(); + + public void initialize(Map<String, Object> configProperties) { + if (configProperties == null) { + return; + } + initInternal(configProperties); + } + + protected void initInternal(Map<String, Object> configProperties) { + try { + this.defaultLevel = (Level) configProperties.get("defaultLevel"); + this.bundleName = (String) configProperties.get("bundleName"); + Properties levels = (Properties) configProperties.get("levels"); + + this.levels = new HashMap<String, Level>(); + if (levels != null) { + for (Map.Entry<Object, Object> entry : levels.entrySet()) { + String method = (String) entry.getKey(); + String level = (String) entry.getValue(); + try { + this.levels.put(method, Level.parse(level)); + } catch (IllegalArgumentException e) { + throw new InvalidLevelException(method, level); + } + } + } + } catch (ClassCastException cce) { + throw new IllegalArgumentException(cce.getLocalizedMessage()); + } + } + + public synchronized <T> T getMonitor(Class<T> monitorInterface) { + T proxy = getCachedMonitor(monitorInterface); + if (proxy == null) { + proxy = createMonitor(monitorInterface); + proxies.put(monitorInterface, new WeakReference<T>(proxy)); + } + return proxy; + } + + protected <T> T getCachedMonitor(Class<T> monitorInterface) { + WeakReference<?> ref = proxies.get(monitorInterface); + return (ref != null) ? monitorInterface.cast(ref.get()) : null; + } + + protected <T> T createMonitor(Class<T> monitorInterface) { + String className = monitorInterface.getName(); + Method[] methods = monitorInterface.getMethods(); + Map<String, Level> levels = new HashMap<String, Level>(methods.length); + for (Method method : methods) { + String key = className + '#' + method.getName(); + Level level = null; + if (this.levels != null) { + this.levels.get(key); + } + // if not specified the in config properties, look for an annotation on the method + if (level == null) { + LogLevel annotation = method.getAnnotation(LogLevel.class); + if (annotation != null && annotation.value() != null) { + try { + level = Level.parse(annotation.value()); + } catch (IllegalArgumentException e) { + // bad value, just use the default + level = defaultLevel; + } + } + } + if (level == null) { + level = defaultLevel; + } + levels.put(method.getName(), level); + } + + InvocationHandler handler = createInvocationHandler(monitorInterface, levels); + Object proxy = Proxy.newProxyInstance(monitorInterface.getClassLoader(), + new Class<?>[]{monitorInterface}, + handler); + return monitorInterface.cast(proxy); + } + + protected <T> ResourceBundle locateBundle(Class<T> monitorInterface, String bundleName) { + Locale locale = Locale.getDefault(); + ClassLoader cl = monitorInterface.getClassLoader(); + String packageName = monitorInterface.getPackage().getName(); + while (true) { + try { + return ResourceBundle.getBundle(packageName + '.' + bundleName, locale, cl); + } catch (MissingResourceException e) { + //ok + } + int index = packageName.lastIndexOf('.'); + if (index == -1) { + break; + } + packageName = packageName.substring(0, index); + } + try { + return ResourceBundle.getBundle(bundleName, locale, cl); + } catch (Exception e) { + return null; + } + } + + public void register(ExceptionFormatter formatter) { + formatters.add(formatter); + } + + public void unregister(ExceptionFormatter formatter) { + formatters.remove(formatter); + } + + protected abstract <T> InvocationHandler createInvocationHandler(Class<T> monitorInterface, + Map<String, Level> levels); + + protected String formatException(Throwable e) { + ExceptionFormatter formatter = defaultFormatter; + for (ExceptionFormatter candidate : formatters) { + if (candidate.canFormat(e.getClass())) { + formatter = candidate; + break; + } + } + StringWriter writer = new StringWriter(); + PrintWriter pw = new PrintWriter(writer); + formatter.write(pw, e); + format(pw, e); + pw.close(); + return writer.toString(); + } + + protected void format(PrintWriter writer, Throwable throwable) { + writer.println(throwable.getClass().getName()); + StackTraceElement[] trace = throwable.getStackTrace(); + for (StackTraceElement aTrace : trace) { + writer.println("\tat " + aTrace); + } + Throwable ourCause = throwable.getCause(); + + if (ourCause != null) { + printStackTraceAsCause(writer, ourCause, trace); + } + } + + protected void printStackTraceAsCause(PrintWriter pw, + Throwable throwable, + StackTraceElement[] causedTrace) { + + // Compute number of frames in common between this and caused + StackTraceElement[] trace = throwable.getStackTrace(); + int m = trace.length - 1; + int n = causedTrace.length - 1; + while (m >= 0 && n >= 0 && trace[m].equals(causedTrace[n])) { + m--; + n--; + } + int framesInCommon = trace.length - 1 - m; + + pw.println("Caused by: " + throwable.getClass().getName()); + + ExceptionFormatter formatter = defaultFormatter; + for (ExceptionFormatter candidate : formatters) { + if (candidate.canFormat(throwable.getClass())) { + formatter = candidate; + break; + } + } + formatter.write(pw, throwable); + + for (int i = 0; i <= m; i++) { + pw.println("\tat " + trace[i]); + } + if (framesInCommon != 0) { + pw.println("\t... " + framesInCommon + " more"); + } + + // Recurse if we have a cause + Throwable ourCause = throwable.getCause(); + if (ourCause != null) { + printStackTraceAsCause(pw, ourCause, trace); + } + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/resolver/AutowireResolver.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/resolver/AutowireResolver.java new file mode 100644 index 0000000000..8502f8d5f8 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/resolver/AutowireResolver.java @@ -0,0 +1,64 @@ +/* + * 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.core.resolver; + +import java.net.URI; + +import org.apache.tuscany.spi.model.ComponentDefinition; +import org.apache.tuscany.spi.model.CompositeComponentType; +import org.apache.tuscany.spi.model.Implementation; +import org.apache.tuscany.spi.model.ServiceContract; +import org.apache.tuscany.spi.resolver.ResolutionException; + +/** + * Implementations are responsible for resolving autowire targets in an SCA Domain. It is assumed that autowire + * resolution occurs after resource resolution as service interface classes may be laoded + * + * @version $Rev$ $Date$ + */ +public interface AutowireResolver { + + /** + * Resolves autowires for a component definition and its decendents + * + * @param parentDefinition the parent + * @param definition the component definition to resolve autowires for + * @throws ResolutionException + */ + void resolve(ComponentDefinition<Implementation<CompositeComponentType<?, ?, ?>>> parentDefinition, + ComponentDefinition<? extends Implementation<?>> definition) throws ResolutionException; + + /** + * Resolves autowires for a composite component type and its decendents + * + * @param compositeType the component type to resolve autowires for + * @throws ResolutionException + */ + @SuppressWarnings({"unchecked"}) + public void resolve(CompositeComponentType<?, ?, ?> compositeType) throws ResolutionException; + + /** + * Adds the uri of a host system service that can be an autowire target + * + * @param contract the service contract of the system service + * @param uri the component uri + */ + void addHostUri(ServiceContract contract, URI uri); + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/resolver/AutowireTargetNotFoundException.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/resolver/AutowireTargetNotFoundException.java new file mode 100644 index 0000000000..1526724ca9 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/resolver/AutowireTargetNotFoundException.java @@ -0,0 +1,30 @@ +/* + * 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.core.resolver; + +import org.apache.tuscany.spi.resolver.ResolutionException; + +/** + * @version $Rev$ $Date$ + */ +public class AutowireTargetNotFoundException extends ResolutionException { + public AutowireTargetNotFoundException(String message, String identifier) { + super(message, identifier); + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/resolver/DefaultAutowireResolver.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/resolver/DefaultAutowireResolver.java new file mode 100644 index 0000000000..eab78e25d9 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/resolver/DefaultAutowireResolver.java @@ -0,0 +1,181 @@ +/* + * 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.core.resolver; + +import java.net.URI; +import java.util.HashMap; +import java.util.Map; + +import org.apache.tuscany.spi.model.ComponentDefinition; +import org.apache.tuscany.spi.model.ComponentType; +import org.apache.tuscany.spi.model.CompositeComponentType; +import org.apache.tuscany.spi.model.Implementation; +import org.apache.tuscany.spi.model.ReferenceDefinition; +import org.apache.tuscany.spi.model.ReferenceTarget; +import org.apache.tuscany.spi.model.ServiceContract; +import org.apache.tuscany.spi.model.ServiceDefinition; +import org.apache.tuscany.spi.resolver.ResolutionException; + +/** + * Default implementation of an autowire resolver + * + * @version $Rev$ $Date$ + */ +public class DefaultAutowireResolver implements AutowireResolver { + private Map<ServiceContract, URI> hostAutowire = new HashMap<ServiceContract, URI>(); + + + @SuppressWarnings({"unchecked"}) + public void resolve(ComponentDefinition<Implementation<CompositeComponentType<?, ?, ?>>> parentDefinition, + ComponentDefinition<? extends Implementation<?>> definition) + throws ResolutionException { + ComponentType<?, ?, ?> type = definition.getImplementation().getComponentType(); + // resolve autowires + if (type instanceof CompositeComponentType) { + CompositeComponentType<?, ?, ?> compositeType = (CompositeComponentType<?, ?, ?>) type; + for (ComponentDefinition<? extends Implementation<?>> child : compositeType.getComponents().values()) { + Implementation<?> implementation = child.getImplementation(); + ComponentType<?, ?, ?> childType = implementation.getComponentType(); + if (childType instanceof CompositeComponentType) { + // recurse decendents for composites + resolve((ComponentDefinition<Implementation<CompositeComponentType<?, ?, ?>>>) definition, child); + } + Map<String, ReferenceTarget> targets = child.getReferenceTargets(); + for (ReferenceDefinition reference : childType.getReferences().values()) { + ReferenceTarget target = targets.get(reference.getUri().getFragment()); + if (target == null) { + continue; + } + if (target.isAutowire()) { + ServiceContract requiredContract = reference.getServiceContract(); + resolve(compositeType, requiredContract, target, reference.isRequired()); + } + } + } + } else { + // a leaf level component + ComponentType<?, ?, ?> componentType = definition.getImplementation().getComponentType(); + Map<String, ReferenceTarget> targets = definition.getReferenceTargets(); + for (ReferenceDefinition reference : componentType.getReferences().values()) { + ReferenceTarget target = targets.get(reference.getUri().getFragment()); + if (target == null) { + continue; + } + if (target.isAutowire()) { + ServiceContract requiredContract = reference.getServiceContract(); + CompositeComponentType<?, ?, ?> ctype = parentDefinition.getImplementation().getComponentType(); + resolve(ctype, requiredContract, target, reference.isRequired()); + } + } + } + } + + public void addHostUri(ServiceContract contract, URI uri) { + hostAutowire.put(contract, uri); + } + + public void resolve(CompositeComponentType<?, ?, ?> compositeType) throws ResolutionException { + for (ComponentDefinition<? extends Implementation<?>> child : compositeType.getComponents().values()) { + Implementation<?> implementation = child.getImplementation(); + ComponentType<?, ?, ?> childType = implementation.getComponentType(); + if (childType instanceof CompositeComponentType) { + // recurse decendents for composites + resolve(null, child); + } + Map<String, ReferenceTarget> targets = child.getReferenceTargets(); + for (ReferenceDefinition reference : childType.getReferences().values()) { + ReferenceTarget target = targets.get(reference.getUri().getFragment()); + if (target == null) { + continue; + } + if (target.isAutowire()) { + ServiceContract requiredContract = reference.getServiceContract(); + resolve(compositeType, requiredContract, target, reference.isRequired()); + } + } + } + } + /** + * Performs the actual resolution against a composite TODO this should be extensible allowing for path + * optimizations + * + * @param compositeType the composite component type to resolve against + * @param requiredContract the required target contract + * @param target the reference target + * @param required true if the autowire is required + * @throws AutowireTargetNotFoundException + * + */ + private void resolve(CompositeComponentType<?, ?, ?> compositeType, + ServiceContract requiredContract, + ReferenceTarget target, + boolean required) throws AutowireTargetNotFoundException { + // for now, attempt to match on interface, assume the class can be loaded + Class<?> requiredInterface = requiredContract.getInterfaceClass(); + if (requiredInterface == null) { + throw new UnsupportedOperationException("Only interfaces support for autowire"); + } + // autowire to a target in the parent + URI targetUri = null; + URI candidateUri = null; + // find a suitable target, starting with components first + for (ComponentDefinition<? extends Implementation<?>> candidate : compositeType.getComponents().values()) { + Implementation<?> candidateImpl = candidate.getImplementation(); + ComponentType<?, ?, ?> candidateType = candidateImpl.getComponentType(); + for (ServiceDefinition service : candidateType.getServices().values()) { + Class<?> serviceInterface = service.getServiceContract().getInterfaceClass(); + if (serviceInterface == null) { + continue; + } + if (requiredInterface.equals(serviceInterface)) { + targetUri = URI.create(candidate.getUri().toString() + service.getUri()); + break; + } else if (candidateUri == null && requiredInterface.isAssignableFrom(serviceInterface)) { + candidateUri = URI.create(candidate.getUri().toString() + service.getUri()); + } + } + if (targetUri != null) { + break; + } + } + if (targetUri == null) { + targetUri = resolvePrimordial(requiredContract); + } + if (candidateUri != null) { + targetUri = candidateUri; + } + if (targetUri != null) { + target.addTarget(targetUri); + } + if (targetUri == null && required) { + String uri = target.getReferenceName().toString(); + throw new AutowireTargetNotFoundException("No suitable target found for", uri); + } + } + + private URI resolvePrimordial(ServiceContract contract) { + Class<?> requiredClass = contract.getInterfaceClass(); + for (Map.Entry<ServiceContract, URI> entry : hostAutowire.entrySet()) { + if (requiredClass.isAssignableFrom(entry.getKey().getInterfaceClass())) { + return entry.getValue(); + } + } + return null; + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/runtime/AbstractRuntime.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/runtime/AbstractRuntime.java new file mode 100644 index 0000000000..4a9cbb1ff5 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/runtime/AbstractRuntime.java @@ -0,0 +1,379 @@ +/* + * 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.core.runtime; + +import static org.apache.tuscany.spi.bootstrap.ComponentNames.TUSCANY_DEPLOYER; +import static org.apache.tuscany.spi.bootstrap.ComponentNames.TUSCANY_SYSTEM; +import static org.apache.tuscany.spi.bootstrap.ComponentNames.TUSCANY_SYSTEM_ROOT; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URI; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.xml.stream.XMLInputFactory; + +import org.apache.tuscany.core.bootstrap.Bootstrapper; +import org.apache.tuscany.core.bootstrap.DefaultBootstrapper; +import org.apache.tuscany.core.bootstrap.ExtensionActivator; +import org.apache.tuscany.core.builder.ConnectorImpl; +import org.apache.tuscany.core.component.ComponentManagerImpl; +import org.apache.tuscany.core.component.SimpleWorkContext; +import org.apache.tuscany.core.component.scope.CompositeScopeContainer; +import org.apache.tuscany.core.component.scope.ScopeRegistryImpl; +import org.apache.tuscany.core.deployer.DeployerImpl; +import org.apache.tuscany.core.monitor.NullMonitorFactory; +import org.apache.tuscany.core.resolver.AutowireResolver; +import org.apache.tuscany.core.resolver.DefaultAutowireResolver; +import org.apache.tuscany.core.services.classloading.ClassLoaderRegistryImpl; +import org.apache.tuscany.core.util.IOHelper; +import org.apache.tuscany.host.MonitorFactory; +import org.apache.tuscany.host.RuntimeInfo; +import org.apache.tuscany.host.management.ManagementService; +import org.apache.tuscany.host.monitor.FormatterRegistry; +import org.apache.tuscany.host.runtime.InitializationException; +import org.apache.tuscany.host.runtime.TuscanyRuntime; +import org.apache.tuscany.spi.builder.BuilderRegistry; +import org.apache.tuscany.spi.builder.Connector; +import org.apache.tuscany.spi.component.AtomicComponent; +import org.apache.tuscany.spi.component.Component; +import org.apache.tuscany.spi.component.ComponentManager; +import org.apache.tuscany.spi.component.RegistrationException; +import org.apache.tuscany.spi.component.ScopeContainerMonitor; +import org.apache.tuscany.spi.component.ScopeRegistry; +import org.apache.tuscany.spi.component.TargetResolutionException; +import org.apache.tuscany.spi.component.WorkContext; +import org.apache.tuscany.spi.deployer.Deployer; +import org.apache.tuscany.spi.idl.java.JavaServiceContract; +import org.apache.tuscany.spi.loader.LoaderRegistry; +import org.apache.tuscany.spi.services.classloading.ClassLoaderRegistry; +import org.apache.tuscany.spi.services.management.TuscanyManagementService; +import org.osoa.sca.ComponentContext; + +/** + * @version $Rev$ $Date$ + */ +public abstract class AbstractRuntime<I extends RuntimeInfo> implements TuscanyRuntime<I> { + private static final URI MONITOR_URI = TUSCANY_SYSTEM_ROOT.resolve("MonitorFactory"); + + private static final URI COMPONENT_MGR_URI = TUSCANY_SYSTEM_ROOT.resolve("ComponentManager"); + + private static final URI AUTOWIRE_RESOLVER_URI = TUSCANY_SYSTEM_ROOT.resolve("AutowireResolver"); + + private static final URI SCOPE_REGISTRY_URI = TUSCANY_SYSTEM_ROOT.resolve("ScopeRegistry"); + + private static final URI WORK_CONTEXT_URI = TUSCANY_SYSTEM.resolve("WorkContext"); + + private static final URI RUNTIME_INFO_URI = TUSCANY_SYSTEM_ROOT.resolve("RuntimeInfo"); + + private static final URI CLASSLOADER_REGISTRY_URI = TUSCANY_SYSTEM_ROOT.resolve("ClassLoaderRegistry"); + + private static final URI HOST_CLASSLOADER_ID = URI.create("sca://./hostClassLoader"); + + private static final URI BOOT_CLASSLOADER_ID = URI.create("sca://./bootClassLoader"); + + protected final XMLInputFactory xmlFactory; + protected URL systemScdl; + protected String applicationName; + protected URL applicationScdl; + protected Class<I> runtimeInfoType; + protected ManagementService<?> managementService; + + // primorial components automatically registered with the runtime + /** + * Information provided by the host about its runtime environment. + */ + protected I runtimeInfo; + + /** + * MonitorFactory provided by the host for directing events to its + * management framework. + */ + protected MonitorFactory monitorFactory; + + /** + * The ComponentManager that manages all components in this runtime. + */ + protected ComponentManager componentManager; + + /** + * Registry for ClassLoaders used by this runtime. + */ + protected ClassLoaderRegistry classLoaderRegistry; + + protected AutowireResolver resolver; + + protected Component systemComponent; + protected Component tuscanySystem; + + protected ScopeRegistry scopeRegistry; + protected Collection<ExtensionActivator> activators; + + protected AbstractRuntime(Class<I> runtimeInfoType) { + this(runtimeInfoType, new NullMonitorFactory()); + } + + protected AbstractRuntime(Class<I> runtimeInfoType, MonitorFactory monitorFactory) { + this.runtimeInfoType = runtimeInfoType; + this.monitorFactory = monitorFactory; + xmlFactory = XMLInputFactory.newInstance("javax.xml.stream.XMLInputFactory", getClass().getClassLoader()); + classLoaderRegistry = new ClassLoaderRegistryImpl(); + classLoaderRegistry.register(BOOT_CLASSLOADER_ID, getClass().getClassLoader()); + } + + public URL getSystemScdl() { + return systemScdl; + } + + public void setSystemScdl(URL systemScdl) { + this.systemScdl = systemScdl; + } + + public String getApplicationName() { + return applicationName; + } + + public void setApplicationName(String applicationName) { + this.applicationName = applicationName; + } + + public URL getApplicationScdl() { + return applicationScdl; + } + + public void setApplicationScdl(URL applicationScdl) { + this.applicationScdl = applicationScdl; + } + + public ClassLoader getHostClassLoader() { + return classLoaderRegistry.getClassLoader(HOST_CLASSLOADER_ID); + } + + public void setHostClassLoader(ClassLoader hostClassLoader) { + classLoaderRegistry.register(HOST_CLASSLOADER_ID, hostClassLoader); + } + + public I getRuntimeInfo() { + return runtimeInfo; + } + + public void setRuntimeInfo(I runtimeInfo) { + this.runtimeInfo = runtimeInfo; + } + + public MonitorFactory getMonitorFactory() { + return monitorFactory; + } + + public void setMonitorFactory(MonitorFactory monitorFactory) { + this.monitorFactory = monitorFactory; + } + + public ManagementService<?> getManagementService() { + return managementService; + } + + public void setManagementService(ManagementService<?> managementService) { + this.managementService = managementService; + } + + public void initialize() throws InitializationException { + // URI name = TUSCANY_SYSTEM_ROOT.resolve("main"); + Bootstrapper bootstrapper = createBootstrapper(); + Deployer deployer = bootstrapper.createDeployer(); + registerSystemComponent(TUSCANY_DEPLOYER, Deployer.class, deployer); + registerSystemComponent(WORK_CONTEXT_URI, WorkContext.class, new SimpleWorkContext()); + + this.scopeRegistry = bootstrapper.getScopeRegistry(); + + LoaderRegistry loaderRegistry = (LoaderRegistry)((DeployerImpl)deployer).getLoader(); + BuilderRegistry builderRegistry = (BuilderRegistry)((DeployerImpl)deployer).getBuilder(); + activators = getInstances(getHostClassLoader(), ExtensionActivator.class); + for (ExtensionActivator activator : activators) { + activator.start(loaderRegistry, builderRegistry); + } + + registerBaselineSystemComponents(); + } + + public void destroy() { + if (tuscanySystem != null) { + tuscanySystem.stop(); + tuscanySystem = null; + } + if (systemComponent != null) { + systemComponent.stop(); + systemComponent = null; + } + } + + public ComponentContext getComponentContext(URI componentId) { + Component component = componentManager.getComponent(componentId); + if (component == null) { + return null; + } + return component.getComponentContext(); + } + + protected Bootstrapper createBootstrapper() { + TuscanyManagementService tms = (TuscanyManagementService)getManagementService(); + resolver = new DefaultAutowireResolver(); + componentManager = new ComponentManagerImpl(tms, resolver); + Connector connector = new ConnectorImpl(componentManager); + return new DefaultBootstrapper(getMonitorFactory(), xmlFactory, componentManager, resolver, connector); + } + + protected void registerBaselineSystemComponents() throws InitializationException { + // register the RuntimeInfo provided by the host + registerSystemComponent(RUNTIME_INFO_URI, runtimeInfoType, runtimeInfo); + + // register the MonitorFactory provided by the host + List<Class<?>> monitorServices = new ArrayList<Class<?>>(); + monitorServices.add(MonitorFactory.class); + monitorServices.add(FormatterRegistry.class); + registerSystemComponent(MONITOR_URI, monitorServices, getMonitorFactory()); + + // register the ClassLoaderRegistry + registerSystemComponent(CLASSLOADER_REGISTRY_URI, ClassLoaderRegistry.class, classLoaderRegistry); + + // register the ComponentManager to that the fabric can wire to it + registerSystemComponent(COMPONENT_MGR_URI, ComponentManager.class, componentManager); + + // register the AutowireResolver + registerSystemComponent(AUTOWIRE_RESOLVER_URI, AutowireResolver.class, resolver); + + // register the ScopeRegistry + registerSystemComponent(SCOPE_REGISTRY_URI, ScopeRegistry.class, scopeRegistry); + } + + protected <S, I extends S> void registerSystemComponent(URI uri, Class<S> type, I component) + throws InitializationException { + try { + JavaServiceContract<S> contract = new JavaServiceContract<S>(type); + componentManager.registerJavaObject(uri, contract, component); + } catch (RegistrationException e) { + throw new InitializationException(e); + } + } + + protected <I> void registerSystemComponent(URI uri, List<Class<?>> types, I component) + throws InitializationException { + try { + List<JavaServiceContract<?>> contracts = new ArrayList<JavaServiceContract<?>>(); + for (Class<?> type : types) { + contracts.add(new JavaServiceContract(type)); + + } + componentManager.registerJavaObject(uri, contracts, component); + } catch (RegistrationException e) { + throw new InitializationException(e); + } + } + + protected ComponentManager getComponentManager() { + return componentManager; + } + + protected ScopeRegistry getScopeRegistry() { + return scopeRegistry; + } + + protected WorkContext getWorkContext() { + try { + AtomicComponent component = (AtomicComponent)getComponentManager().getComponent(WORK_CONTEXT_URI); + return (WorkContext)component.getTargetInstance(); + } catch (TargetResolutionException e) { + throw new AssertionError(e); + } + } + + protected Deployer getDeployer() { + try { + AtomicComponent component = (AtomicComponent)getComponentManager().getComponent(TUSCANY_DEPLOYER); + return (Deployer)component.getTargetInstance(); + } catch (TargetResolutionException e) { + throw new AssertionError(e); + } + } + + /** + * Read the service name from a configuration file + * + * @param classLoader + * @param name The name of the service class + * @return A class name which extends/implements the service class + * @throws IOException + */ + private static Set<String> getServiceNames(ClassLoader classLoader, String name) throws IOException { + Set<String> set = new HashSet<String>(); + Enumeration<URL> urls = classLoader.getResources("META-INF/services/" + name); + while (urls.hasMoreElements()) { + URL url = urls.nextElement(); + String service = getServiceName(url); + if (service != null) { + set.add(service); + + } + } + return set; + } + + private static String getServiceName(URL url) throws IOException { + InputStream is = IOHelper.getInputStream(url); + BufferedReader reader = null; + try { + reader = new BufferedReader(new InputStreamReader(is)); + while (true) { + String line = reader.readLine(); + if (line == null) { + break; + } else if (!line.startsWith("#")) { + return line.trim(); + } + } + } finally { + if (reader != null) { + reader.close(); + } + } + return null; + } + + private static <T> Collection<T> getInstances(final ClassLoader classLoader, Class<T> serviceClass) { + List<T> instances = new ArrayList<T>(); + try { + Set<String> services = getServiceNames(classLoader, serviceClass.getName()); + for (String className : services) { + Class cls = Class.forName(className, true, classLoader); + instances.add(serviceClass.cast(cls.newInstance())); // NOPMD + } + } catch (Exception e) { + throw new IllegalStateException(e); + } + return instances; + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/services/classloading/ClassLoaderRegistryImpl.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/services/classloading/ClassLoaderRegistryImpl.java new file mode 100644 index 0000000000..afa7f64246 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/services/classloading/ClassLoaderRegistryImpl.java @@ -0,0 +1,50 @@ +/* + * 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.core.services.classloading; + +import java.net.URI; +import java.util.concurrent.ConcurrentHashMap; +import java.util.Map; + +import org.apache.tuscany.spi.services.classloading.ClassLoaderRegistry; +import org.apache.tuscany.spi.services.classloading.DuplicateClassLoaderException; + +/** + * Implementation of a registry for classloaders. + * + * @version $Rev$ $Date$ + */ +public class ClassLoaderRegistryImpl implements ClassLoaderRegistry { + private final Map<URI, ClassLoader> registry = new ConcurrentHashMap<URI, ClassLoader>(); + + public synchronized void register(URI id, ClassLoader classLoader) throws DuplicateClassLoaderException { + if (registry.containsKey(id)) { + throw new DuplicateClassLoaderException("Duplicate class loader", id.toString()); + } + registry.put(id, classLoader); + } + + public ClassLoader getClassLoader(URI id) { + return registry.get(id); + } + + public ClassLoader unregister(URI id) { + return registry.remove(id); + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/services/store/memory/MemoryStore.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/services/store/memory/MemoryStore.java new file mode 100644 index 0000000000..a48cd5a2d7 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/services/store/memory/MemoryStore.java @@ -0,0 +1,198 @@ +/* + * 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.core.services.store.memory; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import org.osoa.sca.annotations.Destroy; +import org.osoa.sca.annotations.EagerInit; +import org.osoa.sca.annotations.Init; +import org.osoa.sca.annotations.Property; +import org.osoa.sca.annotations.Service; + +import org.apache.tuscany.spi.component.SCAObject; +import org.apache.tuscany.spi.event.AbstractEventPublisher; +import org.apache.tuscany.spi.services.store.DuplicateRecordException; +import org.apache.tuscany.spi.services.store.RecoveryListener; +import org.apache.tuscany.spi.services.store.Store; +import org.apache.tuscany.spi.services.store.StoreExpirationEvent; +import org.apache.tuscany.spi.services.store.StoreMonitor; +import org.apache.tuscany.spi.services.store.StoreWriteException; + +import org.apache.tuscany.api.annotation.Monitor; + +/** + * Implements a non-durable, non-transactional store using a simple in-memory map + * + * @version $Rev$ $Date$ + */ +@Service(Store.class) +@EagerInit +public class MemoryStore extends AbstractEventPublisher implements Store { + private Map<SCAObject, Map<String, Record>> store; + // TODO integrate with a core threading scheme + private ScheduledExecutorService scheduler; + private long reaperInterval = 300000; + private StoreMonitor monitor; + private long defaultExpirationOffset = 600000; // 10 minutes + + public MemoryStore(@Monitor StoreMonitor monitor) { + this.monitor = monitor; + this.store = new ConcurrentHashMap<SCAObject, Map<String, Record>>(); + this.scheduler = Executors.newSingleThreadScheduledExecutor(); + } + + /** + * Returns the maximum default expiration offset for records in the store + * + * @return the maximum default expiration offset for records in the store + */ + public long getDefaultExpirationOffset() { + return defaultExpirationOffset; + } + + /** + * Sets the maximum default expiration offset for records in the store + */ + @Property + public void setDefaultExpirationOffset(long defaultExpirationOffset) { + this.defaultExpirationOffset = defaultExpirationOffset; + } + + /** + * Sets the interval for expired entry scanning to be performed + */ + @Property + public void setReaperInterval(long reaperInterval) { + this.reaperInterval = reaperInterval; + } + + public long getReaperInterval() { + return reaperInterval; + } + + @Init + public void init() { + scheduler.scheduleWithFixedDelay(new Reaper(), reaperInterval, reaperInterval, TimeUnit.MILLISECONDS); + monitor.start("In-memory store started"); + } + + @Destroy + public void destroy() { + scheduler.shutdown(); + monitor.stop("In-memory store stopped"); + } + + public void insertRecord(SCAObject owner, String id, Object object, long expiration) throws StoreWriteException { + Map<String, Record> map = store.get(owner); + if (map == null) { + map = new ConcurrentHashMap<String, Record>(); + store.put(owner, map); + } + if (map.containsKey(id)) { + throw new DuplicateRecordException(owner.getUri().toString(), id); + } + map.put(id, new Record(object, expiration)); + } + + public void updateRecord(SCAObject owner, String id, Object object, long expiration) throws StoreWriteException { + Map<String, Record> map = store.get(owner); + if (map == null) { + throw new StoreWriteException("Record not found", owner.getUri().toString(), id); + } + Record record = map.get(id); + if (record == null) { + throw new StoreWriteException("Record not found", owner.getUri().toString(), id); + } + record.data = object; + } + + public Object readRecord(SCAObject owner, String id) { + Map<String, Record> map = store.get(owner); + if (map == null) { + return null; + } + Record record = map.get(id); + if (record != null) { + return record.data; + } + return null; + } + + public void removeRecords() { + store.clear(); + } + + public void removeRecord(SCAObject owner, String id) throws StoreWriteException { + Map<String, Record> map = store.get(owner); + if (map == null) { + throw new StoreWriteException("Owner not found", owner.getUri().toString(), id); + } + if (map.remove(id) == null) { + throw new StoreWriteException("Owner not found", owner.getUri().toString(), id); + } + } + + public void recover(RecoveryListener listener) { + throw new UnsupportedOperationException(); + } + + private class Record { + private Object data; + private long expiration = NEVER; + + public Record(Object data, long expiration) { + this.data = data; + this.expiration = expiration; + } + + public Object getData() { + return data; + } + + public long getExpiration() { + return expiration; + } + } + + private class Reaper implements Runnable { + + public void run() { + long now = System.currentTimeMillis(); + for (Map.Entry<SCAObject, Map<String, Record>> entries : store.entrySet()) { + for (Map.Entry<String, Record> entry : entries.getValue().entrySet()) { + final long expiration = entry.getValue().expiration; + if (expiration != NEVER && now >= expiration) { + SCAObject owner = entries.getKey(); + Object instance = entry.getValue().getData(); + // notify listeners of the expiration + StoreExpirationEvent event = new StoreExpirationEvent(this, owner, instance); + publish(event); + entries.getValue().remove(entry.getKey()); + } + } + } + } + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/util/FileHelper.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/util/FileHelper.java new file mode 100644 index 0000000000..2544c90846 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/util/FileHelper.java @@ -0,0 +1,704 @@ +/*
+ * 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.core.util;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.util.regex.Pattern;
+
+public class FileHelper {
+ /**
+ * The extension separator character.
+ */
+ private static final char EXTENSION_SEPARATOR = '.';
+
+ /**
+ * The Unix separator character.
+ */
+ private static final char UNIX_SEPARATOR = '/';
+
+ /**
+ * The Windows separator character.
+ */
+ private static final char WINDOWS_SEPARATOR = '\\';
+
+ protected FileHelper() {
+ }
+
+ /**
+ * Returns the index of the last directory separator character.
+ * <p>
+ * This method will handle a file in either Unix or Windows format. The
+ * position of the last forward or backslash is returned.
+ * <p>
+ * The output will be the same irrespective of the machine that the code is
+ * running on.
+ *
+ * @param filename the filename to find the last path separator in, null
+ * returns -1
+ * @return the index of the last separator character, or -1 if there is no
+ * such character
+ */
+ public static int indexOfLastSeparator(String filename) {
+ if (filename == null) {
+ return -1;
+ }
+ int lastUnixPos = filename.lastIndexOf(UNIX_SEPARATOR);
+ int lastWindowsPos = filename.lastIndexOf(WINDOWS_SEPARATOR);
+ return Math.max(lastUnixPos, lastWindowsPos);
+ }
+
+ /**
+ * Returns the index of the last extension separator character, which is a
+ * dot.
+ * <p>
+ * This method also checks that there is no directory separator after the
+ * last dot. To do this it uses {@link #indexOfLastSeparator(String)} which
+ * will handle a file in either Unix or Windows format.
+ * <p>
+ * The output will be the same irrespective of the machine that the code is
+ * running on.
+ *
+ * @param filename the filename to find the last path separator in, null
+ * returns -1
+ * @return the index of the last separator character, or -1 if there is no
+ * such character
+ */
+ public static int indexOfExtension(String filename) {
+ if (filename == null) {
+ return -1;
+ }
+ int extensionPos = filename.lastIndexOf(EXTENSION_SEPARATOR);
+ int lastSeparator = indexOfLastSeparator(filename);
+ return lastSeparator > extensionPos ? -1 : extensionPos;
+ }
+
+ /**
+ * Gets the name minus the path from a full filename.
+ * <p>
+ * This method will handle a file in either Unix or Windows format. The text
+ * after the last forward or backslash is returned.
+ *
+ * <pre>
+ * a/b/c.txt --> c.txt
+ * a.txt --> a.txt
+ * a/b/c --> c
+ * a/b/c/ --> ""
+ * </pre>
+ *
+ * <p>
+ * The output will be the same irrespective of the machine that the code is
+ * running on.
+ *
+ * @param fileName the filename to query, null returns null
+ * @return the name of the file without the path, or an empty string if none
+ * exists
+ */
+ public static String getName(String fileName) {
+ if (fileName == null) {
+ return null;
+ }
+ int index = indexOfLastSeparator(fileName);
+ return fileName.substring(index + 1);
+ }
+
+ /**
+ * Gets the extension of a filename.
+ * <p>
+ * This method returns the textual part of the filename after the last dot.
+ * There must be no directory separator after the dot.
+ *
+ * <pre>
+ * foo.txt --> "txt"
+ * a/b/c.jpg --> "jpg"
+ * a/b.txt/c --> ""
+ * a/b/c --> ""
+ * </pre>
+ *
+ * <p>
+ * The output will be the same irrespective of the machine that the code is
+ * running on.
+ *
+ * @param filename the filename to retrieve the extension of.
+ * @return the extension of the file or an empty string if none exists.
+ */
+ public static String getExtension(String filename) {
+ if (filename == null) {
+ return null;
+ }
+ int index = indexOfExtension(filename);
+ if (index == -1) {
+ return "";
+ } else {
+ return filename.substring(index + 1);
+ }
+ }
+
+ /**
+ * Make a directory, including any necessary but nonexistent parent
+ * directories. If there already exists a file with specified name or the
+ * directory cannot be created then an exception is thrown.
+ *
+ * @param directory directory to create, not null
+ * @throws NullPointerException if the directory is null
+ * @throws IOException if the directory cannot be created
+ */
+ public static void forceMkdir(File directory) throws IOException {
+ if (directory.exists()) {
+ if (directory.isFile()) {
+ String message =
+ "File " + directory + " exists and is " + "not a directory. Unable to create directory.";
+ throw new IOException(message);
+ }
+ } else {
+ if (!directory.mkdirs()) {
+ String message = "Unable to create directory " + directory;
+ throw new IOException(message);
+ }
+ }
+ }
+
+ /**
+ * Delete a file. If file is a directory, delete it and all sub-directories.
+ * <p>
+ * The difference between File.delete() and this method are:
+ * <ul>
+ * <li>A directory to be deleted does not have to be empty.</li>
+ * <li>You get exceptions when a file or directory cannot be deleted.
+ * (java.io.File methods returns a boolean)</li>
+ * </ul>
+ *
+ * @param file file or directory to delete, not null
+ * @throws NullPointerException if the directory is null
+ * @throws IOException in case deletion is unsuccessful
+ */
+ public static void forceDelete(File file) throws IOException {
+ if (file.isDirectory()) {
+ deleteDirectory(file);
+ } else {
+ if (!file.exists()) {
+ throw new FileNotFoundException("File does not exist: " + file);
+ }
+ if (!file.delete()) {
+ String message = "Unable to delete file: " + file;
+ throw new IOException(message);
+ }
+ }
+ }
+
+ /**
+ * Convert from a <code>URL</code> to a <code>File</code>.
+ * <p>
+ * From version 1.1 this method will decode the URL. Syntax such as
+ * <code>file:///my%20docs/file.txt</code> will be correctly decoded to
+ * <code>/my docs/file.txt</code>.
+ *
+ * @param url the file URL to convert, null returns null
+ * @return the equivalent <code>File</code> object, or <code>null</code>
+ * if the URL's protocol is not <code>file</code>
+ * @throws IllegalArgumentException if the file is incorrectly encoded
+ */
+ public static File toFile(URL url) {
+ if (url == null || !url.getProtocol().equals("file")) {
+ return null;
+ } else {
+ String filename = url.getFile().replace('/', File.separatorChar);
+ int pos = 0;
+ while ((pos = filename.indexOf('%', pos)) >= 0) { // NOPMD
+ if (pos + 2 < filename.length()) {
+ String hexStr = filename.substring(pos + 1, pos + 3);
+ char ch = (char)Integer.parseInt(hexStr, 16);
+ filename = filename.substring(0, pos) + ch + filename.substring(pos + 3);
+ }
+ }
+ return new File(filename);
+ }
+ }
+
+ public static FileFilter getFileFilter(String regExp, boolean ignoreCase) {
+ return new RegExpFilter(regExp, ignoreCase);
+ }
+
+ /**
+ * A regular-expression based resource filter
+ */
+ public static class RegExpFilter implements FileFilter {
+ private Pattern pattern;
+
+ public RegExpFilter(Pattern pattern) {
+ this.pattern = pattern;
+ }
+
+ public RegExpFilter(String patternStr, boolean ignoreCase) {
+ this.pattern = Pattern.compile(patternStr, ignoreCase ? Pattern.CASE_INSENSITIVE : 0);
+ }
+
+ public boolean accept(File file) {
+ return pattern.matcher(file.getName()).matches();
+ }
+
+ /**
+ * Convert wildcard into a regex pattern
+ *
+ * @param str
+ * @return
+ */
+ public static RegExpFilter getWildcardFilter(String str, boolean ignoreCase) {
+ StringBuffer buffer = new StringBuffer();
+ for (int i = 0; i < str.length(); i++) {
+ char ch = str.charAt(i);
+ if (ch == '?') {
+ buffer.append('.');
+ } else if (ch == '*') {
+ buffer.append(".*");
+ } else {
+ buffer.append(ch);
+ }
+ }
+ return new RegExpFilter(buffer.toString(), ignoreCase);
+ }
+
+ }
+
+ /**
+ * Clean a directory without deleting it.
+ *
+ * @param directory directory to clean
+ * @throws IOException in case cleaning is unsuccessful
+ */
+ public static void cleanDirectory(File directory) throws IOException {
+ if (!directory.exists()) {
+ String message = directory + " does not exist";
+ throw new IllegalArgumentException(message);
+ }
+
+ if (!directory.isDirectory()) {
+ String message = directory + " is not a directory";
+ throw new IllegalArgumentException(message);
+ }
+
+ File[] files = directory.listFiles();
+ if (files == null) { // null if security restricted
+ throw new IOException("Failed to list contents of " + directory);
+ }
+
+ IOException exception = null;
+ for (int i = 0; i < files.length; i++) {
+ File file = files[i];
+ try {
+ forceDelete(file);
+ } catch (IOException ioe) {
+ exception = ioe;
+ }
+ }
+
+ if (null != exception) {
+ throw exception;
+ }
+ }
+
+ /**
+ * Clean a directory without deleting it.
+ *
+ * @param directory directory to clean, must not be <code>null</code>
+ * @throws NullPointerException if the directory is <code>null</code>
+ * @throws IOException in case cleaning is unsuccessful
+ */
+ private static void cleanDirectoryOnExit(File directory) throws IOException {
+ if (!directory.exists()) {
+ String message = directory + " does not exist";
+ throw new IllegalArgumentException(message);
+ }
+
+ if (!directory.isDirectory()) {
+ String message = directory + " is not a directory";
+ throw new IllegalArgumentException(message);
+ }
+
+ File[] files = directory.listFiles();
+ if (files == null) { // null if security restricted
+ throw new IOException("Failed to list contents of " + directory);
+ }
+
+ IOException exception = null;
+ for (int i = 0; i < files.length; i++) {
+ File file = files[i];
+ try {
+ forceDeleteOnExit(file);
+ } catch (IOException ioe) {
+ exception = ioe;
+ }
+ }
+
+ if (null != exception) {
+ throw exception;
+ }
+ }
+
+ /**
+ * Copies a whole directory to a new location preserving the file dates.
+ * <p>
+ * This method copies the specified directory and all its child directories
+ * and files to the specified destination. The destination is the new
+ * location and name of the directory.
+ * <p>
+ * The destination directory is created if it does not exist. If the
+ * destination directory did exist, then this method merges the source with
+ * the destination, with the source taking precedence.
+ *
+ * @param srcDir an existing directory to copy, must not be
+ * <code>null</code>
+ * @param destDir the new directory, must not be <code>null</code>
+ * @throws NullPointerException if source or destination is
+ * <code>null</code>
+ * @throws IOException if source or destination is invalid
+ * @throws IOException if an IO error occurs during copying
+ * @since Commons IO 1.1
+ */
+ public static void copyDirectory(File srcDir, File destDir) throws IOException {
+ copyDirectory(srcDir, destDir, true);
+ }
+
+ /**
+ * Copies a whole directory to a new location.
+ * <p>
+ * This method copies the contents of the specified source directory to
+ * within the specified destination directory.
+ * <p>
+ * The destination directory is created if it does not exist. If the
+ * destination directory did exist, then this method merges the source with
+ * the destination, with the source taking precedence.
+ *
+ * @param srcDir an existing directory to copy, must not be
+ * <code>null</code>
+ * @param destDir the new directory, must not be <code>null</code>
+ * @param preserveFileDate true if the file date of the copy should be the
+ * same as the original
+ * @throws NullPointerException if source or destination is
+ * <code>null</code>
+ * @throws IOException if source or destination is invalid
+ * @throws IOException if an IO error occurs during copying
+ * @since Commons IO 1.1
+ */
+ public static void copyDirectory(File srcDir, File destDir, boolean preserveFileDate) throws IOException {
+ if (srcDir == null) {
+ throw new NullPointerException("Source must not be null");
+ }
+ if (destDir == null) {
+ throw new NullPointerException("Destination must not be null");
+ }
+ if (!srcDir.exists()) {
+ throw new FileNotFoundException("Source '" + srcDir + "' does not exist");
+ }
+ if (!srcDir.isDirectory()) {
+ throw new IOException("Source '" + srcDir + "' exists but is not a directory");
+ }
+ if (srcDir.getCanonicalPath().equals(destDir.getCanonicalPath())) {
+ throw new IOException("Source '" + srcDir + "' and destination '" + destDir + "' are the same");
+ }
+ doCopyDirectory(srcDir, destDir, preserveFileDate);
+ }
+
+ // -----------------------------------------------------------------------
+ /**
+ * Copies a directory to within another directory preserving the file dates.
+ * <p>
+ * This method copies the source directory and all its contents to a
+ * directory of the same name in the specified destination directory.
+ * <p>
+ * The destination directory is created if it does not exist. If the
+ * destination directory did exist, then this method merges the source with
+ * the destination, with the source taking precedence.
+ *
+ * @param srcDir an existing directory to copy, must not be
+ * <code>null</code>
+ * @param destDir the directory to place the copy in, must not be
+ * <code>null</code>
+ * @throws NullPointerException if source or destination is
+ * <code>null</code>
+ * @throws IOException if source or destination is invalid
+ * @throws IOException if an IO error occurs during copying
+ * @since Commons IO 1.2
+ */
+ public static void copyDirectoryToDirectory(File srcDir, File destDir) throws IOException {
+ if (srcDir == null) {
+ throw new NullPointerException("Source must not be null");
+ }
+ if (!(srcDir.exists() && srcDir.isDirectory())) {
+ throw new IllegalArgumentException("Source '" + destDir + "' is not a directory");
+ }
+ if (destDir == null) {
+ throw new NullPointerException("Destination must not be null");
+ }
+ if (!(destDir.exists() && destDir.isDirectory())) {
+ throw new IllegalArgumentException("Destination '" + destDir + "' is not a directory");
+ }
+ copyDirectory(srcDir, new File(destDir, srcDir.getName()), true);
+ }
+
+ /**
+ * Copies a file to a new location preserving the file date.
+ * <p>
+ * This method copies the contents of the specified source file to the
+ * specified destination file. The directory holding the destination file is
+ * created if it does not exist. If the destination file exists, then this
+ * method will overwrite it.
+ *
+ * @param srcFile an existing file to copy, must not be <code>null</code>
+ * @param destFile the new file, must not be <code>null</code>
+ * @throws NullPointerException if source or destination is
+ * <code>null</code>
+ * @throws IOException if source or destination is invalid
+ * @throws IOException if an IO error occurs during copying
+ * @see #copyFileToDirectory(File, File)
+ */
+ public static void copyFile(File srcFile, File destFile) throws IOException {
+ copyFile(srcFile, destFile, true);
+ }
+
+ /**
+ * Copies a file to a new location.
+ * <p>
+ * This method copies the contents of the specified source file to the
+ * specified destination file. The directory holding the destination file is
+ * created if it does not exist. If the destination file exists, then this
+ * method will overwrite it.
+ *
+ * @param srcFile an existing file to copy, must not be <code>null</code>
+ * @param destFile the new file, must not be <code>null</code>
+ * @param preserveFileDate true if the file date of the copy should be the
+ * same as the original
+ * @throws NullPointerException if source or destination is
+ * <code>null</code>
+ * @throws IOException if source or destination is invalid
+ * @throws IOException if an IO error occurs during copying
+ * @see #copyFileToDirectory(File, File, boolean)
+ */
+ public static void copyFile(File srcFile, File destFile, boolean preserveFileDate) throws IOException {
+ if (srcFile == null) {
+ throw new NullPointerException("Source must not be null");
+ }
+ if (destFile == null) {
+ throw new NullPointerException("Destination must not be null");
+ }
+ if (!srcFile.exists()) {
+ throw new FileNotFoundException("Source '" + srcFile + "' does not exist");
+ }
+ if (srcFile.isDirectory()) {
+ throw new IOException("Source '" + srcFile + "' exists but is a directory");
+ }
+ if (srcFile.getCanonicalPath().equals(destFile.getCanonicalPath())) {
+ throw new IOException("Source '" + srcFile + "' and destination '" + destFile + "' are the same");
+ }
+ if (!(destFile.getParentFile() != null && destFile.getParentFile().exists())) {
+ if (!destFile.getParentFile().mkdirs()) {
+ throw new IOException("Destination '" + destFile + "' directory cannot be created");
+ }
+ }
+ if (!(destFile.exists() && destFile.canWrite())) {
+ throw new IOException("Destination '" + destFile + "' exists but is read-only");
+ }
+ doCopyFile(srcFile, destFile, preserveFileDate);
+ }
+
+ // -----------------------------------------------------------------------
+ /**
+ * Copies a file to a directory preserving the file date.
+ * <p>
+ * This method copies the contents of the specified source file to a file of
+ * the same name in the specified destination directory. The destination
+ * directory is created if it does not exist. If the destination file
+ * exists, then this method will overwrite it.
+ *
+ * @param srcFile an existing file to copy, must not be <code>null</code>
+ * @param destDir the directory to place the copy in, must not be
+ * <code>null</code>
+ * @throws NullPointerException if source or destination is null
+ * @throws IOException if source or destination is invalid
+ * @throws IOException if an IO error occurs during copying
+ * @see #copyFile(File, File, boolean)
+ */
+ public static void copyFileToDirectory(File srcFile, File destDir) throws IOException {
+ copyFileToDirectory(srcFile, destDir, true);
+ }
+
+ /**
+ * Copies a file to a directory optionally preserving the file date.
+ * <p>
+ * This method copies the contents of the specified source file to a file of
+ * the same name in the specified destination directory. The destination
+ * directory is created if it does not exist. If the destination file
+ * exists, then this method will overwrite it.
+ *
+ * @param srcFile an existing file to copy, must not be <code>null</code>
+ * @param destDir the directory to place the copy in, must not be
+ * <code>null</code>
+ * @param preserveFileDate true if the file date of the copy should be the
+ * same as the original
+ * @throws NullPointerException if source or destination is
+ * <code>null</code>
+ * @throws IOException if source or destination is invalid
+ * @throws IOException if an IO error occurs during copying
+ * @see #copyFile(File, File, boolean)
+ * @since Commons IO 1.3
+ */
+ public static void copyFileToDirectory(File srcFile, File destDir, boolean preserveFileDate) throws IOException {
+ if (destDir == null) {
+ throw new NullPointerException("Destination must not be null");
+ }
+ if (!(destDir.exists() && destDir.isDirectory())) {
+ throw new IllegalArgumentException("Destination '" + destDir + "' is not a directory");
+ }
+ copyFile(srcFile, new File(destDir, srcFile.getName()), preserveFileDate);
+ }
+
+ // -----------------------------------------------------------------------
+ /**
+ * Recursively delete a directory.
+ *
+ * @param directory directory to delete
+ * @throws IOException in case deletion is unsuccessful
+ */
+ public static void deleteDirectory(File directory) throws IOException {
+ if (!directory.exists()) {
+ return;
+ }
+
+ cleanDirectory(directory);
+ if (!directory.delete()) {
+ String message = "Unable to delete directory " + directory + ".";
+ throw new IOException(message);
+ }
+ }
+
+ /**
+ * Recursively schedule directory for deletion on JVM exit.
+ *
+ * @param directory directory to delete, must not be <code>null</code>
+ * @throws NullPointerException if the directory is <code>null</code>
+ * @throws IOException in case deletion is unsuccessful
+ */
+ private static void deleteDirectoryOnExit(File directory) throws IOException {
+ if (!directory.exists()) {
+ return;
+ }
+
+ cleanDirectoryOnExit(directory);
+ directory.deleteOnExit();
+ }
+
+ /**
+ * Internal copy directory method.
+ *
+ * @param srcDir the validated source directory, must not be
+ * <code>null</code>
+ * @param destDir the validated destination directory, must not be
+ * <code>null</code>
+ * @param preserveFileDate whether to preserve the file date
+ * @throws IOException if an error occurs
+ * @since Commons IO 1.1
+ */
+ private static void doCopyDirectory(File srcDir, File destDir, boolean preserveFileDate) throws IOException {
+ if (destDir.exists()) {
+ if (!destDir.isDirectory()) {
+ throw new IOException("Destination '" + destDir + "' exists but is not a directory");
+ }
+ } else {
+ if (!destDir.mkdirs()) {
+ throw new IOException("Destination '" + destDir + "' directory cannot be created");
+ }
+ if (preserveFileDate) {
+ destDir.setLastModified(srcDir.lastModified());
+ }
+ }
+ if (!destDir.canWrite()) {
+ throw new IOException("Destination '" + destDir + "' cannot be written to");
+ }
+ // recurse
+ File[] files = srcDir.listFiles();
+ if (files == null) { // null if security restricted
+ throw new IOException("Failed to list contents of " + srcDir);
+ }
+ for (int i = 0; i < files.length; i++) {
+ File copiedFile = new File(destDir, files[i].getName());
+ if (files[i].isDirectory()) {
+ doCopyDirectory(files[i], copiedFile, preserveFileDate);
+ } else {
+ doCopyFile(files[i], copiedFile, preserveFileDate);
+ }
+ }
+ }
+
+ /**
+ * Internal copy file method.
+ *
+ * @param srcFile the validated source file, must not be <code>null</code>
+ * @param destFile the validated destination file, must not be
+ * <code>null</code>
+ * @param preserveFileDate whether to preserve the file date
+ * @throws IOException if an error occurs
+ */
+ private static void doCopyFile(File srcFile, File destFile, boolean preserveFileDate) throws IOException {
+ if (destFile.exists() && destFile.isDirectory()) {
+ throw new IOException("Destination '" + destFile + "' exists but is a directory");
+ }
+
+ FileInputStream input = new FileInputStream(srcFile);
+ try {
+ FileOutputStream output = new FileOutputStream(destFile);
+ try {
+ IOHelper.copy(input, output);
+ } finally {
+ IOHelper.closeQuietly(output);
+ }
+ } finally {
+ IOHelper.closeQuietly(input);
+ }
+
+ if (srcFile.length() != destFile.length()) {
+ throw new IOException("Failed to copy full contents from '" + srcFile + "' to '" + destFile + "'");
+ }
+ if (preserveFileDate) {
+ destFile.setLastModified(srcFile.lastModified());
+ }
+ }
+
+ /**
+ * Schedule a file to be deleted when JVM exits. If file is directory delete
+ * it and all sub-directories.
+ *
+ * @param file file or directory to delete, must not be <code>null</code>
+ * @throws NullPointerException if the file is <code>null</code>
+ * @throws IOException in case deletion is unsuccessful
+ */
+ public static void forceDeleteOnExit(File file) throws IOException {
+ if (file.isDirectory()) {
+ deleteDirectoryOnExit(file);
+ } else {
+ file.deleteOnExit();
+ }
+ }
+
+}
diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/util/IOHelper.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/util/IOHelper.java new file mode 100644 index 0000000000..62a007bd05 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/util/IOHelper.java @@ -0,0 +1,182 @@ +/*
+ * 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.core.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.JarURLConnection;
+import java.net.URL;
+import java.util.jar.JarFile;
+
+public class IOHelper {
+ /**
+ * The default buffer size to use.
+ */
+ private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
+
+ protected IOHelper() {
+
+ }
+
+ /**
+ * Unconditionally close an <code>InputStream</code>.
+ * <p>
+ * Equivalent to {@link InputStream#close()}, except any exceptions will be ignored.
+ * This is typically used in finally blocks.
+ *
+ * @param input the InputStream to close, may be null or already closed
+ */
+ public static void closeQuietly(InputStream input) {
+ try {
+ if (input != null) {
+ input.close();
+ }
+ } catch (IOException ioe) {
+ // ignore
+ }
+ }
+
+ /**
+ * Unconditionally close an <code>OutputStream</code>.
+ * <p>
+ * Equivalent to {@link OutputStream#close()}, except any exceptions will be ignored.
+ * This is typically used in finally blocks.
+ *
+ * @param output the OutputStream to close, may be null or already closed
+ */
+ public static void closeQuietly(OutputStream output) {
+ try {
+ if (output != null) {
+ output.close();
+ }
+ } catch (IOException ioe) {
+ // ignore
+ }
+ }
+
+ /**
+ * Copy bytes from an <code>InputStream</code> to an
+ * <code>OutputStream</code>.
+ * <p>
+ * This method buffers the input internally, so there is no need to use a
+ * <code>BufferedInputStream</code>.
+ *
+ * @param input the <code>InputStream</code> to read from
+ * @param output the <code>OutputStream</code> to write to
+ * @return the number of bytes copied
+ * @throws NullPointerException if the input or output is null
+ * @throws IOException if an I/O error occurs
+ * @since Commons IO 1.1
+ */
+ public static int copy(InputStream input, OutputStream output) throws IOException {
+ byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
+ int count = 0;
+ int n = 0;
+ while (-1 != (n = input.read(buffer))) { // NOPMD
+ output.write(buffer, 0, n);
+ count += n;
+ }
+ return count;
+ }
+
+ public static InputStream getInputStream(URL url) throws IOException {
+ return new SafeURLInputStream(url);
+ }
+
+ /**
+ * This class is a workaround for URL stream issue as illustrated below.
+ * InputStream is=url.getInputStream(); is.close(); // This line doesn't close
+ * the JAR file if the URL is a jar entry like "jar:file:/a.jar!/my.composite" We
+ * also need to turn off the JarFile cache.
+ *
+ * @see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4950148
+ *
+ * @version $Rev$ $Date$
+ */
+ public static class SafeURLInputStream extends InputStream {
+ private JarFile jarFile;
+ private InputStream is;
+
+ public SafeURLInputStream(URL url) throws IOException {
+ String protocol = url.getProtocol();
+ if (protocol != null && (protocol.equals("jar"))) {
+ JarURLConnection connection = (JarURLConnection)url.openConnection();
+ // We cannot use cache
+ connection.setUseCaches(false);
+ try {
+ is = connection.getInputStream();
+ } catch (IOException e) {
+ throw e;
+ }
+ jarFile = connection.getJarFile();
+ } else {
+ is = url.openStream();
+ }
+ }
+
+ public SafeURLInputStream(JarURLConnection connection) throws IOException {
+ // We cannot use cache
+ connection.setUseCaches(false);
+ is = connection.getInputStream();
+ jarFile = connection.getJarFile();
+ }
+
+ public int available() throws IOException {
+ return is.available();
+ }
+
+ public void close() throws IOException {
+ is.close();
+ // We need to close the JAR file
+ if (jarFile != null) {
+ jarFile.close();
+ }
+ }
+
+ public synchronized void mark(int readlimit) {
+ is.mark(readlimit);
+ }
+
+ public boolean markSupported() {
+ return is.markSupported();
+ }
+
+ public int read() throws IOException {
+ return is.read();
+ }
+
+ public int read(byte[] b, int off, int len) throws IOException {
+ return is.read(b, off, len);
+ }
+
+ public int read(byte[] b) throws IOException {
+ return is.read(b);
+ }
+
+ public synchronized void reset() throws IOException {
+ is.reset();
+ }
+
+ public long skip(long n) throws IOException {
+ return is.skip(n);
+ }
+ }
+}
\ No newline at end of file diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/util/JavaIntrospectionHelper.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/util/JavaIntrospectionHelper.java new file mode 100644 index 0000000000..6b11725481 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/util/JavaIntrospectionHelper.java @@ -0,0 +1,439 @@ +/* + * 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.core.util; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Implements various reflection-related operations + * + * @version $Rev$ $Date$ + */ +public final class JavaIntrospectionHelper { + + private static final Class[] EMPTY_CLASS_ARRY = new Class[0]; + + /** + * Hide the constructor + */ + private JavaIntrospectionHelper() { + } + + + /** + * Returns a collection of public, and protected fields declared by a class or one of its supertypes + */ + public static Set<Field> getAllPublicAndProtectedFields(Class clazz) { + return getAllPublicAndProtectedFields(clazz, new HashSet<Field>()); + } + + /** + * Recursively evaluates the type hierachy to return all fields that are public or protected + */ + private static Set<Field> getAllPublicAndProtectedFields(Class clazz, Set<Field> fields) { + if (clazz == null || clazz.isArray() || Object.class.equals(clazz)) { + return fields; + } + fields = getAllPublicAndProtectedFields(clazz.getSuperclass(), fields); + Field[] declaredFields = clazz.getDeclaredFields(); + for (Field field : declaredFields) { + int modifiers = field.getModifiers(); + if ((Modifier.isPublic(modifiers) || Modifier.isProtected(modifiers)) && !Modifier.isStatic(modifiers)) { + field.setAccessible(true); // ignore Java accessibility + fields.add(field); + } + } + return fields; + } + + /** + * Returns a collection of public and protected methods declared by a class or one of its supertypes. Note that + * overriden methods will not be returned in the collection (i.e. only the method override will be). <p/> This + * method can potentially be expensive as reflection information is not cached. It is assumed that this method will + * be used during a configuration phase. + */ + public static Set<Method> getAllUniquePublicProtectedMethods(Class clazz) { + return getAllUniqueMethods(clazz, new HashSet<Method>()); + } + + /** + * Recursively evaluates the type hierarchy to return all unique methods + */ + private static Set<Method> getAllUniqueMethods(Class pClass, Set<Method> methods) { + if (pClass == null || pClass.isArray() || Object.class.equals(pClass)) { + return methods; + } + // we first evaluate methods of the subclass and then move to the parent + Method[] declaredMethods = pClass.getDeclaredMethods(); + for (Method declaredMethod : declaredMethods) { + int modifiers = declaredMethod.getModifiers(); + if ((!Modifier.isPublic(modifiers) && !Modifier.isProtected(modifiers)) || Modifier.isStatic(modifiers)) { + continue; + } + if (methods.size() == 0) { + methods.add(declaredMethod); + } else { + List<Method> temp = new ArrayList<Method>(); + boolean matched = false; + for (Method method : methods) { + // only add if not already in the set from a supclass (i.e. the + // method is not overrided) + if (exactMethodMatch(declaredMethod, method)) { + matched = true; + break; + } + } + if (!matched) { + // TODO ignore Java accessibility + declaredMethod.setAccessible(true); + temp.add(declaredMethod); + } + methods.addAll(temp); + temp.clear(); + } + } + // evaluate class hierarchy - this is done last to track inherited methods + methods = getAllUniqueMethods(pClass.getSuperclass(), methods); + return methods; + } + + /** + * Finds the closest matching field with the given name, that is, a field of the exact specified type or, + * alternately, of a supertype. + * + * @param name the name of the field + * @param type the field type + * @param fields the collection of fields to search + * @return the matching field or null if not found + */ + public static Field findClosestMatchingField(String name, Class type, Set<Field> fields) { + Field candidate = null; + for (Field field : fields) { + if (field.getName().equals(name)) { + if (field.getType().equals(type)) { + return field; // exact match + } else if (field.getType().isAssignableFrom(type) + || (field.getType().isPrimitive() && primitiveAssignable(field.getType(), type))) { + // We could have the situation where a field parameter is a primitive and the demarshalled value is + // an object counterpart (e.g. Integer and int) + // @spec issue + // either an interface or super class, so keep a reference until + // we know there are no closer types + candidate = field; + } + } + } + if (candidate != null) { + return candidate; + } else { + return null; + } + } + + /** + * Finds the closest matching method with the given name, that is, a method taking the exact parameter types or, + * alternately, parameter supertypes. + * + * @param name the name of the method + * @param types the method parameter types + * @param methods the collection of methods to search + * @return the matching method or null if not found + */ + public static Method findClosestMatchingMethod(String name, Class[] types, Set<Method> methods) { + if (types == null) { + types = EMPTY_CLASS_ARRY; + } + Method candidate = null; + for (Method method : methods) { + if (method.getName().equals(name) && method.getParameterTypes().length == types.length) { + Class<?>[] params = method.getParameterTypes(); + boolean disqualify = false; + boolean exactMatch = true; + for (int i = 0; i < params.length; i++) { + if (!params[i].equals(types[i]) && !params[i].isAssignableFrom(types[i])) { + // no match + disqualify = true; + exactMatch = false; + break; + } else if (!params[i].equals(types[i]) && params[i].isAssignableFrom(types[i])) { + // not exact match + exactMatch = false; + } + } + if (disqualify) { + continue; + } else if (exactMatch) { + return method; + } else { + candidate = method; + } + } + } + if (candidate != null) { + return candidate; + } else { + return null; + } + } + + /** + * Searches a collection of fields for one that matches by name and has a multiplicity type. i.e. a List or Array of + * interfaces + * + * @return a matching field or null + */ + public static Field findMultiplicityFieldByName(String name, Set<Field> fields) { + for (Field candidate : fields) { + if (candidate.getName().equals(name) + && (List.class.isAssignableFrom(candidate.getType()) || (candidate.getType().isArray() + && candidate.getType().getComponentType() != null && candidate.getType().getComponentType() + .isInterface()))) { + return candidate; + } + } + return null; + } + + /** + * Searches a collection of method for one that matches by name and has single parameter of a multiplicity type. + * i.e. a List or Array of interfaces + * + * @return a matching method or null + */ + public static Method findMultiplicityMethodByName(String name, Set<Method> methods) { + for (Method candidate : methods) { + if (candidate.getName().equals(name) + && candidate.getParameterTypes().length == 1 + && (List.class.isAssignableFrom(candidate.getParameterTypes()[0]) + || (candidate.getParameterTypes()[0].isArray() + && candidate.getParameterTypes()[0].getComponentType() != null + && candidate.getParameterTypes()[0].getComponentType().isInterface()))) { + return candidate; + } + } + return null; + } + + /** + * Determines if two methods "match" - that is, they have the same method names and exact parameter types (one is + * not a supertype of the other) + */ + public static boolean exactMethodMatch(Method method1, Method method2) { + if (!method1.getName().equals(method2.getName())) { + return false; + } + Class[] types1 = method1.getParameterTypes(); + Class[] types2 = method2.getParameterTypes(); + if (types1.length == 0 && types2.length == 0) { + return true; + } else if (types1.length == types2.length) { + for (int n = 0; n < types1.length; n++) { + if (!types1[n].equals(types2[n])) { + return false; + } + } + return true; + } + return false; + } + + public static <T> Constructor<T> getDefaultConstructor(Class<T> clazz) throws NoSuchMethodException { + return clazz.getConstructor((Class[]) null); + } + + /** + * Loads a class corresponding to the class name using the current context class loader. + * + * @throws ClassNotFoundException if the class was not found on the classpath + */ + public static Class loadClass(String pName) throws ClassNotFoundException { + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + return Class.forName(pName, true, loader); + } + + /** + * Returns the simple name of a class - i.e. the class name devoid of its package qualifier + * + * @param implClass the implmentation class + */ + public static String getBaseName(Class<?> implClass) { + String baseName = implClass.getName(); + int lastDot = baseName.lastIndexOf('.'); + if (lastDot != -1) { + baseName = baseName.substring(lastDot + 1); + } + return baseName; + } + + public static boolean isImmutable(Class clazz) { + return String.class == clazz + || clazz.isPrimitive() + || Number.class.isAssignableFrom(clazz) + || Boolean.class.isAssignableFrom(clazz) + || Character.class.isAssignableFrom(clazz) + || Byte.class.isAssignableFrom(clazz); + } + + /** + * Takes a property name and converts it to a getter method name according to JavaBean conventions. For example, + * property <code>foo<code> is returned as <code>getFoo</code> + */ + public static String toGetter(String name) { + return "get" + name.toUpperCase().substring(0, 1) + name.substring(1); + } + + /** + * Takes a setter or getter method name and converts it to a property name according to JavaBean conventions. For + * example, <code>setFoo(var)</code> is returned as property <code>foo<code> + */ + public static String toPropertyName(String name) { + if (!name.startsWith("set")) { + return name; + } + return Character.toLowerCase(name.charAt(3)) + name.substring(4); + } + + /** + * Takes a property name and converts it to a setter method name according to JavaBean conventions. For example, the + * property <code>foo<code> is returned as <code>setFoo(var)</code> + */ + public static String toSetter(String name) { + return "set" + name.toUpperCase().substring(0, 1) + name.substring(1); + } + + /** + * Compares a two types, assuming one is a primitive, to determine if the other is its object counterpart + */ + private static boolean primitiveAssignable(Class memberType, Class param) { + if (memberType == Integer.class) { + return param == Integer.TYPE; + } else if (memberType == Double.class) { + return param == Double.TYPE; + } else if (memberType == Float.class) { + return param == Float.TYPE; + } else if (memberType == Short.class) { + return param == Short.TYPE; + } else if (memberType == Character.class) { + return param == Character.TYPE; + } else if (memberType == Boolean.class) { + return param == Boolean.TYPE; + } else if (memberType == Byte.class) { + return param == Byte.TYPE; + } else if (param == Integer.class) { + return memberType == Integer.TYPE; + } else if (param == Double.class) { + return memberType == Double.TYPE; + } else if (param == Float.class) { + return memberType == Float.TYPE; + } else if (param == Short.class) { + return memberType == Short.TYPE; + } else if (param == Character.class) { + return memberType == Character.TYPE; + } else if (param == Boolean.class) { + return memberType == Boolean.TYPE; + } else if (param == Byte.class) { + return memberType == Byte.TYPE; + } else { + return false; + } + } + + /** + * Returns the generic types represented in the given type. Usage as follows: <code> + * JavaIntrospectionHelper.getGenerics(field.getGenericType()); + * <p/> + * JavaIntrospectionHelper.getGenerics(m.getGenericParameterTypes()[0];); </code> + * + * @return the generic types in order of declaration or an empty array if the type is not genericized + */ + public static List<? extends Type> getGenerics(Type genericType) { + List<Type> classes = new ArrayList<Type>(); + if (genericType instanceof ParameterizedType) { + ParameterizedType ptype = (ParameterizedType) genericType; + // get the type arguments + Type[] targs = ptype.getActualTypeArguments(); + for (Type targ : targs) { + classes.add(targ); + } + } + return classes; + } + + /** + * Returns the generic type specified by the class at the given position as in: + * <p/> + * <code> public class Foo<Bar,Baz>{ //.. } + * <p/> + * JavaIntrospectionHelper.introspectGeneric(Foo.class,1); <code> + * <p/> + * will return Baz. + */ + public static Class introspectGeneric(Class<?> clazz, int pos) { + assert clazz != null : "No class specified"; + Type type = clazz.getGenericSuperclass(); + if (type instanceof ParameterizedType) { + Type[] args = ((ParameterizedType) type).getActualTypeArguments(); + if (args.length <= pos) { + throw new IllegalArgumentException("Invalid index value for generic class " + clazz.getName()); + } + return (Class) ((ParameterizedType) type).getActualTypeArguments()[pos]; + } else { + Type[] interfaces = clazz.getGenericInterfaces(); + for (Type itype : interfaces) { + if (!(itype instanceof ParameterizedType)) { + continue; + } + ParameterizedType interfaceType = (ParameterizedType) itype; + return (Class) interfaceType.getActualTypeArguments()[0]; + } + } + return null; + } + + /** + * Returns the set of interfaces implemented by the given class and its ancestors or a blank set if none + */ + public static Set<Class> getAllInterfaces(Class clazz) { + Set<Class> implemented = new HashSet<Class>(); + getAllInterfaces(clazz, implemented); + return implemented; + } + + private static void getAllInterfaces(Class clazz, Set<Class> implemented) { + Class[] interfaces = clazz.getInterfaces(); + for (Class interfaze : interfaces) { + implemented.add(interfaze); + } + Class<?> superClass = clazz.getSuperclass(); + // Object has no superclass so check for null + if (superClass != null && !superClass.equals(Object.class)) { + getAllInterfaces(superClass, implemented); + } + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/CallbackInterfaceInterceptor.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/CallbackInterfaceInterceptor.java new file mode 100644 index 0000000000..c0bf7780f5 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/CallbackInterfaceInterceptor.java @@ -0,0 +1,60 @@ +/* + * 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.core.wire; + +import org.osoa.sca.NoRegisteredCallbackException; + +import org.apache.tuscany.spi.wire.Interceptor; +import org.apache.tuscany.spi.wire.Message; + +/** + * An interceptor applied to the forward direction of a wire that ensures the callback target implements the required + * service contract. This is required as callback targets may be set dynamically by service implementations. + * + * @version $Rev$ $Date$ + */ +public class CallbackInterfaceInterceptor implements Interceptor { + private boolean invokingServiceImplements; + private Interceptor next; + + public CallbackInterfaceInterceptor(boolean invokingServiceImplements) { + this.invokingServiceImplements = invokingServiceImplements; + } + + public Message invoke(Message msg) { + // TODO check in the context if a callback object is set, if so invoke next since the setCallback will + // perform the check + if (!invokingServiceImplements) { + throw new NoRegisteredCallbackException("Callback target does not implement the callback interface"); + } + return next.invoke(msg); + } + + public void setNext(Interceptor next) { + this.next = next; + } + + public Interceptor getNext() { + return next; + } + + public boolean isOptimizable() { + return false; + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/IncompatibleServiceContractExceptionFormatter.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/IncompatibleServiceContractExceptionFormatter.java new file mode 100644 index 0000000000..d5fca62e1b --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/IncompatibleServiceContractExceptionFormatter.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.core.wire; + +import java.io.PrintWriter; + +import org.osoa.sca.annotations.Destroy; +import org.osoa.sca.annotations.EagerInit; +import org.osoa.sca.annotations.Reference; + +import org.apache.tuscany.spi.model.Operation; +import org.apache.tuscany.spi.model.ServiceContract; +import org.apache.tuscany.spi.wire.IncompatibleServiceContractException; + +import org.apache.tuscany.host.monitor.ExceptionFormatter; +import org.apache.tuscany.host.monitor.FormatterRegistry; + +/** + * Formats {@link org.apache.tuscany.spi.wire.IncompatibleServiceContractException} for JDK logging + * + * @version $Rev$ $Date$ + */ +@EagerInit +public class IncompatibleServiceContractExceptionFormatter implements ExceptionFormatter { + private FormatterRegistry factory; + + public IncompatibleServiceContractExceptionFormatter(@Reference FormatterRegistry factory) { + this.factory = factory; + factory.register(this); + } + + public boolean canFormat(Class<?> type) { + return IncompatibleServiceContractException.class.isAssignableFrom(type); + } + + @Destroy + public void destroy() { + factory.unregister(this); + } + + public PrintWriter write(PrintWriter writer, Throwable exception) { + assert exception instanceof IncompatibleServiceContractException; + IncompatibleServiceContractException e = (IncompatibleServiceContractException) exception; + e.appendBaseMessage(writer); + ServiceContract<?> source = e.getSource(); + String sourceContractName = null; + if (source != null) { + sourceContractName = source.getInterfaceName(); + } + Operation<?> sourceOperation = e.getSourceOperation(); + String sourceOpName = null; + if (sourceOperation != null) { + sourceOpName = sourceOperation.getName(); + } + if (sourceOpName == null) { + writer.write("\nSource Contract: " + sourceContractName); + } else { + writer.write("\nSource Contract: " + sourceContractName + "/" + sourceOpName); + } + ServiceContract<?> target = e.getTarget(); + String targetContractName = null; + if (target != null) { + targetContractName = target.getInterfaceName(); + } + Operation<?> targetOperation = e.getTargetOperation(); + String targetOpName = null; + if (targetOperation != null) { + targetOpName = targetOperation.getName(); + } + if (targetOpName == null) { + writer.write("\nTarget Contract: " + targetContractName + "\n"); + } else { + writer.write("\nTarget Contract: " + targetContractName + "/" + targetOpName + "\n"); + + } + return writer; + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/InvocationChainImpl.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/InvocationChainImpl.java new file mode 100644 index 0000000000..921b4e37fa --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/InvocationChainImpl.java @@ -0,0 +1,105 @@ +/* + * 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.core.wire; + +import org.apache.tuscany.spi.model.Operation; +import org.apache.tuscany.spi.model.physical.PhysicalOperationDefinition; +import org.apache.tuscany.spi.wire.Interceptor; +import org.apache.tuscany.spi.wire.InvocationChain; +import org.apache.tuscany.spi.wire.TargetInvoker; + +/** + * Default implementation of an invocation chain + * + * @version $Rev$ $Date$ + */ +public class InvocationChainImpl implements InvocationChain { + protected Operation operation; + protected PhysicalOperationDefinition physicalOperation; + protected TargetInvoker targetInvoker; + protected Interceptor interceptorChainHead; + protected Interceptor interceptorChainTail; + + public InvocationChainImpl(PhysicalOperationDefinition operation) { + this.physicalOperation = operation; + } + + public InvocationChainImpl(Operation operation) { + assert operation != null; + this.operation = operation; + } + + public Operation getOperation() { + return operation; + } + + public PhysicalOperationDefinition getPhysicalOperation() { + return physicalOperation; + } + + public void setTargetInvoker(TargetInvoker invoker) { + this.targetInvoker = invoker; + } + + public TargetInvoker getTargetInvoker() { + return targetInvoker; + } + + public void addInterceptor(Interceptor interceptor) { + if (interceptorChainHead == null) { + interceptorChainHead = interceptor; + } else { + interceptorChainTail.setNext(interceptor); + } + interceptorChainTail = interceptor; + } + + public void addInterceptor(int index, Interceptor interceptor) { + int i = 0; + Interceptor next = interceptorChainHead; + Interceptor prev = null; + while (next != null && i < index) { + prev = next; + next = next.getNext(); + i++; + } + if (i == index) { + if (prev != null) { + prev.setNext(interceptor); + } else { + interceptorChainHead = interceptor; + } + interceptor.setNext(next); + if (next == null) { + interceptorChainTail = interceptor; + } + } else { + throw new ArrayIndexOutOfBoundsException(index); + } + } + + public Interceptor getHeadInterceptor() { + return interceptorChainHead; + } + + public Interceptor getTailInterceptor() { + return interceptorChainTail; + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/InvokerInterceptor.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/InvokerInterceptor.java new file mode 100644 index 0000000000..10cc254451 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/InvokerInterceptor.java @@ -0,0 +1,60 @@ +/* + * 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.core.wire; + +import org.apache.tuscany.spi.wire.Interceptor; +import org.apache.tuscany.spi.wire.InvocationRuntimeException; +import org.apache.tuscany.spi.wire.Message; +import org.apache.tuscany.spi.wire.TargetInvoker; + +/** + * Serves as a tail interceptor on a target wire chain. This implementation dispatches to the target invoker passed + * inside the wire message. Target invokers are passed from the source in order to allow for caching of target + * instances. + * + * @version $Rev$ $Date$ + * @Deprecated + * @see org.apache.tuscany.spi.wire.TargetInvoker + */ +public class InvokerInterceptor implements Interceptor { + + public InvokerInterceptor() { + } + + public Message invoke(Message msg) throws InvocationRuntimeException { + TargetInvoker invoker = msg.getTargetInvoker(); + if (invoker == null) { + throw new InvocationRuntimeException("No target invoker specified on message"); + } + return invoker.invoke(msg); + } + + public void setNext(Interceptor next) { + throw new IllegalStateException("This interceptor must be the last one in an target interceptor chain"); + } + + public Interceptor getNext() { + return null; + } + + public boolean isOptimizable() { + return true; + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/NoMethodForOperationException.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/NoMethodForOperationException.java new file mode 100644 index 0000000000..aec281d190 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/NoMethodForOperationException.java @@ -0,0 +1,42 @@ +/* + * 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.core.wire; + +import org.apache.tuscany.spi.wire.ProxyCreationException; + +/** + * Thrown when an {@link org.apache.tuscany.spi.model.Operation} cannot be mapped to a method on an interface + * @version $Rev$ $Date$ + */ +public class NoMethodForOperationException extends ProxyCreationException { + public NoMethodForOperationException() { + } + + public NoMethodForOperationException(String message) { + super(message); + } + + public NoMethodForOperationException(String message, Throwable cause) { + super(message, cause); + } + + public NoMethodForOperationException(Throwable cause) { + super(cause); + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/NonBlockingInterceptor.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/NonBlockingInterceptor.java new file mode 100644 index 0000000000..d4848cde71 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/NonBlockingInterceptor.java @@ -0,0 +1,193 @@ +/* + * 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.core.wire; + +import java.net.URI; +import java.util.LinkedList; + +import org.osoa.sca.ServiceRuntimeException; + +import org.apache.tuscany.spi.component.WorkContext; +import org.apache.tuscany.spi.model.Scope; +import org.apache.tuscany.spi.services.work.WorkScheduler; +import org.apache.tuscany.spi.wire.Interceptor; +import org.apache.tuscany.spi.wire.Message; +import org.apache.tuscany.spi.wire.TargetInvoker; +import org.apache.tuscany.spi.wire.Wire; + +/** + * Adds non-blocking behavior to an invocation chain + * + * @version $$Rev$$ $$Date$$ + */ +public class NonBlockingInterceptor implements Interceptor { + + private static final Message RESPONSE = new ImmutableMessage(); + + private WorkScheduler workScheduler; + private WorkContext workContext; + private Interceptor next; + + public NonBlockingInterceptor(WorkScheduler workScheduler, WorkContext workContext) { + this.workScheduler = workScheduler; + this.workContext = workContext; + } + + public NonBlockingInterceptor(WorkScheduler workScheduler, WorkContext workContext, Interceptor next) { + this.workScheduler = workScheduler; + this.workContext = workContext; + this.next = next; + } + + public Message invoke(final Message msg) { + // Retrieve conversation id to transfer to new thread + // Notice that we cannot clear the conversation id from the current thread + final Object conversationID = workContext.getIdentifier(Scope.CONVERSATION); + // Schedule the invocation of the next interceptor in a new Work instance + try { + workScheduler.scheduleWork(new Runnable() { + public void run() { + workContext.setCorrelationId(null); + // if we got a conversation id, transfer it to new thread + if (conversationID != null) { + workContext.setIdentifier(Scope.CONVERSATION, conversationID); + } + next.invoke(msg); + } + }); + } catch (Exception e) { + throw new ServiceRuntimeException(e); + } + return RESPONSE; + } + + public Interceptor getNext() { + return next; + } + + public void setNext(Interceptor next) { + this.next = next; + } + + public boolean isOptimizable() { + return false; + } + + /** + * A dummy message passed back on an invocation + */ + private static class ImmutableMessage implements Message { + + public Object getBody() { + return null; + } + + public void setBody(Object body) { + if (body != null) { + throw new UnsupportedOperationException(); + } + } + + public WorkContext getWorkContext() { + throw new UnsupportedOperationException(); + } + + public void setWorkContext(WorkContext workContext) { + throw new UnsupportedOperationException(); + } + + public void setTargetInvoker(TargetInvoker invoker) { + throw new UnsupportedOperationException(); + } + + public TargetInvoker getTargetInvoker() { + return null; + } + + public Message getRelatedCallbackMessage() { + return null; + } + + public URI getFromAddress() { + return null; + } + + public void setFromAddress(URI fromAddress) { + throw new UnsupportedOperationException(); + } + + public void pushCallbackUri(URI fromAddress) { + throw new UnsupportedOperationException(); + } + + public LinkedList<URI> getCallbackUris() { + return null; + } + + public void setCallbackUris(LinkedList<URI> uris) { + throw new UnsupportedOperationException(); + } + + public void pushCallbackWire(Wire wire) { + + } + + public LinkedList<Wire> getCallbackWires() { + return null; + } + + public void setCallbackWires(LinkedList<Wire> wires) { + + } + + 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(); + } + + public short getConversationSequence() { + return TargetInvoker.NONE; + } + + public void setConversationSequence(short sequence) { + + } + + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/NonBlockingInterceptorBuilder.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/NonBlockingInterceptorBuilder.java new file mode 100644 index 0000000000..8afcf8f6ad --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/NonBlockingInterceptorBuilder.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.core.wire; + +import javax.xml.namespace.QName; + +import org.osoa.sca.annotations.Reference; + +import org.apache.tuscany.spi.builder.BuilderException; +import org.apache.tuscany.spi.component.WorkContext; +import org.apache.tuscany.spi.extension.InterceptorBuilderExtension; +import org.apache.tuscany.spi.model.physical.PhysicalInterceptorDefinition; +import org.apache.tuscany.spi.services.work.WorkScheduler; +import org.apache.tuscany.spi.wire.Interceptor; + +/** + * Creates a non-blocking interceptor + * + * @version $Rev$ $Date$ + */ +public class NonBlockingInterceptorBuilder extends InterceptorBuilderExtension { + public static final QName QNAME = new QName("http://tuscany.apache.org/xmlns/sca/system/2.0-alpha", "nonblocking"); + private WorkContext workContext; + private WorkScheduler scheduler; + + public NonBlockingInterceptorBuilder(@Reference(required = true)WorkContext workContext, + @Reference(required = true)WorkScheduler scheduler) { + this.workContext = workContext; + this.scheduler = scheduler; + } + + public Interceptor build(PhysicalInterceptorDefinition definition) throws BuilderException { + return new NonBlockingInterceptor(scheduler, workContext); + } + + protected QName getName() { + return QNAME; + } +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/OptimizedWireObjectFactory.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/OptimizedWireObjectFactory.java new file mode 100644 index 0000000000..ab958234bd --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/OptimizedWireObjectFactory.java @@ -0,0 +1,49 @@ +/* + * 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.core.wire; + +import org.apache.tuscany.spi.ObjectCreationException; +import org.apache.tuscany.spi.ObjectFactory; +import org.apache.tuscany.spi.component.TargetResolutionException; +import org.apache.tuscany.spi.wire.Wire; + +/** + * Returns a target instance directly from a wire + * + * @version $Rev$ $Date$ + * @Deprecated + */ +public class OptimizedWireObjectFactory<B> implements ObjectFactory<B> { + private final Class<B> type; + private Wire wire; + + public OptimizedWireObjectFactory(Class<B> type, Wire factory) { + this.wire = factory; + this.type = type; + } + + public B getInstance() throws ObjectCreationException { + try { + return type.cast(wire.getTargetInstance()); + } catch (TargetResolutionException e) { + throw new ObjectCreationException(e); + } + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/ProxyServiceExtension.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/ProxyServiceExtension.java new file mode 100644 index 0000000000..7c8cf0db3a --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/ProxyServiceExtension.java @@ -0,0 +1,115 @@ +/* + * 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.core.wire; + +import org.apache.tuscany.spi.component.WorkContext; +import org.apache.tuscany.spi.model.Operation; +import org.apache.tuscany.spi.model.ServiceContract; +import org.apache.tuscany.spi.wire.IncompatibleServiceContractException; +import org.apache.tuscany.spi.wire.ProxyService; + +/** + * Base class for wire service extensions + * + * @version $Rev$ $Date$ + */ +public abstract class ProxyServiceExtension implements ProxyService { + protected WorkContext context; + + protected ProxyServiceExtension(WorkContext context) { + this.context = context; + } + + public boolean checkCompatibility(ServiceContract<?> source, + ServiceContract<?> target, + boolean ignoreCallback, + boolean silent) + throws IncompatibleServiceContractException { + if (source == target) { + // Shortcut for performance + return true; + } + if (source.isRemotable() != target.isRemotable()) { + if (!silent) { + throw new IncompatibleServiceContractException("Remotable settings do not match", source, target); + } else { + return false; + } + } + if (source.isConversational() != target.isConversational()) { + if (!silent) { + throw new IncompatibleServiceContractException("Interaction scopes do not match", source, target); + } else { + return false; + } + } + + for (Operation<?> operation : source.getOperations().values()) { + Operation<?> targetOperation = target.getOperations().get(operation.getName()); + if (targetOperation == null) { + if (!silent) { + throw new IncompatibleServiceContractException("Operation not found on target", source, target); + } else { + return false; + } + } + if (!operation.equals(targetOperation)) { + if (!silent) { + throw new IncompatibleServiceContractException("Target operations are not compatible", source, + target); + } else { + return false; + } + } + } + + if (ignoreCallback) { + return true; + } + + for (Operation<?> operation : source.getCallbackOperations().values()) { + Operation<?> targetOperation = target.getCallbackOperations().get(operation.getName()); + if (targetOperation == null) { + if (!silent) { + throw new IncompatibleServiceContractException("Callback operation not found on target", + source, + target, + null, + targetOperation); + } else { + return false; + } + } + if (!operation.equals(targetOperation)) { + if (!silent) { + throw new IncompatibleServiceContractException("Target callback operation is not compatible", + source, + target, + operation, + targetOperation); + } else { + return false; + } + } + } + return true; + } + + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/WireImpl.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/WireImpl.java new file mode 100644 index 0000000000..7f748a15db --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/WireImpl.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.core.wire; + +import java.net.URI; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import javax.xml.namespace.QName; + +import org.apache.tuscany.spi.component.AtomicComponent; +import org.apache.tuscany.spi.component.TargetResolutionException; +import org.apache.tuscany.spi.model.Operation; +import org.apache.tuscany.spi.model.ServiceContract; +import org.apache.tuscany.spi.model.physical.PhysicalOperationDefinition; +import org.apache.tuscany.spi.wire.InvocationChain; +import org.apache.tuscany.spi.wire.Wire; + +/** + * Default implementation of a Wire + * + * @version $Rev$ $Date$ + */ +public class WireImpl implements Wire { + private URI sourceUri; + private URI targetUri; + private QName bindingType; + private ServiceContract sourceContract; + private ServiceContract targetContract; + private boolean optimizable; + private Map<Operation<?>, InvocationChain> chains = new HashMap<Operation<?>, InvocationChain>(); + private Map<Operation<?>, InvocationChain> callbackChains = new HashMap<Operation<?>, InvocationChain>(); + private Map<PhysicalOperationDefinition, InvocationChain> pChains = + new HashMap<PhysicalOperationDefinition, InvocationChain>(); + private Map<PhysicalOperationDefinition, InvocationChain> pCallbackChains = + new HashMap<PhysicalOperationDefinition, InvocationChain>(); + private AtomicComponent target; + + /** + * Creates a wire with a local binding + */ + public WireImpl() { + } + + /** + * Creates a wire with the given binding type + * + * @param bindingType the binding type + */ + public WireImpl(QName bindingType) { + this.bindingType = bindingType; + } + + public URI getSourceUri() { + return sourceUri; + } + + public void setSourceUri(URI sourceUri) { + this.sourceUri = sourceUri; + } + + public URI getTargetUri() { + return targetUri; + } + + public void setTargetUri(URI targetUri) { + this.targetUri = targetUri; + } + + public QName getBindingType() { + return bindingType; + } + + + public ServiceContract getSourceContract() { + return sourceContract; + } + + public void setSourceContract(ServiceContract contract) { + this.sourceContract = contract; + } + + + public ServiceContract getTargetContract() { + return targetContract; + } + + public void setTargetContract(ServiceContract contract) { + this.targetContract = contract; + } + + public boolean isOptimizable() { + return optimizable; + } + + public void setOptimizable(boolean optimizable) { + this.optimizable = optimizable; + } + + public Object getTargetInstance() throws TargetResolutionException { + if (target == null) { + return null; + } + return target.getTargetInstance(); + } + + public void setTarget(AtomicComponent target) { + this.target = target; + } + + public Map<Operation<?>, InvocationChain> getInvocationChains() { + return Collections.unmodifiableMap(chains); + } + + public void addInvocationChain(Operation<?> operation, InvocationChain chain) { + chains.put(operation, chain); + } + + public void addInvocationChain(PhysicalOperationDefinition operation, InvocationChain chain) { + pChains.put(operation, chain); + } + + public Map<PhysicalOperationDefinition, InvocationChain> getPhysicalInvocationChains() { + return Collections.unmodifiableMap(pChains); + } + + public Map<Operation<?>, InvocationChain> getCallbackInvocationChains() { + return Collections.unmodifiableMap(callbackChains); + } + + public void addCallbackInvocationChain(Operation<?> operation, InvocationChain chain) { + callbackChains.put(operation, chain); + } + + public Map<PhysicalOperationDefinition, InvocationChain> getCallbackPhysicalInvocationChains() { + return Collections.unmodifiableMap(pCallbackChains); + } + + public void addCallbackInvocationChain(PhysicalOperationDefinition operation, InvocationChain chain) { + pCallbackChains.put(operation, chain); + } + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/WireObjectFactory.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/WireObjectFactory.java new file mode 100644 index 0000000000..3d14138d56 --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/WireObjectFactory.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.core.wire; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +import org.apache.tuscany.spi.ObjectCreationException; +import org.apache.tuscany.spi.ObjectFactory; +import org.apache.tuscany.spi.component.TargetResolutionException; +import org.apache.tuscany.spi.wire.ChainHolder; +import org.apache.tuscany.spi.wire.Wire; +import org.apache.tuscany.spi.wire.ProxyService; + +/** + * Uses a wire to return an object instance + * @Deprecated + * + * @version $Rev$ $Date$ + */ +public class WireObjectFactory<T> implements ObjectFactory<T> { + private Class<T> interfaze; + private Wire wire; + private ProxyService proxyService; + // the cache of proxy interface method to operation mappings + private Map<Method, ChainHolder> mappings; + private boolean optimizable; + + /** + * Constructor. + * + * @param interfaze the interface to inject on the client + * @param wire the backing wire + * @param proxyService the wire service to create the proxy + * @throws NoMethodForOperationException + */ + public WireObjectFactory(Class<T> interfaze, Wire wire, ProxyService proxyService) + throws NoMethodForOperationException { + this.interfaze = interfaze; + this.wire = wire; + this.proxyService = proxyService; + this.mappings = WireUtils.createInterfaceToWireMapping(interfaze, wire); + if (wire.isOptimizable() + && wire.getSourceContract().getInterfaceClass() != null + && interfaze.isAssignableFrom(wire.getSourceContract().getInterfaceClass())) { + optimizable = true; + } + } + + public T getInstance() throws ObjectCreationException { + if (optimizable) { + try { + return interfaze.cast(wire.getTargetInstance()); + } catch (TargetResolutionException e) { + throw new ObjectCreationException(e); + } + } else { + // clone the cached mappings + Map<Method, ChainHolder> newChains = new HashMap<Method, ChainHolder>(mappings.size()); + for (Map.Entry<Method, ChainHolder> entry : mappings.entrySet()) { + newChains.put(entry.getKey(), entry.getValue().clone()); + } + return interfaze.cast(proxyService.createProxy(interfaze, wire, newChains)); + } + } + + +} diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/WireObjectFactory2.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/WireObjectFactory2.java new file mode 100644 index 0000000000..b5fab62d2f --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/WireObjectFactory2.java @@ -0,0 +1,65 @@ +/* + * 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.core.wire; + +import java.lang.reflect.Method; +import java.util.Map; + +import org.apache.tuscany.spi.ObjectCreationException; +import org.apache.tuscany.spi.ObjectFactory; +import org.apache.tuscany.spi.wire.InvocationChain; +import org.apache.tuscany.spi.wire.ProxyService; +import org.apache.tuscany.spi.wire.Wire; + +/** + * Uses a wire to return an object instance + * + * @version $Rev$ $Date$ + */ +public class WireObjectFactory2<T> implements ObjectFactory<T> { + private Class<T> interfaze; + private boolean conversational; + private Wire wire; + private ProxyService proxyService; + // the cache of proxy interface method to operation mappings + private Map<Method, InvocationChain> mappings; + + /** + * Constructor. + * + * @param interfaze the interface to inject on the client + * @param conversational if the wire is conversational + * @param wire the backing wire + * @param proxyService the wire service to create the proxy + * @throws NoMethodForOperationException if a method matching the operation cannot be found + */ + public WireObjectFactory2(Class<T> interfaze, boolean conversational, Wire wire, ProxyService proxyService) + throws NoMethodForOperationException { + this.interfaze = interfaze; + this.conversational = conversational; + this.wire = wire; + this.proxyService = proxyService; + this.mappings = WireUtils.createInterfaceToWireMapping2(interfaze, wire); + } + + public T getInstance() throws ObjectCreationException { + return interfaze.cast(proxyService.createProxy2(interfaze, conversational, wire)); + } +} + diff --git a/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/WireUtils.java b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/WireUtils.java new file mode 100644 index 0000000000..8b839dc8df --- /dev/null +++ b/sandbox/rfeng/minicore/src/main/java/org/apache/tuscany/core/wire/WireUtils.java @@ -0,0 +1,116 @@ +/* + * 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.core.wire; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +import static org.apache.tuscany.spi.idl.java.JavaIDLUtils.findMethod; +import static org.apache.tuscany.spi.idl.java.JavaIDLUtils.findMethod2; +import org.apache.tuscany.spi.model.Operation; +import org.apache.tuscany.spi.model.physical.PhysicalOperationDefinition; +import org.apache.tuscany.spi.wire.ChainHolder; +import org.apache.tuscany.spi.wire.Interceptor; +import org.apache.tuscany.spi.wire.InvocationChain; +import org.apache.tuscany.spi.wire.ProxyCreationException; +import org.apache.tuscany.spi.wire.Wire; + +/** + * Utilities for operating on wires + * + * @version $Rev$ $Date$ + */ +public final class WireUtils { + + private WireUtils() { + } + + + /** + * Maps methods on an interface to operations on a wire + * + * @param interfaze the interface to map from + * @param wire the wire to map to + * @return a collection of method to operation mappings + * @throws NoMethodForOperationException + * @Deprecated + */ + public static Map<Method, ChainHolder> createInterfaceToWireMapping(Class<?> interfaze, Wire wire) + throws NoMethodForOperationException { + Map<Operation<?>, InvocationChain> invocationChains = wire.getInvocationChains(); + + Map<Method, ChainHolder> chains = new HashMap<Method, ChainHolder>(invocationChains.size()); + for (Map.Entry<Operation<?>, InvocationChain> entry : invocationChains.entrySet()) { + Operation operation = entry.getKey(); + try { + Method method = findMethod(interfaze, operation); + chains.put(method, new ChainHolder(entry.getValue())); + } catch (NoSuchMethodException e) { + throw new NoMethodForOperationException(operation.getName()); + } + } + return chains; + } + + public static Map<Method, InvocationChain> createInterfaceToWireMapping2(Class<?> interfaze, Wire wire) + throws NoMethodForOperationException { + Map<PhysicalOperationDefinition, InvocationChain> invocationChains = wire.getPhysicalInvocationChains(); + + Map<Method, InvocationChain> chains = new HashMap<Method, InvocationChain>(invocationChains.size()); + for (Map.Entry<PhysicalOperationDefinition, InvocationChain> entry : invocationChains.entrySet()) { + PhysicalOperationDefinition operation = entry.getKey(); + try { + Method method = findMethod2(interfaze, operation); + chains.put(method, entry.getValue()); + } catch (NoSuchMethodException e) { + throw new NoMethodForOperationException(operation.getName()); + } catch (ClassNotFoundException e) { + throw new ProxyCreationException(e); + } + } + return chains; + } + + /** + * Determines if the given wire is optimizable, i.e. its invocation chains may be bypassed during an invocation. + * This is typically calculated during the connect phase to optimize away invocation chains. + * + * @param wire the wire + * @return true if the wire is optimizable + */ + public static boolean isOptimizable(Wire wire) { + for (InvocationChain chain : wire.getInvocationChains().values()) { + if (chain.getHeadInterceptor() != null) { + Interceptor current = chain.getHeadInterceptor(); + if (current == null) { + break; + } + while (current != null) { + if (!current.isOptimizable()) { + return false; + } + current = current.getNext(); + } + } + } + // if there is a callback, the wire is never optimizable since the callback target needs to be disambiguated + return wire.getCallbackInvocationChains().isEmpty(); + } +} |