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