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