| /* NameParser.java -- |
| Copyright (C) 2005, 2006 Free Software Foundation, Inc. |
| |
| This file is part of GNU Classpath. |
| |
| GNU Classpath is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU Classpath is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Classpath; see the file COPYING. If not, write to the |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| 02110-1301 USA. |
| |
| Linking this library statically or dynamically with other modules is |
| making a combined work based on this library. Thus, the terms and |
| conditions of the GNU General Public License cover the whole |
| combination. |
| |
| As a special exception, the copyright holders of this library give you |
| permission to link this library with independent modules to produce an |
| executable, regardless of the license terms of these independent |
| modules, and to copy and distribute the resulting executable under |
| terms of your choice, provided that you also meet, for each linked |
| independent module, the terms and conditions of the license of that |
| module. An independent module is a module which is not derived from |
| or based on this library. If you modify this library, you may extend |
| this exception to your version of the library, but you are not |
| obligated to do so. If you do not wish to do so, delete this |
| exception statement from your version. */ |
| |
| |
| package gnu.CORBA.NamingService; |
| |
| import gnu.CORBA.Minor; |
| import gnu.CORBA.OrbFunctional; |
| import gnu.CORBA.IOR; |
| import gnu.CORBA.Unexpected; |
| import gnu.CORBA.Version; |
| |
| import org.omg.CORBA.BAD_PARAM; |
| import org.omg.CORBA.DATA_CONVERSION; |
| import org.omg.CORBA.ORB; |
| import org.omg.CORBA.Object; |
| import org.omg.CORBA.ORBPackage.InvalidName; |
| import org.omg.CORBA.portable.Delegate; |
| import org.omg.CORBA.portable.ObjectImpl; |
| import org.omg.CosNaming.NamingContext; |
| import org.omg.CosNaming._NamingContextStub; |
| |
| import java.io.File; |
| import java.io.FileReader; |
| import java.io.IOException; |
| import java.io.InputStreamReader; |
| import java.io.UnsupportedEncodingException; |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| import java.net.URLDecoder; |
| import java.util.ArrayList; |
| import java.util.StringTokenizer; |
| |
| /** |
| * Parses the alternative IOR representations into our IOR structure. |
| * |
| * TODO This parser currently supports only one address per target string. A |
| * string with the multiple addresses will be accepted, but only the last |
| * address will be taken into consideration. The fault tolerance is not yet |
| * implemented. |
| * |
| * The key string is filtered using {@link java.net.URLDecoder} that replaces |
| * the agreed escape sequences by the corresponding non alphanumeric characters. |
| * |
| * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) |
| */ |
| public class NameParser |
| extends NameTransformer |
| { |
| /** |
| * The corbaloc prefix. |
| */ |
| public static final String pxCORBALOC = "corbaloc"; |
| |
| /** |
| * The corbaname prefix. |
| */ |
| public static final String pxCORBANAME = "corbaname"; |
| |
| /** |
| * The IOR prefix. |
| */ |
| public static final String pxIOR = "ior"; |
| |
| /** |
| * The file:// prefix. |
| */ |
| public static final String pxFILE = "file://"; |
| |
| /** |
| * The ftp:// prefix. |
| */ |
| public static final String pxFTP = "ftp://"; |
| |
| /** |
| * The http:// prefix. |
| */ |
| public static final String pxHTTP = "http://"; |
| |
| /** |
| * Marks iiop protocol. |
| */ |
| public static final String IIOP = "iiop"; |
| |
| /** |
| * Marks rir protocol. |
| */ |
| public static final String RIR = "rir"; |
| |
| /** |
| * The default port value, as specified in OMG documentation. |
| */ |
| public static final int DEFAULT_PORT = 2809; |
| |
| /** |
| * The default name. |
| */ |
| public static final String DEFAULT_NAME = "NameService"; |
| |
| /** |
| * The string to name converter, initialized on demand. |
| */ |
| static NameTransformer converter; |
| |
| /** |
| * The current position. |
| */ |
| int p; |
| |
| /** |
| * The address being parsed, splitted into tokens. |
| */ |
| String[] t; |
| |
| /** |
| * Parse CORBALOC. |
| * |
| * The expected format is: <br> |
| * 1. corbaloc:[iiop][version.subversion@]:host[:port]/key <br> |
| * 2. corbaloc:rir:[/key] <br> |
| * 3. corbaname:[iiop][version.subversion@]:host[:port]/key <br> |
| * 4. corbaname:rir:[/key] <br> |
| * 5. file://[file name]<br> |
| * 6. http://[url]<br> |
| * 7. ftp://[url]<br> |
| * |
| * Protocol defaults to IOP, the object key defaults to the NameService. |
| * |
| * @param corbaloc the string to parse. |
| * @param orb the ORB, needed to create IORs and resolve rir references. |
| * |
| * @return the resolved object. |
| */ |
| public synchronized org.omg.CORBA.Object corbaloc(String corbaloc, |
| OrbFunctional orb) |
| throws BAD_PARAM |
| { |
| return corbaloc(corbaloc, orb, 0); |
| } |
| |
| /** |
| * Parse controlling against the infinite recursion loop. |
| */ |
| private org.omg.CORBA.Object corbaloc(String corbaloc, |
| OrbFunctional orb, int recursion) |
| { |
| // The used CORBA specification does not state how many times we should to |
| //redirect, but the infinite loop may be used to knock out the system. |
| // by malicious attempt. |
| if (recursion > 10) |
| throw new DATA_CONVERSION("More than 10 redirections"); |
| |
| if (corbaloc.startsWith(pxFILE)) |
| return corbaloc(readFile(corbaloc.substring(pxFILE.length())), orb, recursion+1); |
| else if (corbaloc.startsWith(pxHTTP)) |
| return corbaloc(readUrl(corbaloc), orb, recursion+1); |
| else if (corbaloc.startsWith(pxFTP)) |
| return corbaloc(readUrl(corbaloc), orb, recursion+1); |
| |
| boolean corbaname; |
| |
| // The alternative addresses, if given. |
| ArrayList alt_addr = new ArrayList(); |
| |
| // The version numbers with default values. |
| int major = 1; |
| int minor = 0; |
| |
| // The host address. |
| String host; |
| |
| // The port. |
| int port = DEFAULT_PORT; |
| |
| // The object key as string. |
| String key; |
| |
| StringTokenizer st = new StringTokenizer(corbaloc, ":@/.,#", true); |
| |
| t = new String[st.countTokens()]; |
| |
| for (int i = 0; i < t.length; i++) |
| { |
| t[i] = st.nextToken(); |
| } |
| |
| p = 0; |
| |
| if (t[p].startsWith(pxCORBANAME)) |
| corbaname = true; |
| else if (t[p].equalsIgnoreCase(pxCORBALOC)) |
| corbaname = false; |
| else if (t[p].equalsIgnoreCase(pxIOR)) |
| { |
| IOR ior = IOR.parse(corbaloc); |
| return orb.ior_to_object(ior); |
| } |
| else |
| throw new DATA_CONVERSION("Unsupported protocol: '" + t[p] + "'"); |
| |
| p++; |
| |
| if (!t[p++].equals(":")) |
| throw new BAD_PARAM("Syntax (':' expected after name prefix)"); |
| |
| // Check for rir: |
| if (t[p].equals(RIR)) |
| { |
| p++; |
| if (!t[p++].equals(":")) |
| throw new BAD_PARAM("':' expected after 'rir'"); |
| |
| key = readKey("/"); |
| |
| Object object; |
| try |
| { |
| object = orb.resolve_initial_references(key); |
| return corbaname ? resolve(object) : object; |
| } |
| catch (InvalidName e) |
| { |
| throw new BAD_PARAM("Unknown initial reference '" + key + "'"); |
| } |
| } |
| else |
| // Check for iiop. |
| if (t[p].equals(IIOP) || t[p].equals(":")) |
| { |
| IOR ior = new IOR(); |
| |
| Addresses: do |
| { // Read addresses. |
| if (t[p].equals(":")) |
| { |
| p++; |
| } |
| else |
| { |
| p++; |
| if (!t[p++].equals(":")) |
| throw new BAD_PARAM("':' expected after 'iiop'"); |
| // Check if version is present. |
| if (t[p + 1].equals(".")) |
| if (t[p + 3].equals("@")) |
| { |
| // Version info present. |
| try |
| { |
| major = Integer.parseInt(t[p++]); |
| } |
| catch (NumberFormatException e) |
| { |
| throw new BAD_PARAM("Major version number '" |
| + t[p - 1] + "'"); |
| } |
| p++; // '.' at this point. |
| try |
| { |
| minor = Integer.parseInt(t[p++]); |
| } |
| catch (NumberFormatException e) |
| { |
| throw new BAD_PARAM("Major version number '" |
| + t[p - 1] + "'"); |
| } |
| p++; // '@' at this point. |
| } |
| } |
| |
| ior.Internet.version = new Version(major, minor); |
| |
| // Then host data goes till '/' or ':'. |
| StringBuffer bhost = new StringBuffer(corbaloc.length()); |
| while (!t[p].equals(":") && !t[p].equals("/") && !t[p].equals(",")) |
| bhost.append(t[p++]); |
| |
| host = bhost.toString(); |
| |
| ior.Internet.host = host; |
| |
| if (t[p].equals(":")) |
| { |
| // Port specified. |
| p++; |
| try |
| { |
| port = Integer.parseInt(t[p++]); |
| } |
| catch (NumberFormatException e) |
| { |
| throw new BAD_PARAM("Invalid port '" + t[p - 1] + "'"); |
| } |
| } |
| |
| ior.Internet.port = port; |
| |
| // Id is not listed. |
| ior.Id = ""; |
| |
| if (t[p].equals(",")) |
| p++; |
| else |
| break Addresses; |
| } |
| while (true); |
| |
| key = readKey("/"); |
| ior.key = key.getBytes(); |
| |
| org.omg.CORBA.Object object = orb.ior_to_object(ior); |
| return corbaname ? resolve(object) : object; |
| } |
| |
| else |
| throw new DATA_CONVERSION("Unsupported protocol '" + t[p] + "'"); |
| } |
| |
| /** |
| * Read IOR from the file in the local file system. |
| */ |
| String readFile(String file) |
| { |
| File f = new File(file); |
| if (!f.exists()) |
| { |
| DATA_CONVERSION err = new DATA_CONVERSION(f.getAbsolutePath() |
| + " does not exist."); |
| err.minor = Minor.Missing_IOR; |
| } |
| try |
| { |
| char[] c = new char[(int) f.length()]; |
| FileReader fr = new FileReader(f); |
| fr.read(c); |
| fr.close(); |
| return new String(c).trim(); |
| } |
| catch (IOException ex) |
| { |
| DATA_CONVERSION d = new DATA_CONVERSION(); |
| d.initCause(ex); |
| d.minor = Minor.Missing_IOR; |
| throw (d); |
| } |
| } |
| |
| /** |
| * Read IOR from the remote URL. |
| */ |
| String readUrl(String url) |
| { |
| URL u; |
| try |
| { |
| u = new URL(url); |
| } |
| catch (MalformedURLException mex) |
| { |
| throw new BAD_PARAM("Malformed URL: '" + url + "'"); |
| } |
| |
| try |
| { |
| InputStreamReader r = new InputStreamReader(u.openStream()); |
| |
| StringBuffer b = new StringBuffer(); |
| int c; |
| |
| while ((c = r.read()) > 0) |
| b.append((char) c); |
| |
| return b.toString().trim(); |
| } |
| catch (Exception exc) |
| { |
| DATA_CONVERSION d = new DATA_CONVERSION("Reading " + url + " failed."); |
| d.minor = Minor.Missing_IOR; |
| throw d; |
| } |
| } |
| |
| private org.omg.CORBA.Object resolve(org.omg.CORBA.Object object) |
| { |
| NamingContext ns; |
| String key = "?"; |
| try |
| { |
| if (object instanceof NamingContext) |
| ns = (NamingContext) object; |
| else |
| { |
| Delegate delegate = ((ObjectImpl) object)._get_delegate(); |
| ns = new _NamingContextStub(); |
| ((_NamingContextStub) ns)._set_delegate(delegate); |
| } |
| } |
| catch (Exception ex) |
| { |
| BAD_PARAM bad = new BAD_PARAM("The CORBANAME target " + object |
| + " is not a NamingContext"); |
| bad.minor = 10; |
| bad.initCause(ex); |
| throw bad; |
| } |
| |
| if (converter == null) |
| converter = new NameTransformer(); |
| |
| try |
| { |
| key = readKey("#"); |
| object = ns.resolve(converter.toName(key)); |
| return object; |
| } |
| catch (Exception ex) |
| { |
| BAD_PARAM bad = new BAD_PARAM("Wrong CORBANAME '" + key + "'"); |
| bad.minor = 10; |
| bad.initCause(ex); |
| throw bad; |
| } |
| } |
| |
| private String readKey(String delimiter) |
| throws BAD_PARAM |
| { |
| if (p < t.length) |
| if (!t[p].equals(delimiter)) |
| { |
| if (t[p].equals("#")) |
| return DEFAULT_NAME; |
| else |
| throw new BAD_PARAM("'" + delimiter + "String' expected '" + t[p] |
| + "' found"); |
| } |
| |
| StringBuffer bKey = new StringBuffer(); |
| p++; |
| |
| while (p < t.length && !t[p].equals("#")) |
| bKey.append(t[p++]); |
| |
| if (bKey.length() == 0) |
| return DEFAULT_NAME; |
| |
| try |
| { |
| return URLDecoder.decode(bKey.toString(), "UTF-8"); |
| } |
| catch (UnsupportedEncodingException e) |
| { |
| throw new Unexpected("URLDecoder does not support UTF-8", e); |
| } |
| } |
| |
| static NameParser n = new NameParser(); |
| |
| static void corbalocT(String ior, OrbFunctional orb) |
| { |
| System.out.println(ior); |
| System.out.println(n.corbaloc(ior, orb)); |
| System.out.println(); |
| } |
| |
| public static void main(String[] args) |
| { |
| try |
| { |
| OrbFunctional orb = (OrbFunctional) ORB.init(args, null); |
| corbalocT("corbaloc:iiop:1.3@155axyz.com/Prod/aTradingService", orb); |
| corbalocT("corbaloc:iiop:2.7@255bxyz.com/Prod/bTradingService", orb); |
| corbalocT("corbaloc:iiop:355cxyz.com/Prod/cTradingService", orb); |
| corbalocT("corbaloc:iiop:2.7@255bxyz.com/Prod/bTradingService", orb); |
| corbalocT("corbaloc:iiop:355cxyz.com:7777/Prod/cTradingService", orb); |
| |
| corbalocT("corbaloc::556xyz.com:80/Dev/NameService", orb); |
| corbalocT("corbaloc:iiop:1.2@host1:3076/0", orb); |
| |
| corbalocT("corbaloc:rir:/NameService", orb); |
| corbalocT("corbaloc:rir:/", orb); |
| corbalocT("corbaloc:rir:", orb); |
| |
| corbalocT("corbaloc:rir:/NameService", orb); |
| corbalocT("corbaloc:rir:/", orb); |
| corbalocT("corbaloc:rir:", orb); |
| |
| corbalocT("corbaloc::555xyz.com,:556xyz.com:80/Dev/NameService", orb); |
| } |
| catch (BAD_PARAM e) |
| { |
| e.printStackTrace(System.out); |
| } |
| } |
| } |