aoqi@0: /* aoqi@0: * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. Oracle designates this aoqi@0: * particular file as subject to the "Classpath" exception as provided aoqi@0: * by Oracle in the LICENSE file that accompanied this code. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: */ aoqi@0: aoqi@0: package com.sun.xml.internal.bind.api.impl; aoqi@0: aoqi@0: import javax.lang.model.SourceVersion; aoqi@0: import java.util.ArrayList; aoqi@0: import java.util.List; aoqi@0: import java.util.StringTokenizer; aoqi@0: aoqi@0: /** aoqi@0: * Converts aribitrary strings into Java identifiers. aoqi@0: * aoqi@0: * @author aoqi@0: * Kohsuke KAWAGUCHI aoqi@0: */ aoqi@0: public interface NameConverter aoqi@0: { aoqi@0: /** aoqi@0: * converts a string into an identifier suitable for classes. aoqi@0: * aoqi@0: * In general, this operation should generate "NamesLikeThis". aoqi@0: */ aoqi@0: String toClassName( String token ); aoqi@0: aoqi@0: /** aoqi@0: * converts a string into an identifier suitable for interfaces. aoqi@0: * aoqi@0: * In general, this operation should generate "NamesLikeThis". aoqi@0: * But for example, it can prepend every interface with 'I'. aoqi@0: */ aoqi@0: String toInterfaceName( String token ); aoqi@0: aoqi@0: /** aoqi@0: * converts a string into an identifier suitable for properties. aoqi@0: * aoqi@0: * In general, this operation should generate "NamesLikeThis", aoqi@0: * which will be used with known prefixes like "get" or "set". aoqi@0: */ aoqi@0: String toPropertyName( String token ); aoqi@0: aoqi@0: /** aoqi@0: * converts a string into an identifier suitable for constants. aoqi@0: * aoqi@0: * In the standard Java naming convention, this operation should aoqi@0: * generate "NAMES_LIKE_THIS". aoqi@0: */ aoqi@0: String toConstantName( String token ); aoqi@0: aoqi@0: /** aoqi@0: * Converts a string into an identifier suitable for variables. aoqi@0: * aoqi@0: * In general it should generate "namesLikeThis". aoqi@0: */ aoqi@0: String toVariableName( String token ); aoqi@0: aoqi@0: /** aoqi@0: * Converts a namespace URI into a package name. aoqi@0: * This method should expect strings like aoqi@0: * "http://foo.bar.zot/org", "urn:abc:def:ghi" "", or even "###" aoqi@0: * (basically anything) and expected to return a package name, aoqi@0: * liks "org.acme.foo". aoqi@0: * aoqi@0: */ aoqi@0: String toPackageName( String namespaceUri ); aoqi@0: aoqi@0: /** aoqi@0: * The name converter implemented by Code Model. aoqi@0: * aoqi@0: * This is the standard name conversion for JAXB. aoqi@0: */ aoqi@0: public static final NameConverter standard = new Standard(); aoqi@0: aoqi@0: static class Standard extends NameUtil implements NameConverter { aoqi@0: public String toClassName(String s) { aoqi@0: return toMixedCaseName(toWordList(s), true); aoqi@0: } aoqi@0: public String toVariableName(String s) { aoqi@0: return toMixedCaseName(toWordList(s), false); aoqi@0: } aoqi@0: public String toInterfaceName( String token ) { aoqi@0: return toClassName(token); aoqi@0: } aoqi@0: public String toPropertyName(String s) { aoqi@0: String prop = toClassName(s); aoqi@0: // property name "Class" with collide with Object.getClass, aoqi@0: // so escape this. aoqi@0: if(prop.equals("Class")) aoqi@0: prop = "Clazz"; aoqi@0: return prop; aoqi@0: } aoqi@0: public String toConstantName( String token ) { aoqi@0: return super.toConstantName(token); aoqi@0: } aoqi@0: /** aoqi@0: * Computes a Java package name from a namespace URI, aoqi@0: * as specified in the spec. aoqi@0: * aoqi@0: * @return aoqi@0: * null if it fails to derive a package name. aoqi@0: */ aoqi@0: public String toPackageName( String nsUri ) { aoqi@0: // remove scheme and :, if present aoqi@0: // spec only requires us to remove 'http' and 'urn'... aoqi@0: int idx = nsUri.indexOf(':'); aoqi@0: String scheme = ""; aoqi@0: if(idx>=0) { aoqi@0: scheme = nsUri.substring(0,idx); aoqi@0: if( scheme.equalsIgnoreCase("http") || scheme.equalsIgnoreCase("urn") ) aoqi@0: nsUri = nsUri.substring(idx+1); aoqi@0: } aoqi@0: aoqi@0: // tokenize string aoqi@0: ArrayList tokens = tokenize( nsUri, "/: " ); aoqi@0: if( tokens.size() == 0 ) { aoqi@0: return null; aoqi@0: } aoqi@0: aoqi@0: // remove trailing file type, if necessary aoqi@0: if( tokens.size() > 1 ) { aoqi@0: // for uri's like "www.foo.com" and "foo.com", there is no trailing aoqi@0: // file, so there's no need to look at the last '.' and substring aoqi@0: // otherwise, we loose the "com" (which would be wrong) aoqi@0: String lastToken = tokens.get( tokens.size()-1 ); aoqi@0: idx = lastToken.lastIndexOf( '.' ); aoqi@0: if( idx > 0 ) { aoqi@0: lastToken = lastToken.substring( 0, idx ); aoqi@0: tokens.set( tokens.size()-1, lastToken ); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // tokenize domain name and reverse. Also remove :port if it exists aoqi@0: String domain = tokens.get( 0 ); aoqi@0: idx = domain.indexOf(':'); aoqi@0: if( idx >= 0) domain = domain.substring(0, idx); aoqi@0: ArrayList r = reverse( tokenize( domain, scheme.equals("urn")?".-":"." ) ); aoqi@0: if( r.get( r.size()-1 ).equalsIgnoreCase( "www" ) ) { aoqi@0: // remove leading www aoqi@0: r.remove( r.size()-1 ); aoqi@0: } aoqi@0: aoqi@0: // replace the domain name with tokenized items aoqi@0: tokens.addAll( 1, r ); aoqi@0: tokens.remove( 0 ); aoqi@0: aoqi@0: // iterate through the tokens and apply xml->java name algorithm aoqi@0: for( int i = 0; i < tokens.size(); i++ ) { aoqi@0: aoqi@0: // get the token and remove illegal chars aoqi@0: String token = tokens.get( i ); aoqi@0: token = removeIllegalIdentifierChars( token ); aoqi@0: aoqi@0: // this will check for reserved keywords aoqi@0: if (SourceVersion.isKeyword(token.toLowerCase())) { aoqi@0: token = '_' + token; aoqi@0: } aoqi@0: aoqi@0: tokens.set( i, token.toLowerCase() ); aoqi@0: } aoqi@0: aoqi@0: // concat all the pieces and return it aoqi@0: return combine( tokens, '.' ); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: private static String removeIllegalIdentifierChars(String token) { aoqi@0: StringBuilder newToken = new StringBuilder(token.length() + 1); // max expected length aoqi@0: for( int i = 0; i < token.length(); i++ ) { aoqi@0: char c = token.charAt( i ); aoqi@0: if (i == 0 && !Character.isJavaIdentifierStart(c)) { // c can't be used as FIRST char aoqi@0: newToken.append('_'); aoqi@0: } aoqi@0: if (!Character.isJavaIdentifierPart(c)) { // c can't be used aoqi@0: newToken.append('_'); aoqi@0: } else { aoqi@0: newToken.append(c); // c is valid aoqi@0: } aoqi@0: } aoqi@0: return newToken.toString(); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: private static ArrayList tokenize( String str, String sep ) { aoqi@0: StringTokenizer tokens = new StringTokenizer(str,sep); aoqi@0: ArrayList r = new ArrayList(); aoqi@0: aoqi@0: while(tokens.hasMoreTokens()) aoqi@0: r.add( tokens.nextToken() ); aoqi@0: aoqi@0: return r; aoqi@0: } aoqi@0: aoqi@0: private static ArrayList reverse( List a ) { aoqi@0: ArrayList r = new ArrayList(); aoqi@0: aoqi@0: for( int i=a.size()-1; i>=0; i-- ) aoqi@0: r.add( a.get(i) ); aoqi@0: aoqi@0: return r; aoqi@0: } aoqi@0: aoqi@0: private static String combine( List r, char sep ) { aoqi@0: StringBuilder buf = new StringBuilder(r.get(0).toString()); aoqi@0: aoqi@0: for( int i=1; i