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

com.thoughtworks.qdox.library.AbstractClassLibrary Maven / Gradle / Ivy

There is a newer version: 1.2.2.1-jre17
Show newest version
package com.thoughtworks.qdox.library;

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import java.net.URL;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import com.thoughtworks.qdox.builder.Builder;
import com.thoughtworks.qdox.builder.ModelBuilderFactory;
import com.thoughtworks.qdox.builder.impl.ModelBuilder;
import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaModule;
import com.thoughtworks.qdox.model.JavaPackage;
import com.thoughtworks.qdox.model.JavaSource;
import com.thoughtworks.qdox.model.impl.DefaultDocletTagFactory;
import com.thoughtworks.qdox.model.impl.DefaultJavaPackage;
import com.thoughtworks.qdox.parser.structs.ClassDef;
import com.thoughtworks.qdox.writer.ModelWriterFactory;

/**
 * A ClassLibrary can be compared with a java classloader. 
 * Its main task is to serve JavaClasses based on the Fully Qualified Name.
 * AbstractClassLibraries hold a reference a parent library, in which way they can be chained.
 * Besides that it contains a context only for this library. 
 * 
 * @author Robert Scholte
 * @since 2.0
 */
public abstract class AbstractClassLibrary
    implements ClassLibrary
{
    private AbstractClassLibrary parentClassLibrary;
    
    private ModelBuilderFactory modelBuilderFactory;

    private ModelWriterFactory modelWriterFactory;
    
    private JavaClassContext context = new JavaClassContext();

    /**
     * constructor for root ClassLibrary
     */
    public AbstractClassLibrary()
    {
    }

    /**
     * constructor for chained ClassLibrary
     * @param parent the parent library
     */
    public AbstractClassLibrary( AbstractClassLibrary parent )
    {
        this.parentClassLibrary = parent;
    }
    
    public Collection getJavaModules()
    {
        Collection modules = null;
        if ( parentClassLibrary != null )
        {
            modules = parentClassLibrary.getJavaModules();
        }
        return modules;
    }

    /**
     * First checks if there's a JavaClass available in the private context by this name. Otherwise try to resolve it by
     * the concrete class. If there's still no JavaClass, ask the parent (if available) to resolve it.
     * 
     * @param name the binary name of the class
     * @return the JavaClass matching the name, otherwise null
     */
    public final JavaClass getJavaClass( String name ) {
       return getJavaClass( name, false ); 
    }
    
    public final JavaClass getJavaClass( String name, boolean createStub ) {
        JavaClass result = context.getClassByName( name );
        if ( result == null )
        {
            result = resolveJavaClass( name );

            if ( result != null )  
            {
                context.add( result );
                context.add( result.getSource() );
                
                JavaPackage contextPackage = context.getPackageByName( result.getPackageName() ); 
                if( contextPackage == null ) {
                    DefaultJavaPackage newContextPackage = new DefaultJavaPackage( result.getPackageName() );
                    newContextPackage.setClassLibrary( this );
                    context.add( newContextPackage );    

                    contextPackage  = newContextPackage;
                }
                contextPackage.getClasses().addAll( result.getNestedClasses() );
            }
        }
        if ( result == null && parentClassLibrary != null )
        {
            result = parentClassLibrary.getJavaClass( name );
        }
        if (result == null && createStub) {
            result = createStub(name);
        }
        return result;
    }

    private JavaClass createStub( String name )
    {
        Builder unknownBuilder = getModelBuilder();
        unknownBuilder.beginClass( new ClassDef( name ) );
        unknownBuilder.endClass();
        JavaSource unknownSource = unknownBuilder.getSource();
        return unknownSource.getClasses().get( 0 );
    }

    /**
     * The implementation should check it's sources to see if it can build a JavaClass Model If not, just return null;
     * Once found it will be mapped, so there's no need to keep a reference to this object.
     * 
     * @param name the fully qualified name
     * @return the resolved JavaClass, otherwise null
     */
    protected abstract JavaClass resolveJavaClass( String name );
    
    public Collection getJavaSources()
    {
        return context.getSources();
    }
    
    /**
     * 
     * 
     * @param filter the classlibrary filter
     * @return JavaSources matching the filter
     */
    protected final Collection getJavaSources( ClassLibraryFilter filter) {
        List result = new LinkedList(); 
        if(filter.accept(this)) {
            result.addAll( context.getSources() );
        }
        if ( parentClassLibrary != null ) {
            result.addAll( parentClassLibrary.getJavaSources( filter ) );
        }
        return Collections.unmodifiableList( result );
    }
    
    /**
     * Get all the classes of the current {@link AbstractClassLibrary}.
     * Subclasses can overwrite this method by including the following code
     * 
 
     * public List<JavaClass> getClasses()
     * {
     *   return getJavaClasses( new ClassLibraryFilter()
     *   {
     *      public boolean accept( AbstractClassLibrary classLibrary )
     *      {
     *          return true;
     *      }
     *   });
     * }
     * 
* This example would return all created {@link JavaClass } objects, including those from the classloaders. * * @return all JavaClasses of this ClassLibrary */ public Collection getJavaClasses() { return context.getClasses(); } /** * Subclasses can call this method to gather all JavaClass object, including those from the parent. * * @param filter the classlibrary filter * @return JavaClasses matching the filter */ protected final Collection getJavaClasses( ClassLibraryFilter filter) { List result = new LinkedList(); if(filter.accept(this)) { result.addAll( context.getClasses() ); } if ( parentClassLibrary != null ) { result.addAll( parentClassLibrary.getJavaClasses( filter ) ); } return Collections.unmodifiableList( result ); } /** * Get all packages of the current {@link AbstractClassLibrary}. * Subclasses can overwrite this method by including the following code *
 
     * public List<JavaPackage> getJavaPackages()
     * {
     *   return getJavaPackages( new ClassLibraryFilter()
     *   {
     *      public boolean accept( AbstractClassLibrary classLibrary )
     *      {
     *          return true;
     *      }
     *   });
     * }
     * 
* This example would return all created {@link JavaPackage } objects, including those from the classloaders. * * @return all JavaPackages of this ClassLibrary */ public Collection getJavaPackages() { return context.getPackages(); } /** * @param name the fully qualified name * @return the JavaPackage matching the name, otherwise null */ public final JavaPackage getJavaPackage( String name ) { JavaPackage result = context.getPackageByName( name ); if (result == null) { result = resolveJavaPackage( name ); if (result != null) { context.add(result); } } if(result == null && parentClassLibrary != null ) { result = parentClassLibrary.getJavaPackage( name ); } return result; } protected abstract JavaPackage resolveJavaPackage(String name); protected final Collection getJavaPackages( ClassLibraryFilter filter) { List result = new LinkedList(); if( filter.accept( this ) ) { result.addAll( context.getPackages() ); } if ( parentClassLibrary != null ) { result.addAll( parentClassLibrary.getJavaPackages( filter ) ); } return Collections.unmodifiableList( result ); } /** * First checks if the context already has a JavaClass with this name. * If not, find out if this classlibrary is able to build a model for this class * Otherwise ask the parent if it could build a JavaClass. * * @param name the fully qualified name * @return true if there is a reference, otherwise false */ public boolean hasClassReference( String name ) { boolean result = context.getClassByName( name ) != null; if ( !result ) { result = containsClassReference( name ); } if ( !result && parentClassLibrary != null ) { result = parentClassLibrary.hasClassReference( name ); } return result; } /** * This method is used to detect if there's a match with this classname. * The name could be constructed based on imports and inner class paths. * * @param name the fully qualified name of the class * @return true if this ClassLibrary has a reference to this class. */ protected abstract boolean containsClassReference( String name ); /** * Set the ModelBuilderFactory for this classLibrary. * * @param factory the model builder factory */ public final void setModelBuilderFactory( ModelBuilderFactory factory ) { this.modelBuilderFactory = factory; } /** * Set the ModelWriterFactory for this class. * * @param factory the model writer factory */ public final void setModelWriterFactory( ModelWriterFactory factory ) { this.modelWriterFactory = factory; } protected final ModelWriterFactory getModelWriterFactory() { return modelWriterFactory; } protected final ModelBuilderFactory getModelBuilderFactory() { return modelBuilderFactory; } /** * If there's a modelBuilderFactory available, ask it for a new instance. * Otherwise, return a default ModelBuilder. * In both cases, pass this library as argument. * * @return a new instance of a ModelBuilder, never null */ protected Builder getModelBuilder() { ModelBuilder result; if ( modelBuilderFactory != null ) { result = modelBuilderFactory.newInstance( this ); } else { result = new ModelBuilder( this, new DefaultDocletTagFactory() ); } result.setModelWriterFactory( modelWriterFactory ); return result; } protected Builder getModelBuilder( URL url ) { Builder result = getModelBuilder(); result.setUrl( url ); return result; } /** * A filter to use when checking all ancestors. * * @author Robert Scholte */ interface ClassLibraryFilter { /** * * @param classLibrary * @return */ boolean accept( AbstractClassLibrary classLibrary ); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy