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