org.eclipse.jdt.internal.core.PackageFragment.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.jdt.internal.core.PackageFragment.java

Source

/*******************************************************************************
 * Copyright (c) 2000, 2017 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.jdt.internal.core;

import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IModularClassFile;
import org.eclipse.jdt.core.IOrdinaryClassFile;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IParent;
import org.eclipse.jdt.core.ISourceManipulation;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.WorkingCopyOwner;
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
import org.eclipse.jdt.internal.core.JavaModelManager.PerProjectInfo;
import org.eclipse.jdt.internal.core.util.MementoTokenizer;
import org.eclipse.jdt.internal.core.util.Messages;
import org.eclipse.jdt.internal.core.util.Util;

/**
 * @see IPackageFragment
 */
@SuppressWarnings({ "rawtypes", "unchecked" })
public class PackageFragment extends Openable implements IPackageFragment, SuffixConstants {
    /**
     * Constant empty list of class files
     */
    protected static final IClassFile[] NO_CLASSFILES = new IClassFile[] {};
    protected static final IOrdinaryClassFile[] NO_ORDINARY_CLASSFILES = new IOrdinaryClassFile[] {};
    /**
     * Constant empty list of compilation units
     */
    protected static final ICompilationUnit[] NO_COMPILATION_UNITS = new ICompilationUnit[] {};

    public String[] names;

    private boolean isValidPackageName;

    protected PackageFragment(PackageFragmentRoot root, String[] names) {
        super(root);
        this.names = names;
        this.isValidPackageName = internalIsValidPackageName();
    }

    /**
     * @see Openable
     */
    @Override
    protected boolean buildStructure(OpenableElementInfo info, IProgressMonitor pm, Map newElements,
            IResource underlyingResource) throws JavaModelException {
        // add compilation units/class files from resources
        HashSet vChildren = new HashSet();
        int kind = getKind();
        try {
            PackageFragmentRoot root = getPackageFragmentRoot();
            char[][] inclusionPatterns = root.fullInclusionPatternChars();
            char[][] exclusionPatterns = root.fullExclusionPatternChars();
            IResource[] members = ((IContainer) underlyingResource).members();
            int length = members.length;
            if (length > 0) {
                IJavaProject project = getJavaProject();
                String sourceLevel = project.getOption(JavaCore.COMPILER_SOURCE, true);
                String complianceLevel = project.getOption(JavaCore.COMPILER_COMPLIANCE, true);
                for (int i = 0; i < length; i++) {
                    IResource child = members[i];
                    if (child.getType() != IResource.FOLDER
                            && !Util.isExcluded(child, inclusionPatterns, exclusionPatterns)) {
                        IJavaElement childElement;
                        if (kind == IPackageFragmentRoot.K_SOURCE
                                && Util.isValidCompilationUnitName(child.getName(), sourceLevel, complianceLevel)) {
                            childElement = new CompilationUnit(this, child.getName(),
                                    DefaultWorkingCopyOwner.PRIMARY);
                            vChildren.add(childElement);
                        } else if (kind == IPackageFragmentRoot.K_BINARY
                                && Util.isValidClassFileName(child.getName(), sourceLevel, complianceLevel)) {
                            childElement = getClassFile(child.getName());
                            vChildren.add(childElement);
                        }
                    }
                }
            }
        } catch (CoreException e) {
            throw new JavaModelException(e);
        }

        if (kind == IPackageFragmentRoot.K_SOURCE) {
            // add primary compilation units
            ICompilationUnit[] primaryCompilationUnits = getCompilationUnits(DefaultWorkingCopyOwner.PRIMARY);
            for (int i = 0, length = primaryCompilationUnits.length; i < length; i++) {
                ICompilationUnit primary = primaryCompilationUnits[i];
                vChildren.add(primary);
            }
        }

        if (!vChildren.isEmpty()) {
            IJavaElement[] children = new IJavaElement[vChildren.size()];
            vChildren.toArray(children);
            info.setChildren(children);
        } else {
            info.setChildren(JavaElement.NO_ELEMENTS);
        }
        return true;
    }

    /**
     * Returns true if this fragment contains at least one java resource.
     * Returns false otherwise.
     */
    @Override
    public boolean containsJavaResources() throws JavaModelException {
        return ((PackageFragmentInfo) getElementInfo()).containsJavaResources();
    }

    /**
     * @see ISourceManipulation
     */
    @Override
    public void copy(IJavaElement container, IJavaElement sibling, String rename, boolean force,
            IProgressMonitor monitor) throws JavaModelException {
        if (container == null) {
            throw new IllegalArgumentException(Messages.operation_nullContainer);
        }
        IJavaElement[] elements = new IJavaElement[] { this };
        IJavaElement[] containers = new IJavaElement[] { container };
        IJavaElement[] siblings = null;
        if (sibling != null) {
            siblings = new IJavaElement[] { sibling };
        }
        String[] renamings = null;
        if (rename != null) {
            renamings = new String[] { rename };
        }
        getJavaModel().copy(elements, containers, siblings, renamings, force, monitor);
    }

    /**
     * @see IPackageFragment
     */
    @Override
    public ICompilationUnit createCompilationUnit(String cuName, String contents, boolean force,
            IProgressMonitor monitor) throws JavaModelException {
        CreateCompilationUnitOperation op = new CreateCompilationUnitOperation(this, cuName, contents, force);
        op.runOperation(monitor);
        return new CompilationUnit(this, cuName, DefaultWorkingCopyOwner.PRIMARY);
    }

    /**
     * @see JavaElement
     */
    @Override
    protected Object createElementInfo() {
        return new PackageFragmentInfo();
    }

    /**
     * @see ISourceManipulation
     */
    @Override
    public void delete(boolean force, IProgressMonitor monitor) throws JavaModelException {
        IJavaElement[] elements = new IJavaElement[] { this };
        getJavaModel().delete(elements, force, monitor);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o)
            return true;
        if (!(o instanceof PackageFragment))
            return false;

        PackageFragment other = (PackageFragment) o;
        return Util.equalArraysOrNull(this.names, other.names) && this.parent.equals(other.parent);
    }

    @Override
    public boolean exists() {
        // super.exist() only checks for the parent and the resource existence
        // so also ensure that:
        //  - the package is not excluded (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=138577)
        //  - its name is valide (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=108456)
        return super.exists() && !Util.isExcluded(this) && isValidPackageName();
    }

    /**
     * @see IPackageFragment#getOrdinaryClassFile(String)
     * @exception IllegalArgumentException if the name does not end with ".class" or if the name is "module-info.class".
     */
    @Override
    public IOrdinaryClassFile getOrdinaryClassFile(String classFileName) {
        if (!org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(classFileName)) {
            throw new IllegalArgumentException(Messages.bind(Messages.element_invalidClassFileName, classFileName));
        }
        if (TypeConstants.MODULE_INFO_CLASS_NAME_STRING.equals(classFileName)) {
            throw new IllegalArgumentException(Messages.element_moduleInfoNotSupported);
        }
        // don't hold on the .class file extension to save memory
        // also make sure to not use substring as the resulting String may hold on the underlying char[] which might be much bigger than necessary
        int length = classFileName.length() - 6;
        char[] nameWithoutExtension = new char[length];
        classFileName.getChars(0, length, nameWithoutExtension, 0);
        return new ClassFile(this, new String(nameWithoutExtension));
    }

    /**
     * @see IPackageFragment#getClassFile(String)
     * @exception IllegalArgumentException if the name does not end with ".class".
     */
    @Override
    public IClassFile getClassFile(String classFileName) {
        if (TypeConstants.MODULE_INFO_CLASS_NAME_STRING.equals(classFileName))
            return getModularClassFile();
        return getOrdinaryClassFile(classFileName);
    }

    @Override
    public IModularClassFile getModularClassFile() {
        // don't hold on the .class file extension to save memory
        // also make sure to not use substring as the resulting String may hold on the underlying char[] which might be much bigger than necessary
        return new ModularClassFile(this);
    }

    /**
     * Returns a collection of ordinary class files in this - a folder package fragment which has a root
     * that has its kind set to <code>IPackageFragmentRoot.K_Source</code> does not
     * recognize class files.
     *
     * @see IPackageFragment#getOrdinaryClassFiles()
     */
    @Override
    public IOrdinaryClassFile[] getOrdinaryClassFiles() throws JavaModelException {
        if (getKind() == IPackageFragmentRoot.K_SOURCE) {
            return NO_ORDINARY_CLASSFILES;
        }

        ArrayList list = getChildrenOfType(CLASS_FILE);
        for (Iterator iterator = list.iterator(); iterator.hasNext();) {
            if (iterator.next() instanceof ModularClassFile)
                iterator.remove();
        }
        IOrdinaryClassFile[] array = new IOrdinaryClassFile[list.size()];
        list.toArray(array);
        return array;
    }

    /**
     * Returns a collection of all class files in this - a folder package fragment which has a root
     * that has its kind set to <code>IPackageFragmentRoot.K_Source</code> does not
     * recognize class files.
     *
     * @see IPackageFragment#getAllClassFiles()
     */
    @Override
    public IClassFile[] getAllClassFiles() throws JavaModelException {
        if (getKind() == IPackageFragmentRoot.K_SOURCE) {
            return NO_CLASSFILES;
        }

        ArrayList list = getChildrenOfType(CLASS_FILE);
        IClassFile[] array = new IClassFile[list.size()];
        list.toArray(array);
        return array;
    }

    @Deprecated
    @Override
    public IClassFile[] getClassFiles() throws JavaModelException {
        return getOrdinaryClassFiles();
    }

    /**
     * @see IPackageFragment#getCompilationUnit(String)
     * @exception IllegalArgumentException if the name does not end with ".java"
     */
    @Override
    public ICompilationUnit getCompilationUnit(String cuName) {
        if (!org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(cuName)) {
            throw new IllegalArgumentException(Messages.convention_unit_notJavaName);
        }
        return new CompilationUnit(this, cuName, DefaultWorkingCopyOwner.PRIMARY);
    }

    /**
     * @see IPackageFragment#getCompilationUnits()
     */
    @Override
    public ICompilationUnit[] getCompilationUnits() throws JavaModelException {
        if (getKind() == IPackageFragmentRoot.K_BINARY) {
            return NO_COMPILATION_UNITS;
        }

        ArrayList list = getChildrenOfType(COMPILATION_UNIT);
        ICompilationUnit[] array = new ICompilationUnit[list.size()];
        list.toArray(array);
        return array;
    }

    /**
     * @see IPackageFragment#getCompilationUnits(WorkingCopyOwner)
     */
    @Override
    public ICompilationUnit[] getCompilationUnits(WorkingCopyOwner owner) {
        ICompilationUnit[] workingCopies = JavaModelManager.getJavaModelManager().getWorkingCopies(owner,
                false/*don't add primary*/);
        if (workingCopies == null)
            return JavaModelManager.NO_WORKING_COPY;
        int length = workingCopies.length;
        ICompilationUnit[] result = new ICompilationUnit[length];
        int index = 0;
        for (int i = 0; i < length; i++) {
            ICompilationUnit wc = workingCopies[i];
            if (equals(wc.getParent()) && !Util.isExcluded(wc)) { // 59933 - excluded wc shouldn't be answered back
                result[index++] = wc;
            }
        }
        if (index != length) {
            System.arraycopy(result, 0, result = new ICompilationUnit[index], 0, index);
        }
        return result;
    }

    @Override
    public String getElementName() {
        if (this.names.length == 0)
            return DEFAULT_PACKAGE_NAME;
        return Util.concatWith(this.names, '.');
    }

    /**
     * @see IJavaElement
     */
    @Override
    public int getElementType() {
        return PACKAGE_FRAGMENT;
    }

    /*
     * @see JavaElement
     */
    @Override
    public IJavaElement getHandleFromMemento(String token, MementoTokenizer memento, WorkingCopyOwner owner) {
        switch (token.charAt(0)) {
        case JEM_CLASSFILE:
            if (!memento.hasMoreTokens())
                return this;
            String classFileName = memento.nextToken();
            JavaElement classFile = (JavaElement) getClassFile(classFileName);
            return classFile.getHandleFromMemento(memento, owner);
        case JEM_MODULAR_CLASSFILE:
            classFile = (JavaElement) getModularClassFile();
            return classFile.getHandleFromMemento(memento, owner);
        case JEM_COMPILATIONUNIT:
            if (!memento.hasMoreTokens())
                return this;
            String cuName = memento.nextToken();
            JavaElement cu = new CompilationUnit(this, cuName, owner);
            return cu.getHandleFromMemento(memento, owner);
        }
        return null;
    }

    /**
     * @see JavaElement#getHandleMementoDelimiter()
     */
    @Override
    protected char getHandleMementoDelimiter() {
        return JavaElement.JEM_PACKAGEFRAGMENT;
    }

    /**
     * @see IPackageFragment#getKind()
     */
    @Override
    public int getKind() throws JavaModelException {
        return ((IPackageFragmentRoot) getParent()).getKind();
    }

    /**
     * Returns an array of non-java resources contained in the receiver.
     */
    @Override
    public Object[] getNonJavaResources() throws JavaModelException {
        if (isDefaultPackage()) {
            // We don't want to show non java resources of the default package (see PR #1G58NB8)
            return JavaElementInfo.NO_NON_JAVA_RESOURCES;
        } else {
            return ((PackageFragmentInfo) getElementInfo()).getNonJavaResources(resource(),
                    getPackageFragmentRoot());
        }
    }

    /**
     * @see IJavaElement#getPath()
     */
    @Override
    public IPath getPath() {
        PackageFragmentRoot root = getPackageFragmentRoot();
        if (root.isArchive()) {
            return root.getPath();
        } else {
            IPath path = root.getPath();
            for (int i = 0, length = this.names.length; i < length; i++) {
                String name = this.names[i];
                path = path.append(name);
            }
            return path;
        }
    }

    /**
     * @see JavaElement#resource()
     */
    @Override
    public IResource resource(PackageFragmentRoot root) {
        int length = this.names.length;
        if (length == 0) {
            return root.resource(root);
        } else {
            IPath path = new Path(this.names[0]);
            for (int i = 1; i < length; i++)
                path = path.append(this.names[i]);
            return ((IContainer) root.resource(root)).getFolder(path);
        }
    }

    /**
     * @see IJavaElement#getUnderlyingResource()
     */
    @Override
    public IResource getUnderlyingResource() throws JavaModelException {
        IResource rootResource = this.parent.getUnderlyingResource();
        if (rootResource == null) {
            //jar package fragment root that has no associated resource
            return null;
        }
        // the underlying resource may be a folder or a project (in the case that the project folder
        // is atually the package fragment root)
        if (rootResource.getType() == IResource.FOLDER || rootResource.getType() == IResource.PROJECT) {
            IContainer folder = (IContainer) rootResource;
            String[] segs = this.names;
            for (int i = 0; i < segs.length; ++i) {
                IResource child = folder.findMember(segs[i]);
                if (child == null || child.getType() != IResource.FOLDER) {
                    throw newNotPresentException();
                }
                folder = (IFolder) child;
            }
            return folder;
        } else {
            return rootResource;
        }
    }

    @Override
    public int hashCode() {
        int hash = this.parent.hashCode();
        for (int i = 0, length = this.names.length; i < length; i++)
            hash = Util.combineHashCodes(this.names[i].hashCode(), hash);
        return hash;
    }

    /**
     * @see IParent
     */
    @Override
    public boolean hasChildren() throws JavaModelException {
        return getChildren().length > 0;
    }

    /**
     * @see IPackageFragment#hasSubpackages()
     */
    @Override
    public boolean hasSubpackages() throws JavaModelException {
        IJavaElement[] packages = ((IPackageFragmentRoot) getParent()).getChildren();
        int namesLength = this.names.length;
        nextPackage: for (int i = 0, length = packages.length; i < length; i++) {
            String[] otherNames = ((PackageFragment) packages[i]).names;
            if (otherNames.length <= namesLength)
                continue nextPackage;
            for (int j = 0; j < namesLength; j++)
                if (!this.names[j].equals(otherNames[j]))
                    continue nextPackage;
            return true;
        }
        return false;
    }

    protected boolean internalIsValidPackageName() {
        // if package fragment refers to folder in another IProject, then
        // resource().getProject() is different than getJavaProject().getProject()
        // use the other java project's options to verify the name
        IJavaProject javaProject = JavaCore.create(resource().getProject());
        String sourceLevel = javaProject.getOption(JavaCore.COMPILER_SOURCE, true);
        String complianceLevel = javaProject.getOption(JavaCore.COMPILER_COMPLIANCE, true);
        for (int i = 0, length = this.names.length; i < length; i++) {
            if (!Util.isValidFolderNameForPackage(this.names[i], sourceLevel, complianceLevel))
                return false;
        }
        return true;
    }

    /**
     * @see IPackageFragment#isDefaultPackage()
     */
    @Override
    public boolean isDefaultPackage() {
        return this.names.length == 0;
    }

    protected final boolean isValidPackageName() {
        return this.isValidPackageName;
    }

    /**
     * @see ISourceManipulation#move(IJavaElement, IJavaElement, String, boolean, IProgressMonitor)
     */
    @Override
    public void move(IJavaElement container, IJavaElement sibling, String rename, boolean force,
            IProgressMonitor monitor) throws JavaModelException {
        if (container == null) {
            throw new IllegalArgumentException(Messages.operation_nullContainer);
        }
        IJavaElement[] elements = new IJavaElement[] { this };
        IJavaElement[] containers = new IJavaElement[] { container };
        IJavaElement[] siblings = null;
        if (sibling != null) {
            siblings = new IJavaElement[] { sibling };
        }
        String[] renamings = null;
        if (rename != null) {
            renamings = new String[] { rename };
        }
        getJavaModel().move(elements, containers, siblings, renamings, force, monitor);
    }

    /**
     * @see ISourceManipulation#rename(String, boolean, IProgressMonitor)
     */
    @Override
    public void rename(String newName, boolean force, IProgressMonitor monitor) throws JavaModelException {
        if (newName == null) {
            throw new IllegalArgumentException(Messages.element_nullName);
        }
        IJavaElement[] elements = new IJavaElement[] { this };
        IJavaElement[] dests = new IJavaElement[] { getParent() };
        String[] renamings = new String[] { newName };
        getJavaModel().rename(elements, dests, renamings, force, monitor);
    }

    /**
     * Debugging purposes
     */
    @Override
    protected void toStringChildren(int tab, StringBuffer buffer, Object info) {
        if (tab == 0) {
            super.toStringChildren(tab, buffer, info);
        }
    }

    /**
     * Debugging purposes
     */
    @Override
    protected void toStringInfo(int tab, StringBuffer buffer, Object info, boolean showResolvedInfo) {
        buffer.append(tabString(tab));
        if (this.names.length == 0) {
            buffer.append("<default>"); //$NON-NLS-1$
        } else {
            toStringName(buffer);
        }
        if (info == null) {
            buffer.append(" (not open)"); //$NON-NLS-1$
        } else {
            if (tab > 0) {
                buffer.append(" (...)"); //$NON-NLS-1$
            }
        }
    }

    @Override
    public String getAttachedJavadoc(IProgressMonitor monitor) throws JavaModelException {
        PerProjectInfo projectInfo = JavaModelManager.getJavaModelManager()
                .getPerProjectInfoCheckExistence(getJavaProject().getProject());
        String cachedJavadoc = null;
        synchronized (projectInfo.javadocCache) {
            cachedJavadoc = (String) projectInfo.javadocCache.get(this);
        }
        if (cachedJavadoc != null) {
            return cachedJavadoc;
        }
        URL baseLocation = getJavadocBaseLocation();
        if (baseLocation == null) {
            return null;
        }
        StringBuffer pathBuffer = new StringBuffer(baseLocation.toExternalForm());

        if (!(pathBuffer.charAt(pathBuffer.length() - 1) == '/')) {
            pathBuffer.append('/');
        }
        String packPath = getElementName().replace('.', '/');
        pathBuffer.append(packPath).append('/').append(JavadocConstants.PACKAGE_FILE_NAME);

        if (monitor != null && monitor.isCanceled())
            throw new OperationCanceledException();
        String contents = getURLContents(baseLocation, String.valueOf(pathBuffer));
        if (monitor != null && monitor.isCanceled())
            throw new OperationCanceledException();
        if (contents == null)
            return null;

        contents = (new JavadocContents(contents)).getPackageDoc();
        if (contents == null)
            contents = ""; //$NON-NLS-1$
        synchronized (projectInfo.javadocCache) {
            projectInfo.javadocCache.put(this, contents);
        }
        return contents;
    }

    @Override
    protected IStatus validateExistence(IResource underlyingResource) {
        // check that the name of the package is valid (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=108456)
        if (!isValidPackageName())
            return newDoesNotExistStatus();

        // check whether this pkg can be opened
        if (underlyingResource != null && !resourceExists(underlyingResource))
            return newDoesNotExistStatus();

        // check that it is not excluded (https://bugs.eclipse.org/bugs/show_bug.cgi?id=138577)
        int kind;
        try {
            kind = getKind();
        } catch (JavaModelException e) {
            return e.getStatus();
        }
        if (kind == IPackageFragmentRoot.K_SOURCE && Util.isExcluded(this))
            return newDoesNotExistStatus();

        return JavaModelStatus.VERIFIED_OK;
    }
}