Source for gnu.CORBA.NamingService.NameTransformer

   1: /* NameTransformer.java --
   2:    Copyright (C) 2005 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package gnu.CORBA.NamingService;
  40: 
  41: import org.omg.CORBA.IntHolder;
  42: import org.omg.CosNaming.NameComponent;
  43: import org.omg.CosNaming.NamingContextPackage.InvalidName;
  44: 
  45: import java.util.ArrayList;
  46: import java.util.StringTokenizer;
  47: 
  48: /**
  49:  * This class converts between string and array representations of the
  50:  * multi component object names.
  51:  *
  52:  * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
  53:  */
  54: public class NameTransformer
  55: {
  56:   /**
  57:    * A string, indicating the escape character.
  58:    */
  59:   public static final String ESCAPE = "\\";
  60: 
  61:   /**
  62:    * Convert the string name representation into the array name
  63:    * representation. See {@link #toString(NameComponent)} for the
  64:    * description of this format.
  65:    *
  66:    * @param name the string form of the name.
  67:    *
  68:    * @return the array form of the name.
  69:    *
  70:    * @throws InvalidName if the name cannot be parsed.
  71:    */
  72:   public NameComponent[] toName(String a_name)
  73:                          throws InvalidName
  74:   {
  75:     ArrayList components = new ArrayList();
  76:     StringTokenizer st = new StringTokenizer(a_name, "./\\", true);
  77: 
  78:     String id;
  79:     String kind;
  80:     String next;
  81: 
  82:     // Create the buffer array, reserving the last element for null.
  83:     String[] n = new String[ st.countTokens() + 1 ];
  84: 
  85:     int pp = 0;
  86:     while (st.hasMoreTokens())
  87:       n [ pp++ ] = st.nextToken();
  88: 
  89:     IntHolder p = new IntHolder();
  90: 
  91:     NameComponent node = readNode(p, n);
  92: 
  93:     while (node != null)
  94:       {
  95:         components.add(node);
  96:         node = readNode(p, n);
  97:       }
  98: 
  99:     NameComponent[] name = new NameComponent[ components.size() ];
 100:     for (int i = 0; i < name.length; i++)
 101:       {
 102:         name [ i ] = (NameComponent) components.get(i);
 103:       }
 104: 
 105:     NameValidator.check(name);
 106: 
 107:     return name;
 108:   }
 109: 
 110:   /**
 111:    * Converts the name into its string representation, as defined in
 112:    * the specification CORBA naming service.
 113:    *
 114:    * A string representation for the name consists of the name components,
 115:    * separated by a slash '/' character (for example, 'a/b/c'). If the
 116:    * {@link NameComponent#kind} field is  not empty, it is given after
 117:    * period ('.'), for example 'a.b/c.d/.' .
 118:    * The period alone represents node where part where both
 119:    * {@link NameComponent#kind} and {@link NameComponent#id} are empty strings.
 120:    *
 121:    * If slash or dot are part of the name, they are escaped by backslash ('\').
 122:    * If the backslash itself is part of the name, it is doubled.
 123:    *
 124:    * @param a_name a name to convert.
 125:    * @return a string representation.
 126:    */
 127:   public String toString(NameComponent[] a_name)
 128:                   throws InvalidName
 129:   {
 130:     NameValidator.check(a_name);
 131: 
 132:     StringBuffer b = new StringBuffer();
 133: 
 134:     NameComponent n;
 135: 
 136:     for (int ni = 0; ni < a_name.length; ni++)
 137:       {
 138:         n = a_name [ ni ];
 139:         appEscaping(b, n.id);
 140:         if (n.kind.length() > 0)
 141:           {
 142:             b.append('.');
 143:             appEscaping(b, n.kind);
 144:           }
 145: 
 146:         if (ni < a_name.length - 1)
 147:           b.append('/');
 148:       }
 149:     return b.toString();
 150:   }
 151: 
 152:   /**
 153:    * Append the contents of the string to this
 154:    * string buffer, inserting the escape sequences, where required.
 155:    *
 156:    * @param b a buffer to append the contents to.
 157:    * @param s a string to append.
 158:    */
 159:   private void appEscaping(StringBuffer b, String s)
 160:   {
 161:     char c;
 162:     for (int i = 0; i < s.length(); i++)
 163:       {
 164:         c = s.charAt(i);
 165:         switch (c)
 166:           {
 167:             case '.' :
 168:             case '/' :
 169:             case '\\' :
 170:               b.append('\\');
 171:               b.append(c);
 172:               break;
 173: 
 174:             default :
 175:               b.append(c);
 176:               break;
 177:           }
 178:       }
 179:   }
 180: 
 181:   /**
 182:    * Assert the end of the current name component.
 183:    */
 184:   private void assertEndOfNode(IntHolder p, String[] t)
 185:                         throws InvalidName
 186:   {
 187:     if (t [ p.value ] != null)
 188:       if (!t [ p.value ].equals("/"))
 189:         throw new InvalidName("End of node expected at token " + p.value);
 190:   }
 191: 
 192:   /**
 193:    * Read the named component node. After reading the current positon
 194:    * advances to the beginning of the next node in an array.
 195:    *
 196:    * @param p the current position being wrapped inside the passed
 197:    * IntHolder.
 198:    *
 199:    * @param t the text buffer.
 200:    *
 201:    * @return the created node.
 202:    */
 203:   private NameComponent readNode(IntHolder p, String[] t)
 204:                           throws InvalidName
 205:   {
 206:     // End of stream has been reached.
 207:     if (t [ p.value ] == null)
 208:       return null;
 209: 
 210:     NameComponent n = new NameComponent();
 211: 
 212:     if (t [ p.value ].equals("."))
 213:       {
 214:         // The 'id' is missing, but the 'kind' may follow.
 215:         n.id = "";
 216:         p.value++;
 217:         n.kind = readPart(p, t);
 218:         assertEndOfNode(p, t);
 219:         if (t [ p.value ] != null)
 220:           p.value++;
 221:       }
 222:     else if (t [ p.value ].equals("/"))
 223:       {
 224:         // This is not allowed here and may happen only
 225:         // on two subsequent slashes.
 226:         throw new InvalidName("Unexpected '/' token " + p.value);
 227:       }
 228:     else
 229:       {
 230:         n.id = readPart(p, t);
 231: 
 232:         // If some chars follow the id.
 233:         if (t [ p.value ] != null)
 234:           {
 235:             // Dot means that the kind part follows
 236:             if (t [ p.value ].equals("."))
 237:               {
 238:                 p.value++;
 239:                 n.kind = readPart(p, t);
 240:                 assertEndOfNode(p, t);
 241:                 if (t [ p.value ] != null)
 242:                   p.value++;
 243:               }
 244: 
 245:             // The next name component follows - advance to
 246:             // the beginning of the next name component.
 247:             else if (t [ p.value ].equals("/"))
 248:               {
 249:                 n.kind = "";
 250:                 p.value++;
 251:               }
 252:             else
 253:               throw new InvalidName("Unexpected '" + t [ p.value ] +
 254:                                        "' at token " + p.value
 255:                                       );
 256:           }
 257:         else
 258: 
 259:           // Id, and then end of sequence.
 260:           n.kind = "";
 261:       }
 262: 
 263:     return n;
 264:   }
 265: 
 266:   /**
 267:    * Read the name part (id or kind).
 268:    *
 269:    * @param p the current position. After reading, advances
 270:    * to the beginning of the next name fragment.
 271:    *
 272:    * @param t the string buffer.
 273:    *
 274:    * @return the name part with resolved escape sequences.
 275:    */
 276:   private String readPart(IntHolder p, String[] t)
 277:   {
 278:     StringBuffer part = new StringBuffer();
 279: 
 280:     while (t [ p.value ] != null && !t [ p.value ].equals(".") &&
 281:            !t [ p.value ].equals("/")
 282:           )
 283:       {
 284:         if (t [ p.value ].equals(ESCAPE))
 285:           {
 286:             p.value++;
 287:             part.append(t [ p.value ]);
 288:           }
 289:         else
 290:           part.append(t [ p.value ]);
 291: 
 292:         p.value++;
 293:       }
 294: 
 295:     return part.toString();
 296:   }
 297: 
 298:   public static void main(String[] args)
 299:   {
 300:     NameComponent a = new NameComponent("a", "ak");
 301:     NameComponent b = new NameComponent("b/z", "b.k");
 302:     NameComponent c = new NameComponent("c", "");
 303: 
 304:     NameTransformer sn = new NameTransformer();
 305: 
 306:     try
 307:       {
 308:         String s = sn.toString(new NameComponent[] { a, b, c });
 309:         System.out.println(s);
 310: 
 311:         //NameComponent[] k = toName("a.k/b.k2/c/d/.");
 312:         //NameComponent[] k = toName("a.bc/.b/c.x");
 313: 
 314:         NameComponent[] k = sn.toName(s);
 315:         System.out.println("ToString");
 316: 
 317:         for (int i = 0; i < k.length; i++)
 318:           {
 319:             System.out.println(k [ i ].id + ":" + k [ i ].kind);
 320:           }
 321:       }
 322:     catch (InvalidName ex)
 323:       {
 324:         ex.printStackTrace();
 325:       }
 326:   }
 327: 
 328: }