diff options
Diffstat (limited to 'sca-java-2.x/tags/2.0-M5.1-RC1/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/EJBLocator.java')
-rw-r--r-- | sca-java-2.x/tags/2.0-M5.1-RC1/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/EJBLocator.java | 483 |
1 files changed, 483 insertions, 0 deletions
diff --git a/sca-java-2.x/tags/2.0-M5.1-RC1/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/EJBLocator.java b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/EJBLocator.java new file mode 100644 index 0000000000..0b97f42746 --- /dev/null +++ b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/EJBLocator.java @@ -0,0 +1,483 @@ +/* + * 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.ejb.util; + +import java.net.URL; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Properties; +import java.util.Set; + +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +import org.omg.CORBA.ORB; +import org.omg.CosNaming.NamingContextExt; + +/** + * CosNaming utility + * + * @version $Rev$ $Date$ + */ +class EJBLocator { + + /* + * Root Context Initial Reference Key ------------ + * ----------------------------------- Server Root NameServiceServerRoot + * Cell Persistent Root NameServiceCellPersistentRoot Cell Root + * NameServiceCellRoot, NameService Node Root NameServiceNodeRoot + */ + public static final String SERVER_ROOT = "NameServiceServerRoot"; + public static final String CELL_PERSISTENT_ROOT = "NameServiceCellPersistentRoot"; + public static final String CELL_ROOT = "NameServiceCellRoot"; + public static final String NODE_ROOT = "NameServiceNodeRoot"; + public static final String DEFAULT_ROOT = "NameService"; // Same as + // CELL_ROOT + + public static final String DEFAULT_HOST = "127.0.0.1"; // Default host name + // or IP address for + // WebSphere + public static final int DEFAULT_NAMING_PORT = 2809; // Default port + public static final String NAMING_SERVICE = "NameService"; // The name of + // the naming + // service + private static final Set<String> ROOTS = + new HashSet<String>(Arrays.asList(new String[] {SERVER_ROOT, CELL_PERSISTENT_ROOT, CELL_ROOT, DEFAULT_ROOT, + NODE_ROOT})); + + // private static final String CHARS_TO_ESCAPE = "\\/."; + private static final String RFC2396 = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789;/:?@&=+$,-_.!~*'()"; + private static final String HEX = "0123456789ABCDEF"; + + private String hostName = DEFAULT_HOST; + private int port = DEFAULT_NAMING_PORT; + private String root = SERVER_ROOT; + + private ORB orb = null; + private ObjectLocator locator = null; + private boolean managed = true; + + EJBLocator(boolean managed) { + this.managed = managed; + if (!managed) { + String url = AccessController.doPrivileged(new PrivilegedAction<String>() { + public String run() { + return System.getProperty(Context.PROVIDER_URL); + } + }); + processCorbaURL(url); + } + } + + EJBLocator(String hostName, int port) { + this.hostName = (hostName == null) ? DEFAULT_HOST : hostName; + this.port = port > 0 ? port : DEFAULT_NAMING_PORT; + this.root = SERVER_ROOT; + } + + EJBLocator(String hostName, int port, String root) { + this(hostName, port); + if (ROOTS.contains(root)) { + this.root = root; + } else { + throw new IllegalArgumentException(root + " is not a legal root"); + } + } + + EJBLocator(String corbaName, boolean managed) { + this.managed = managed; + if (corbaName.startsWith("corbaname:iiop:")) { + processCorbaURL(corbaName); + } else { + throw new IllegalArgumentException(corbaName + " is not a legal corbaname"); + } + } + + private void processCorbaURL(String url) { + if (url != null && (url.startsWith("corbaname:iiop:") || url.startsWith("corbaloc:iiop:"))) { + /** + * corbaname:iiop:<hostName>:<port>/<root>#name corbaloc:iiop:<hostname>:<port>/<root> + * For example, + * "corbaname:iiop:localhost:2809/NameServiceServerRoot#ejb/MyEJBHome"; + * or "corbaloc:iiop:myhost:2809/NameServiceServerRoot" + */ + String[] parts = url.split("(:|/|#)"); + if (parts.length > 2 && parts[2].length() > 0) { + hostName = parts[2]; // The host name + int index = hostName.lastIndexOf('@'); // version@hostname + if (index != -1) { + hostName = hostName.substring(index + 1); + } + } + if (parts.length > 3 && parts[3].length() > 0) { + port = Integer.parseInt(parts[3]); // The port number + } + if (parts.length > 4 && parts[4].length() > 0) { + root = parts[4]; // The root of naming + } + } + } + + /** + * The corbaloc and corbaname formats enable you to provide a URL to access + * CORBA objects. Use the corbaloc format for resolving to a particular + * CORBAservice without going through a naming service. Use the corbaname + * format to resolve a stringified name from a specific naming context. + */ + + /** + * corbaname Syntax The full corbaname BNF is: <corbaname> = + * "corbaname:"<corbaloc_obj>["#"<string_name>] + * <corbaloc_obj> = <obj_addr_list> ["/"<key_string>] + * <obj_addr_list> = as defined in a corbaloc URL <key_string> = + * as defined in a corbaloc URL <string_name>= stringified Name + * empty_string Where: + * <ul> + * <li>corbaloc_obj: portion of a corbaname URL that identifies the naming + * context. The syntax is identical to its use in a corbaloc URL. + * <li>obj_addr_list: as defined in a corbaloc URL + * <li>key_string: as defined in a corbaloc URL. + * <li>string_name: a stringified Name with URL escapes as defined below. + * </ul> + * + * @param hostName The host name or IP address of the naming server + * @param port The port number of the naming service + * @param root The root of the namespace + * @param name The JNDI name + */ + private static String getCorbaname(String hostName, int port, String root, String name) { + if (name == null) { + return "corbaname:iiop:" + hostName + ":" + port + "/" + root; + } else { + return "corbaname:iiop:" + hostName + ":" + port + "/" + root + "#" + toCorbaname(name); + } + } + + String getCorbaname(String name) { + return getCorbaname(hostName, port, root, name); + } + + /** + * Connect to the ORB. + */ + + // FIXME. May need to change the IBM classes if this binding is contributed + // to Tuscany + public ORB connect() { + if (orb == null) { + Properties props = new Properties(); + /* + * This code is for IBM JVM props.put("org.omg.CORBA.ORBClass", + * "com.ibm.CORBA.iiop.ORB"); + * props.put("com.ibm.CORBA.ORBInitRef.NameService", + * getCorbaloc(NAMING_SERVICE)); + * props.put("com.ibm.CORBA.ORBInitRef.NameServiceServerRoot", + * getCorbaloc("NameServiceServerRoot")); + */ + orb = ORB.init((String[])null, props); + } + return orb; + } + + /** + * Replace substrings + * + * @param source The source string. + * @param match The string to search for within the source string. + * @param replace The replacement for any matching components. + * @return + */ + private static String replace(String source, String match, String replace) { + int index = source.indexOf(match, 0); + if (index >= 0) { + + // We have at least one match, so got to do the + // work... + + StringBuffer result = new StringBuffer(source.length() + 16); + int matchLength = match.length(); + int startIndex = 0; + + while (index >= 0) { + result.append(source.substring(startIndex, index)); + result.append(replace); + startIndex = index + matchLength; + index = source.indexOf(match, startIndex); + } + + // Grab the last piece, if any... + if (startIndex < source.length()) { + result.append(source.substring(startIndex)); + } + + return result.toString(); + + } else { + // No matches, just return the source... + return source; + } + } + + /** + * Resolved the JNDI name from the initial CosNaming context + * + * @param jndiName + * @return resolved CORBA object + * @throws NamingException + */ + private static org.omg.CORBA.Object resovleString(NamingContextExt initCtx, String jndiName) throws NamingException { + try { + String name = stringify(jndiName); + return initCtx.resolve_str(name); + } catch (Exception e) { + NamingException ne = new NamingException(e.getMessage()); + ne.setRootCause(e); + throw ne; + } + } + + /** + * Look up a CORBA object by its JNDI name + * + * @param jndiName + * @return + * @throws NamingException + */ + org.omg.CORBA.Object stringToObject(String jndiName) throws NamingException { + /* + * Using an existing ORB and invoking string_to_object with a CORBA + * object URL with multiple name server addresses to get an initial + * context CORBA object URLs can contain more than one bootstrap server + * address. Use this feature when attempting to obtain an initial + * context from a server cluster. You can specify the bootstrap server + * addresses for all servers in the cluster in the URL. The operation + * will succeed if at least one of the servers is running, eliminating a + * single point of failure. There is no guarantee of any particular + * order in which the address list will be processed. For example, the + * second bootstrap server address may be used to obtain the initial + * context even though the first bootstrap server in the list is + * available. An example of a corbaloc URL with multiple addresses + * follows. obj = + * orb.string_to_object("corbaloc::myhost1:9810,:myhost1:9811,:myhost2:9810/NameService"); + */ + String corbaName = null; + if (jndiName.startsWith("corbaloc:") || jndiName.startsWith("corbaname:")) { + // Keep the qualified URL + corbaName = jndiName; + } else { + // Create a corbaname URL + corbaName = getCorbaname(jndiName); + } + + connect(); + org.omg.CORBA.Object obj = orb.string_to_object(corbaName); + return obj; + } + + private boolean isJndiConfigured() { + if (managed) + return true; + Boolean provided = AccessController.doPrivileged(new PrivilegedAction<Boolean>() { + public Boolean run() { + String initCtxFactory = System.getProperty(Context.INITIAL_CONTEXT_FACTORY); + if (initCtxFactory == null) { + URL file = Thread.currentThread().getContextClassLoader().getResource("jndi.properties"); + if (file != null) { + return Boolean.TRUE; + } else { + return Boolean.FALSE; + } + } else { + return Boolean.TRUE; + } + } + }); + return provided.booleanValue(); + } + + /** + * The character escape rules for the stringified name portion of an + * corbaname are: US-ASCII alphanumeric characters are not escaped. + * Characters outside this range are escaped, except for the following: ; / : ? @ & = + $ , - _ . ! ~ * ' ( ) + * corbaname Escape Mechanism The percent '%' character is used as an + * escape. If a character that requires escaping is present in a name + * component it is encoded as two hexadecimal digits following a "%" + * character to represent the octet. (The first hexadecimal character + * represent the highorder nibble of the octet, the second hexadecimal + * character represents the low-order nibble.) If a '%' is not followed by + * two hex digits, the stringified name is syntactically invalid. + * @param s + * @return RFC2396-encoded stringified name + */ + static String encode2396(String s) { + if (s == null) { + return null; + } + StringBuffer encoded = new StringBuffer(s); + for (int i = 0; i < encoded.length(); i++) { + char c = encoded.charAt(i); + if (RFC2396.indexOf(c) == -1) { + encoded.setCharAt(i, '%'); + char[] ac = Integer.toHexString(c).toCharArray(); + if (ac.length == 2) { + encoded.insert(i + 1, ac); + } else if (ac.length == 1) { + encoded.insert(i + 1, '0'); + encoded.insert(i + 2, ac[0]); + } else { + throw new IllegalArgumentException("Invalid character '" + c + "' in \"" + s + "\""); + } + i += 2; // NOPMD + } + } + return encoded.toString(); + } + + /** + * Decode an RFC2396-encoded string + * + * @param s + * @return Plain string + */ + static String decode2396(String s) { + if (s == null) { + return null; + } + StringBuffer decoded = new StringBuffer(s); + for (int i = 0; i < decoded.length(); i++) { + char c = decoded.charAt(i); + if (c == '%') { + if (i + 2 >= decoded.length()) { + throw new IllegalArgumentException("Incomplete key_string escape sequence"); + } + int j; + j = HEX.indexOf(decoded.charAt(i + 1)) * 16 + HEX.indexOf(decoded.charAt(i + 2)); + decoded.setCharAt(i, (char)j); + decoded.delete(i + 1, i + 3); + } else if (RFC2396.indexOf(c) == -1) { + throw new IllegalArgumentException("Invalid key_string character '" + c + "'"); + } + } + return decoded.toString(); + } + + /** + * The backslash '\' character escapes the reserved meaning of '/', '.', and + * '\' in a stringified name. + * + * @param jndiName + * @return Escaped stringified name for CosNaming + */ + private static String stringify(String jndiName) { + // Escape . into \. since it's an INS naming delimiter + return replace(encode2396(jndiName), ".", "\\."); + } + + /** + * Escape the "." into "%5C%2E" + * + * @param jndiName + * @return corbaname treating "." as a literal + */ + private static String toCorbaname(String jndiName) { + // Escape . into %5C%2E (\.) since it's an INS naming delimiter + // For example, sca.sample.StockQuote ---> + // sca%5C%2Esample%5C%2EStockQuote/StockQuote + return replace(encode2396(jndiName), ".", "%5C%2E"); + } + + private ObjectLocator getObjectLocator() throws NamingException { + if (locator != null) { + return locator; + } + /* + * For managed env, JNDI is assumed to be configured by default For + * unmanaged environment, JNDI could have configured through + * jndi.properties file + */ + if (isJndiConfigured()) { + locator = new JndiLocator(); + } else { // this is definitely JSE env without JNDI configured. Use + // CORBA. + locator = new CosNamingLocator(); + } + return locator; + } + + public Object locate(String jndiName) throws NamingException { + + Object result = getObjectLocator().locate(jndiName); + return result; + } + + private static interface ObjectLocator { + Object locate(String name) throws NamingException; + } + + private final class JndiLocator implements ObjectLocator { + private Context context; + + private JndiLocator() throws NamingException { + /* + final Properties props = AccessController.doPrivileged(new PrivilegedAction<Properties>() { + public Properties run() { + return System.getProperties(); + } + }); + Properties properties = new Properties(); + for (Map.Entry e : props.entrySet()) { + String name = (String)e.getKey(); + if (name.startsWith("java.naming.")) { + properties.setProperty(name, (String)e.getValue()); + } + } + // System.out.println(properties); + this.context = new InitialContext(properties); + */ + this.context = new InitialContext(); + } + + public Object locate(String name) throws NamingException { + return context.lookup(name); + } + } + + private final class CosNamingLocator implements ObjectLocator { + private NamingContextExt context; + + private CosNamingLocator() { + } + + public Object locate(String name) throws NamingException { + if (context != null) { + return resovleString(context, name); + } else { + return stringToObject(name); + } + } + } + + public void setHostEnv(boolean managed) { + this.managed = managed; + } +} |