001: /**
002: * Redistribution and use of this software and associated documentation
003: * ("Software"), with or without modification, are permitted provided
004: * that the following conditions are met:
005: *
006: * 1. Redistributions of source code must retain copyright
007: * statements and notices. Redistributions must also contain a
008: * copy of this document.
009: *
010: * 2. Redistributions in binary form must reproduce the
011: * above copyright notice, this list of conditions and the
012: * following disclaimer in the documentation and/or other
013: * materials provided with the distribution.
014: *
015: * 3. The name "Exolab" must not be used to endorse or promote
016: * products derived from this Software without prior written
017: * permission of Intalio, Inc. For written permission,
018: * please contact info@exolab.org.
019: *
020: * 4. Products derived from this Software may not be called "Exolab"
021: * nor may "Exolab" appear in their names without prior written
022: * permission of Intalio, Inc. Exolab is a registered
023: * trademark of Intalio, Inc.
024: *
025: * 5. Due credit should be given to the Exolab Project
026: * (http://www.exolab.org/).
027: *
028: * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS
029: * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
030: * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
031: * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
032: * INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
033: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
034: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
035: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
036: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
037: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
038: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
039: * OF THE POSSIBILITY OF SUCH DAMAGE.
040: *
041: * Copyright 1999-2003 (C) Intalio, Inc. All Rights Reserved.
042: *
043: * $Id: JavaNaming.java 6216 2006-09-15 23:26:59Z rjoachim $
044: */package org.exolab.castor.xml;
045:
046: import java.io.File;
047: import java.util.Hashtable;
048:
049: /**
050: * This class converts XML Names to proper Java names.
051: * Also see Unmarshaller and Marshaller since they use some
052: * of their own methods for now.
053: * @author <a href="mailto:kvisco@intalio.com">Keith Visco</a>
054: * @version $Revision: 6216 $ $Date: 2003-03-03 00:05:44 -0700 (Mon, 03 Mar 2003) $
055: **/
056: public class JavaNaming {
057:
058: /**
059: * The property name to use in the castor.properties file to specify
060: * the value of the <code>upperCaseAfterUnderscore</code> variable.
061: */
062: public static final String UPPER_CASE_AFTER_UNDERSCORE_PROPERTY = "org.exolab.castor.xml.JavaNaming.upperCaseAfterUnderscore";
063:
064: /**
065: * Used for backward compatibility, if you wish
066: * to be backward compatible with 0.9.3.9 and earlier
067: * set this boolean to true.
068: */
069: public static boolean upperCaseAfterUnderscore = false;
070:
071: private static final Hashtable subst = keywordMap();
072:
073: private static final String[] keywords = { "abstract", "boolean",
074: "break", "byte", "case", "catch", "char", "class", "const",
075: "continue", "default", "do", "double", "else", "extends",
076: "false", "final", "finally", "float", "for", "goto", "if",
077: "implements", "import", "instanceof", "int", "interface",
078: "long", "native", "new", "null", "package", "private",
079: "protected", "public", "return", "short", "static",
080: "super", "switch", "synchronized", "this", "throw",
081: "throws", "transient", "true", "try", "void", "volatile",
082: "while" }; //-- keywords
083:
084: /**
085: * private constructor
086: **/
087: private JavaNaming() {
088: super ();
089: } //-- JavaNaming
090:
091: /**
092: * Returns true if the given String is a Java keyword which
093: * will cause a problem when used as a variable name
094: **/
095: public static boolean isKeyword(String name) {
096: if (name == null)
097: return false;
098: for (int i = 0; i < keywords.length; i++) {
099: if (keywords[i].equals(name))
100: return true;
101: }
102: return false;
103: } //-- isKeyword
104:
105: /**
106: * Returns true if the given String matches the production of a valid Java identifier.
107: *
108: * @param string The String to check the production of.
109: * @return true if the given String matches the production of a valid Java name,
110: * otherwise false.
111: */
112: public static boolean isValidJavaIdentifier(String string) {
113: if ((string == null) || (string.length() == 0))
114: return false;
115:
116: for (int i = 0; i < string.length(); i++) {
117: char ch = string.charAt(i);
118:
119: //-- digit
120: if (ch == '_')
121: continue;
122: if (ch == '$')
123: continue;
124:
125: if ((ch >= 'A') && (ch <= 'Z'))
126: continue;
127: if ((ch >= 'a') && (ch <= 'z'))
128: continue;
129: if ((ch >= '0') && (ch <= '9')) {
130: if (i == 0)
131: return false;
132: continue;
133: }
134:
135: return false;
136: }
137: if (isKeyword(string))
138: return false;
139: return true;
140: } //-- isValidJavaIdentifier
141:
142: public static String toJavaClassName(String name) {
143:
144: if ((name == null) || (name.length() <= 0)) {
145: // handle error
146: return name; //-- for now just return name
147: }
148: // Remove namespace prefix (Andrew Fawcett, temporary until namespace changes go in)
149: int colon = name.indexOf(':');
150: if (colon != -1)
151: name = name.substring(colon + 1);
152: return toJavaName(name, true);
153:
154: } //-- toJavaClassName
155:
156: public static String toJavaMemberName(String name) {
157: return toJavaMemberName(name, true);
158: } //-- toJavaMemberName
159:
160: public static String toJavaMemberName(String name,
161: boolean useKeywordSubstitutions) {
162:
163: if (name == null)
164: return null;
165:
166: String memberName = toJavaName(name, false);
167:
168: if (isKeyword(memberName) && useKeywordSubstitutions) {
169: String mappedName = (String) subst.get(memberName);
170: if (mappedName != null)
171: memberName = mappedName;
172: else
173: memberName = "_" + memberName;
174: }
175: return memberName;
176: } //-- toJavaMemberName
177:
178: /**
179: * Converts the given Package name to it's corresponding
180: * Path. The path will be a relative path.
181: **/
182: public static String packageToPath(String packageName) {
183: if (packageName == null)
184: return packageName;
185: return packageName.replace('.', File.separatorChar);
186: } //-- packageToPath
187:
188: private static Hashtable keywordMap() {
189: Hashtable ht = new Hashtable();
190: ht.put("class", "clazz");
191: return ht;
192: } //-- keywordMap
193:
194: /**
195: * Converts the given xml name to a Java name.
196: * @param name the name to convert to a Java Name
197: * @param upperFirst a flag to indicate whether or not the
198: * the first character should be converted to uppercase.
199: **/
200: private static String toJavaName(String name, boolean upperFirst) {
201:
202: int size = name.length();
203: char[] ncChars = name.toCharArray();
204: int next = 0;
205:
206: boolean uppercase = upperFirst;
207:
208: //-- initialize lowercase, this is either (!uppercase) or
209: //-- false depending on if the first two characters
210: //-- are uppercase
211: boolean lowercase = (!uppercase);
212: if ((size > 1) && lowercase) {
213: if (Character.isUpperCase(ncChars[0])
214: && Character.isUpperCase(ncChars[1]))
215: lowercase = false;
216: }
217:
218: for (int i = 0; i < size; i++) {
219: char ch = ncChars[i];
220:
221: switch (ch) {
222: case '.':
223: case ' ':
224: ncChars[next++] = '_';
225: break;
226: case ':':
227: case '-':
228: uppercase = true;
229: break;
230: case '_':
231: //-- backward compatibility with 0.9.3.9
232: if (upperCaseAfterUnderscore) {
233: uppercase = true;
234: ncChars[next] = ch;
235: ++next;
236: break;
237: }
238: //-- for backward compatibility with 0.9.3
239: /* if (replaceUnderscore) {
240: uppercase = true;
241: break;
242: }
243: */
244: //--> do not break here for anything greater
245: //--> than 0.9.3.9
246: default:
247: if (uppercase) {
248: ncChars[next] = Character.toUpperCase(ch);
249: uppercase = false;
250: } else if (lowercase) {
251: ncChars[next] = Character.toLowerCase(ch);
252: lowercase = false;
253: } else
254: ncChars[next] = ch;
255: ++next;
256: break;
257: }
258: }
259: return new String(ncChars, 0, next);
260: } //-- toJavaName
261:
262: /* for debuging
263: public static void main(String[] args) {
264:
265: String[] names = {
266: "name",
267: "myName",
268: "my-name",
269: "my----name",
270: "my_name",
271: "NAME"
272: };
273:
274: System.out.println("JavaXMLNaming Tests: ");
275: System.out.println();
276: for (int i = 0; i < names.length; i++) {
277: System.out.println();
278: System.out.print("Test #");
279: System.out.println(i+1);
280: System.out.print("toJavaClassName(\"");
281: System.out.print(names[i]);
282: System.out.print("\") ==> \"");
283: System.out.print(toJavaClassName(names[i]));
284: System.out.println("\"");
285: System.out.println();
286: System.out.print("toJavaMemberName(\"");
287: System.out.print(names[i]);
288: System.out.print("\") ==> \"");
289: System.out.print(toJavaMemberName(names[i]));
290: System.out.println("\"");
291:
292: }
293: } //-- main /* */
294:
295: } //-- JavaXMLNaming
|