diff options
Diffstat (limited to 'branches/sca-android/modules/host-corba-jse/src/main/java')
7 files changed, 1909 insertions, 0 deletions
diff --git a/branches/sca-android/modules/host-corba-jse/src/main/java/org/apache/tuscany/sca/host/corba/jse/CorbaRuntimeModuleActivator.java b/branches/sca-android/modules/host-corba-jse/src/main/java/org/apache/tuscany/sca/host/corba/jse/CorbaRuntimeModuleActivator.java new file mode 100644 index 0000000000..252a1512e4 --- /dev/null +++ b/branches/sca-android/modules/host-corba-jse/src/main/java/org/apache/tuscany/sca/host/corba/jse/CorbaRuntimeModuleActivator.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.host.corba.jse; + +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.ModuleActivator; +import org.apache.tuscany.sca.host.corba.CorbaHostExtensionPoint; + +/** + * @version $Rev$ $Date$ + */ +public class CorbaRuntimeModuleActivator implements ModuleActivator { + // private static final Logger logger = + // Logger.getLogger(CorbaRuntimeModuleActivator.class.getName()); + + private DefaultCorbaHost server; + + public void start(ExtensionPointRegistry extensionPointRegistry) { + + // Register our Corba host + CorbaHostExtensionPoint corbaHosts = extensionPointRegistry.getExtensionPoint(CorbaHostExtensionPoint.class); + server = new DefaultCorbaHost(); + corbaHosts.addCorbaHost(server); + } + + public void stop(ExtensionPointRegistry registry) { + if (server != null) { + server.stop(); + } + } + +} diff --git a/branches/sca-android/modules/host-corba-jse/src/main/java/org/apache/tuscany/sca/host/corba/jse/DefaultCorbaHost.java b/branches/sca-android/modules/host-corba-jse/src/main/java/org/apache/tuscany/sca/host/corba/jse/DefaultCorbaHost.java new file mode 100644 index 0000000000..015644e19d --- /dev/null +++ b/branches/sca-android/modules/host-corba-jse/src/main/java/org/apache/tuscany/sca/host/corba/jse/DefaultCorbaHost.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.sca.host.corba.jse; + +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.apache.tuscany.sca.host.corba.CorbaHost; +import org.apache.tuscany.sca.host.corba.CorbaHostException; +import org.apache.tuscany.sca.host.corba.CorbaHostUtils; +import org.apache.tuscany.sca.host.corba.CorbanameURL; +import org.omg.CORBA.ORB; +import org.omg.CORBA.Object; +import org.omg.CosNaming.NameComponent; +import org.omg.CosNaming.NamingContext; +import org.omg.CosNaming.NamingContextExt; +import org.omg.CosNaming.NamingContextExtHelper; +import org.omg.CosNaming.NamingContextHelper; +import org.omg.CosNaming.NamingContextPackage.InvalidName; +import org.omg.CosNaming.NamingContextPackage.NotFound; + +/** + * @version $Rev$ $Date$ + * Default implementation of JSE CORBA host + */ +public class DefaultCorbaHost implements CorbaHost { + private static final Logger logger = Logger.getLogger(DefaultCorbaHost.class.getName()); + + private Map<String, ORB> orbs = new ConcurrentHashMap<String, ORB>(); + + private void validatePort(int port) throws IllegalArgumentException { + if (port < 1) { + throw new IllegalArgumentException("Port value should be > 0"); + } + } + + private NamingContextExt getNamingContext(ORB orb, String nameService) throws Exception { + org.omg.CORBA.Object objRef = orb.resolve_initial_references(nameService); + return NamingContextExtHelper.narrow(objRef); + } + + private void handleException(Exception e) throws CorbaHostException { + // The cause of the Exception is JDK specific + if (e instanceof NotFound) { + throw new CorbaHostException(CorbaHostException.NO_SUCH_OBJECT, e); + } else if (e instanceof InvalidName) { + throw new CorbaHostException(e); + } else { + throw new CorbaHostException(e); + } + } + + public void registerServant(String uri, Object servantObject) throws CorbaHostException { + CorbanameURL details = CorbaHostUtils.getServiceDetails(uri); + ORB orb = createORB(details.getHost(), details.getPort(), false); + try { + NamingContext namingCtx = getNamingContext(orb, details.getNameService()); + for (int i = 0; i < details.getNamePath().size() - 1; i++) { + NameComponent nc = new NameComponent(details.getNamePath().get(i), ""); + NameComponent[] path = new NameComponent[] {nc}; + try { + namingCtx = NamingContextHelper.narrow(namingCtx.resolve(path)); + } catch (Exception e) { + namingCtx = namingCtx.bind_new_context(path); + } + } + NameComponent finalName = + new NameComponent(details.getNamePath().get(details.getNamePath().size() - 1), ""); + try { + namingCtx.resolve(new NameComponent[] {finalName}); + // no exception means that some object is already registered + // under this name, we need to crash here + throw new CorbaHostException(CorbaHostException.BINDING_IN_USE); + } catch (NotFound e) { + namingCtx.bind(new NameComponent[] {finalName}, servantObject); + } + } catch (CorbaHostException e) { + throw e; + } catch (Exception e) { + handleException(e); + } + } + + public void unregisterServant(String uri) throws CorbaHostException { + CorbanameURL details = CorbaHostUtils.getServiceDetails(uri); + ORB orb = createORB(details.getHost(), details.getPort(), false); + try { + NamingContextExt namingCtx = getNamingContext(orb, details.getNameService()); + namingCtx.unbind(namingCtx.to_name(details.getName())); + } catch (Exception e) { + handleException(e); + } + } + + public Object lookup(String uri) throws CorbaHostException { + Object result = null; + try { + CorbanameURL url = new CorbanameURL(uri); + ORB orb = createORB(url.getHost(), url.getPort(), false); + NamingContextExt context = getNamingContext(orb, url.getNameService()); + result = context.resolve_str(url.getName()); + } catch (Exception e) { + handleException(e); + } + if (result == null) { + throw new CorbaHostException(CorbaHostException.NO_SUCH_OBJECT); + } + return result; + } + + public ORB createORB(String host, int port, boolean server) throws CorbaHostException { + validatePort(port); + + String key = host + ":" + port; + ORB orb = orbs.get(key); + if (orb != null) { + return orb; + } + // Create an ORB object + Properties props = new Properties(); + props.putAll(System.getProperties()); + + String portStr = String.valueOf(port); + props.put("org.omg.CORBA.ORBServerId", "1000000"); + props.put("org.omg.CORBA.ORBInitialHost", host); + props.put("org.omg.CORBA.ORBInitialPort", portStr); + + // STEP 1: Set ORBPeristentServerPort property + // Set the proprietary property to open up a port to listen to + // INS requests. + + if (server) { + props.put("com.sun.CORBA.POA.ORBPersistentServerPort", portStr); + props.put("com.ibm.CORBA.ListenerPort", portStr); + props.put("gnu.CORBA.ListenerPort", portStr); + // props.put("org.omg.CORBA.ORBClass", + // "org.apache.yoko.orb.CORBA.ORB"); + // props.put("org.omg.CORBA.ORBSingletonClass", + // "org.apache.yoko.orb.CORBA.ORBSingleton"); + props.put("yoko.orb.oa.endpoint", "iiop --host " + host + " --port " + port); + props.put("yoko.orb.poamanager.TNameService.endpoint", "iiop --host " + host); + } + + String[] args = {"-ORBInitialHost", host, "-ORBInitialPort", "" + port}; + orb = ORB.init(args, props); + orbs.put(key, orb); + return orb; + } + + public void stop() { + for (ORB orb : orbs.values()) { + try { + orb.shutdown(true); + orb.destroy(); + } catch (Throwable e) { + logger.log(Level.SEVERE, e.getMessage(), e); + } + } + } + +} diff --git a/branches/sca-android/modules/host-corba-jse/src/main/java/org/apache/tuscany/sca/host/corba/naming/NamingContextBase.java b/branches/sca-android/modules/host-corba-jse/src/main/java/org/apache/tuscany/sca/host/corba/naming/NamingContextBase.java new file mode 100644 index 0000000000..59f0ce9a53 --- /dev/null +++ b/branches/sca-android/modules/host-corba-jse/src/main/java/org/apache/tuscany/sca/host/corba/naming/NamingContextBase.java @@ -0,0 +1,863 @@ +/* + * 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. + */ +/** + * @version $Rev$ $Date$ + */ + +package org.apache.tuscany.sca.host.corba.naming; + +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.omg.CORBA.BAD_PARAM; +import org.omg.CORBA.CompletionStatus; +import org.omg.CORBA.ORB; +import org.omg.CORBA.SystemException; +import org.omg.CosNaming.BindingType; +import org.omg.CosNaming.BindingTypeHolder; +import org.omg.CosNaming.NameComponent; +import org.omg.CosNaming.NamingContext; +import org.omg.CosNaming.NamingContextExtPOA; +import org.omg.CosNaming.NamingContextHelper; +import org.omg.CosNaming.NamingContextExtPackage.InvalidAddress; +import org.omg.CosNaming.NamingContextPackage.AlreadyBound; +import org.omg.CosNaming.NamingContextPackage.InvalidName; +import org.omg.CosNaming.NamingContextPackage.NotFound; +import org.omg.CosNaming.NamingContextPackage.NotFoundReason; +import org.omg.PortableServer.POA; + +public abstract class NamingContextBase extends NamingContextExtPOA { + // the real logger backing instance. We use the interface class as the locator + protected static final Logger logger = Logger.getLogger(NamingContext.class.getName()); + + // set of URL characters that don't require escaping when encoded. + protected final String nonEscaped = ";/?:@&=+$;-_.!~* ()"; + // the orb we're attached to + protected ORB orb; + // the poa we're associated with + protected POA poa; + + /** + * Create a new base NamingContext (super class constructor + * for the derived classes). + * + * @param orb The ORB this is hosted on. + * + * @exception java.lang.Exception + */ + public NamingContextBase(ORB orb, POA poa) throws java.lang.Exception { + super(); + this.orb = orb; + this.poa = poa; + } + + /** + * Bind an object to a given name. + * + * @param n An array of NameComponents that are the target name. + * The last element in the array is binding name for the + * object. The remainder of the array is the path + * for resolving the naming context, relative to the + * current context. All path contexts must already be + * bound in the context tree. + * @param obj The object to be bound. + * + * @exception org.omg.CosNaming.NamingContextPackage.NotFound + * @exception org.omg.CosNaming.NamingContextPackage.CannotProceed + * @exception org.omg.CosNaming.NamingContextPackage.InvalidName + * @exception org.omg.CosNaming.NamingContextPackage.AlreadyBound + */ + public void bind(org.omg.CosNaming.NameComponent[] n, org.omg.CORBA.Object obj) + throws org.omg.CosNaming.NamingContextPackage.NotFound, org.omg.CosNaming.NamingContextPackage.CannotProceed, + org.omg.CosNaming.NamingContextPackage.InvalidName, org.omg.CosNaming.NamingContextPackage.AlreadyBound { + // perform various name validations + validateName(n); + + logNameComponent("bind() name", n); + + // do we need to push through to a deeper naming context first? + if (n.length > 1) { + // resolve the top level name to a context, and have that context + // resolve the rest. + NamingContext context = resolveContext(n[0]); + NameComponent[] subName = extractSubName(n); + + // now pass this along to the next context for the real bind operation. + context.bind(subName, obj); + } else { + NameComponent name = n[0]; + // we need the resolveObject() and bindObject() calls to be consistent, so + // synchronize on this + synchronized (this) { + // see if we have this bound already...can't replace these. + BindingTypeHolder type = new BindingTypeHolder(); + if (resolveObject(name, type) != null) { + throw new AlreadyBound(); + } + type.value = BindingType.nobject; + // ok, this is a new binding, go do it. + bindObject(name, obj, type); + } + } + } + + /** + * Rebind an object to a given name. If an object is + * already bound with this name, the new object replaces + * the bound object's value. If no object has been + * bound already, this is the same as a bind operation. + * + * @param n An array of NameComponents that are the target name. + * The last element in the array is binding name for the + * object. The remainder of the array is the path + * for resolving the naming context, relative to the + * current context. All path contexts must already be + * bound in the context tree. + * @param obj The new value for this binding. + * + * @exception org.omg.CosNaming.NamingContextPackage.NotFound + * @exception org.omg.CosNaming.NamingContextPackage.CannotProceed + * @exception org.omg.CosNaming.NamingContextPackage.InvalidName + * @exception org.omg.CosNaming.NamingContextPackage.AlreadyBound + */ + public void rebind(org.omg.CosNaming.NameComponent[] n, org.omg.CORBA.Object obj) + throws org.omg.CosNaming.NamingContextPackage.NotFound, org.omg.CosNaming.NamingContextPackage.CannotProceed, + org.omg.CosNaming.NamingContextPackage.InvalidName { + // perform various name validations + validateName(n); + + logNameComponent("rebind() name", n); + + // do we need to push through to a deeper naming context first? + if (n.length > 1) { + // resolve the top level name to a context, and have that context + // resolve the rest. + NamingContext context = resolveContext(n[0]); + NameComponent[] subName = extractSubName(n); + + // now pass this along to the next context for the real bind operation. + context.rebind(subName, obj); + } else { + NameComponent name = n[0]; + // we need the resolveObject() and bindObject() calls to be consistent, so + // synchronize on this + synchronized (this) { + // see if we have this bound already...can't replace these. + BindingTypeHolder type = new BindingTypeHolder(); + // for a rebind, we must have an object, and it must be a real object + if (resolveObject(name, type) != null) { + // it has to resolve to a real object. If it is a naming context, + // then this is the wrong binding operation. + if (type.value.value() == BindingType._ncontext) { + throw new NotFound(NotFoundReason.not_object, n); + } + // safe to unbind + unbindObject(name); + } + type.value = BindingType.nobject; + // now bind this object + bindObject(name, obj, type); + } + } + } + + /** + * Bind a new context to a given name. + * + * @param n An array of NameComponents that are the target name. + * The last element in the array is binding name for the + * object. The remainder of the array is the path + * for resolving the naming context, relative to the + * current context. All path contexts must already be + * bound in the context tree. + * @param nc The new naming context added to the tree. + * + * @exception org.omg.CosNaming.NamingContextPackage.NotFound + * @exception org.omg.CosNaming.NamingContextPackage.CannotProceed + * @exception org.omg.CosNaming.NamingContextPackage.InvalidName + * @exception org.omg.CosNaming.NamingContextPackage.AlreadyBound + */ + public void bind_context(org.omg.CosNaming.NameComponent[] n, org.omg.CosNaming.NamingContext nc) + throws org.omg.CosNaming.NamingContextPackage.NotFound, org.omg.CosNaming.NamingContextPackage.CannotProceed, + org.omg.CosNaming.NamingContextPackage.InvalidName, org.omg.CosNaming.NamingContextPackage.AlreadyBound { + // perform various name validations + validateName(n); + + logNameComponent("bind_context() name", n); + + // do we need to push through to a deeper naming context first? + if (n.length > 1) { + // resolve the top level name to a context, and have that context + // resolve the rest. + NamingContext context = resolveContext(n[0]); + NameComponent[] subName = extractSubName(n); + + // now pass this along to the next context for the real bind operation. + context.bind_context(subName, nc); + } else { + NameComponent name = n[0]; + // we need the resolveObject() and bindObject() calls to be consistent, so + // synchronize on this + synchronized (this) { + // see if we have this bound already...can't replace these. + BindingTypeHolder type = new BindingTypeHolder(); + if (resolveObject(name, type) != null) { + throw new AlreadyBound(); + } + type.value = BindingType.ncontext; + // ok, this is a new binding, go do it. + bindObject(name, nc, type); + } + } + } + + /** + * Rebind a context to a given name. If a context is + * already bound with this name, the new context replaces + * the existing context. If no context has been + * bound already, this is the same as a bind operation. + * + * @param n An array of NameComponents that are the target name. + * The last element in the array is binding name for the + * object. The remainder of the array is the path + * for resolving the naming context, relative to the + * current context. All path contexts must already be + * bound in the context tree. + * @param nc The new context to be bound with the name. + * + * @exception org.omg.CosNaming.NamingContextPackage.NotFound + * @exception org.omg.CosNaming.NamingContextPackage.CannotProceed + * @exception org.omg.CosNaming.NamingContextPackage.InvalidName + * @exception org.omg.CosNaming.NamingContextPackage.AlreadyBound + */ + public void rebind_context(org.omg.CosNaming.NameComponent[] n, org.omg.CosNaming.NamingContext nc) + throws org.omg.CosNaming.NamingContextPackage.NotFound, org.omg.CosNaming.NamingContextPackage.CannotProceed, + org.omg.CosNaming.NamingContextPackage.InvalidName { + // perform various name validations + validateName(n); + + logNameComponent("rebind_context() name", n); + + // do we need to push through to a deeper naming context first? + if (n.length > 1) { + // resolve the top level name to a context, and have that context + // resolve the rest. + NamingContext context = resolveContext(n[0]); + NameComponent[] subName = extractSubName(n); + + // now pass this along to the next context for the real bind operation. + context.rebind_context(subName, nc); + } else { + NameComponent name = n[0]; + // we need the resolveObject() and bindObject() calls to be consistent, so + // synchronize on this + synchronized (this) { + // see if we have this bound already...can't replace these. + BindingTypeHolder type = new BindingTypeHolder(); + // for a rebind, we must have an object, and it must be a real object + if (resolveObject(name, type) != null) { + // it has to resolve to a real object. If it is a naming context, + // then this is the wrong binding operation. + if (type.value.value() != BindingType._ncontext) { + throw new NotFound(NotFoundReason.not_context, n); + } + // safe to unbind + unbindObject(name); + } + type.value = BindingType.ncontext; + // now bind this object + bindObject(name, nc, type); + } + } + } + + /** + * Resolve an an entry in the context tree. The + * resolved object may be a bound object or another + * NamingContext. If the named entry is not found, + * a NotFound exception is thrown. + * + * @param n An array of NameComponents that are the target name. + * The last element in the array is binding name for the + * object. The remainder of the array is the path + * for resolving the naming context, relative to the + * current context. All path contexts must already be + * bound in the context tree. + * + * @return The object bound at the indicated location. + * @exception org.omg.CosNaming.NamingContextPackage.NotFound + * @exception org.omg.CosNaming.NamingContextPackage.CannotProceed + * @exception org.omg.CosNaming.NamingContextPackage.InvalidName + * @exception org.omg.CosNaming.NamingContextPackage.AlreadyBound + */ + public org.omg.CORBA.Object resolve(org.omg.CosNaming.NameComponent[] n) + throws org.omg.CosNaming.NamingContextPackage.NotFound, org.omg.CosNaming.NamingContextPackage.CannotProceed, + org.omg.CosNaming.NamingContextPackage.InvalidName { + // perform various name validations + validateName(n); + + logNameComponent("resolve() name", n); + + // do we need to push through to a deeper naming context first? + if (n.length > 1) { + // resolve the top level name to a context, and have that context + // resolve the rest. + NamingContext context = resolveContext(n[0]); + NameComponent[] subName = extractSubName(n); + + // now pass this along to the next context for the real bind operation. + return context.resolve(subName); + } else { + NameComponent name = n[0]; + // see if we have this bound already...can't replace these. + BindingTypeHolder type = new BindingTypeHolder(); + org.omg.CORBA.Object obj = resolveObject(name, type); + if (obj == null) { + // Object was not found + throw new NotFound(NotFoundReason.missing_node, n); + } + return obj; + } + } + + /** + * Remove an entry from the context tree. The + * target object may be a bound object or another + * NamingContext. If the named entry is not found, + * a NotFound exception is thrown. + * + * @param n An array of NameComponents that are the target name. + * The last element in the array is binding name for the + * object. The remainder of the array is the path + * for resolving the naming context, relative to the + * current context. All path contexts must already be + * bound in the context tree. + * + * @exception org.omg.CosNaming.NamingContextPackage.NotFound + * @exception org.omg.CosNaming.NamingContextPackage.CannotProceed + * @exception org.omg.CosNaming.NamingContextPackage.InvalidName + * @exception org.omg.CosNaming.NamingContextPackage.AlreadyBound + */ + public void unbind(org.omg.CosNaming.NameComponent[] n) throws org.omg.CosNaming.NamingContextPackage.NotFound, + org.omg.CosNaming.NamingContextPackage.CannotProceed, org.omg.CosNaming.NamingContextPackage.InvalidName { + // perform various name validations + validateName(n); + + logNameComponent("unbind() name", n); + + // do we need to push through to a deeper naming context first? + if (n.length > 1) { + // resolve the top level name to a context, and have that context + // resolve the rest. + NamingContext context = resolveContext(n[0]); + NameComponent[] subName = extractSubName(n); + + // now pass this along to the next context for the real bind operation. + context.unbind(subName); + } else { + NameComponent name = n[0]; + synchronized (this) { + // see if we have this bound already...can't replace these. + BindingTypeHolder type = new BindingTypeHolder(); + org.omg.CORBA.Object obj = unbindObject(name); + if (obj == null) { + // Object was not found + throw new NotFound(NotFoundReason.missing_node, n); + } + } + } + } + + /** + * Create a new context and bind it in at the target + * location. + * + * @param n An array of NameComponents that are the target name. + * The last element in the array is binding name for the + * object. The remainder of the array is the path + * for resolving the naming context, relative to the + * current context. All path contexts must already be + * bound in the context tree. + * + * @return The newly created context. + * @exception org.omg.CosNaming.NamingContextPackage.NotFound + * @exception org.omg.CosNaming.NamingContextPackage.CannotProceed + * @exception org.omg.CosNaming.NamingContextPackage.InvalidName + * @exception org.omg.CosNaming.NamingContextPackage.AlreadyBound + */ + public synchronized org.omg.CosNaming.NamingContext bind_new_context(org.omg.CosNaming.NameComponent[] n) + throws org.omg.CosNaming.NamingContextPackage.NotFound, org.omg.CosNaming.NamingContextPackage.AlreadyBound, + org.omg.CosNaming.NamingContextPackage.CannotProceed, org.omg.CosNaming.NamingContextPackage.InvalidName { + logNameComponent("bind_new_context() name", n); + + NamingContext context = new_context(); + try { + bind_context(n, context); + NamingContext returnContext = context; + // transfer this to another variable so the finally block doesn't try to destroy this. + context = null; + return returnContext; + } finally { + // if there is a bind failure on this, we need to ensure the context has + // an opportunity to clean up any of its resources. + if (context != null) { + try { + context.destroy(); + } catch (org.omg.CosNaming.NamingContextPackage.NotEmpty e) { + // new contexts should be empty. + } + } + } + } + + /** + * Convert an array of NameComponents into the string + * form of a context name. + * + * @param n The array of NameComponents to convert. + * + * @return The context name, in string form. + * @exception org.omg.CosNaming.NamingContextPackage.InvalidName + */ + public String to_string(org.omg.CosNaming.NameComponent[] n) + throws org.omg.CosNaming.NamingContextPackage.InvalidName { + validateName(n); + + logNameComponent("to_string() name", n); + + // convert the first part of the name + StringBuffer value = new StringBuffer(); + ; + // convert the first component, then build up from there. + nameToString(n[0], value); + + // the remainder need to get a separator + for (int i = 1; i < n.length; i++) { + value.append('/'); + nameToString(n[i], value); + } + return value.toString(); + } + + /** + * Perform the reverse operation of the to_string() method, + * parsing a String context name into an array of + * NameComponents. + * + * @param sn The string form of the name. + * + * @return An array of NameComponents parsed from the String name. + * @exception org.omg.CosNaming.NamingContextPackage.InvalidName + */ + public org.omg.CosNaming.NameComponent[] to_name(String sn) + throws org.omg.CosNaming.NamingContextPackage.InvalidName { + // must have a argument to parse + if (sn == null || sn.length() == 0) { + throw new InvalidName(); + } + + List components = new ArrayList(); + + StringBuffer component = new StringBuffer(); + + int index = 0; + String id = null; + String kind = null; + while (index < sn.length()) { + char ch = sn.charAt(index++); + + // found an escape character or a delimiter? + if (ch == '\\') { + // nothing after the escape? Trouble + if (index >= sn.length()) { + throw new InvalidName(); + } + // get the next character + ch = sn.charAt(index++); + component.append(ch); + } + // we need to process the periods here, to avoid getting + // mixed up with unescaped periods. + else if (ch == '.') { + // already seen a period while scanning? That's not allowed + if (id != null) { + throw new InvalidName(); + } + // pull off the id piece and reset the buffer + id = component.toString(); + component.setLength(0); + } + // found a component delimiter? + else if (ch == '/') { + // not seen a id/kind separator yet? This is an id with no kind + if (id == null) { + id = component.toString(); + kind = ""; + } else { + // we have an id already, pull off the kind + kind = component.toString(); + } + // add the parsed name component + components.add(new NameComponent(id, kind)); + // make sure these are all reset after pulling off a component + component.setLength(0); + id = null; + kind = null; + } else { + component.append(ch); + } + } + + // parse the last section + // not seen a id/kind separator yet? This is an id with no kind + if (id == null) { + id = component.toString(); + kind = ""; + } else { + // we have an id already, pull off the kind + kind = component.toString(); + } + // add the parsed name component + components.add(new NameComponent(id, kind)); + + // and turn this into a component array + return (NameComponent[])components.toArray(new NameComponent[components.size()]); + } + + /** + * Create a URL name for accessing a component by name. The + * URL will have a corbaname: protocol. + * + * @param addr The address location for the naming service used + * to resolve the object. This is in "host:port" form, + * just line a corbaloc: URL. + * @param sn The string mae of the target object. + * + * @return A URL for accessing this object, in String form. + * @exception org.omg.CosNaming.NamingContextExtPackage.InvalidAddress + * @exception org.omg.CosNaming.NamingContextPackage.InvalidName + */ + public String to_url(String addr, String sn) throws org.omg.CosNaming.NamingContextExtPackage.InvalidAddress, + org.omg.CosNaming.NamingContextPackage.InvalidName { + // basic validation + if (addr == null || addr.length() == 0) { + throw new InvalidAddress(); + } + + if (sn == null || sn.length() == 0) { + throw new InvalidName(); + } + + // TODO: What validation, if any, needs to be done here? + return "corbaname:" + addr + "#" + encodeRFC2396Name(sn); + } + + /** + * Resolve a bound object or context using a name + * in String form. + * + * @param n The string name of the object context. This must + * be a form parseable by to_name(). + * + * @return The bound object or context. + * @exception org.omg.CosNaming.NamingContextPackage.NotFound + * @exception org.omg.CosNaming.NamingContextPackage.CannotProceed + * @exception org.omg.CosNaming.NamingContextPackage.InvalidName + */ + public org.omg.CORBA.Object resolve_str(String n) throws org.omg.CosNaming.NamingContextPackage.NotFound, + org.omg.CosNaming.NamingContextPackage.CannotProceed, org.omg.CosNaming.NamingContextPackage.InvalidName { + // this is just a simple convenience method + return resolve(to_name(n)); + } + + // abstract methods that are part of the NamingContext interface that need to be + // implemented by the subclasses. + + /** + * Create a new context of the same type as the + * calling context. + * + * @return A new NamingContext item. + * @exception org.omg.CosNaming.NamingContextPackage.NotFound + * @exception SystemException + */ + public abstract org.omg.CosNaming.NamingContext new_context() throws SystemException; + + /** + * Destroy a context. This method should clean up + * any backing resources associated with the context. + * + * @exception org.omg.CosNaming.NamingContextPackage.NotEmpty + */ + public abstract void destroy() throws org.omg.CosNaming.NamingContextPackage.NotEmpty; + + /** + * Create a list of bound objects an contexts contained + * within this context. + * + * @param how_many The count of elements to return as a BindingList. + * @param bl A holder element for returning the source binding list. + * @param bi A holder for returning a BindingIterator. Any extra + * elements not returned in the BindingList are returned + * in the BindingIterator. + * + * @exception SystemException + */ + public abstract void list(int how_many, + org.omg.CosNaming.BindingListHolder bl, + org.omg.CosNaming.BindingIteratorHolder bi) throws SystemException; + + // abstract methods for the sub class to implement + + /** + * Resolve an object in this context (single level + * resolution). + * + * @param n The name of the target object. + * @param type A type holder for returning the bound object type + * information. + * + * @return The bound object. Returns null if the object does not + * exist in the context. + * @exception SystemException + */ + protected abstract org.omg.CORBA.Object resolveObject(NameComponent n, BindingTypeHolder type) + throws SystemException; + + /** + * Bind an object into the current context. This can + * be either an object or a naming context. + * + * @param n The single-level name of the target object. + * @param obj The object or context to be bound. + * @param type + * + * @exception SystemException + */ + protected abstract void bindObject(NameComponent n, org.omg.CORBA.Object obj, BindingTypeHolder type) + throws SystemException; + + /** + * Unbind an object from the current context. + * + * @param n The name of the target object (single level). + * + * @return The object associated with the binding. Returns null + * if there was no binding currently associated with this + * name. + * @exception SystemException + */ + protected abstract org.omg.CORBA.Object unbindObject(NameComponent n) throws SystemException; + + // implementation specific routines + + /** + * Resolve a name to a context object stored that has + * already been stored in this context. Throws an exception + * if the name cannot be resolved or if the resolved + * object is not a naming context. + * + * @param name The target name. + * + * @return The resolved NamingContext object. + * @exception org.omg.CosNaming.NamingContextPackage.NotFound + */ + protected synchronized NamingContext resolveContext(NameComponent name) + throws org.omg.CosNaming.NamingContextPackage.NotFound { + BindingTypeHolder type = new BindingTypeHolder(); + // Resolve this to an object. We must be able to resolve this. + org.omg.CORBA.Object resolvedReference = resolveObject(name, type); + if (resolvedReference == null) { + throw new NotFound(NotFoundReason.missing_node, new NameComponent[] {name}); + } + + // it has to resolve to a naming context + if (type.value.value() != BindingType._ncontext) { + throw new NotFound(NotFoundReason.not_context, new NameComponent[] {name}); + } + + // in theory, this is a naming context. Narrow it an return. Any + // errors just become a NotFound exception + try { + return NamingContextHelper.narrow(resolvedReference); + } catch (org.omg.CORBA.BAD_PARAM ex) { + throw new NotFound(NotFoundReason.not_context, new NameComponent[] {name}); + } + } + + /** + * Extract the tail portion of a name. This is used + * to strip off the first name element so we can recurse + * on the name resolutions with a resolved context. + * + * @param name The current name array (this MUST have 2 or more + * elements). + * + * @return An array of NameComponent items that is one element + * smaller than the argument array, with the elements + * shifted over. + */ + protected NameComponent[] extractSubName(NameComponent[] name) { + NameComponent[] subName = new NameComponent[name.length - 1]; + System.arraycopy(name, 1, subName, 0, name.length - 1); + return subName; + } + + /** + * Perform common name validity checking. + * + * @param n The NameComponent array to check. + * + * @exception InvalidName + */ + protected void validateName(NameComponent[] n) throws InvalidName { + // perform various name validations + if (n == null) { + throw new BAD_PARAM(27 | org.omg.CORBA.OMGVMCID.value, CompletionStatus.COMPLETED_NO); + } + + // Valid name? + if (n.length < 1) { + throw new InvalidName(); + } + + // we have at least one name, so validate the toplevel item + NameComponent name = n[0]; + + // more name validation + if (name.id.length() == 0 && name.kind.length() == 0) { + throw new InvalidName(); + } + } + + /** + * Convert a NameComponent item into a string form, + * appending it to a StringBuffer. + * + * @param name The source NameComponent. + * @param out The StringBuffer location used to store the name + * value (appended to the end). + */ + protected void nameToString(NameComponent name, StringBuffer out) { + // if the id is null, then we base off of the kind. + if (name.id == null || name.id.length() == 0) { + out.append("."); + // true null name element? That displays as a "." + if (name.kind != null && name.kind.length() != 0) { + escapeName(name.kind, out); + } + } else { + // escape the name + escapeName(name.id, out); + // have a kind qualifier to add on? + if (name.kind != null && name.kind.length() != 0) { + out.append("."); + escapeName(name.kind, out); + } + } + } + + /** + * Process a name or kind element of a NameComponent, + * adding escape characters for '.' or '/' characters + * that might appear in the name. + * + * @param name The name element to process. + * @param out The StringBuffer to copy the escaped name into. + */ + protected void escapeName(String name, StringBuffer out) { + // no characters requiring escapes (common)? + // use this directly + if (name.indexOf('.') == -1 && name.indexOf('/') == -1) { + out.append(name); + } else { + // scan the string adding the escapes + for (int i = 0; i < name.length(); i++) { + char ch = name.charAt(i); + if (ch == '.' || ch == '/') { + out.append('/'); + } + out.append(ch); + } + } + } + + /** + * Perform RFC 2396 escape encoding of a name value. + * + * @param name The input name value. + * + * @return An encoded name, with special characters converted + * into a hex encoded value. + */ + protected String encodeRFC2396Name(String name) { + StringBuffer value = new StringBuffer(); + + for (int i = 0; i < name.length(); i++) { + char ch = name.charAt(i); + + // Alphanumerics and the "acceptable" set of special characters just get copied + // without encoding. + if (Character.isLetterOrDigit(ch) || nonEscaped.indexOf(ch) != -1) { + value.append(ch); + } else { + // this gets converted into a hex value, marked by "%". + value.append('%'); + value.append(Integer.toHexString((int)ch)); + } + } + return value.toString(); + } + + /** + * Test if debug logging is currently available. + * + * @return True if debug level (FINE) logging is currently turned on. + */ + protected boolean isDebugEnabled() { + return logger.isLoggable(Level.FINE); + } + + /** + * Log a line of debug output + * + * @param message The message to log + */ + protected void debug(String message) { + logger.fine(message); + } + + /** + * Log the name components passed in for a request. + * + * @param message A message describing the request context. + * @param n The array of name components. + */ + protected void logNameComponent(String message, NameComponent[] n) { + if (isDebugEnabled()) { + debug(message); + for (int i = 0; i < n.length; i++) { + debug(" NameComponent " + i + " id=" + n[i].id + " kind=" + n[i].kind); + } + } + } + +} diff --git a/branches/sca-android/modules/host-corba-jse/src/main/java/org/apache/tuscany/sca/host/corba/naming/TransientNameServer.java b/branches/sca-android/modules/host-corba-jse/src/main/java/org/apache/tuscany/sca/host/corba/naming/TransientNameServer.java new file mode 100644 index 0000000000..599f5bca54 --- /dev/null +++ b/branches/sca-android/modules/host-corba-jse/src/main/java/org/apache/tuscany/sca/host/corba/naming/TransientNameServer.java @@ -0,0 +1,133 @@ +/* + * 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. + */ + +/** + * @version $Rev$ $Date$ + */ +package org.apache.tuscany.sca.host.corba.naming; + +import org.omg.CORBA.ORB; + +/** + * A stand-alone naming service launchable from a command line. + */ +public class TransientNameServer { + private final TransientNameService service; + private final Object flag = new Object(); + private Boolean started; + + public TransientNameServer(String host, int port, String serviceName) { + this.service = new TransientNameService(host, port, serviceName); + } + + public ORB getORB() { + return service.getORB(); + } + + public Thread start() { + Thread t = new Thread() { + public void run() { + ORB orb = null; + synchronized (flag) { + try { + service.run(); + orb = service.getORB(); + started = Boolean.TRUE; + } catch (Throwable e) { + started = Boolean.FALSE; + throw new IllegalStateException(e); + } finally { + flag.notifyAll(); + } + } + // Wait for requests + orb.run(); + } + }; + t.setDaemon(true); + t.start(); + checkState(); + return t.isAlive() ? t : null; + } + + private Boolean checkState() { + synchronized (flag) { + while (started == null) { + try { + flag.wait(); + } catch (InterruptedException e) { + return null; + } + } + return started; + } + } + + public void stop() { + if (started == Boolean.TRUE) { + service.destroy(); + } + } + + /** + * Launch a name service as a stand alone process. The + * Host, port, and service name are controlled using + * program arguments. + * + * @param args The array of arguments for tailoring the service. + * + * @exception Exception + */ + public static void main(String args[]) throws Exception { + int port = TransientNameService.DEFAULT_SERVICE_PORT; + String host = TransientNameService.DEFAULT_SERVICE_HOST; + String serviceName = TransientNameService.DEFAULT_SERVICE_NAME; + + // see if we have + for (int i = 0; i < args.length; i++) { + if (args[i].equals("-ORBInitialPort")) { + i++; + if (i < args.length) { + port = java.lang.Integer.parseInt(args[i]); + } else { + throw new IllegalArgumentException("Invalid -ORBInitialPort option"); + } + } else if (args[i].equals("-ORBInitialHost")) { + i++; + if (i < args.length) { + host = args[i]; + } else { + throw new IllegalArgumentException("Invalid -ORBInitialHost option"); + } + } else if (args[i].equals("-ORBServiceName")) { + i++; + if (i < args.length) { + serviceName = args[i]; + } else { + throw new IllegalArgumentException("Invalid -ORBServiceName option"); + } + } + + } + // create a services, and just spin it off. We wait forever after that. + TransientNameServer server = new TransientNameServer(host, port, serviceName); + server.start().join(); + } + +} diff --git a/branches/sca-android/modules/host-corba-jse/src/main/java/org/apache/tuscany/sca/host/corba/naming/TransientNameService.java b/branches/sca-android/modules/host-corba-jse/src/main/java/org/apache/tuscany/sca/host/corba/naming/TransientNameService.java new file mode 100644 index 0000000000..77617a6c5c --- /dev/null +++ b/branches/sca-android/modules/host-corba-jse/src/main/java/org/apache/tuscany/sca/host/corba/naming/TransientNameService.java @@ -0,0 +1,200 @@ +/* + * 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. + */ + +/** + * @version $Rev$ $Date$ + */ +package org.apache.tuscany.sca.host.corba.naming; + +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.Properties; + +import org.omg.CORBA.ORB; +import org.omg.CORBA.Policy; +import org.omg.PortableServer.IdAssignmentPolicyValue; +import org.omg.PortableServer.LifespanPolicyValue; +import org.omg.PortableServer.POA; +import org.omg.PortableServer.ServantRetentionPolicyValue; + +/** + * A transient name service attached to an ORB. This + * class manages all of the housekeeping for creating a + * TransientNamingContext and a exposing it using an + * ORB. + */ +public class TransientNameService { + // the default registered name service + static public final String DEFAULT_SERVICE_NAME = "TNameService"; + // the default listening port + static public final int DEFAULT_SERVICE_PORT = 900; + // the default host name + static public final String DEFAULT_SERVICE_HOST = "localhost"; + + // the service root context + protected TransientNamingContext initialContext; + // initial listening port + protected int port; + // initial listening host + protected String host; + // the service name (used for registing for the corbaloc:: URL name + protected String serviceName; + // the orb instance we're running on + protected ORB createdOrb; + + /** + * Create a new TransientNameService, using all default + * attributes. + */ + public TransientNameService() { + this(DEFAULT_SERVICE_HOST, DEFAULT_SERVICE_PORT, DEFAULT_SERVICE_NAME); + } + + /** + * Create a default-named name service using the specified + * host and port parameters. + * + * @param host The host to expose this under. + * @param port The initial listening port. + */ + public TransientNameService(String host, int port) { + this(host, port, DEFAULT_SERVICE_NAME); + } + + /** + * Create a specifically-named name service using the specified + * host and port parameters. + * + * @param host The host to expose this under. + * @param port The initial listening port. + * @param name The name to register this service under using the + * BootManager. + */ + public TransientNameService(String host, int port, String name) { + this.port = port; + this.host = host; + this.serviceName = name; + } + + /** + * Start up the name service, including creating an + * ORB instance to expose it under. + * + * @exception TransientServiceException + */ + public void run() throws TransientServiceException { + // Create an ORB object + Properties props = new Properties(); + props.putAll(System.getProperties()); + + String portStr = String.valueOf(port); + props.put("org.omg.CORBA.ORBServerId", "1000000"); + props.put("org.omg.CORBA.ORBInitialHost", host); + props.put("org.omg.CORBA.ORBInitialPort", portStr); + + // STEP 1: Set ORBPeristentServerPort property + // Set the proprietary property to open up a port to listen to + // INS requests. + + props.put("com.sun.CORBA.POA.ORBPersistentServerPort", portStr); + props.put("com.ibm.CORBA.ListenerPort", portStr); + props.put("gnu.CORBA.ListenerPort", portStr); + // props.put("org.omg.CORBA.ORBClass", "org.apache.yoko.orb.CORBA.ORB"); + // props.put("org.omg.CORBA.ORBSingletonClass", "org.apache.yoko.orb.CORBA.ORBSingleton"); + props.put("yoko.orb.oa.endpoint", "iiop --host " + host + " --port " + port); + props.put("yoko.orb.poamanager.TNameService.endpoint", "iiop --host " + host); + + String[] args = {"-ORBInitialHost", host, "-ORBInitialPort", "" + port}; + createdOrb = ORB.init(args, props); + + // now initialize the service + initialize(createdOrb); + + } + + /** + * Initialize a transient name service on a specific + * ORB. + * + * @param orb The ORB hosting the service. + * + * @exception TransientServiceException + */ + public void initialize(ORB orb) throws TransientServiceException { + try { + // get the root POA. We're going to re + POA rootPOA = (POA)orb.resolve_initial_references("RootPOA"); + rootPOA.the_POAManager().activate(); + + // we need to create a POA to manage this named instance, and then activate + // a context on it. + Policy[] policy = new Policy[3]; + policy[0] = rootPOA.create_lifespan_policy(LifespanPolicyValue.TRANSIENT); + policy[1] = rootPOA.create_id_assignment_policy(IdAssignmentPolicyValue.SYSTEM_ID); + policy[2] = rootPOA.create_servant_retention_policy(ServantRetentionPolicyValue.RETAIN); + + POA nameServicePOA = rootPOA.create_POA("TNameService", null, policy); + nameServicePOA.the_POAManager().activate(); + + // create our initial context, and register that with the ORB as the name service + initialContext = new TransientNamingContext(orb, nameServicePOA); + org.omg.CORBA.Object context = initialContext.getRootContext(); + Method method = + orb.getClass().getMethod("register_initial_reference", String.class, org.omg.CORBA.Object.class); + method.invoke(orb, serviceName, context); + method.invoke(orb, "NamingService", context); + method.invoke(orb, "NameService", context); + } catch (Exception e) { + throw new TransientServiceException("Unable to initialize name service", e); + } + } + + /** + * Destroy the created service. + */ + public void destroy() { + // only destroy this if we created the orb instance. + if (createdOrb != null) { + createdOrb.shutdown(false); + createdOrb.destroy(); + + try { + // This is a workaround to close the sockets for SUN ORB + Method m = createdOrb.getClass().getMethod("getTransportManager"); + Object tm = m.invoke(createdOrb); + m = tm.getClass().getMethod("close"); + m.invoke(tm); + m = tm.getClass().getMethod("getAcceptors"); + Collection acceptors = (Collection) m.invoke(tm); + for(Object a: acceptors) { + m = a.getClass().getMethod("close"); + m.invoke(a); + } + } catch (Throwable e) { + // Ignore + } + createdOrb = null; + } + } + + public ORB getORB() { + return createdOrb; + } + +} diff --git a/branches/sca-android/modules/host-corba-jse/src/main/java/org/apache/tuscany/sca/host/corba/naming/TransientNamingContext.java b/branches/sca-android/modules/host-corba-jse/src/main/java/org/apache/tuscany/sca/host/corba/naming/TransientNamingContext.java new file mode 100644 index 0000000000..a7164e9ef3 --- /dev/null +++ b/branches/sca-android/modules/host-corba-jse/src/main/java/org/apache/tuscany/sca/host/corba/naming/TransientNamingContext.java @@ -0,0 +1,440 @@ +/* + * 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. + */ +/** + * @version $Rev$ $Date$ + */ + +package org.apache.tuscany.sca.host.corba.naming; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +import org.omg.CORBA.INTERNAL; +import org.omg.CORBA.ORB; +import org.omg.CORBA.SystemException; +import org.omg.CosNaming.Binding; +import org.omg.CosNaming.BindingHolder; +import org.omg.CosNaming.BindingIteratorHelper; +import org.omg.CosNaming.BindingIteratorPOA; +import org.omg.CosNaming.BindingType; +import org.omg.CosNaming.BindingTypeHolder; +import org.omg.CosNaming.NameComponent; +import org.omg.CosNaming.NamingContext; +import org.omg.CosNaming.NamingContextHelper; +import org.omg.CosNaming.NamingContextPackage.NotEmpty; +import org.omg.PortableServer.POA; + +public class TransientNamingContext extends NamingContextBase { + // the bindings maintained by this context + protected HashMap bindings = new HashMap(); + // the root context object + protected org.omg.CORBA.Object rootContext = null; + + /** + * Create a top-level naming context. + * + * @param orb The orb hosting this context. + * @param poa The POA used to activate the object. + * + * @exception Exception + */ + public TransientNamingContext(ORB orb, POA poa) throws Exception { + this(orb, poa, null); + // now get the initial root context as a corba object. + + byte[] objectId = poa.activate_object(this); + rootContext = poa.id_to_reference(objectId); + + } + + /** + * Construct a TransientNamingContext subcontext. + * + * @param orb The orb this context is associated with. + * @param poa The POA the root context is activated under. + * @param root The root context. + * + * @exception Exception + */ + public TransientNamingContext(ORB orb, POA poa, org.omg.CORBA.Object root) throws Exception { + super(orb, poa); + // save the root context link. + rootContext = root; + } + + // abstract methods part of the interface contract that the implementation is required + // to supply. + + /** + * Create a new context of the same type as the + * calling context. + * + * @return A new NamingContext item. + * @exception org.omg.CosNaming.NamingContextPackage.NotFound + * @exception SystemException + */ + public NamingContext new_context() throws SystemException { + try { + // create a new context. Then we need to register this with the POA and activate it. + TransientNamingContext newContext = new TransientNamingContext(orb, poa, rootContext); + + byte[] objectId = poa.activate_object(newContext); + org.omg.CORBA.Object obj = poa.id_to_reference(objectId); + return NamingContextHelper.narrow(obj); + } catch (SystemException e) { + // just propagate system exceptions + throw e; + } catch (Exception e) { + throw (INTERNAL)(new INTERNAL("Unable to create new naming context").initCause(e)); + } + } + + /** + * Destroy a context. This method should clean up + * any backing resources associated with the context. + * + * @exception org.omg.CosNaming.NamingContextPackage.NotEmpty + */ + public synchronized void destroy() throws org.omg.CosNaming.NamingContextPackage.NotEmpty { + // still holding bound objects? Not allowed to destroy + if (!bindings.isEmpty()) { + throw new NotEmpty(); + } + + try { + // now detach ourselves from the POA + byte[] objectId = poa.servant_to_id(this); + if (objectId != null) { + poa.deactivate_object(objectId); + } + } catch (Exception e) { + // ignore + } + } + + /** + * Create a list of bound objects an contexts contained + * within this context. + * + * @param how_many The count of elements to return as a BindingList. + * @param bl A holder element for returning the source binding list. + * @param bi A holder for returning a BindingIterator. Any extra + * elements not returned in the BindingList are returned + * in the BindingIterator. + * + * @exception SystemException + */ + public synchronized void list(int how_many, + org.omg.CosNaming.BindingListHolder bl, + org.omg.CosNaming.BindingIteratorHolder bi) throws SystemException { + TransientBindingIterator iterator = new TransientBindingIterator(poa, (HashMap)bindings.clone()); + // have the iterator fill in the entries here + iterator.next_n(how_many, bl); + + // now it's necessary to activate this iterator with the poa. The value we pass + // back is the narrowed activated object + try { + byte[] objectId = poa.activate_object(iterator); + org.omg.CORBA.Object obj = poa.id_to_reference(objectId); + + bi.value = BindingIteratorHelper.narrow(obj); + } catch (SystemException e) { + // just propagate system exceptions + throw e; + } catch (Exception e) { + throw (INTERNAL)(new INTERNAL("Unable to activate BindingIterator").initCause(e)); + } + } + + // lower level functions that are used by the base class + + /** + * Resolve an object in this context (single level + * resolution). + * + * @param n The name of the target object. + * @param type A type holder for returning the bound object type + * information. + * + * @return The bound object. Returns null if the object does not + * exist in the context. + * @exception SystemException + */ + protected org.omg.CORBA.Object resolveObject(NameComponent n, BindingTypeHolder type) throws SystemException { + // special call to resolve the root context. This is the only one that goes backwards. + if (n.id.length() == 0 && n.kind.length() == 0) { + // this is a name context item, so set it properly. + type.value = BindingType.ncontext; + return rootContext; + } + + BindingKey key = new BindingKey(n); + BoundObject obj = (BoundObject)bindings.get(key); + // if not in the table, just return null + if (obj == null) { + return null; + } + // update the type information and return the bound object reference. + type.value = obj.type; + return obj.boundObject; + } + + /** + * Bind an object into the current context. This can + * be either an object or a naming context. + * + * @param n The single-level name of the target object. + * @param obj The object or context to be bound. + * @param type + * + * @exception SystemException + */ + protected void bindObject(NameComponent n, org.omg.CORBA.Object obj, BindingTypeHolder type) throws SystemException { + // fairly simple table put... + bindings.put(new BindingKey(n), new BoundObject(n, obj, type.value)); + } + + /** + * Unbind an object from the current context. + * + * @param n The name of the target object (single level). + * + * @return The object associated with the binding. Returns null + * if there was no binding currently associated with this + * name. + * @exception SystemException + */ + protected org.omg.CORBA.Object unbindObject(NameComponent n) throws SystemException { + //remove the object from the hash table, returning the bound object if it exists. + BindingKey key = new BindingKey(n); + BoundObject obj = (BoundObject)bindings.remove(key); + + if (obj != null) { + return obj.boundObject; + } + return null; + } + + /** + * Retrieve the rootContext for this NamingContext. + * + * @return The rootContext CORBA object associated with this context. + */ + public org.omg.CORBA.Object getRootContext() { + return rootContext; + } + + /** + * Internal class used for HashMap lookup keys. + */ + class BindingKey { + // the name component this is a HashMap key for. + public NameComponent name; + private int hashval = 0; + + /** + * Create a new BindingKey for a NameComponent. + * + * @param n The lookup name. + */ + public BindingKey(NameComponent n) { + name = n; + // create a hash value used for lookups + if (name.id != null) { + hashval += name.id.hashCode(); + } + if (name.kind != null) { + hashval += name.kind.hashCode(); + } + } + + /** + * Return the hashcode associated with this binding key. The + * hashcode is created using the NameComponent id and + * kind fields. + * + * @return The lookup hashvalue associated with this key. + */ + public int hashCode() { + return hashval; + } + + /** + * Compare two BindingKeys for equality (used for HashMap + * lookups). + * + * @param other The comparison partner. + * + * @return True if the keys are equivalent, false otherwise. + */ + public boolean equals(Object other) { + // if not given or the wrong type, this is false. + if (other == null || !(other instanceof BindingKey)) { + return false; + } + + BindingKey otherKey = (BindingKey)other; + + // verify first on the id name. + if (name.id != null) { + if (otherKey.name.id == null) { + return false; + } + if (!name.id.equals(otherKey.name.id)) { + return false; + } + } else { + if (otherKey.name.id != null) { + return false; + } + } + // this is a match so far...now compare the kinds + if (name.kind != null) { + if (otherKey.name.kind == null) { + return false; + } + if (!name.kind.equals(otherKey.name.kind)) { + return false; + } + } else { + if (otherKey.name.kind != null) { + return false; + } + } + return true; + } + } + + /** + * Internal class used to store bound objects in the HashMap. + */ + public class BoundObject { + // the name this object is bound under. + public NameComponent name; + // the type of binding (either nobject or ncontext). + public BindingType type; + // the actual bound object. + public org.omg.CORBA.Object boundObject; + + /** + * Create a new object binding for our HashMap. + * + * @param name The bound object's name. + * @param boundObject + * The bound object (real object or NamingContext). + * @param type The type information associated with this binding. + */ + public BoundObject(NameComponent name, org.omg.CORBA.Object boundObject, BindingType type) { + this.name = name; + this.boundObject = boundObject; + this.type = type; + } + } + + /** + * Context implementation version of the BindingIterator + * object used to return list items. + */ + public class TransientBindingIterator extends BindingIteratorPOA { + // the POA used to activate this object (required for destroy(); + private POA poa; + // the binding set we're iterating over (this must be a snapshot copy) + private HashMap bindings; + // the iterator use to access the bindings + private Iterator iterator; + + /** + * Create a new BindingIterator hosted by the given POA and + * iterating over the map of items. + * + * @param poa The hosting POA. + * @param bindings The HashMap of bound objects. + */ + public TransientBindingIterator(POA poa, HashMap bindings) { + this.poa = poa; + this.bindings = bindings; + this.iterator = bindings.values().iterator(); + } + + /** + * Return the next object in the iteration sequence. + * + * @param b The BindingHolder used to return the next item. If + * we've reached the end of the sequence, an item + * with an empty name is returned. + * + * @return true if there is another item, false otherwise. + */ + public boolean next_one(org.omg.CosNaming.BindingHolder b) { + if (iterator.hasNext()) { + // return this as a Binding value. + BoundObject obj = (BoundObject)iterator.next(); + b.value = new Binding(new NameComponent[] {obj.name}, obj.type); + return true; + } else { + // return an empty element + b.value = new Binding(new NameComponent[0], BindingType.nobject); + return false; + } + } + + /** + * Retrieve the next "n" items from the list, returned + * as a BindingList. + * + * @param how_many The count of items to retrieve. + * @param bl A holder for returning an array of Bindings for + * the returned items. + * + * @return true if any items were returned, false if there's + * nothing left to return. + */ + public boolean next_n(int how_many, org.omg.CosNaming.BindingListHolder bl) { + List accum = new ArrayList(); + BindingHolder holder = new BindingHolder(); + int i = 0; + // Keep iterating as long as there are entries + while (i < how_many && next_one(holder)) { + accum.add(holder.value); + i++; + } + + // convert to an array and return whether we found anything. + bl.value = (Binding[])accum.toArray(new Binding[accum.size()]); + return accum.isEmpty(); + } + + /** + * Destory this BindingIterator instance, which deativates + * it from the hosting POA. + */ + public void destroy() { + try { + // we need to deactivate this from the POA. + byte[] objectId = poa.servant_to_id(this); + if (objectId != null) { + poa.deactivate_object(objectId); + } + } catch (Exception e) { + } + } + } +} diff --git a/branches/sca-android/modules/host-corba-jse/src/main/java/org/apache/tuscany/sca/host/corba/naming/TransientServiceException.java b/branches/sca-android/modules/host-corba-jse/src/main/java/org/apache/tuscany/sca/host/corba/naming/TransientServiceException.java new file mode 100644 index 0000000000..444143f173 --- /dev/null +++ b/branches/sca-android/modules/host-corba-jse/src/main/java/org/apache/tuscany/sca/host/corba/naming/TransientServiceException.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. + */ + +/** + * @version $Rev$ $Date$ + */ +package org.apache.tuscany.sca.host.corba.naming; + +public class TransientServiceException extends Exception { + + /** + * + */ + private static final long serialVersionUID = -2611596914331994827L; + + public TransientServiceException() { + super(); + } + + public TransientServiceException(String reason) { + super(reason); + } + + public TransientServiceException(String reason, Exception cause) { + super(reason, cause); + } + +} |