diff options
Diffstat (limited to 'sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany')
12 files changed, 1549 insertions, 0 deletions
diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/binding/hazelcast/EndpointStash.java b/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/binding/hazelcast/EndpointStash.java new file mode 100644 index 0000000000..42f6193940 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/binding/hazelcast/EndpointStash.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.sca.binding.hazelcast; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; + + +public class EndpointStash { + + // TODO a better way of sharing these endpoints than a static + // the issue is that the ServiceInvoker needs to get hold of the Endpoint + // for a URI. The ServiceInvoker runs in the context of a Hazelcast spawned + // thread so can only get to Tuscany via a static. The Hazelcast endpoint + // registry does actually have these endpoints so perhaps an alternative could be + // to use NodeFactory.getNodeFactories to get at the Hazelcast endpoint registry. + private static Map<String, RuntimeEndpoint> endpoints = new ConcurrentHashMap<String, RuntimeEndpoint>(); + + public static void addEndpoint(RuntimeEndpoint endpoint) { + endpoints.put(endpoint.getURI(), endpoint); + } + + public static RuntimeEndpoint getEndpoint(String uri) { + for (RuntimeEndpoint ep : endpoints.values()) { + if (ep.matches(uri)) { + return ep; + } + } + return null; + } + + public static void removeEndpoint(String uri) { + endpoints.remove(uri); + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/binding/hazelcast/HazelcastBinding.java b/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/binding/hazelcast/HazelcastBinding.java new file mode 100644 index 0000000000..1636ed16ca --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/binding/hazelcast/HazelcastBinding.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.sca.binding.hazelcast; + +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.assembly.impl.BindingImpl; + +public class HazelcastBinding extends BindingImpl { + + public static final QName TYPE = new QName(SCA11_TUSCANY_NS, "binding.hazelcast"); + + public HazelcastBinding() { + super(TYPE); + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/binding/hazelcast/HazelcastBindingProviderFactory.java b/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/binding/hazelcast/HazelcastBindingProviderFactory.java new file mode 100644 index 0000000000..3a1b89e83e --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/binding/hazelcast/HazelcastBindingProviderFactory.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.sca.binding.hazelcast; + +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.databinding.xml.DOMDataBinding; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.provider.BindingProviderFactory; +import org.apache.tuscany.sca.provider.ReferenceBindingProvider; +import org.apache.tuscany.sca.provider.ServiceBindingProvider; +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; +import org.apache.tuscany.sca.runtime.RuntimeEndpointReference; + +public class HazelcastBindingProviderFactory implements BindingProviderFactory<HazelcastBinding> { + + private ExtensionPointRegistry extensionsRegistry; + + public HazelcastBindingProviderFactory(ExtensionPointRegistry extensionsRegistry) { + this.extensionsRegistry = extensionsRegistry; + } + + public ReferenceBindingProvider createReferenceBindingProvider(RuntimeEndpointReference endpointReference) { + InterfaceContract interfaceContract = endpointReference.getGeneratedWSDLContract(endpointReference.getComponentReferenceInterfaceContract()); + interfaceContract.getInterface().resetDataBinding(DOMDataBinding.NAME); + return new HazelcastReferenceBindingProvider(extensionsRegistry, endpointReference.getBinding().getURI(), interfaceContract); + } + + public ServiceBindingProvider createServiceBindingProvider(RuntimeEndpoint endpoint) { + InterfaceContract interfaceContract = endpoint.getGeneratedWSDLContract(endpoint.getComponentServiceInterfaceContract()); + interfaceContract.getInterface().resetDataBinding(DOMDataBinding.NAME); + return new HazelcastServiceBindingProvider(endpoint, interfaceContract); + } + + public Class<HazelcastBinding> getModelType() { + return HazelcastBinding.class; + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/binding/hazelcast/HazelcastReferenceBindingProvider.java b/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/binding/hazelcast/HazelcastReferenceBindingProvider.java new file mode 100644 index 0000000000..29546f405e --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/binding/hazelcast/HazelcastReferenceBindingProvider.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.sca.binding.hazelcast; + +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.provider.ReferenceBindingProvider; + +public class HazelcastReferenceBindingProvider implements ReferenceBindingProvider { + + private ExtensionPointRegistry extensionsRegistry; + private String serviceURI; + private InterfaceContract interfaceContract; + + public HazelcastReferenceBindingProvider(ExtensionPointRegistry extensionsRegistry, String serviceURI, InterfaceContract interfaceContract) { + this.extensionsRegistry = extensionsRegistry; + this.serviceURI = serviceURI; + this.interfaceContract = interfaceContract; + } + + public Invoker createInvoker(Operation operation) { + return new ReferenceInvoker(extensionsRegistry, serviceURI, operation); + } + + public InterfaceContract getBindingInterfaceContract() { + return interfaceContract; + } + + public boolean supportsOneWayInvocation() { + return false; + } + + public void start() { + } + + public void stop() { + } + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/binding/hazelcast/HazelcastServiceBindingProvider.java b/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/binding/hazelcast/HazelcastServiceBindingProvider.java new file mode 100644 index 0000000000..6ac3542a8e --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/binding/hazelcast/HazelcastServiceBindingProvider.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.sca.binding.hazelcast; + +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.provider.ServiceBindingProvider; +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; + +public class HazelcastServiceBindingProvider implements ServiceBindingProvider { + + private RuntimeEndpoint endpoint; + private InterfaceContract interfaceContract; + + + public HazelcastServiceBindingProvider(RuntimeEndpoint endpoint, InterfaceContract interfaceContract) { + this.endpoint = endpoint; + this.interfaceContract = interfaceContract; + } + + public void start() { + EndpointStash.addEndpoint(endpoint); + } + + public void stop() { + EndpointStash.removeEndpoint(endpoint.getURI()); + } + + public InterfaceContract getBindingInterfaceContract() { + return interfaceContract; + } + + public boolean supportsOneWayInvocation() { + return false; + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/binding/hazelcast/ReferenceInvoker.java b/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/binding/hazelcast/ReferenceInvoker.java new file mode 100644 index 0000000000..1585684691 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/binding/hazelcast/ReferenceInvoker.java @@ -0,0 +1,127 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.binding.hazelcast; + +import java.io.IOException; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.FutureTask; + +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.common.xml.dom.DOMHelper; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.interfacedef.util.FaultException; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.invocation.MessageFactory; +import org.apache.tuscany.sca.registry.hazelcast.HazelcastDomainRegistry; +import org.apache.tuscany.sca.runtime.DomainRegistryFactory; +import org.apache.tuscany.sca.runtime.DomainRegistry; +import org.apache.tuscany.sca.runtime.ExtensibleDomainRegistryFactory; +import org.oasisopen.sca.ServiceRuntimeException; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.xml.sax.SAXException; + +import com.hazelcast.core.DistributedTask; +import com.hazelcast.core.Member; + +public class ReferenceInvoker implements Invoker { + + HazelcastDomainRegistry hzRegistry; + DOMHelper domHelper; + String serviceURI; + private Operation operation; + MessageFactory messageFactory; + + public ReferenceInvoker(ExtensionPointRegistry extensionsRegistry, String serviceURI, Operation operation) { + this.serviceURI = serviceURI; + this.operation = operation; + DomainRegistryFactory domainRegistryFactory = ExtensibleDomainRegistryFactory.getInstance(extensionsRegistry); + for (DomainRegistry r : domainRegistryFactory.getEndpointRegistries()) { + if (r instanceof HazelcastDomainRegistry) { + hzRegistry = (HazelcastDomainRegistry)r; + break; + } + } + this.domHelper = DOMHelper.getInstance(extensionsRegistry); + FactoryExtensionPoint modelFactories = extensionsRegistry.getExtensionPoint(FactoryExtensionPoint.class); + this.messageFactory = modelFactories.getFactory(MessageFactory.class); + } + + public Message invoke(Message msg) { + Member owningMember = hzRegistry.getOwningMember(serviceURI); + if (owningMember == null) { + throw new ServiceRuntimeException("service not found: " + serviceURI); + } + String requestXML = getRequestXML(msg); + Callable<String> callable = new ServiceInvoker(serviceURI, operation.getName(), requestXML); + FutureTask<String> task = new DistributedTask<String>(callable, owningMember); + ExecutorService executorService = getExecutorService(); + executorService.execute(task); + try { + return getResponseNode(task.get()); + } catch (Exception e) { + throw new ServiceRuntimeException(e); + } + } + + /** + * Hazelcast ExecutorService can't nest invocations so use a separate ExecutorService + * for nested calls. See http://groups.google.com/group/hazelcast/browse_thread/thread/1cc0b943716476e9 + */ + private ExecutorService getExecutorService() { + String threadName = Thread.currentThread().getName(); + if (!threadName.startsWith("hz.executor.") || threadName.indexOf("binding.sca.") == -1) { + return hzRegistry.getHazelcastInstance().getExecutorService("binding.sca.1"); + } else { + String oldName = threadName.substring(threadName.lastIndexOf("binding.sca."), threadName.lastIndexOf(".thread-")); + int x = Integer.parseInt(oldName.substring(oldName.lastIndexOf('.') + 1)); + return hzRegistry.getHazelcastInstance().getExecutorService(oldName.substring(0, 12) + (x + 1)); + } + } + + private String getRequestXML(Message msg) { + Object[] args = msg.getBody(); + String msgXML = domHelper.saveAsString((Node)args[0]); + return msgXML; + } + + private Message getResponseNode(String responseXML) throws IOException, SAXException { + Message msg = messageFactory.createMessage(); + if (responseXML.startsWith("DECLAREDEXCEPTION:")) { + Document responseDOM = domHelper.load(responseXML.substring(18)); + FaultException e = new FaultException("remote exception", responseDOM); + Node node = ((Node)responseDOM).getFirstChild(); + e.setFaultName(new QName(node.getNamespaceURI(), node.getLocalName())); + msg.setFaultBody(e); + } else if (responseXML.startsWith("EXCEPTION:")) { + throw new ServiceRuntimeException("Remote exception:" + responseXML.substring(10)); + } else { + Document responseDOM = domHelper.load(responseXML); + msg.setBody(responseDOM); + } + return msg; + } + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/binding/hazelcast/ServiceInvoker.java b/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/binding/hazelcast/ServiceInvoker.java new file mode 100644 index 0000000000..42cac191aa --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/binding/hazelcast/ServiceInvoker.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.sca.binding.hazelcast; + +import java.io.IOException; +import java.io.Serializable; +import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.Callable; + +import org.apache.tuscany.sca.common.xml.dom.DOMHelper; +import org.apache.tuscany.sca.interfacedef.Interface; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.interfacedef.util.FaultException; +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; +import org.oasisopen.sca.NoSuchServiceException; +import org.oasisopen.sca.ServiceRuntimeException; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.xml.sax.SAXException; + +public class ServiceInvoker implements Callable<String>, Serializable { + private static final long serialVersionUID = 1L; + + // all fields MUST be Serializable + private String serviceURI; + private String operationName; + private String requestXML; + + public ServiceInvoker(String serviceURI, String operationName, String msgXML) { + this.serviceURI = serviceURI; + this.operationName = operationName; + this.requestXML = msgXML; + } + + public String call() throws Exception { + RuntimeEndpoint endpoint = EndpointStash.getEndpoint(serviceURI); + if (endpoint == null) { + throw new NoSuchServiceException(serviceURI); + } + Operation operation = getRequestOperation(endpoint); + DOMHelper domHelper = DOMHelper.getInstance(endpoint.getCompositeContext().getExtensionPointRegistry()); + Object[] args = getRequestArgs(domHelper); + String responseXML; + try { + Object response = endpoint.invoke(operation, args); + responseXML = getResponseXML(domHelper, response); + } catch (Exception e) { + if (e instanceof InvocationTargetException && ((InvocationTargetException)e).getTargetException() instanceof FaultException) { + responseXML = "DECLAREDEXCEPTION:" + getResponseXML(domHelper, ((FaultException)((InvocationTargetException)e).getTargetException()).getFaultInfo()); + } else { + responseXML = "EXCEPTION: " + e.getClass() + ":" + e.getMessage(); + } + } + return responseXML; + } + + private Operation getRequestOperation(RuntimeEndpoint endpoint) { + InterfaceContract ic = endpoint.getBindingInterfaceContract(); + Interface iface = ic.getInterface(); + for (Operation op : iface.getOperations()) { + if (op.getName().equals(operationName)) { + return op; + } + + } + // TODO: return err msg + throw new ServiceRuntimeException("operation not found " + operationName); + } + + private Object[] getRequestArgs(DOMHelper domHelper) throws IOException, SAXException { + Document requestDOM = domHelper.load(requestXML); + return new Object[] {requestDOM}; + } + + private String getResponseXML(DOMHelper domHelper, Object response) { + String responseXML = domHelper.saveAsString((Node)response); + return responseXML; + } + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/registry/hazelcast/HazelcastDomainRegistry.java b/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/registry/hazelcast/HazelcastDomainRegistry.java new file mode 100644 index 0000000000..d7a31a38ef --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/registry/hazelcast/HazelcastDomainRegistry.java @@ -0,0 +1,666 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.registry.hazelcast; + +import java.io.ByteArrayOutputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.FutureTask; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.assembly.Endpoint; +import org.apache.tuscany.sca.common.xml.stax.StAXHelper; +import org.apache.tuscany.sca.contribution.processor.ContributionReadException; +import org.apache.tuscany.sca.contribution.processor.ContributionWriteException; +import org.apache.tuscany.sca.contribution.processor.ExtensibleStAXArtifactProcessor; +import org.apache.tuscany.sca.contribution.processor.ProcessorContext; +import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessorExtensionPoint; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; +import org.apache.tuscany.sca.core.LifeCycleListener; +import org.apache.tuscany.sca.core.UtilityExtensionPoint; +import org.apache.tuscany.sca.runtime.BaseDomainRegistry; +import org.apache.tuscany.sca.runtime.ContributionDescription; +import org.apache.tuscany.sca.runtime.ContributionListener; +import org.apache.tuscany.sca.runtime.DomainRegistry; +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; +import org.apache.tuscany.sca.runtime.RuntimeProperties; +import org.oasisopen.sca.ServiceRuntimeException; + +import com.hazelcast.config.Config; +import com.hazelcast.config.NearCacheConfig; +import com.hazelcast.config.TcpIpConfig; +import com.hazelcast.config.XmlConfigBuilder; +import com.hazelcast.core.DistributedTask; +import com.hazelcast.core.EntryEvent; +import com.hazelcast.core.EntryListener; +import com.hazelcast.core.Hazelcast; +import com.hazelcast.core.HazelcastInstance; +import com.hazelcast.core.ILock; +import com.hazelcast.core.IMap; +import com.hazelcast.core.Member; +import com.hazelcast.core.MembershipEvent; +import com.hazelcast.core.MembershipListener; +import com.hazelcast.core.MultiMap; +import com.hazelcast.core.Transaction; +import com.hazelcast.nio.Address; + +/** + * An DomainRegistry using a Hazelcast + */ +public class HazelcastDomainRegistry extends BaseDomainRegistry implements DomainRegistry, LifeCycleListener, EntryListener<String, Endpoint>, MembershipListener { + private final static Logger logger = Logger.getLogger(HazelcastDomainRegistry.class.getName()); + + private HazelcastInstance hazelcastInstance; + + protected Map<Object, Object> endpointMap; + protected MultiMap<String, String> endpointOwners; + + // key contributionURI, value map key compositeURI value compositeXML + protected Map<String, Map<String, String>> runningComposites; + // key member, value map key contributionURI value list of compositeURI + protected Map<String, Map<String, List<String>>> runningCompositeOwners; + // key componentName, value contributionURI + protected Map<String, String> runningComponentContributions; + + protected Map<String, Endpoint> localEndpoints = new ConcurrentHashMap<String, Endpoint>(); + + protected Map<String, ContributionDescription> contributionDescriptions; + + protected AssemblyFactory assemblyFactory; + protected Object shutdownMutex = new Object(); + protected Properties properties; + + public HazelcastDomainRegistry(ExtensionPointRegistry registry, Properties properties, String domainURI, String domainName) { + super(registry, null, domainURI, domainName); + this.assemblyFactory = registry.getExtensionPoint(FactoryExtensionPoint.class).getFactory(AssemblyFactory.class); + this.properties = properties; + } + + public HazelcastDomainRegistry(ExtensionPointRegistry registry, + Map<String, String> attributes, + String domainURI, + String domainName) { + super(registry, attributes, domainURI, domainName); + this.assemblyFactory = registry.getExtensionPoint(FactoryExtensionPoint.class).getFactory(AssemblyFactory.class); + this.properties = registry.getExtensionPoint(UtilityExtensionPoint.class).getUtility(RuntimeProperties.class).getProperties(); + } + + public HazelcastInstance getHazelcastInstance() { + return hazelcastInstance; + } + + public void start() { + if (endpointMap != null) { + throw new IllegalStateException("The registry has already been started"); + } +// if (configURI.toString().startsWith("tuscany:vm:")) { +// endpointMap = new HashMap<Object, Object>(); +// } else { + initHazelcastInstance(); + IMap imap = hazelcastInstance.getMap(domainURI + "/Endpoints"); + imap.addEntryListener(this, true); + endpointMap = imap; + + endpointOwners = hazelcastInstance.getMultiMap(domainURI + "/EndpointOwners"); + + runningComposites = hazelcastInstance.getMap(domainURI + "/RunningComposites"); + runningCompositeOwners = hazelcastInstance.getMap(domainURI + "/RunningCompositeOwners"); + runningComponentContributions = hazelcastInstance.getMap(domainURI + "/RunningComponentContributions"); + + contributionDescriptions = hazelcastInstance.getMap(domainURI + "/ContributionDescriptions"); + ((IMap<String, ContributionDescription>)contributionDescriptions).addEntryListener(new EntryListener<String, ContributionDescription>() { + public void entryAdded(EntryEvent<String, ContributionDescription> event) { + } + public void entryRemoved(EntryEvent<String, ContributionDescription> event) { + for (ContributionListener listener : contributionlisteners) { + listener.contributionRemoved(event.getKey()); + } + } + public void entryUpdated(EntryEvent<String, ContributionDescription> event) { + for (ContributionListener listener : contributionlisteners) { + listener.contributionUpdated(event.getKey()); + } + } + public void entryEvicted(EntryEvent<String, ContributionDescription> event) { + } + }, false); + + hazelcastInstance.getCluster().addMembershipListener(this); +// } + } + + public void stop() { + if (hazelcastInstance != null) { + synchronized (shutdownMutex) { + hazelcastInstance.shutdown(); + hazelcastInstance = null; + endpointMap = null; + endpointOwners = null; + runningComposites = null; + runningCompositeOwners = null; + } + } + } + + private void initHazelcastInstance() { + + // Hazelcast is outputs a lot on info level log messages which are unnecessary for us, + // so disable info logging for hazelcast client classes unless fine logging is on for tuscany. + if (!logger.isLoggable(Level.CONFIG)) { + Logger hzl = Logger.getLogger("com.hazelcast"); + if (!hzl.isLoggable(Level.FINE)) { + hzl.setLevel(Level.WARNING); + // we want the ClusterManager info messages so we can see nodes come and go + Logger.getLogger("com.hazelcast.cluster.ClusterManager").setLevel(Level.INFO); + // we don't want any of the XmlConfigBuilder warnings as set the config programatically + Logger.getLogger("com.hazelcast.config.XmlConfigBuilder").setLevel(Level.SEVERE); + } + } + + Config config = getHazelcastConfig(); + + // do this when theres a way to have adders be the key owners + // config.getMapConfig(configURI.getDomainName() + "/Endpoints").setBackupCount(0); + + // this caches reads locally + config.getMapConfig("default").setNearCacheConfig(new NearCacheConfig(0, 0, "NONE", 0, true)); + + // Disable the Hazelcast shutdown hook as Tuscany has its own and with both there are race conditions + config.setProperty("hazelcast.shutdownhook.enabled", + // GroupProperties.PROP_SHUTDOWNHOOK_ENABLED, + "false"); + + // By default this is 5 seconds, not sure what the implications are but dropping it down to 1 makes + // things like the samples look much faster + config.setProperty("hazelcast.wait.seconds.before.join", + // GroupProperties.PROP_WAIT_SECONDS_BEFORE_JOIN, + "1"); + + this.hazelcastInstance = Hazelcast.newHazelcastInstance(config); + if (logger.isLoggable(Level.INFO)) { + logger.info("started node in domain '" + domainURI + "' + at: " + hazelcastInstance.getCluster().getLocalMember().getInetSocketAddress()); + } + } + + protected Config getHazelcastConfig() { + Config config; + this.properties = registry.getExtensionPoint(UtilityExtensionPoint.class).getUtility(RuntimeProperties.class).getProperties(); + String configFile = properties.getProperty("hazelcastConfig"); + if (configFile != null) { + try { + config = new XmlConfigBuilder(configFile).build(); + } catch (FileNotFoundException e) { + throw new IllegalArgumentException(configFile, e); + } + } else { + // TUSCANY-3675 - domainRegistryURI properties don't seem to be copied into the + // properties collection anywhere + config = new XmlConfigBuilder().build(); + RegistryConfig rc = RegistryConfig.parseConfigURI(domainRegistryURI); + config.setPort(rc.getBindPort()); + //config.setPortAutoIncrement(false); + + if (!rc.getBindAddress().equals("*")) { + config.getNetworkConfig().getInterfaces().setEnabled(true); + config.getNetworkConfig().getInterfaces().clear(); + config.getNetworkConfig().getInterfaces().addInterface(rc.getBindAddress()); + } + + config.getGroupConfig().setName(rc.getUserid()); + config.getGroupConfig().setPassword(rc.getPassword()); + + if (rc.isMulticastDisabled()) { + config.getNetworkConfig().getJoin().getMulticastConfig().setEnabled(false); + } else { + config.getNetworkConfig().getJoin().getMulticastConfig().setEnabled(true); + config.getNetworkConfig().getJoin().getMulticastConfig().setMulticastPort(rc.getMulticastPort()); + config.getNetworkConfig().getJoin().getMulticastConfig().setMulticastGroup(rc.getMulticastAddress()); + } + + if (rc.getWKAs().size() > 0) { + TcpIpConfig tcpconfig = config.getNetworkConfig().getJoin().getTcpIpConfig(); + tcpconfig.setEnabled(true); + List<Address> lsMembers = tcpconfig.getAddresses(); + lsMembers.clear(); + for (String addr : rc.getWKAs()) { + String[] ipNPort = addr.split(":"); + try { + lsMembers.add(new Address(ipNPort[0], Integer.parseInt(ipNPort[1]))); + } catch (UnknownHostException e) { + throw new RuntimeException(e); + } + } + } + } + return config; + } + + public void addEndpoint(Endpoint endpoint) { + if (findEndpoint(endpoint.getURI()).size() > 0) { + Member m = getOwningMember(endpoint.getURI()); + throw new IllegalStateException("Endpoint " + endpoint.getURI() + " already exists in domain " + domainURI + " at " + (m == null? "null" : m.getInetSocketAddress())); + } + + String localMemberAddr = hazelcastInstance.getCluster().getLocalMember().getInetSocketAddress().toString(); + String endpointURI = endpoint.getURI(); + String componentName = endpoint.getComponent().getName(); + String curi = null; + if (endpoint instanceof RuntimeEndpoint) { + Composite dc = ((RuntimeEndpoint)endpoint).getCompositeContext().getDomainComposite(); + if (dc != null) { + curi = dc.getContributionURI(); + } + } + Transaction txn = hazelcastInstance.getTransaction(); + txn.begin(); + try { + localEndpoints.put(endpointURI, endpoint); + endpointMap.put(endpointURI, endpoint); + endpointOwners.put(localMemberAddr, endpointURI); + if (curi != null) { + runningComponentContributions.put(componentName, curi); + } + txn.commit(); + } catch (Throwable e) { + txn.rollback(); + throw new ServiceRuntimeException(e); + } + logger.info("Add endpoint - " + endpoint); + } + + public List<Endpoint> findEndpoint(String uri) { + List<Endpoint> foundEndpoints = new ArrayList<Endpoint>(); + for (Object v : endpointMap.values()) { + Endpoint endpoint = (Endpoint)v; + logger.fine("Matching against - " + endpoint); + if (endpoint.matches(uri)) { + endpoint = localizeEndpoint(endpoint); + foundEndpoints.add(endpoint); + logger.fine("Found endpoint with matching service - " + endpoint); + } + } + return foundEndpoints; + } + + private Endpoint localizeEndpoint(Endpoint endpoint) { + if (endpoint == null) return null; + if (!isLocal(endpoint)) { + endpoint.setRemote(true); + ((RuntimeEndpoint)endpoint).bind(registry, this); + } else { + // get the local version of the endpoint + // this local version won't have been serialized + // won't be marked as remote and will have the + // full interface contract information + endpoint = localEndpoints.get(endpoint.getURI()); + } + return endpoint; + } + + private boolean isLocal(Endpoint endpoint) { + return localEndpoints.containsKey(endpoint.getURI()); + } + + public Endpoint getEndpoint(String uri) { + return localizeEndpoint((Endpoint)endpointMap.get(uri)); + } + + public List<Endpoint> getEndpoints() { + ArrayList<Endpoint> eps = new ArrayList(); + for (Object ep : endpointMap.values()) { + eps.add(localizeEndpoint((Endpoint)ep)); + } + return eps; + } + + public void removeEndpoint(Endpoint endpoint) { + if (hazelcastInstance == null) { + return; + } + synchronized (shutdownMutex) { + String localMemberAddr = hazelcastInstance.getCluster().getLocalMember().getInetSocketAddress().toString(); + String endpointURI = endpoint.getURI(); + String componentName = endpoint.getComponent().getName(); + Transaction txn = hazelcastInstance.getTransaction(); + txn.begin(); + try { + endpointOwners.remove(localMemberAddr, endpointURI); + endpointMap.remove(endpointURI); + runningComponentContributions.remove(componentName); + txn.commit(); + } catch (Throwable e) { + txn.rollback(); + throw new ServiceRuntimeException(e); + } + localEndpoints.remove(endpointURI); + logger.info("Removed endpoint - " + endpoint); + } + } + + + public void entryAdded(EntryEvent<String, Endpoint> event) { + entryAdded(event.getKey(), event.getValue()); + } + + public void entryEvicted(EntryEvent<String, Endpoint> event) { + // Should not happen + } + + public void entryRemoved(EntryEvent<String, Endpoint> event) { + entryRemoved(event.getKey(), event.getValue()); + } + + public void entryUpdated(EntryEvent<String, Endpoint> event) { + entryUpdated(event.getKey(), null, event.getValue()); + } + + public void entryAdded(Object key, Object value) { + Endpoint newEp = (Endpoint)value; + if (!isLocal(newEp)) { + logger.info(" Remote endpoint added: " + newEp); + } + endpointAdded(newEp); + } + + public void entryRemoved(Object key, Object value) { + Endpoint oldEp = (Endpoint)value; + if (!isLocal(oldEp)) { + logger.info(" Remote endpoint removed: " + value); + } + endpointRemoved(oldEp); + } + + public void entryUpdated(Object key, Object oldValue, Object newValue) { + Endpoint oldEp = (Endpoint)oldValue; + Endpoint newEp = (Endpoint)newValue; + if (!isLocal(newEp)) { + logger.info(" Remote endpoint updated: " + newEp); + } + endpointUpdated(oldEp, newEp); + } + + public void memberAdded(MembershipEvent event) { + } + + public void memberRemoved(MembershipEvent event) { + try { + String memberAddr = event.getMember().getInetSocketAddress().toString(); + if (endpointOwners.containsKey(memberAddr)) { + synchronized (shutdownMutex) { + ILock lock = hazelcastInstance.getLock("EndpointOwners/" + memberAddr); + lock.lock(); + try { + if (endpointOwners.containsKey(memberAddr)) { + Collection<String> keys = endpointOwners.remove(memberAddr); + for (Object k : keys) { + Endpoint endpoint = (Endpoint)endpointMap.remove(k); + runningComponentContributions.remove(endpoint.getComponent().getName()); + } + } + if (runningCompositeOwners.containsKey(memberAddr)) { + Map<String, List<String>> cs = runningCompositeOwners.remove(memberAddr); + for (String curi : cs.keySet()) { + Map<String, String> rcs = runningComposites.get(curi); + for (String uri : cs.get(curi)) { + rcs.remove(uri); + } + } + } + } finally { + lock.unlock(); + } + } + } + } catch (Exception e) { + if (e.getCause() != null && e.getCause().getCause() != null) { + // ignore hazelcast already shutdown exception + if (!"Hazelcast Instance is not active!".equals(e.getCause().getCause().getMessage())) { + throw new ServiceRuntimeException(e); + } + } + } + } + + public Member getOwningMember(String serviceURI) { + for (String memberAddr : endpointOwners.keySet()) { + for (String service : endpointOwners.get(memberAddr)) { + Endpoint ep = assemblyFactory.createEndpoint(); + ep.setURI(service); + if (ep.matches(serviceURI)) { + for (Member m : getHazelcastInstance().getCluster().getMembers()) { + if (memberAddr.equals(m.getInetSocketAddress().toString())) { + return m; + } + } + } + } + } + return null; + } + + public void addRunningComposite(String curi, Composite composite) { + String localMemberAddr = hazelcastInstance.getCluster().getLocalMember().getInetSocketAddress().toString(); + String compositeXML = writeComposite(composite); + Transaction txn = hazelcastInstance.getTransaction(); + txn.begin(); + try { + Map<String, String> cs = runningComposites.get(curi); + if (cs == null) { + cs = new HashMap<String, String>(); + } + cs.put(composite.getURI(), compositeXML); + runningComposites.put(curi, cs); + Map<String, List<String>> ocs = runningCompositeOwners.get(localMemberAddr); + if (ocs == null) { + ocs = new HashMap<String, List<String>>(); + } + List<String> lcs = ocs.get(curi); + if (lcs == null) { + lcs = new ArrayList<String>(); + ocs.put(curi, lcs); + } + lcs.add(composite.getURI()); + runningCompositeOwners.put(localMemberAddr, ocs); + txn.commit(); + } catch (Throwable e) { + txn.rollback(); + throw new ServiceRuntimeException(e); + } + } + + public void removeRunningComposite(String curi, String compositeURI) { + String localMemberAddr = hazelcastInstance.getCluster().getLocalMember().getInetSocketAddress().toString(); + Transaction txn = hazelcastInstance.getTransaction(); + txn.begin(); + try { + Map<String, String> cs = runningComposites.get(curi); + if (cs != null) { + cs.remove(compositeURI); + if (cs.size() > 0) { + runningComposites.put(curi, cs); + } else { + runningComposites.remove(curi); + } + } + Map<String, List<String>> ocs = runningCompositeOwners.get(localMemberAddr); + if (ocs != null) { + List<String> xya = ocs.get(curi); + if (xya != null) { + xya.remove(compositeURI); + if (xya.size() > 0) { + runningCompositeOwners.put(localMemberAddr, ocs); + } else { + runningCompositeOwners.remove(localMemberAddr); + } + } + } + txn.commit(); + } catch (Throwable e) { + txn.rollback(); + throw new ServiceRuntimeException(e); + } + } + + public Map<String, List<String>> getRunningCompositeURIs() { + Map<String, List<String>> compositeURIs = new HashMap<String, List<String>>(); + for (String curi : runningComposites.keySet()) { + List<String> uris = new ArrayList<String>(); + compositeURIs.put(curi, uris); + for (String uri : runningComposites.get(curi).keySet()) { + uris.add(uri); + } + } + return compositeURIs; + } + + @Override + public Composite getRunningComposite(String contributionURI, String compositeURI) { + Map<String, String> cs = runningComposites.get(contributionURI); + if (cs != null) { + String compositeXML = cs.get(compositeURI); + // TODO: cache the Composite locally so that it doesn't get deserialized multiple times + Composite composite = readComposite(compositeXML); + composite.setContributionURI(contributionURI); + return composite; + } + return null; + } + + protected Composite readComposite(String compositeXML) { + try { + StAXHelper stAXHelper = StAXHelper.getInstance(registry); + StAXArtifactProcessorExtensionPoint staxProcessors = registry.getExtensionPoint(StAXArtifactProcessorExtensionPoint.class); + ExtensibleStAXArtifactProcessor staxProcessor = new ExtensibleStAXArtifactProcessor(staxProcessors, stAXHelper.getInputFactory(), null); + XMLStreamReader reader = stAXHelper.createXMLStreamReader(compositeXML); + Composite composite = (Composite)staxProcessor.read(reader, new ProcessorContext(registry)); + return composite; + } catch (XMLStreamException e) { + throw new RuntimeException(e); + } catch (ContributionReadException e) { + throw new RuntimeException(e); + } + } + + protected String writeComposite(Composite composite) { + try { + StAXHelper stAXHelper = StAXHelper.getInstance(registry); + StAXArtifactProcessorExtensionPoint staxProcessors = registry.getExtensionPoint(StAXArtifactProcessorExtensionPoint.class); + ExtensibleStAXArtifactProcessor staxProcessor = new ExtensibleStAXArtifactProcessor(staxProcessors, null, stAXHelper.getOutputFactory()); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + staxProcessor.write(composite, bos, new ProcessorContext(registry)); + bos.close(); + return bos.toString(); + } catch (ContributionWriteException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public List<String> getInstalledContributionURIs() { + return new ArrayList<String>(contributionDescriptions.keySet()); + } + + public ContributionDescription getInstalledContribution(String uri) { + return contributionDescriptions.get(uri); + } + + public void uninstallContribution(String uri) { + contributionDescriptions.remove(uri); + } + + @Override + public void installContribution(ContributionDescription cd) { + contributionDescriptions.put(cd.getURI(), cd); + } + + @Override + public void updateInstalledContribution(ContributionDescription cd) { + contributionDescriptions.put(cd.getURI(), cd); + } + + @Override + public List<String> getNodeNames() { + List<String> members = new ArrayList<String>(); + for (Member m : hazelcastInstance.getCluster().getMembers()) { + if (!m.isSuperClient()) { + members.add(m.getInetSocketAddress().toString()); + } + } + return members; + } + + @Override + public String getLocalNodeName() { + return hazelcastInstance.getCluster().getLocalMember().getInetSocketAddress().toString(); + } + + @Override + public String getRunningNodeName(String contributionURI, String compositeURI) { + for (String m : runningCompositeOwners.keySet()) { + Map<String, List<String>> rcs = runningCompositeOwners.get(m); + if (rcs != null) { + List<String> cs = rcs.get(contributionURI); + if (cs != null && cs.contains(compositeURI)) { + return m; + } + } + } + return null; + } + + @Override + public String remoteCommand(String memberName, Callable<String> command) { + for (Member member : hazelcastInstance.getCluster().getMembers()) { + if (member.getInetSocketAddress().toString().equals(memberName)) { + FutureTask<String> task = new DistributedTask<String>(command, member); + hazelcastInstance.getExecutorService().execute(task); + try { + return task.get(); + } catch (Exception e) { + throw new ServiceRuntimeException(e); + } + } + } + throw new IllegalArgumentException("member not found: " + memberName); + } + + @Override + public String getContainingCompositesContributionURI(String componentName) { + int x = runningComponentContributions.size(); + return runningComponentContributions.get(componentName); + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/registry/hazelcast/HazelcastDomainRegistryFactory.java b/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/registry/hazelcast/HazelcastDomainRegistryFactory.java new file mode 100644 index 0000000000..ca75679caa --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/registry/hazelcast/HazelcastDomainRegistryFactory.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.sca.registry.hazelcast; + +import java.util.Properties; + +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.UtilityExtensionPoint; +import org.apache.tuscany.sca.runtime.BaseDomainRegistryFactory; +import org.apache.tuscany.sca.runtime.DomainRegistry; +import org.apache.tuscany.sca.runtime.RuntimeProperties; + +/** + * The utility responsible for finding the endpoint regstry by the scheme and creating instances for the + * given domain + */ +public class HazelcastDomainRegistryFactory extends BaseDomainRegistryFactory { + private final static String[] schemes = new String[] {"multicast", "wka", "tuscany", "hazelcast", "uri"}; + + public HazelcastDomainRegistryFactory(ExtensionPointRegistry registry) { + super(registry); + } + + protected DomainRegistry createEndpointRegistry(String domainURI, String domainName) { + Properties properties = registry.getExtensionPoint(UtilityExtensionPoint.class).getUtility(RuntimeProperties.class).getProperties(); + return new HazelcastDomainRegistry(registry, properties, domainURI, domainName); + } + + public String[] getSupportedSchemes() { + return schemes; + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/registry/hazelcast/RegistryConfig.java b/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/registry/hazelcast/RegistryConfig.java new file mode 100644 index 0000000000..316abc7e2d --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/registry/hazelcast/RegistryConfig.java @@ -0,0 +1,177 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.registry.hazelcast; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + + +/** + * Utility to parse the config properties. + * + * bind - ip[:port] - defines the local bind address and port, it defaults port 14820 and if that port in use it will try + * incrementing by one till a free port is found. + * + * multicast - groupip:port | off - defines if multicast discovery is used and if so what multicast ip group and port is used + * defaults to 224.5.12.10:51482. A value of off means multicast is disabled. + * + * wka - ip[:port] - a comma separated list of ip address and port for remote nodes in the domain group. The port defaults to 14820. + * + * userid - is the userid other nodes must use to connect to this domain group. The default is the default domain name. + * + * password - is the password other nodes must use to connect to this domain group. The default is 'tuscany'. + * + * client - true means this is an SCAClient call + * + */ +public class RegistryConfig { + + private String bindAddress = "*"; + private int bindPort = 14820; + private boolean multicastDisabled = false; + private String multicastAddress = "224.5.12.10"; + private int multicastPort = 51482; + private List<String> wkas = new ArrayList<String>(); + private String userid; + private String password; + boolean client; + + public RegistryConfig(Properties properties) { + init(properties); + } + + private void init(Properties properties) { + + String bindValue = properties.getProperty("bind"); + if (bindValue != null) { + if (bindValue.indexOf(":") == -1) { + this.bindAddress = bindValue; + } else { + String[] addr = bindValue.split(":"); + this.bindAddress = addr[0]; + this.bindPort = Integer.parseInt(addr[1]); + } + } + + String multicastValue = properties.getProperty("multicast"); + if (multicastValue != null) { + if ("off".equalsIgnoreCase(multicastValue)) { + this.multicastDisabled = true; + } else { + if (multicastValue.indexOf(":") == -1) { + this.multicastAddress = multicastValue; + } else { + String[] addr = multicastValue.split(":"); + this.multicastAddress = addr[0]; + this.multicastPort = Integer.parseInt(addr[1]); + } + } + } + + String wkaValue = properties.getProperty("wka"); + if (wkaValue != null) { + String[] ips = wkaValue.split(","); + for (String ip : ips) { + if (ip.indexOf(":") == -1) { + wkas.add(ip + ":14820"); + } else { + wkas.add(ip); + } + } + } + + this.client = Boolean.parseBoolean(properties.getProperty("client", "false")); + this.password = properties.getProperty("password", "tuscany"); + this.userid = properties.getProperty("userid", properties.getProperty("defaultDomainName", "default")); + + } + + public String getBindAddress() { + return bindAddress; + } + + public int getBindPort() { + return bindPort; + } + + public boolean isMulticastDisabled() { + return multicastDisabled; + } + + public String getMulticastAddress() { + return multicastAddress; + } + + public int getMulticastPort() { + return multicastPort; + } + + public List<String> getWKAs() { + return wkas; + } + + public String getUserid() { + return userid; + } + public String getPassword() { + return password; + } + + /** + * Parse the config string into a Properties object. + * The config URI has the following format: + * uri:<domainName>?name=value&... + */ + public static RegistryConfig parseConfigURI(String configURI) { + Properties properties = new Properties(); + int c = configURI.indexOf(':'); + if (c > -1) { + configURI = configURI.substring(c+1); + } + int qm = configURI.indexOf('?'); + if (qm < 0) { + properties.setProperty("defaultDomainName", configURI); + } else { + if (qm == 0) { + properties.setProperty("defaultDomainName", "default"); + } else { + properties.setProperty("defaultDomainName", configURI.substring(0, qm)); + } + if (configURI.length() > qm+1) { + Map<String, String> params = new HashMap<String, String>(); + for (String param : configURI.substring(qm+1).split("&")) { + String[] px = param.split("="); + if (px.length == 2) { + params.put(px[0], px[1]); + } else { + params.put(px[0], ""); + } + } + for (String name : params.keySet()) { + properties.setProperty(name, params.get(name)); + } + } + } + return new RegistryConfig(properties); + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/registry/hazelcast/client/HazelcastClientDomainRegistryFactory.java b/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/registry/hazelcast/client/HazelcastClientDomainRegistryFactory.java new file mode 100644 index 0000000000..5193b577da --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/registry/hazelcast/client/HazelcastClientDomainRegistryFactory.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.sca.registry.hazelcast.client; + +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.runtime.BaseDomainRegistryFactory; +import org.apache.tuscany.sca.runtime.DomainRegistry; + +/** + * The utility responsible for finding the endpoint regstry by the scheme and creating instances for the + * given domain + */ +public class HazelcastClientDomainRegistryFactory extends BaseDomainRegistryFactory { + private final static String[] schemes = new String[] {"hazelcastclient", "tuscanyclient"}; + + /** + * @param extensionRegistry + */ + public HazelcastClientDomainRegistryFactory(ExtensionPointRegistry registry) { + super(registry); + } + + protected DomainRegistry createEndpointRegistry(String endpointRegistryURI, String domainURI) { + DomainRegistry domainRegistry = + new HazelcastClientEndpointRegistry(registry, null, endpointRegistryURI, domainURI); + return domainRegistry; + } + + public String[] getSupportedSchemes() { + return schemes; + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/registry/hazelcast/client/HazelcastClientEndpointRegistry.java b/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/registry/hazelcast/client/HazelcastClientEndpointRegistry.java new file mode 100644 index 0000000000..972bd43075 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/domain-hazelcast/src/main/java/org/apache/tuscany/sca/registry/hazelcast/client/HazelcastClientEndpointRegistry.java @@ -0,0 +1,132 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.registry.hazelcast.client; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.UtilityExtensionPoint; +import org.apache.tuscany.sca.registry.hazelcast.HazelcastDomainRegistry; +import org.apache.tuscany.sca.registry.hazelcast.RegistryConfig; +import org.apache.tuscany.sca.runtime.RuntimeProperties; + +import com.hazelcast.client.ClientProperties; +import com.hazelcast.client.ClientProperties.ClientPropertyName; +import com.hazelcast.client.HazelcastClient; +import com.hazelcast.core.HazelcastInstance; + +/** + * An DomainRegistry using a Hazelcast Native Client + */ +public class HazelcastClientEndpointRegistry extends HazelcastDomainRegistry { + + RegistryConfig rc; + HazelcastClient hazelcastClient; + + public HazelcastClientEndpointRegistry(ExtensionPointRegistry registry, + Map<String, String> attributes, + String domainRegistryURI, + String domainURI) { + super(registry, attributes, domainRegistryURI, domainURI); + } + + @Override + public void start() { + if (endpointMap != null) { + throw new IllegalStateException("The registry has already been started"); + } + initHazelcastClientInstance(); + endpointMap = hazelcastClient.getMap(rc.getUserid() + "/Endpoints"); + endpointOwners = hazelcastClient.getMultiMap(rc.getUserid() + "/EndpointOwners"); + runningComponentContributions = hazelcastClient.getMap(rc.getUserid() + "/RunningComponentContributions"); + contributionDescriptions = hazelcastClient.getMap(rc.getUserid() + "/ContributionDescriptions"); + } + + @Override + public void stop() { + if (hazelcastClient != null) { + hazelcastClient.shutdown(); + hazelcastClient = null; + endpointMap = null; + } + } + + private void initHazelcastClientInstance() { + if (this.domainURI == null) { + this.properties = registry.getExtensionPoint(UtilityExtensionPoint.class).getUtility(RuntimeProperties.class).getProperties(); + this.domainURI = properties.getProperty("defaultDomainName", "default"); + } + this.rc = RegistryConfig.parseConfigURI(domainURI); + if (rc.getWKAs().size() < 1) { + String ip = getDefaultWKA(); + if (ip != null) { + rc.getWKAs().add(ip); + } + } + if (rc.getWKAs().size() < 1) { + throw new IllegalArgumentException("No local domain instance found, please use domain URI 'wka=' argument to define IP address(es) for domain"); + } + + // Hazelcast is outputs a lot on info level log messages which are unnecessary for us, + // so disable info logging for hazelcast client classes unless fine logging is on for tuscany. + if (!Logger.getLogger(this.getClass().getName()).isLoggable(Level.CONFIG)) { + Logger hzl = Logger.getLogger("com.hazelcast"); + if (!hzl.isLoggable(Level.FINE)) { + hzl.setLevel(Level.WARNING); + } + } + + ClientProperties clientProps = ClientProperties.crateBaseClientProperties(rc.getUserid(), rc.getPassword()); + clientProps.setPropertyValue(ClientPropertyName.INIT_CONNECTION_ATTEMPTS_LIMIT, "1"); + this.hazelcastClient = HazelcastClient.newHazelcastClient(clientProps, rc.getWKAs().toArray(new String[0])); + } + + @Override + public HazelcastInstance getHazelcastInstance() { + return hazelcastClient; + } + + /** + * As a default connect to a local runtime instance listening on port 14820 + */ + protected static String getDefaultWKA() { + Socket s = null; + try { + s = new Socket(InetAddress.getLocalHost(), 14820); + if (s.isConnected()) { + return s.getInetAddress().getHostAddress() + ":14820"; + } + } catch (IOException e) { + } finally { + if (s != null) { + try { + s.close(); + } catch (IOException e) { + } + } + } + return null; + } +} |