FileDocCategorySizeDatePackage
IDLNameTranslatorImpl.javaAPI DocJava SE 5 API31879Fri Aug 26 14:54:30 BST 2005com.sun.corba.se.impl.presentation.rmi

IDLNameTranslatorImpl

public class IDLNameTranslatorImpl extends Object implements com.sun.corba.se.spi.presentation.rmi.IDLNameTranslator
Bidirectional translator between RMI-IIOP interface methods and and IDL Names.

Fields Summary
private static String[]
IDL_KEYWORDS
private static char[]
HEX_DIGITS
private static final String
UNDERSCORE
private static final String
INNER_CLASS_SEPARATOR
private static final String[]
BASE_IDL_ARRAY_MODULE_TYPE
private static final String
BASE_IDL_ARRAY_ELEMENT_TYPE
private static final String
LEADING_UNDERSCORE_CHAR
private static final String
ID_CONTAINER_CLASH_CHAR
private static final String
OVERLOADED_TYPE_SEPARATOR
private static final String
ATTRIBUTE_METHOD_CLASH_MANGLE_CHARS
private static final String
GET_ATTRIBUTE_PREFIX
private static final String
SET_ATTRIBUTE_PREFIX
private static final String
IS_ATTRIBUTE_PREFIX
private static Set
idlKeywords_
private Class[]
interf_
private Map
methodToIDLNameMap_
private Map
IDLNameToMethodMap_
private Method[]
methods_
Constructors Summary
private IDLNameTranslatorImpl(Class[] interfaces)
Initialize an IDLNameTranslator for the given interface.

throws
IllegalStateException if given class is not a valid RMI/IIOP Remote Interface


        try {
            IDLTypesUtil idlTypesUtil = new IDLTypesUtil();
	    for (int ctr=0; ctr<interfaces.length; ctr++)
		idlTypesUtil.validateRemoteInterface(interfaces[ctr]);
            interf_ = interfaces;
            buildNameTranslation();
        } catch( IDLTypeException ite) {
            String msg = ite.getMessage();
            IllegalStateException ise = new IllegalStateException(msg);
            ise.initCause(ite);
            throw ise;
        }
    
Methods Summary
private voidbuildNameTranslation()

	// holds method info, keyed by method
	Map allMethodInfo = new HashMap() ;

	for (int ctr=0; ctr<interf_.length; ctr++) {
	    Class interf = interf_[ctr] ;

	    IDLTypesUtil idlTypesUtil = new IDLTypesUtil();
	    final Method[] methods = interf.getMethods();
	    // Handle the case of a non-public interface!
            AccessController.doPrivileged(new PrivilegedAction() {
                public Object run() {
		    Method.setAccessible( methods, true ) ;
		    return null ;
		} 
	    } ) ;

	    // Take an initial pass through all the methods and create some
	    // information that will be used to track the IDL name 
	    // transformation.
	    for(int i = 0; i < methods.length; i++) {
		
		Method nextMethod = methods[i];

		IDLMethodInfo methodInfo = new IDLMethodInfo();

		methodInfo.method = nextMethod;           

		if (idlTypesUtil.isPropertyAccessorMethod(nextMethod, interf)) {
		    methodInfo.isProperty = true;
		    String attributeName = idlTypesUtil.
			getAttributeNameForProperty(nextMethod.getName());
		    methodInfo.originalName = attributeName;
		    methodInfo.mangledName  = attributeName;               
		} else {
		    methodInfo.isProperty = false;
		    methodInfo.originalName = nextMethod.getName();
		    methodInfo.mangledName  = nextMethod.getName();
		}
		
		allMethodInfo.put(nextMethod, methodInfo);
	    }
	}

        //
        // Perform case sensitivity test first.  This applies to all
        // method names AND attributes.  Compare each method name and 
        // attribute to all other method names and attributes.  If names 
        // differ only in case, apply mangling as defined in section 1.3.2.7
        // of Java2IDL spec.  Note that we compare using the original names.
        //
        for(Iterator outerIter=allMethodInfo.values().iterator();
            outerIter.hasNext();) {
            IDLMethodInfo outer = (IDLMethodInfo) outerIter.next();           
            for(Iterator innerIter = allMethodInfo.values().iterator(); 
                innerIter.hasNext();) {
                IDLMethodInfo inner = (IDLMethodInfo) innerIter.next();

                if( (outer != inner) &&
                    (!outer.originalName.equals(inner.originalName)) &&
                    outer.originalName.equalsIgnoreCase(inner.originalName) ) {
                    outer.mangledName = 
                        mangleCaseSensitiveCollision(outer.originalName);
                    break;
                }

            }
        }
                   
        for(Iterator iter = allMethodInfo.values().iterator(); 
            iter.hasNext();) {
            IDLMethodInfo next = (IDLMethodInfo) iter.next();           
            next.mangledName = 
                mangleIdentifier(next.mangledName, next.isProperty);
        }         

        //
        // Now check for overloaded method names and apply 1.3.2.6.
        //
        for(Iterator outerIter=allMethodInfo.values().iterator();
            outerIter.hasNext();) {
            IDLMethodInfo outer = (IDLMethodInfo) outerIter.next();
            if( outer.isProperty ) {
                continue;
            }
            for(Iterator innerIter = allMethodInfo.values().iterator(); 
                innerIter.hasNext();) {
                IDLMethodInfo inner = (IDLMethodInfo) innerIter.next();

                if( (outer != inner) &&
                    !inner.isProperty &&
                    outer.originalName.equals(inner.originalName) ) {
                    outer.mangledName = mangleOverloadedMethod
                        (outer.mangledName, outer.method);
                    break;
                }
            }
        }
       
        //
        // Now mangle any properties that clash with method names.
        //
        for(Iterator outerIter=allMethodInfo.values().iterator();
            outerIter.hasNext();) {
            IDLMethodInfo outer = (IDLMethodInfo) outerIter.next();
            if( !outer.isProperty ) {
                continue;
            }
            for(Iterator innerIter = allMethodInfo.values().iterator(); 
                innerIter.hasNext();) {
                IDLMethodInfo inner = (IDLMethodInfo) innerIter.next();
                if( (outer != inner) &&
                    !inner.isProperty &&
                    outer.mangledName.equals(inner.mangledName) ) {
                    outer.mangledName = outer.mangledName + 
                        ATTRIBUTE_METHOD_CLASH_MANGLE_CHARS;
                    break;
                }
            }
        }

        //
        // Ensure that no mapped method names clash with mapped name
        // of container(1.3.2.9).  This is a case insensitive comparison.
        //
	for (int ctr=0; ctr<interf_.length; ctr++ ) {
	    Class interf = interf_[ctr] ;
	    String mappedContainerName = getMappedContainerName(interf);
	    for(Iterator iter = allMethodInfo.values().iterator(); 
		iter.hasNext();) {
		IDLMethodInfo next = (IDLMethodInfo) iter.next();           
		if( !next.isProperty &&
		    identifierClashesWithContainer(mappedContainerName, 
						   next.mangledName)) {
		    next.mangledName = mangleContainerClash(next.mangledName);
		}
	    }         
	}

        //
        // Populate name translation maps.
        //
        methodToIDLNameMap_ = new HashMap();
        IDLNameToMethodMap_ = new HashMap();
	methods_ = (Method[])allMethodInfo.keySet().toArray( 
	    new Method[0] ) ;

        for(Iterator iter = allMethodInfo.values().iterator(); 
            iter.hasNext();) {
            IDLMethodInfo next = (IDLMethodInfo) iter.next();           
            String idlName = next.mangledName;
            if( next.isProperty ) {                
                String origMethodName = next.method.getName();
                String prefix = "";

                if( origMethodName.startsWith("get") ) {
                    prefix = GET_ATTRIBUTE_PREFIX;
                } else if( origMethodName.startsWith("set") ) {
                    prefix = SET_ATTRIBUTE_PREFIX;
                } else {
                    prefix = IS_ATTRIBUTE_PREFIX;
                }

                idlName = prefix + next.mangledName;
            }
            
            methodToIDLNameMap_.put(next.method, idlName);

            // Final check to see if there are any clashes after all the
            // manglings have been applied.  If so, this is treated as an
            // invalid interface.  Currently, we do a CASE-SENSITIVE 
            // comparison since that matches the rmic behavior.  
            // @@@ Shouldn't this be a case-insensitive check?
            if( IDLNameToMethodMap_.containsKey(idlName) ) {
                // @@@ I18N
                Method clash = (Method) IDLNameToMethodMap_.get(idlName);
                throw new IllegalStateException("Error : methods " + 
                    clash + " and " + next.method + 
                    " both result in IDL name '" + idlName + "'");
            } else {
                IDLNameToMethodMap_.put(idlName, next.method);
            }
        }

        return;

    
public static java.lang.StringcharToUnicodeRepresentation(char c)
Returns Unicode mangling as defined in Section 1.3.2.4 of Java2IDL spec. "For Java identifiers that contain illegal OMG IDL identifier characters such as '$' or Unicode characters outside of ISO Latin 1, any such illegal characters are replaced by "U" followed by the 4 hexadecimal characters(in upper case) representing the Unicode value. So, the Java name a$b is mapped to aU0024b and x\u03bCy is mapped to xU03BCy."

        
        int orig = (int) c;
        StringBuffer hexString = new StringBuffer();
        
        int value = orig;

        while( value > 0 ) {
            int div = value / 16;
            int mod = value % 16;
            hexString.insert(0, HEX_DIGITS[mod]);
            value = div;
        }

        int numZerosToAdd = 4 - hexString.length();
        for(int i = 0; i < numZerosToAdd; i++) {
            hexString.insert(0, "0");
        }

        hexString.insert(0, "U");
        return hexString.toString();
    
private static com.sun.corba.se.impl.presentation.rmi.IDLTypeclassToIDLType(java.lang.Class c)

               
        IDLType idlType = null;
        IDLTypesUtil idlTypesUtil = new IDLTypesUtil();

        if( idlTypesUtil.isPrimitive(c) ) {

            idlType = idlTypesUtil.getPrimitiveIDLTypeMapping(c);

        } else if( c.isArray() ) {
            
            // Calculate array depth, as well as base element type.
            Class componentType = c.getComponentType();
            int numArrayDimensions = 1;
            while(componentType.isArray()) {
                componentType = componentType.getComponentType();
                numArrayDimensions++;
            }
            IDLType componentIdlType = classToIDLType(componentType);
            
            String[] modules = BASE_IDL_ARRAY_MODULE_TYPE;
            if( componentIdlType.hasModule() ) {
                modules = (String[])ObjectUtility.concatenateArrays( modules, 
                    componentIdlType.getModules() ) ;
            }

            String memberName = BASE_IDL_ARRAY_ELEMENT_TYPE + 
                numArrayDimensions + UNDERSCORE + 
                componentIdlType.getMemberName();                
            
            idlType = new IDLType(c, modules, memberName);
               
        } else {
            idlType = idlTypesUtil.getSpecialCaseIDLTypeMapping(c);

            if (idlType == null) {
                // Section 1.3.2.5 of Java2IDL spec defines mangling rules for
                // inner classes.
                String memberName = getUnmappedContainerName(c);

                // replace inner class separator with double underscore
                memberName = memberName.replaceAll("\\$", 
                                                   INNER_CLASS_SEPARATOR);
                                
                if( hasLeadingUnderscore(memberName) ) {
                    memberName = mangleLeadingUnderscore(memberName);
                }                    

                // Get raw package name.  If there is a package, it
                // will still have the "." separators and none of the
                // mangling rules will have been applied.
                String packageName = getPackageName(c);                 
                
                if (packageName == null) {
		    idlType = new IDLType( c, memberName ) ;
		} else {
		    // If this is a generated IDL Entity Type we need to
		    // prepend org_omg_boxedIDL per sections 1.3.5 and 1.3.9
		    if (idlTypesUtil.isEntity(c)) {
			packageName = "org.omg.boxedIDL." + packageName ;
		    }
		    
		    // Section 1.3.2.1 and 1.3.2.6 of Java2IDL spec defines 
		    // rules for mapping java packages to IDL modules and for 
		    // mangling module name portion of type name.  NOTE that
		    // of the individual identifier mangling rules, 
		    // only the leading underscore test is done here.  
		    // The other two(IDL Keyword, Illegal Unicode chars) are
		    // done in mangleOverloadedMethodName.  
                    StringTokenizer tokenizer = 
                        new StringTokenizer(packageName, ".");
		    
		    String[] modules = new String[ tokenizer.countTokens() ] ;
		    int index = 0 ;
                    while (tokenizer.hasMoreElements()) {
                        String next = tokenizer.nextToken();
                        String moreMangled = hasLeadingUnderscore( next ) ?
                            mangleLeadingUnderscore( next ) : next;

			modules[index++] = moreMangled ;
                    }                                                          

		    idlType = new IDLType(c, modules, memberName);
                }
            }
        }

        return idlType;
    
public static com.sun.corba.se.spi.presentation.rmi.IDLNameTranslatorget(java.lang.Class interf)
Return an IDLNameTranslator for the given interface.

throws
IllegalStateException if given class is not a valid RMI/IIOP Remote Interface

        
        return new IDLNameTranslatorImpl(new Class[] { interf } );

    
public static com.sun.corba.se.spi.presentation.rmi.IDLNameTranslatorget(java.lang.Class[] interfaces)
Return an IDLNameTranslator for the given interfacex.

throws
IllegalStateException if given classes are not valid RMI/IIOP Remote Interfaces

        
        return new IDLNameTranslatorImpl(interfaces );

    
public static java.lang.StringgetExceptionId(java.lang.Class cls)

	// Requirements for this method:
	// 1. cls must be an exception but not a RemoteException.
	// 2. If cls has an IDL keyword name, an underscore is prepended (1.3.2.2).
	// 3. If cls jas a leading underscore, J is prepended (1.3.2.3).
	// 4. If cls has an illegal IDL ident char, it is mapped to UXXXX where
	//    XXXX is the unicode value in hex of the char (1.3.2.4).
	// 5. double underscore for inner class (1.3.2.5).
	// 6. The ID is "IDL:" + name with / separators + ":1.0".
	IDLType itype = classToIDLType( cls ) ;
	return itype.getExceptionName() ;
    
public java.lang.StringgetIDLName(java.lang.reflect.Method method)

        return (String) methodToIDLNameMap_.get(method);
    
public java.lang.Class[]getInterfaces()

        return interf_;
    
private static java.lang.StringgetMappedContainerName(java.lang.Class c)

        String unmappedName = getUnmappedContainerName(c);

        return mangleIdentifier(unmappedName);
    
public java.lang.reflect.MethodgetMethod(java.lang.String idlName)

        return (Method) IDLNameToMethodMap_.get(idlName);
    
public java.lang.reflect.Method[]getMethods()

	return methods_ ;
    
private static java.lang.StringgetPackageName(java.lang.Class c)
Return Class' package name or null if there is no package.

        Package thePackage = c.getPackage();
        String packageName = null;

        // Try to get package name by introspection.  Some classloaders might
        // not provide this information, so check for null.
        if( thePackage != null ) {
            packageName = thePackage.getName();
        } else {
            // brute force method
            String fullyQualifiedClassName = c.getName();
            int lastDot = fullyQualifiedClassName.indexOf('.");
            packageName = (lastDot == -1) ? null :
                fullyQualifiedClassName.substring(0, lastDot);
        }
        return packageName;
    
private static java.lang.StringgetUnmappedContainerName(java.lang.Class c)
Return portion of class name excluding package name.


        String memberName  = null;
        String packageName = getPackageName(c);

        String fullyQualifiedClassName = c.getName();
               
        if( packageName != null ) {
            int packageLength = packageName.length();
            memberName = fullyQualifiedClassName.substring(packageLength + 1);
        } else {
            memberName = fullyQualifiedClassName;

        }

        return memberName;
    
private static booleanhasLeadingUnderscore(java.lang.String identifier)
Checks whether a java identifier starts with an underscore. Used to implement section 1.3.2.3 of Java2IDL spec.

        return identifier.startsWith(UNDERSCORE);
    
private static booleanidentifierClashesWithContainer(java.lang.String mappedContainerName, java.lang.String identifier)
Implements Section 1.3.2.9 of Java2IDL Mapping. Container in this context means the name of the java Class(excluding package) in which the identifier is defined. Comparison is case-insensitive.


        return identifier.equalsIgnoreCase(mappedContainerName);
    
private static booleanisIDLAlphabeticChar(char c)
True if character is one of 114 Alphabetic characters as specified in Table 2 of Chapter 3 in CORBA spec.


        // NOTE that we can't use the java.lang.Character
        // isUpperCase, isLowerCase, etc. methods since they
        // include many characters other than the Alphabetic list in
        // the CORBA spec.  Instead, we test for inclusion in the
        // Unicode value ranges for the corresponding legal characters.

        boolean alphaChar = 
            (
             // A - Z
             ((c >= 0x0041) && (c <= 0x005A)) 

             ||
             
             // a - z
             ((c >= 0x0061) && (c <= 0x007A)) 
             
             ||
             
             // other letter uppercase, other letter lowercase, which is
             // the entire upper half of C1 Controls except X and /
             ((c >= 0x00C0) && (c <= 0x00FF)
              && (c != 0x00D7) && (c != 0x00F7)));
        
        return alphaChar;
    
private static booleanisIDLDecimalDigit(char c)
True if character is one of 10 Decimal Digits specified in Table 3 of Chapter 3 in CORBA spec.

        return ( (c >= 0x0030) && (c <= 0x0039) );
    
private static booleanisIDLIdentifier(java.lang.String identifier)


        boolean isIdentifier = true;

        for(int i = 0; i < identifier.length(); i++) {
            char nextChar = identifier.charAt(i);
            // 1st char must be alphbetic.
            isIdentifier  = (i == 0) ?
                isIDLAlphabeticChar(nextChar) : 
                isIDLIdentifierChar(nextChar);
            if( !isIdentifier ) {
                break;
            }
        }

        return isIdentifier;
        
    
private static booleanisIDLIdentifierChar(char c)

        return (isIDLAlphabeticChar(c) || 
                isIDLDecimalDigit(c)   ||
                isUnderscore(c));
    
static booleanisIDLKeyword(java.lang.String identifier)
Checks whether a java identifier clashes with an IDL keyword. Note that this is a case-insensitive comparison. Used to implement section 1.3.2.2 of Java2IDL spec.

        
        String identifierAllCaps = identifier.toUpperCase();

        return idlKeywords_.contains(identifierAllCaps);
    
private static booleanisUnderscore(char c)

        return ( c == 0x005F );
    
public static voidmain(java.lang.String[] args)

        
        Class remoteInterface = java.rmi.Remote.class;
        
        if( args.length > 0 ) {
            String className = args[0];
            try {
                remoteInterface = Class.forName(className);
            } catch(Exception e) {
                e.printStackTrace();
                System.exit(-1);
            }            
        }
        
        System.out.println("Building name translation for " + remoteInterface);
        try {
            IDLNameTranslator nameTranslator = 
                IDLNameTranslatorImpl.get(remoteInterface);
            System.out.println(nameTranslator);
        } catch(IllegalStateException ise) {
            ise.printStackTrace();
        }
    
java.lang.StringmangleCaseSensitiveCollision(java.lang.String identifier)
Implements mangling portion of Section 1.3.2.7 of Java2IDL spec. This method only deals with the actual mangling. Decision about whether case-sensitive collision mangling is required is made elsewhere. "...a mangled name is generated consisting of the original name followed by an underscore separated list of decimal indices into the string, where the indices identify all the upper case characters in the original string. Indices are zero based."


        StringBuffer mangledIdentifier = new StringBuffer(identifier);

        // There is always at least one trailing underscore, whether or 
        // not the identifier has uppercase letters.
        mangledIdentifier.append(UNDERSCORE);

        boolean needUnderscore = false;
        for(int i = 0; i < identifier.length(); i++) {
            char next = identifier.charAt(i);
            if( Character.isUpperCase(next) ) {
                // This bit of logic is needed to ensure that we have
                // an underscore separated list of indices but no 
                // trailing underscores.  Basically, after we have at least
                // one uppercase letter, we always put an undercore before
                // printing the next one.
                if( needUnderscore ) {
                    mangledIdentifier.append(UNDERSCORE);
                }
                mangledIdentifier.append(i);
                needUnderscore = true;
            }
        }

        return mangledIdentifier.toString();
    
private static java.lang.StringmangleContainerClash(java.lang.String identifier)

        return identifier + ID_CONTAINER_CLASH_CHAR;
    
static java.lang.StringmangleIDLKeywordClash(java.lang.String identifier)

        return UNDERSCORE + identifier;
    
private static java.lang.StringmangleIdentifier(java.lang.String identifier)
Perform all necessary stand-alone identifier mangling operations on a java identifier that is being transformed into an IDL name. That is, mangling operations that don't require looking at anything else but the identifier itself. This covers sections 1.3.2.2, 1.3.2.3, and 1.3.2.4 of the Java2IDL spec. Method overloading and case-sensitivity checks are handled elsewhere.

        return mangleIdentifier(identifier, false);
    
private static java.lang.StringmangleIdentifier(java.lang.String identifier, boolean attribute)


        String mangledName = identifier;

        //
        // Apply leading underscore test (1.3.2.3) 
        // This should be done before IDL Keyword clash test, since clashing 
        // IDL keywords are mangled by adding a leading underscore.
        //
        if( hasLeadingUnderscore(mangledName) ) {
            mangledName = mangleLeadingUnderscore(mangledName);            
        }         
        
        //
        // Apply IDL keyword clash test (1.3.2.2).
        // This is not needed for attributes since when the full property 
        // name is composed it cannot clash with an IDL keyword.
        // (Also, rmic doesn't do it.)
        //
        
        if( !attribute && isIDLKeyword(mangledName) ) {
            mangledName = mangleIDLKeywordClash(mangledName);           
        } 

        //
        // Replace illegal IDL identifier characters (1.3.2.4) 
        // for all method names and attributes.
        //
        if( !isIDLIdentifier(mangledName) ) {
            mangledName = mangleUnicodeChars(mangledName);
        }       
        
        return mangledName;
    
private static java.lang.StringmangleLeadingUnderscore(java.lang.String identifier)

        return LEADING_UNDERSCORE_CHAR + identifier;
    
private static java.lang.StringmangleOverloadedMethod(java.lang.String mangledName, java.lang.reflect.Method m)
Mangle an overloaded method name as defined in Section 1.3.2.6 of Java2IDL spec. Current value of method name is passed in as argument. We can't start from original method name since the name might have been partially mangled as a result of the other rules.


        IDLTypesUtil idlTypesUtil = new IDLTypesUtil();

        // Start by appending the separator string
        String newMangledName = mangledName + OVERLOADED_TYPE_SEPARATOR;
        
        Class[] parameterTypes = m.getParameterTypes();
        
        for(int i = 0; i < parameterTypes.length; i++) {
            Class nextParamType = parameterTypes[i];
            
            if( i > 0 ) {
                newMangledName = newMangledName + OVERLOADED_TYPE_SEPARATOR;
            }            
            IDLType idlType = classToIDLType(nextParamType);

            String moduleName = idlType.getModuleName();
            String memberName = idlType.getMemberName();

            String typeName = (moduleName.length() > 0) ?
                moduleName + UNDERSCORE + memberName : memberName;
                                   
            if( !idlTypesUtil.isPrimitive(nextParamType) && 
                (idlTypesUtil.getSpecialCaseIDLTypeMapping(nextParamType) 
                 == null) &&               
                isIDLKeyword(typeName) ) {
                typeName = mangleIDLKeywordClash(typeName);
            }

            typeName = mangleUnicodeChars(typeName);

            newMangledName = newMangledName + typeName;
        }        

        return newMangledName;        
    
static java.lang.StringmangleUnicodeChars(java.lang.String identifier)
Implements Section 1.3.2.4 of Java2IDL Mapping. All non-IDL identifier characters must be replaced with their Unicode representation.

        StringBuffer mangledIdentifier = new StringBuffer();

        for(int i = 0; i < identifier.length(); i++) {
            char nextChar = identifier.charAt(i);
            if( isIDLIdentifierChar(nextChar) ) {
                mangledIdentifier.append(nextChar);
            } else {
                String unicode = charToUnicodeRepresentation(nextChar);
                mangledIdentifier.append(unicode);
            }
        }
        
        return mangledIdentifier.toString();
    
public java.lang.StringtoString()


        StringBuffer contents = new StringBuffer();
        contents.append("IDLNameTranslator[" );
	for( int ctr=0; ctr<interf_.length; ctr++) {
	    if (ctr != 0)
		contents.append( " " ) ;
	    contents.append( interf_[ctr].getName() ) ;
	}
        contents.append("]\n");
        for(Iterator iter = methodToIDLNameMap_.keySet().iterator();
            iter.hasNext();) {

            Method method  = (Method) iter.next();
            String idlName = (String) methodToIDLNameMap_.get(method);

            contents.append(idlName + ":" + method + "\n");

        }

        return contents.toString();