Source for gnu.CORBA.NamingService.NameTransformer

   1: /* NameTransformer.java --
   2:    Copyright (C) 2005, 2006 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:     // Create the buffer array, reserving the last element for null.
  79:     String[] n = new String[ st.countTokens() + 1 ];
  80: 
  81:     int pp = 0;
  82:     while (st.hasMoreTokens())
  83:       n [ pp++ ] = st.nextToken();
  84: 
  85:     IntHolder p = new IntHolder();
  86: 
  87:     NameComponent node = readNode(p, n);
  88: 
  89:     while (node != null)
  90:       {
  91:         components.add(node);
  92:         node = readNode(p, n);
  93:       }
  94: 
  95:     NameComponent[] name = new NameComponent[ components.size() ];
  96:     for (int i = 0; i < name.length; i++)
  97:       {
  98:         name [ i ] = (NameComponent) components.get(i);
  99:       }
 100: 
 101:     NameValidator.check(name);
 102: 
 103:     return name;
 104:   }
 105: 
 106:   /**
 107:    * Converts the name into its string representation, as defined in
 108:    * the specification CORBA naming service.
 109:    *
 110:    * A string representation for the name consists of the name components,
 111:    * separated by a slash '/' character (for example, 'a/b/c'). If the
 112:    * {@link NameComponent#kind} field is  not empty, it is given after
 113:    * period ('.'), for example 'a.b/c.d/.' .
 114:    * The period alone represents node where part where both
 115:    * {@link NameComponent#kind} and {@link NameComponent#id} are empty strings.
 116:    *
 117:    * If slash or dot are part of the name, they are escaped by backslash ('\').
 118:    * If the backslash itself is part of the name, it is doubled.
 119:    *
 120:    * @param a_name a name to convert.
 121:    * @return a string representation.
 122:    */
 123:   public String toString(NameComponent[] a_name)
 124:                   throws InvalidName
 125:   {
 126:     NameValidator.check(a_name);
 127: 
 128:     StringBuffer b = new StringBuffer();
 129: 
 130:     NameComponent n;
 131: 
 132:     for (int ni = 0; ni < a_name.length; ni++)
 133:       {
 134:         n = a_name [ ni ];
 135:         appEscaping(b, n.id);
 136:         if (n.kind.length() > 0)
 137:           {
 138:             b.append('.');
 139:             appEscaping(b, n.kind);
 140:           }
 141: 
 142:         if (ni < a_name.length - 1)
 143:           b.append('/');
 144:       }
 145:     return b.toString();
 146:   }
 147: 
 148:   /**
 149:    * Append the contents of the string to this
 150:    * string buffer, inserting the escape sequences, where required.
 151:    *
 152:    * @param b a buffer to append the contents to.
 153:    * @param s a string to append.
 154:    */
 155:   private void appEscaping(StringBuffer b, String s)
 156:   {
 157:     char c;
 158:     for (int i = 0; i < s.length(); i++)
 159:       {
 160:         c = s.charAt(i);
 161:         switch (c)
 162:           {
 163:             case '.' :
 164:             case '/' :
 165:             case '\\' :
 166:               b.append('\\');
 167:               b.append(c);
 168:               break;
 169: 
 170:             default :
 171:               b.append(c);
 172:               break;
 173:           }
 174:       }
 175:   }
 176: 
 177:   /**
 178:    * Assert the end of the current name component.
 179:    */
 180:   private void assertEndOfNode(IntHolder p, String[] t)
 181:                         throws InvalidName
 182:   {
 183:     if (t [ p.value ] != null)
 184:       if (!t [ p.value ].equals("/"))
 185:         throw new InvalidName("End of node expected at token " + p.value);
 186:   }
 187: 
 188:   /**
 189:    * Read the named component node. After reading the current positon
 190:    * advances to the beginning of the next node in an array.
 191:    *
 192:    * @param p the current position being wrapped inside the passed
 193:    * IntHolder.
 194:    *
 195:    * @param t the text buffer.
 196:    *
 197:    * @return the created node.
 198:    */
 199:   private NameComponent readNode(IntHolder p, String[] t)
 200:                           throws InvalidName
 201:   {
 202:     // End of stream has been reached.
 203:     if (t [ p.value ] == null)
 204:       return null;
 205: 
 206:     NameComponent n = new NameComponent();
 207: 
 208:     if (t [ p.value ].equals("."))
 209:       {
 210:         // The 'id' is missing, but the 'kind' may follow.
 211:         n.id = "";
 212:         p.value++;
 213:         n.kind = readPart(p, t);
 214:         assertEndOfNode(p, t);
 215:         if (t [ p.value ] != null)
 216:           p.value++;
 217:       }
 218:     else if (t [ p.value ].equals("/"))
 219:       {
 220:         // This is not allowed here and may happen only
 221:         // on two subsequent slashes.
 222:         throw new InvalidName("Unexpected '/' token " + p.value);
 223:       }
 224:     else
 225:       {
 226:         n.id = readPart(p, t);
 227: 
 228:         // If some chars follow the id.
 229:         if (t [ p.value ] != null)
 230:           {
 231:             // Dot means that the kind part follows
 232:             if (t [ p.value ].equals("."))
 233:               {
 234:                 p.value++;
 235:                 n.kind = readPart(p, t);
 236:                 assertEndOfNode(p, t);
 237:                 if (t [ p.value ] != null)
 238:                   p.value++;
 239:               }
 240: 
 241:             // The next name component follows - advance to
 242:             // the beginning of the next name component.
 243:             else if (t [ p.value ].equals("/"))
 244:               {
 245:                 n.kind = "";
 246:                 p.value++;
 247:               }
 248:             else
 249:               throw new InvalidName("Unexpected '" + t [ p.value ] +
 250:                                        "' at token " + p.value
 251:                                       );
 252:           }
 253:         else
 254: 
 255:           // Id, and then end of sequence.
 256:           n.kind = "";
 257:       }
 258: 
 259:     return n;
 260:   }
 261: 
 262:   /**
 263:    * Read the name part (id or kind).
 264:    *
 265:    * @param p the current position. After reading, advances
 266:    * to the beginning of the next name fragment.
 267:    *
 268:    * @param t the string buffer.
 269:    *
 270:    * @return the name part with resolved escape sequences.
 271:    */
 272:   private String readPart(IntHolder p, String[] t)
 273:   {
 274:     StringBuffer part = new StringBuffer();
 275: 
 276:     while (t [ p.value ] != null && !t [ p.value ].equals(".") &&
 277:            !t [ p.value ].equals("/")
 278:           )
 279:       {
 280:         if (t [ p.value ].equals(ESCAPE))
 281:           {
 282:             p.value++;
 283:             part.append(t [ p.value ]);
 284:           }
 285:         else
 286:           part.append(t [ p.value ]);
 287: 
 288:         p.value++;
 289:       }
 290: 
 291:     return part.toString();
 292:   }
 293: 
 294:   public static void main(String[] args)
 295:   {
 296:     NameComponent a = new NameComponent("a", "ak");
 297:     NameComponent b = new NameComponent("b/z", "b.k");
 298:     NameComponent c = new NameComponent("c", "");
 299: 
 300:     NameTransformer sn = new NameTransformer();
 301: 
 302:     try
 303:       {
 304:         String s = sn.toString(new NameComponent[] { a, b, c });
 305:         System.out.println(s);
 306: 
 307:         //NameComponent[] k = toName("a.k/b.k2/c/d/.");
 308:         //NameComponent[] k = toName("a.bc/.b/c.x");
 309: 
 310:         NameComponent[] k = sn.toName(s);
 311:         System.out.println("ToString");
 312: 
 313:         for (int i = 0; i < k.length; i++)
 314:           {
 315:             System.out.println(k [ i ].id + ":" + k [ i ].kind);
 316:           }
 317:       }
 318:     catch (InvalidName ex)
 319:       {
 320:         ex.printStackTrace();
 321:       }
 322:   }
 323: 
 324: }