All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.codehaus.modello.plugin.java.javasource.JStructure Maven / Gradle / Ivy

/**
 * Redistribution and use of this software and associated documentation
 * ("Software"), with or without modification, are permitted provided
 * that the following conditions are met:
 *
 * 1. Redistributions of source code must retain copyright
 *    statements and notices.  Redistributions must also contain a
 *    copy of this document.
 *
 * 2. Redistributions in binary form must reproduce the
 *    above copyright notice, this list of conditions and the
 *    following disclaimer in the documentation and/or other
 *    materials provided with the distribution.
 *
 * 3. The name "Exolab" must not be used to endorse or promote
 *    products derived from this Software without prior written
 *    permission of Intalio, Inc.  For written permission,
 *    please contact [email protected].
 *
 * 4. Products derived from this Software may not be called "Exolab"
 *    nor may "Exolab" appear in their names without prior written
 *    permission of Intalio, Inc. Exolab is a registered
 *    trademark of Intalio, Inc.
 *
 * 5. Due credit should be given to the Exolab Project
 *    (http://www.codehaus.org/).
 *
 * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
 * INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Copyright 2001-2002 (C) Intalio, Inc. All Rights Reserved.
 *
 * $Id$
 */

package org.codehaus.modello.plugin.java.javasource;

/*
 * Copyright (c) 2004, Codehaus.org
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is furnished to do
 * so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

import java.io.File;
import java.util.Enumeration;
import java.util.Vector;

import org.codehaus.plexus.util.WriterFactory;

/**
 * This class represents the basic Java "structure" for a Java
 * source file. This is the base class for JClass and JInterface.
 *
 * This is a useful utility when creating in memory source code.
 * The code in this package was modelled after the Java Reflection API
 * as much as possible to reduce the learning curve.
 *
 * @author Martin Skopp
 * @author Keith Visco
 * @version $Revision$ $Date$
 */
public abstract class JStructure extends JType
{

    /**
     * The Id for Source control systems
     * I needed to separate this line to prevent CVS from
     * expanding it here! ;-)
     */
    static final String DEFAULT_HEADER
        = "$" + "Id$";

    /**
     * The source control version for listed in the JavaDoc
     * I needed to separate this line to prevent CVS from
     * expanding it here! ;-)
     */
    static final String version = "$" + "Revision$ $" + "Date$";

    /**
     * The source header
     */
    private JComment header = null;

    /**
     * List of imported classes and packages
     */
    private Vector imports = null;

    /**
     * The set of interfaces implemented/extended by this JStructure
     */
    private Vector interfaces = null;

    /**
     * The Javadoc for this JStructure
     */
    private JDocComment jdc = null;

    /**
     * The JModifiers for this JStructure, which allows us to
     * change the resulting qualifiers
     */
    private JModifiers modifiers = null;

    /**
     * The package to which this JStructure belongs
     */
    private String packageName = null;

    private JAnnotations annotations = null;

    /**
     * Creates a new JStructure with the given name.
     *
     * @param name the name of the JStructure.
     * @throws java.lang.IllegalArgumentException when the given name
     * is not a valid Class name.
     */
    protected JStructure( String name )
        throws IllegalArgumentException
    {
        super( name );

        //-- verify name is a valid java class name
        if ( !isValidClassName( name ) )
        {
            String lname = getLocalName();
            String err = "'" + lname + "' is ";
            if ( JNaming.isKeyword( lname ) )
                err += "a reserved word and may not be used as "
                    + " a class name.";
            else
                err += "not a valid Java identifier.";

            throw new IllegalArgumentException( err );
        }
        this.packageName = getPackageFromClassName( name );
        imports = new Vector();
        interfaces = new Vector();
        jdc = new JDocComment();
        modifiers = new JModifiers();
        //-- initialize default Java doc
        jdc.addDescriptor( JDocDescriptor.createVersionDesc( version ) );

    } //-- JStructure

    /**
     * Adds the given JField to this JStructure.
     * 

* This method is implemented by subclasses and * should only accept the proper fields for the * subclass otherwise an IllegalArgumentException * will be thrown. For example a JInterface will * only accept static fields. *

* @param jField, the JField to add * @exception java.lang.IllegalArgumentException when the given * JField has a name of an existing JField */ public abstract void addField( JField jField ) throws IllegalArgumentException; /** * Adds the given JMember to this JStructure. *

* This method is implemented by subclasses and * should only accept the proper types for the * subclass otherwise an IllegalArgumentException * will be thrown. *

* @param jMember the JMember to add to this JStructure. * @throws java.lang.IllegalArgumentException when the given * JMember has the same name of an existing JField * or JMethod respectively. */ public abstract void addMember( JMember jMember ) throws IllegalArgumentException; /** * Adds the given import to this JStructure * * @param the className of the class to import. */ public void addImport( String className ) { if ( className == null ) return; if ( className.length() == 0 ) return; //-- getPackageName String pkgName = getPackageFromClassName( className ); if ( pkgName != null ) { if ( pkgName.equals( this.packageName ) ) return; //-- XXX: Fix needed for this... //-- This may cause issues if the current package //-- defines any classes that have the same name //-- name as the java.lang package. if ( "java.lang".equals( pkgName ) ) return; //-- for readabilty keep import list sorted, and make sure //-- we do not include more than one of the same import for ( int i = 0; i < imports.size(); i++ ) { String imp = (String) imports.elementAt( i ); if ( imp.equals( className ) ) return; if ( imp.compareTo( className ) > 0 ) { imports.insertElementAt( className, i ); return; } } imports.addElement( className ); } } //-- addImport /** * Adds the given interface to the list of interfaces this * JStructure inherits method declarations from, and either * implements (JClass) or extends (JInterface). * * @param interfaceName the name of the interface to "inherit" * method declarations from. */ public void addInterface( String interfaceName ) { if ( !interfaces.contains( interfaceName ) ) interfaces.addElement( interfaceName ); } //-- addInterface /** * Adds the given interface to the list of interfaces this * JStructure inherits method declarations from, and either * implements (JClass) or extends (JInterface). * * @param jInterface the JInterface to inherit from. */ public void addInterface( JInterface jInterface ) { if ( jInterface == null ) return; String interfaceName = jInterface.getName(); if ( !interfaces.contains( interfaceName ) ) { interfaces.addElement( interfaceName ); } } //-- addInterface /** * Adds the given JMethodSignature to this JClass * * @param jMethodSig the JMethodSignature to add. * @throws java.lang.IllegalArgumentException when the given * JMethodSignature conflicts with an existing * method signature. */ /* public void addMethod(JMethodSignature jMethodSig) throws IllegalArgumentException { if (jMethodSig == null) { String err = "The JMethodSignature cannot be null."; throw new IllegalArgumentException(err); } //-- XXXX: check method name and signatures *add later* //-- keep method list sorted for esthetics when printing //-- START SORT :-) boolean added = false; short modifierVal = 0; JModifiers modifiers = jMethodSig.getModifiers(); for (int i = 0; i < methods.size(); i++) { JMethodSignature tmp = (JMethodSignature) methods.elementAt(i); //-- first compare modifiers if (tmp.getModifiers().isProtected()) { if (!modifiers.isProtected()) { methods.insertElementAt(jMethodSig, i); added = true; break; } } //-- compare names if (jMethodSig.getName().compareTo(tmp.getName()) < 0) { methods.insertElementAt(jMethodSig, i); added = true; break; } } //-- END SORT if (!added) methods.addElement(jMethodSig); //-- check parameter packages to make sure we have them //-- in our import list String[] pkgNames = jMethodSig.getParameterClassNames(); for (int i = 0; i < pkgNames.length; i++) { addImport(pkgNames[i]); } //-- check return type to make sure it's included in the //-- import list JType jType = jMethodSig.getReturnType(); if (jType != null) { while (jType.isArray()) jType = jType.getComponentType(); if (!jType.isPrimitive()) addImport(jType.getName()); } //-- check exceptions JClass[] exceptions = jMethodSig.getExceptions(); for (int i = 0; i < exceptions.length; i++) { addImport(exceptions[i].getName()); } } //-- addMethod */ /** * Returns the field with the given name, or null if no field * was found with the given name. * * @param name the name of the field to return. * @return the field with the given name, or null if no field * was found with the given name. */ public abstract JField getField( String name ); /** * Returns an array of all the JFields of this JStructure * * @return an array of all the JFields of this JStructure */ public abstract JField[] getFields(); /** * Returns the name of the file that this JStructure would be * printed to, given a call to #print. * * @param destDir the destination directory. This may be null. * @return the name of the file that this JInterface would be * printed as, given a call to #print. */ public String getFilename( String destDir ) { String filename = getLocalName() + ".java"; //-- Convert Java package to path string String javaPackagePath = ""; if ( ( packageName != null ) && ( packageName.length() > 0 ) ) { javaPackagePath = packageName.replace( '.', File.separatorChar ); } //-- Create fully qualified path (including 'destDir') to file File pathFile; if ( destDir == null ) pathFile = new File( javaPackagePath ); else pathFile = new File( destDir, javaPackagePath ); if ( !pathFile.exists() ) { pathFile.mkdirs(); } //-- Prefix filename with path if ( pathFile.toString().length() > 0 ) filename = pathFile.toString() + File.separator + filename; return filename; } //-- getFilename /** * Returns the JComment header to display at the top of the source file * for this JStructure, or null if no header was set. * * @return the JComment header or null if none exists. */ public JComment getHeader() { return this.header; } //-- getHeader /** * Returns an Enumeration of imported package and * class names for this JStructure. * * @return the Enumeration of imports. May be empty. */ public Enumeration getImports() { return imports.elements(); } //-- getImports /** * Returns an Enumeration of interface names that this * JStructure inherits from. * * @return the Enumeration of interface names for this * JStructure. May be empty. */ public Enumeration getInterfaces() { return interfaces.elements(); } //-- getInterfaces /** * Returns the Java Doc comment for this JStructure * * @return the JDocComment for this JStructure */ public JDocComment getJDocComment() { return jdc; } //-- getJDocComment /** * Returns an array of all the JMethodSignatures of this JInterface. * * @return an array of all the JMethodSignatures of this JInterface. */ /* public JMethodSignature[] getMethods() { JMethodSignature[] marray = new JMethodSignature[methods.size()]; methods.copyInto(marray); return marray; } //-- getMethods */ /** * Returns the JMethodSignature with the given name, * and occuring at or after the given starting index. * * @param name the name of the JMethodSignature to return. * @param startIndex the starting index to begin searching * from. * @return the JMethodSignature, or null if not found. */ /* public JMethodSignature getMethod(String name, int startIndex) { for (int i = startIndex; i < methods.size(); i++) { JMethodSignature jMethod = (JMethodSignature)methods.elementAt(i); if (jMethod.getName().equals(name)) return jMethod; } return null; } //-- getMethod */ /** * Returns the JMethodSignature at the given index. * * @param index the index of the JMethodSignature to return. * @return the JMethodSignature at the given index. */ /* public JMethodSignature getMethod(int index) { return (JMethodSignature)methods.elementAt(index); } //-- getMethod */ /** * Returns the JModifiers which allows the qualifiers to be changed. * * @return the JModifiers for this JStructure. */ public JModifiers getModifiers() { return modifiers; } //-- getModifiers /** * Returns the name of the package that this JStructure is a member * of. * * @return the name of the package that this JStructure is a member * of, or null if there is no current package name defined. */ public String getPackageName() { return this.packageName; } //-- getPackageName /** * Returns the name of the interface. * * @param stripPackage a boolean that when true indicates that only * the local name (no package) should be returned. * @return the name of the class. */ public String getName( boolean stripPackage ) { String name = super.getName(); if ( stripPackage ) { int period = name.lastIndexOf( "." ); if ( period > 0 ) name = name.substring( period + 1 ); } return name; } //-- getName /** * Returns true if the given classname exists in the imports * of this JStructure * * @param classname the class name to check for * @return true if the given classname exists in the imports list */ public boolean hasImport( String classname ) { return imports.contains( classname ); } //-- hasImport public boolean removeImport( String className ) { boolean result = false; if ( className == null ) return result; if ( className.length() == 0 ) return result; result = imports.removeElement( className ); return result; } //-- removeImport public boolean isAbstract() { return modifiers.isAbstract(); } public static boolean isValidClassName( String name ) { if ( name == null ) return false; //-- ignore package information, for now int period = name.lastIndexOf( "." ); if ( period > 0 ) name = name.substring( period + 1 ); return JNaming.isValidJavaIdentifier( name ); } //-- isValidClassName /** * Prints the source code for this JStructure in the current * working directory. Sub-directories will be created if necessary * for the package. */ public void print() { print( (String) null, (String) null ); } //-- printSrouce /** * Prints the source code for this JStructure to the destination * directory. Sub-directories will be created if necessary for the * package. * * @param lineSeparator the line separator to use at the end of each line. * If null, then the default line separator for the runtime platform will * be used. */ public void print( String destDir, String lineSeparator ) { // String name = getLocalName(); //-- open output file String filename = getFilename( destDir ); File file = new File( filename ); JSourceWriter jsw = null; try { jsw = new JSourceWriter( WriterFactory.newPlatformWriter( file ) ); } catch ( java.io.IOException ioe ) { System.out.println( "unable to create class file: " + filename ); return; } if ( lineSeparator == null ) { lineSeparator = System.getProperty( "line.separator" ); } jsw.setLineSeparator( lineSeparator ); print( jsw ); jsw.close(); } //-- print /** * Prints the source code for this JStructure to the given * JSourceWriter. * * @param jsw the JSourceWriter to print to. */ public abstract void print( JSourceWriter jsw ); /** * A utility method that prints the header to the given * JSourceWriter * * @param jsw the JSourceWriter to print to. */ public void printHeader( JSourceWriter jsw ) { if ( jsw == null ) { throw new IllegalArgumentException( "argument 'jsw' should not be null." ); } //-- write class header JComment header = getHeader(); if ( header != null ) header.print( jsw ); else { jsw.writeln( "/*" ); jsw.writeln( " * " + DEFAULT_HEADER ); jsw.writeln( " */" ); } jsw.writeln(); jsw.flush(); } //-- printHeader /** * A utility method that prints the imports to the given * JSourceWriter * * @param jsw the JSourceWriter to print to. */ public void printImportDeclarations( JSourceWriter jsw ) { if ( jsw == null ) { throw new IllegalArgumentException( "argument 'jsw' should not be null." ); } //-- print imports if ( imports.size() > 0 ) { jsw.writeln( " //---------------------------------/" ); jsw.writeln( " //- Imported classes and packages -/" ); jsw.writeln( "//---------------------------------/" ); jsw.writeln(); Enumeration e = imports.elements(); while ( e.hasMoreElements() ) { jsw.write( "import " ); jsw.write( e.nextElement() ); jsw.writeln( ';' ); } jsw.writeln(); jsw.flush(); } } //-- printImportDeclarations /** * A utility method that prints the packageDeclaration to * the given JSourceWriter * * @param jsw the JSourceWriter to print to. */ public void printPackageDeclaration( JSourceWriter jsw ) { if ( jsw == null ) { throw new IllegalArgumentException( "argument 'jsw' should not be null." ); } //-- print package name if ( ( packageName != null ) && ( packageName.length() > 0 ) ) { jsw.write( "package " ); jsw.write( packageName ); jsw.writeln( ';' ); jsw.writeln(); } jsw.flush(); } //-- printPackageDeclaration /** * Prints the source code for this JStructure to the given * JSourceWriter. * * @param jsw the JSourceWriter to print to. * public abstract void print(JSourceWriter jsw); StringBuffer buffer = new StringBuffer(); printHeader(); printPackageDeclaration(); printImportDeclarations(); //------------/ //- Java Doc -/ //------------/ jdc.print(jsw); //-- print class information //-- we need to add some JavaDoc API adding comments buffer.setLength(0); if (modifiers.isPrivate()) { buffer.append("private "); } else if (modifiers.isPublic()) { buffer.append("public "); } if (modifiers.isAbstract()) { buffer.append("abstract "); } buffer.append("interface "); buffer.append(getLocalName()); buffer.append(' '); if (interfaces.size() > 0) { boolean endl = false; if (interfaces.size() > 1) { jsw.writeln(buffer.toString()); buffer.setLength(0); endl = true; } buffer.append("extends "); for (int i = 0; i < interfaces.size(); i++) { if (i > 0) buffer.append(", "); buffer.append(interfaces.elementAt(i)); } if (endl) { jsw.writeln(buffer.toString()); buffer.setLength(0); } else buffer.append(' '); } buffer.append('{'); jsw.writeln(buffer.toString()); buffer.setLength(0); jsw.writeln(); jsw.indent(); //-- print method signatures if (methods.size() > 0) { jsw.writeln(); jsw.writeln(" //-----------/"); jsw.writeln(" //- Methods -/"); jsw.writeln("//-----------/"); jsw.writeln(); } for (int i = 0; i < methods.size(); i++) { JMethodSignature signature = (JMethodSignature) methods.elementAt(i); signature.print(jsw); jsw.writeln(';'); } jsw.unindent(); jsw.writeln('}'); jsw.flush(); jsw.close(); } //-- printSource */ /** * Sets the header comment for this JStructure * * @param comment the comment to display at the top of the source file * when printed */ public void setHeader( JComment comment ) { this.header = comment; } //-- setHeader /** * Allows changing the package name of this JStructure * * @param packageName the package name to use * @deprecated removed in future version of javasource */ public void setPackageName( String packageName ) { this.packageName = packageName; changePackage( packageName ); } //-- setPackageName //---------------------/ //- Protected Methods -/ //---------------------/ protected int getInterfaceCount() { return interfaces.size(); } /** * Prints the given source string to the JSourceWriter using the given prefix at * the beginning of each new line. * * @param prefix the prefix for each new line. * @param source the source code to print * @param jsw the JSourceWriter to print to. */ protected static void printlnWithPrefix( String prefix, String source, JSourceWriter jsw ) { jsw.write( prefix ); if ( source == null ) return; char[] chars = source.toCharArray(); int lastIdx = 0; for ( int i = 0; i < chars.length; i++ ) { char ch = chars[i]; if ( ch == '\n' ) { //-- free buffer jsw.write( chars, lastIdx, ( i - lastIdx ) + 1 ); lastIdx = i + 1; if ( i < chars.length ) { jsw.write( prefix ); } } } //-- free buffer if ( lastIdx < chars.length ) { jsw.write( chars, lastIdx, chars.length - lastIdx ); } jsw.writeln(); } //-- printlnWithPrefix /** * Returns the package name from the given class name */ protected static String getPackageFromClassName( String className ) { int idx = -1; if ( ( idx = className.lastIndexOf( '.' ) ) > 0 ) { return className.substring( 0, idx ); } return null; } //-- getPackageFromClassName /** * @return the annotations */ public JAnnotations getAnnotations() { return annotations; } /** * @param annotation the annotation to append */ public void appendAnnotation( String annotation ) { if ( annotations == null ) { annotations = new JAnnotations(); } annotations.appendAnnotation( annotation ); } /** * @param annotations the annotations to set */ public void setAnnotations( JAnnotations annotations ) { this.annotations = annotations; } } //-- JStructure





© 2015 - 2025 Weber Informatics LLC | Privacy Policy