org.eclipseguru.gwt.core.GwtModule.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipseguru.gwt.core.GwtModule.java

Source

/*******************************************************************************
 * Copyright (c) 2006, 2010 EclipseGuru and others.
 * All rights reserved.
 *
 * This program and the accompanying materials are made available under the terms of the
 * Eclipse Public License v1.0 which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     EclipseGuru - initial API and implementation
 *     dobesv - contributed patch for issue 58
 *******************************************************************************/
package org.eclipseguru.gwt.core;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IStorage;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import java.io.IOException;
import java.io.InputStream;

import javax.xml.parsers.ParserConfigurationException;

/**
 * A GWT Module
 */
public class GwtModule extends GwtElement {

    /** FOLDER_NAME_SERVER */
    private static final String FOLDER_NAME_SERVER = "server";

    /** FOLDER_NAME_PUBLIC */
    private static final String FOLDER_NAME_PUBLIC = "public";

    /** FILE_EXTENSION_GWT_MODULE_DESCRIPTOR */
    private static final String FILE_EXTENSION_GWT_MODULE_DESCRIPTOR = "gwt.xml";

    /** ENTRY_POINT_TYPE */
    public static final String ENTRY_POINT_TYPE = "com.google.gwt.core.client.EntryPoint";

    /**
     * Indicates if the specified type is an entry point, i.e. implements the
     * <code>{@value #ENTRY_POINT_TYPE}</code> interface.
     * 
     * @param someType
     *            a type
     * @return <code>true</code> if the specified type implements the
     *         <code>{@value #ENTRY_POINT_TYPE}</code> interface,
     *         <code>false</code> otherwise
     * @throws JavaModelException
     */
    public static boolean isEntryPoint(final IType someType) throws JavaModelException {
        // ignore non-classes
        if (!someType.isClass()) {
            return false;
        }

        // for every interface implemented by that type
        final IType[] stypes = someType.newSupertypeHierarchy(null).getAllSuperInterfaces(someType);
        for (final IType element : stypes) {
            if (element.getFullyQualifiedName().equals(ENTRY_POINT_TYPE)) {
                return true;
            }
        }

        return false;
    }

    /** moduleId */
    private final String moduleId;

    /** moduleDescriptor */
    private final IStorage moduleDescriptor;

    /** modulePackage */
    private final IPackageFragment modulePackage;

    /** entryPointType */
    private IType entryPointType;

    /** entryPointTypeName */
    private String entryPointTypeName;

    /** inheritedModules */
    private GwtModule[] inheritedModules;

    /** moduleSourceInfo */
    private GwtModuleSourceHandler moduleSourceInfo;

    /**
     * Creates a new module from a file.
     * 
     * @param moduleDescriptor
     * @param parent
     */
    GwtModule(final IFile moduleDescriptor, final GwtProject parent) {
        super(parent);

        if (!GwtUtil.isModuleDescriptor(moduleDescriptor)) {
            throw new IllegalArgumentException("Module descriptor is invalid");
        }

        this.moduleDescriptor = moduleDescriptor;

        // module package
        final IJavaElement element = JavaCore.create(moduleDescriptor.getParent());
        if (null != element) {
            switch (element.getElementType()) {
            case IJavaElement.PACKAGE_FRAGMENT_ROOT:
                modulePackage = ((IPackageFragmentRoot) element).getPackageFragment("");
                break;
            case IJavaElement.PACKAGE_FRAGMENT:
                modulePackage = (IPackageFragment) element;
                break;
            default:
                modulePackage = null;
                break;
            }
        } else {
            modulePackage = null;
        }

        // the module id
        final StringBuilder moduleIdBuilder = new StringBuilder();
        if (null != modulePackage) {
            moduleIdBuilder.append(modulePackage.getElementName());
            if (moduleIdBuilder.length() > 0) {
                moduleIdBuilder.append('.');
            }
            moduleIdBuilder.append(moduleDescriptor.getName().substring(0,
                    moduleDescriptor.getName().length() - FILE_EXTENSION_GWT_MODULE_DESCRIPTOR.length() - 1));
        } else {
            final String path = moduleDescriptor.getFullPath().makeRelative().toString();
            moduleIdBuilder.append(path.substring(0, path.length() - GwtUtil.GWT_MODULE_SOURCE_EXTENSION.length())
                    .replace('/', '.'));
        }
        moduleId = moduleIdBuilder.toString();
    }

    /**
     * Creates a binary module.
     * 
     * @param moduleDescriptor
     * @param packageFragment
     * @param parent
     */
    GwtModule(final IStorage moduleDescriptor, final IPackageFragment packageFragment, final GwtProject parent) {
        super(parent);

        if (null == moduleDescriptor) {
            throw new IllegalArgumentException("Module descriptor cannot be null");
        }

        if (null == packageFragment) {
            throw new IllegalArgumentException("Package fragment cannot be null");
        }

        final String simpleName = GwtUtil.getSimpleName(moduleDescriptor);
        if (null == simpleName) {
            throw new IllegalArgumentException("Invalid storage name");
        }

        if (packageFragment.isDefaultPackage()) {
            moduleId = GwtUtil.getSimpleName(moduleDescriptor);
        } else {
            moduleId = packageFragment.getElementName().concat(".").concat(simpleName);
        }
        modulePackage = packageFragment;
        this.moduleDescriptor = moduleDescriptor;
    }

    /**
     * Creates a GWT remote service for the specified type.
     * 
     * @param type
     * @return
     */
    /* package */GwtRemoteService createRemoteService(final IType type) {
        return new GwtRemoteService(type, this);
    }

    @Override
    public boolean equals(final Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (!GwtModule.class.isAssignableFrom(obj.getClass())) {
            return false;
        }
        final GwtModule other = (GwtModule) obj;
        if (moduleId == null) {
            if (other.moduleId != null) {
                return false;
            }
        } else if (!moduleId.equals(other.moduleId)) {
            return false;
        }
        return true;
    }

    /**
     * Finds the entry point type.
     * 
     * @return the entry point type (maybe <code>null</code>)
     * @throws GwtModelException
     */
    private synchronized IType findEntryPointType() throws GwtModelException {
        // check if already set
        if (null != entryPointType) {
            return entryPointType;
        }

        // get entry point type name
        final String entryPointClass = getEntryPointTypeName();
        if (null == entryPointClass) {
            return null;
        }

        try {
            return getProject().getJavaProject().findType(entryPointClass);
        } catch (final JavaModelException e) {
            throw new GwtModelException(e.getStatus());
        }
    }

    /**
     * Finds the entry point type name.
     * 
     * @return the entry point type name (maybe <code>null</code>)
     * @throws GwtModelException
     */
    private synchronized String findEntryPointTypeName() throws GwtModelException {
        // check if already set
        if (null != entryPointTypeName) {
            return entryPointTypeName;
        }

        // get type name from module source
        return getModuleSourceInfo().getEntryPointClass();
    }

    /**
     * Finds the modules inherited by this module.
     * 
     * @return
     * @throws CoreException
     */
    private synchronized GwtModule[] findInheritedModules() throws GwtModelException {
        if (null != inheritedModules) {
            return inheritedModules;
        }

        final GwtModuleSourceHandler info = getModuleSourceInfo();

        // read all inherited module ids
        final String[] inheritedModuleIds = info.getInheritedModules();

        // resolve modules
        final GwtModule[] resolvedModules = GwtModelManager.findModules(inheritedModuleIds, getProject());
        return null != resolvedModules ? resolvedModules : GwtModelManager.NO_MODULES;
    }

    /**
     * Returns the optional alternate module name.
     * <p>
     * The alternate module name is defined in the module descriptor on the
     * <code>module</code> element using the <code>rename-to</code> attribute.
     * It will be used for renaming modules at deploy/compile time.
     * </p>
     * 
     * @return the optional alternate module name (maybe <code>null</code> if
     *         not defined)
     * @throws GwtModelException
     */
    public String getAlternateName() throws GwtModelException {
        return getModuleSourceInfo().getAlternateModuleName();
    }

    /**
     * Returns the entry point type.
     * 
     * @return the entry point type (maybe <code>null</code>)
     * @throws GwtModelException
     */
    public IType getEntryPointType() throws GwtModelException {
        if (null == entryPointType) {
            entryPointType = findEntryPointType();
        }

        return entryPointType;
    }

    /**
     * Returns the entry point type name.
     * 
     * @return the entry point type name (maybe <code>null</code>)
     * @throws GwtModelException
     */
    public String getEntryPointTypeName() throws GwtModelException {
        if (null == entryPointTypeName) {
            entryPointTypeName = findEntryPointTypeName();
        }

        return entryPointTypeName;
    }

    /**
     * Returns the list of modules directly inherited my this module.
     * 
     * @return the inheritedModules
     * @throws CoreException
     */
    public GwtModule[] getInheritedModules() throws CoreException {
        if (null == inheritedModules) {
            inheritedModules = findInheritedModules();
        }

        return inheritedModules;
    }

    /**
     * Returns the module descriptor.
     * 
     * @return the moduleDescriptor
     */
    public IStorage getModuleDescriptor() {
        return moduleDescriptor;
    }

    /**
     * Returns the module id.
     * 
     * @return the module id
     */
    public String getModuleId() {
        return moduleId;
    }

    /**
     * Returns the module package. <code>null</code> is returned if the module
     * is not on the classpath.
     * 
     * @return the modulePackage (maybe <code>null</code>)
     */
    public IPackageFragment getModulePackage() {
        return modulePackage;
    }

    /**
     * Returns (creates if necessary) the module source info.
     * 
     * @return the module source info
     * @throws GwtModelException
     */
    private synchronized GwtModuleSourceHandler getModuleSourceInfo() throws GwtModelException {
        if (null == moduleSourceInfo) {
            moduleSourceInfo = new GwtModuleSourceHandler();
            InputStream contents = null;
            try {
                contents = getModuleDescriptor().getContents();
                moduleSourceInfo.parseContents(new InputSource(contents));
            } catch (final IOException e) {
                throw new GwtModelException(GwtCore.newErrorStatus("Error while parsing module source", e));
            } catch (final ParserConfigurationException e) {
                final String message = "Internal Error: XML parser configuration error during pasing module source file."; //$NON-NLS-1$
                GwtCore.logError(message, e);
                throw new RuntimeException(message, e);
            } catch (final SAXException e) {
                throw new GwtModelException(GwtCore.newErrorStatus("Error while parsing module source", e));
            } catch (final CoreException e) {
                throw new GwtModelException(e.getStatus());
            } finally {
                if (null != contents) {
                    try {
                        contents.close();
                    } catch (final IOException e) {
                        // ignore
                    }
                }
            }
        }
        return moduleSourceInfo;
    }

    /**
     * Returns the module id.
     * 
     * @return the module id
     */
    @Override
    public String getName() {
        return moduleId;
    }

    /**
     * Returns the project.
     * 
     * @return the project
     */
    public GwtProject getProject() {
        return (GwtProject) getParent();
    }

    /**
     * Returns the project name.
     * 
     * @return the project name
     */
    public String getProjectName() {
        return getProject().getName();
    }

    /**
     * Returns the project resource.
     * 
     * @return the project resource
     */
    public IProject getProjectResource() {
        return getProject().getProjectResource();
    }

    /**
     * Returns the simple module name, i.e. the last part of the module id.
     * 
     * @return the simple module name
     */
    public String getSimpleName() {
        return GwtUtil.getSimpleName(moduleId);
    }

    /**
     * Returns the source paths of the module as defined in the module
     * descriptor.
     * <p>
     * If the module descriptor does not define custom source paths a default
     * will be returned which is an array containing the string
     * <code>"client"</code>
     * </p>
     * <p>
     * Note, the paths are returned as defined in the module descriptor and
     * should be considered relative to the {@link #getModuleDescriptor() module
     * descriptor}.
     * </p>
     * 
     * @return the source paths of the module as defined in the module
     *         descriptor or an array containing the string
     *         <code>"client"</code>
     * @throws GwtModelException
     */
    public String[] getSourcePaths() throws GwtModelException {
        return getModuleSourceInfo().getSourcePaths();
    }

    /*
     * (non-Javadoc)
     * @see org.eclipseguru.gwt.core.GwtElement#getType()
     */
    @Override
    public int getType() {
        return GWT_MODULE;
    }

    @Override
    public int hashCode() {
        final int PRIME = 31;
        int result = 1;
        result = PRIME * result + ((moduleId == null) ? 0 : moduleId.hashCode());
        return result;
    }

    /**
     * Indicates if this module is a binary module.
     * 
     * @return <code>true</code> if this module is a binary module
     */
    public boolean isBinary() {
        return !(moduleDescriptor instanceof IFile);
    }

    /**
     * Indicates if the specified path points to a resource within this module.
     * <p>
     * A path is considered to be with a module if it points to any resouce
     * somewhere inside the client, server or public directory or one of their
     * subdirectories. Note that the resource specified by the path does not
     * need to exist.
     * </p>
     * 
     * @param fullPath
     *            the full, absolute path rooted at the workspace root
     * @return <code>true</code> if the path points to a resource within the
     *         module, <code>false</code> otherwise
     * @throws GwtModelException
     */
    boolean isModulePath(final IPath fullPath) throws GwtModelException {
        final IPath moduleRoot = isBinary() ? modulePackage.getPath()
                : ((IFile) moduleDescriptor).getParent().getFullPath();

        // client folder
        final GwtModuleSourceHandler info = getModuleSourceInfo();
        for (final String sourcePath : info.getSourcePaths()) {
            if (moduleRoot.append(sourcePath).isPrefixOf(fullPath)) {
                return true;
            }
        }

        // public folder
        if (moduleRoot.append(FOLDER_NAME_PUBLIC).isPrefixOf(fullPath)) {
            return true;
        } else if (moduleRoot.append(FOLDER_NAME_SERVER).isPrefixOf(fullPath)) {
            return true;
        }

        return false;
    }

    /**
     * Indicates if the specified resource is part of this module.
     * <p>
     * This method just calls <code>{@link #isModulePath(IPath)}</code>.
     * </p>
     * 
     * @param resource
     * @return <code>true</code> if the resource is a module resource,
     *         <code>false</code> otherwise
     * @throws GwtModelException
     * @see #isModulePath(IPath)
     */
    public boolean isModuleResource(final IResource resource) throws GwtModelException {
        // if the resource is below the module path, then consider it a module resource
        if (isModulePath(resource.getFullPath())) {
            return true;
        }

        // check if resource in reachable from classpath and is within a module package
        final IJavaProject javaProject = JavaCore.create(getProjectResource());
        if (javaProject.isOnClasspath(resource)) {
            final String resourceFullPath = resource.getFullPath().toString();
            final String modulePackageBaseName = getModulePackage().getElementName().replace('.', '/');
            final GwtModuleSourceHandler info = getModuleSourceInfo();
            for (final String sourcePath : info.getSourcePaths()) {
                String modulePackageName;
                if (sourcePath.equals(".") || sourcePath.equals("./") || sourcePath.equals("/")
                        || sourcePath.equals("")) {
                    modulePackageName = modulePackageBaseName;
                } else {
                    modulePackageName = modulePackageBaseName.concat("/").concat(sourcePath);
                }
                if (resourceFullPath.indexOf(modulePackageName) != -1) {
                    // resource is on the classpath *AND* within a module package
                    return true;
                }
            }
        }

        // give up
        return false;
    }

    /*
     * (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "GwtModule: " + moduleId;
    }
}