KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > xml > binding > Util


1 /*
2  * JBoss, the OpenSource J2EE webOS
3  *
4  * Distributable under LGPL license.
5  * See terms of license at gnu.org.
6  */

7 package org.jboss.xml.binding;
8
9 import org.jboss.util.Classes;
10
11 /**
12  * Various utilities for XML binding.
13  *
14  * @author <a HREF="mailto:alex@jboss.org">Alexey Loubyansky</a>
15  * @version <tt>$Revision: 1.1.2.6 $</tt>
16  */

17 public final class Util
18 {
19    /**
20     * Characters that are considered to be word separators while convertinging XML names to Java identifiers
21     * according to JAXB 2.0 spec.
22     */

23    public static final char HYPHEN_MINUS = '\u002D';
24    public static final char FULL_STOP = '\u002E';
25    public static final char COLLON = '\u003A';
26    public static final char LOW_LINE = '\u005F';
27    public static final char MIDDLE_DOT = '\u00B7';
28    public static final char GREEK_ANO_TELEIA = '\u0387';
29    public static final char ARABIC_END_OF_AYAH = '\u06DD';
30    public static final char ARABIC_START_OF_RUB_EL_HIZB = '\u06DE';
31
32    /**
33     * Converts XML name to Java class name according to
34     * Binding XML Names to Java Identifiers
35     * C.2. The Name to Identifier Mapping Algorithm
36     * jaxb-2_0-edr-spec-10_jun_2004.pdf
37     *
38     * @param name XML name
39     * @param ignoreLowLine whether low lines should not be parts of Java identifiers
40     * @return Java class name
41     */

42    public static String JavaDoc xmlNameToClassName(String JavaDoc name, boolean ignoreLowLine)
43    {
44       return XMLNameToJavaIdentifierConverter.PARSER.parse(XMLNameToJavaIdentifierConverter.CLASS_NAME,
45          name,
46          ignoreLowLine
47       );
48    }
49
50    /**
51     * Converts XML name to Java getter method name according to
52     * Binding XML Names to Java Identifiers
53     * C.2. The Name to Identifier Mapping Algorithm
54     * jaxb-2_0-edr-spec-10_jun_2004.pdf
55     *
56     * @param name XML name
57     * @param ignoreLowLine whether low lines should not be parts of Java identifiers
58     * @return Java getter method name
59     */

60    public static String JavaDoc xmlNameToGetMethodName(String JavaDoc name, boolean ignoreLowLine)
61    {
62       return "get" + xmlNameToClassName(name, ignoreLowLine);
63    }
64
65    /**
66     * Converts XML name to Java setter method name according to
67     * Binding XML Names to Java Identifiers
68     * C.2. The Name to Identifier Mapping Algorithm
69     * jaxb-2_0-edr-spec-10_jun_2004.pdf
70     *
71     * @param name XML name
72     * @param ignoreLowLine whether low lines should not be parts of Java identifiers
73     * @return Java setter method name
74     */

75    public static String JavaDoc xmlNameToSetMethodName(String JavaDoc name, boolean ignoreLowLine)
76    {
77       return "set" + xmlNameToClassName(name, ignoreLowLine);
78    }
79
80    /**
81     * Converts XML name to Java constant name according to
82     * Binding XML Names to Java Identifiers
83     * C.2. The Name to Identifier Mapping Algorithm
84     * jaxb-2_0-edr-spec-10_jun_2004.pdf
85     *
86     * @param name XML name
87     * @return Java constant name
88     */

89    public static String JavaDoc xmlNameToConstantName(String JavaDoc name)
90    {
91       return XMLNameToJavaIdentifierConverter.PARSER.parse(XMLNameToJavaIdentifierConverter.CONSTANT_NAME,
92          name,
93          true
94       );
95    }
96
97    /**
98     * Converts XML namespace to Java package name.
99     * The base algorithm is described in JAXB-2.0 spec in 'C.5 Generating a Java package name'.
100     *
101     * @param namespace XML namespace
102     * @return Java package name
103     */

104    public static String JavaDoc xmlNamespaceToJavaPackage(String JavaDoc namespace)
105    {
106       if(namespace.length() == 0)
107       {
108          return namespace;
109       }
110
111       char[] src = namespace.toLowerCase().toCharArray();
112       char[] dst = new char[namespace.length()];
113
114       int srcInd = 0;
115       // skip protocol part, i.e. http://, urn://
116
while(src[srcInd++] != ':')
117       {
118          ;
119       }
120
121       while(src[srcInd] == '/')
122       {
123          ++srcInd;
124       }
125
126       // skip www part
127
if(src[srcInd] == 'w' && src[srcInd + 1] == 'w' && src[srcInd + 2] == 'w')
128       {
129          srcInd += 4;
130       }
131
132       // find domain start and end indexes
133
int domainStart = srcInd;
134       while(srcInd < src.length && src[srcInd] != '/')
135       {
136          ++srcInd;
137       }
138
139       int dstInd = 0;
140       // copy domain parts in the reverse order
141
for(int start = srcInd - 1, end = srcInd; true; --start)
142       {
143          if(start == domainStart)
144          {
145             System.arraycopy(src, start, dst, dstInd, end - start);
146             dstInd += end - start;
147             break;
148          }
149
150          if(src[start] == '.')
151          {
152             System.arraycopy(src, start + 1, dst, dstInd, end - start - 1);
153             dstInd += end - start;
154             dst[dstInd - 1] = '.';
155             end = start;
156          }
157       }
158
159       // copy the rest
160
while(srcInd < src.length)
161       {
162          char c = src[srcInd++];
163          if(c == '/')
164          {
165             if(srcInd < src.length)
166             {
167                dst = append(dst, dstInd++, '.');
168                if(!Character.isJavaIdentifierStart(src[srcInd]))
169                {
170                   dst = append(dst, dstInd++, '_');
171                }
172             }
173          }
174          else if(c == '.')
175          {
176             // for now assume it's an extention, i.e. '.xsd'
177
break;
178          }
179          else
180          {
181             dst = append(dst, dstInd++, Character.isJavaIdentifierPart(c) ? c : '_');
182          }
183       }
184
185       return String.valueOf(dst, 0, dstInd);
186    }
187
188    /**
189     * Converts XML namespace URI and local name to fully qualified class name.
190     *
191     * @param namespaceUri namespace URI
192     * @param localName local name
193     * @param ignoreLowLine should low lines be ignored in the class name
194     * @return fully qualified class name
195     */

196    public static String JavaDoc xmlNameToClassName(String JavaDoc namespaceUri, String JavaDoc localName, boolean ignoreLowLine)
197    {
198       return namespaceUri == null || namespaceUri.length() == 0 ?
199          xmlNameToClassName(localName, ignoreLowLine) :
200          xmlNamespaceToJavaPackage(namespaceUri) + '.' + xmlNameToClassName(localName, ignoreLowLine);
201    }
202
203    public static boolean isAttributeType(final Class JavaDoc type)
204    {
205       return Classes.isPrimitive(type) ||
206          type == String JavaDoc.class ||
207          type == java.util.Date JavaDoc.class;
208    }
209
210    // Private
211

212    /**
213     * Sets an array character's element with the given index to a character value.
214     * If index is more or equal to the length of the array, a new array is created with enough length to set
215     * the element.
216     *
217     * @param buf array of characters
218     * @param index index of the element to set
219     * @param ch character to set
220     * @return if the index parameter is less then array's length then the original array is returned,
221     * otherwise a new array is returned
222     */

223    private static char[] append(char[] buf, int index, char ch)
224    {
225       if(index >= buf.length)
226       {
227          char[] tmp = buf;
228          buf = new char[index + 4];
229          System.arraycopy(tmp, 0, buf, 0, tmp.length);
230       }
231       buf[index] = ch;
232       return buf;
233    }
234
235    // Inner
236

237    /**
238     * An interface for XML name to Java identifier (class name, get/set methods, constant names) converter.
239     * The following rules and algorithms should be supported
240     * <ul>
241     * <li>Binding XML Names to Java Identifiers,
242     * C.2. The Name to Identifier Mapping Algorithm,
243     * jaxb-2_0-edr-spec-10_jun_2004.pdf</li>
244     * <li>http://www.w3.org/TR/soap12-part2/#namemap</li>
245     * </ul>
246     * <p/>
247     * But these are not guaranteed to work yet. Instead, a simplified implementation is provided.
248     * Incompatabilities should be fixed.
249     */

250    interface XMLNameToJavaIdentifierConverter
251    {
252       // commands indicating what should be done with the next character from the XML name
253
byte IGNORE = 0;
254       byte APPEND = 1;
255       byte APPEND_WITH_LOW_LINE = 2;
256       byte APPEND_UPPER_CASED = 3;
257       byte APPEND_UPPER_CASED_WITH_LOW_LINE = 4;
258
259       /**
260        * Returns a command for the next character given the previous character.
261        *
262        * @param prev previous character
263        * @param next next character
264        * @param ignoreLowLine whether low lines are allowed in the Java identifier or should be ignored
265        * @return command for the next character
266        */

267       byte commandForNext(char prev, char next, boolean ignoreLowLine);
268
269       /**
270        * An XML name parser class that parses the XML name and asks the outer interface implementation
271        * what to do with the next parsed character from the XML name.
272        */

273       final class PARSER
274       {
275          /**
276           * Parses an XML name, asks the converter for a command for the next parsed character,
277           * applies the command, composed the resulting Java identifier.
278           *
279           * @param converter an implementation of XMLNameToJavaIdentifierConverter
280           * @param xmlName XML name
281           * @param ignoreLowLine indicated whether low lines are allowed as part of the Java identifier or
282           * should be ignored
283           * @return Java identifier
284           */

285          static String JavaDoc parse(XMLNameToJavaIdentifierConverter converter, String JavaDoc xmlName, boolean ignoreLowLine)
286          {
287             if(xmlName == null || xmlName.length() == 0)
288             {
289                throw new IllegalArgumentException JavaDoc("Bad XML name: " + xmlName);
290             }
291
292             char c = xmlName.charAt(0);
293             int i = 1;
294             if(!Character.isJavaIdentifierStart(c) || (c == LOW_LINE && ignoreLowLine))
295             {
296                while(i < xmlName.length())
297                {
298                   c = xmlName.charAt(i++);
299                   if(Character.isJavaIdentifierStart(c) && !(c == LOW_LINE && ignoreLowLine))
300                   {
301                      break;
302                   }
303                }
304
305                if(i == xmlName.length())
306                {
307                   throw new IllegalArgumentException JavaDoc(
308                      "XML name contains no valid character to start Java identifier: " + xmlName
309                   );
310                }
311             }
312
313             char[] buf = new char[xmlName.length() - i + 1];
314             buf[0] = Character.toUpperCase(c);
315             int bufInd = 1;
316             while(i < xmlName.length())
317             {
318                char prev = c;
319                c = xmlName.charAt(i++);
320                byte command = converter.commandForNext(prev, c, ignoreLowLine);
321                switch(command)
322                {
323                   case IGNORE:
324                      break;
325                   case APPEND:
326                      buf = Util.append(buf, bufInd++, c);
327                      break;
328                   case APPEND_WITH_LOW_LINE:
329                      buf = Util.append(buf, bufInd++, LOW_LINE);
330                      buf = Util.append(buf, bufInd++, c);
331                      break;
332                   case APPEND_UPPER_CASED:
333                      buf = Util.append(buf, bufInd++, Character.toUpperCase(c));
334                      break;
335                   case APPEND_UPPER_CASED_WITH_LOW_LINE:
336                      buf = Util.append(buf, bufInd++, LOW_LINE);
337                      buf = Util.append(buf, bufInd++, Character.toUpperCase(c));
338                      break;
339                   default:
340                      throw new IllegalArgumentException JavaDoc("Unexpected command: " + command);
341                }
342             }
343
344             return new String JavaDoc(buf, 0, bufInd);
345          }
346       }
347
348       /**
349        * XML name to Java class name converter
350        */

351       XMLNameToJavaIdentifierConverter CLASS_NAME = new XMLNameToJavaIdentifierConverter()
352       {
353          public byte commandForNext(char prev, char next, boolean ignoreLowLine)
354          {
355             byte command;
356             if(Character.isDigit(next))
357             {
358                command = APPEND;
359             }
360             else if(next == LOW_LINE)
361             {
362                command = ignoreLowLine ? IGNORE : APPEND;
363             }
364             else if(Character.isJavaIdentifierPart(next))
365             {
366                if(Character.isJavaIdentifierPart(prev) && !Character.isDigit(prev))
367                {
368                   command = prev == LOW_LINE ? APPEND_UPPER_CASED : APPEND;
369                }
370                else
371                {
372                   command = APPEND_UPPER_CASED;
373                }
374             }
375             else
376             {
377                command = IGNORE;
378             }
379             return command;
380          }
381       };
382
383       /**
384        * XML name to Java constant name converter
385        */

386       XMLNameToJavaIdentifierConverter CONSTANT_NAME = new XMLNameToJavaIdentifierConverter()
387       {
388          public byte commandForNext(char prev, char next, boolean ignoreLowLine)
389          {
390             byte command;
391             if(Character.isDigit(next))
392             {
393                command = Character.isDigit(prev) ? APPEND : APPEND_UPPER_CASED_WITH_LOW_LINE;
394             }
395             else if(Character.isJavaIdentifierPart(next))
396             {
397                if(Character.isDigit(prev))
398                {
399                   command = APPEND_UPPER_CASED_WITH_LOW_LINE;
400                }
401                else if(Character.isJavaIdentifierPart(prev))
402                {
403                   command = Character.isUpperCase(next) ? APPEND_WITH_LOW_LINE : APPEND_UPPER_CASED;
404                }
405                else
406                {
407                   command = APPEND_UPPER_CASED_WITH_LOW_LINE;
408                }
409             }
410             else
411             {
412                command = IGNORE;
413             }
414             return command;
415          }
416       };
417    }
418 }
419
Popular Tags