blob: 790d5fa65a0c0791e108400e174c75973b84eff6 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2000, 2020 IBM Corporation and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0.
#
# SPDX-License-Identifier: EPL-2.0
#
# Contributors:
# IBM Corporation - org.eclipse.jdt: initial API and implementation
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.ltk.buildpaths.core;
import java.util.Objects;
import org.eclipse.core.runtime.IPath;
import org.eclipse.statet.jcommons.collections.ImCollections;
import org.eclipse.statet.jcommons.collections.ImList;
import org.eclipse.statet.jcommons.lang.ObjectUtils;
public class BuildpathElement implements IBuildpathElement {
private static final ImList<String> UNINITIALIZED_PATTERNS= ImCollections.newList("UNINITIALIZED_PATTERNS"); //$NON-NLS-1$
private final BuildpathElementType type;
/**
* The meaning of the path of a classpath entry depends on its entry kind:<ul>
* <li>Source code in the current project (<code>SOURCE</code>) -
* The path associated with this entry is the absolute path to the root folder. </li>
* <li>A binary library in the current project (<code>LIBRARY</code>) - the path
* associated with this entry is the absolute path to the JAR (or root folder), and
* in case it refers to an external JAR, then there is no associated resource in
* the workbench.
* <li>A required project (<code>PROJECT</code>) - the path of the entry denotes the
* path to the corresponding project resource.</li>
* <li>A variable entry (<code>VARIABLE</code>) - the first segment of the path
* is the name of a classpath variable. If this classpath variable
* is bound to the path <it>P</it>, the path of the corresponding classpath entry
* is computed by appending to <it>P</it> the segments of the returned
* path without the variable.</li>
* <li> A container entry (<code>CONTAINER</code>) - the first segment of the path is denoting
* the unique container identifier (for which a <code>ClasspathContainerInitializer</code> could be
* registered), and the remaining segments are used as additional hints for resolving the container entry to
* an actual <code>IClasspathContainer</code>.</li>
*/
private final IPath path;
/**
* Patterns allowing to include/exclude portions of the resource tree denoted by this entry path.
*/
private final ImList<IPath> inclusionPatterns;
private volatile ImList<String> fullInclusionPatterns;
private final ImList<IPath> exclusionPatterns;
private volatile ImList<String> fullExclusionPatterns;
/**
* Describes the path to the source archive associated with this
* classpath entry, or <code>null</code> if this classpath entry has no
* source attachment.
* <p>
* Only library and variable classpath entries may have source attachments.
* For library classpath entries, the result path (if present) locates a source
* archive. For variable classpath entries, the result path (if present) has
* an analogous form and meaning as the variable path, namely the first segment
* is the name of a classpath variable.
*/
private final IPath sourceAttachmentPath;
/**
* Describes the path within the source archive where package fragments
* are located. An empty path indicates that packages are located at
* the root of the source archive. Returns a non-<code>null</code> value
* if and only if <code>getSourceAttachmentPath</code> returns
* a non-<code>null</code> value.
*/
private final IPath sourceAttachmentRootPath;
/**
* See {@link IBuildpathElement#getReferencingEntry()}
*/
private final IBuildpathElement referencingElement;
/**
* Specific output location (for this source entry)
*/
private final IPath specificOutputPath;
/**
* The export flag
*/
private final boolean isExported;
/**
* The extra attributes
*/
private final ImList<IBuildpathAttribute> extraAttributes;
/**
* Creates a class path entry of the specified kind with the given path.
*/
public BuildpathElement(final BuildpathElementType type,
final IPath path, final ImList<IPath> inclusionPatterns, final ImList<IPath> exclusionPatterns,
final IPath sourceAttachmentPath, final IPath sourceAttachmentRootPath,
final IPath specificOutputLocation,
final IBuildpathElement referencingEntry,
final boolean isExported,
final ImList<IBuildpathAttribute> extraAttributes) {
if (type == null) {
throw new NullPointerException("type"); //$NON-NLS-1$
}
if (path == null) {
throw new NullPointerException("path"); //$NON-NLS-1$
}
this.type= type;
this.path= path;
this.inclusionPatterns= inclusionPatterns;
this.exclusionPatterns= exclusionPatterns;
this.referencingElement= referencingEntry;
if (this.inclusionPatterns != null && !this.inclusionPatterns.isEmpty()) {
this.fullInclusionPatterns= UNINITIALIZED_PATTERNS;
}
if (this.exclusionPatterns != null && !this.exclusionPatterns.isEmpty()) {
this.fullExclusionPatterns= UNINITIALIZED_PATTERNS;
}
this.sourceAttachmentPath= sourceAttachmentPath;
this.sourceAttachmentRootPath= sourceAttachmentRootPath;
this.specificOutputPath= specificOutputLocation;
this.isExported= isExported;
this.extraAttributes= (extraAttributes != null) ? extraAttributes : ImCollections.<IBuildpathAttribute>emptyList();
}
@Override
public final BuildpathElementType getType() {
return this.type;
}
@Override
public final String getTypeName() {
return this.type.getName();
}
@Override
public final IPath getPath() {
return this.path;
}
@Override
public final ImList<IPath> getInclusionPatterns() {
return this.inclusionPatterns;
}
@Override
public final ImList<IPath> getExclusionPatterns() {
return this.exclusionPatterns;
}
private ImList<String> createFullPatterns(final ImList<IPath> patterns) {
final int length= patterns.size();
final String[] fullPatterns= new String[length];
final IPath prefixPath= this.path.removeTrailingSeparator();
for (int i= 0; i < length; i++) {
fullPatterns[i]= prefixPath.append(patterns.get(i)).toString();
}
return ImCollections.newList(fullPatterns);
}
public ImList<String> getFullInclusionPatterns() {
ImList<String> patterns= this.fullInclusionPatterns;
if (patterns == UNINITIALIZED_PATTERNS) {
patterns= this.fullInclusionPatterns= createFullPatterns(this.inclusionPatterns);
}
return patterns;
}
public ImList<String> getFullExclusionPatterns() {
ImList<String> patterns= this.fullExclusionPatterns;
if (patterns == UNINITIALIZED_PATTERNS) {
patterns= this.fullExclusionPatterns= createFullPatterns(this.exclusionPatterns);
}
return patterns;
}
@Override
public IPath getOutputPath() {
return this.specificOutputPath;
}
@Override
public ImList<IBuildpathAttribute> getExtraAttributes() {
return this.extraAttributes;
}
public IBuildpathAttribute getAttribute(final String name) {
for (final IBuildpathAttribute attribute : this.extraAttributes) {
if (attribute.getName().equals(name)) {
return attribute;
}
}
return null;
}
@Override
public IPath getSourceAttachmentPath() {
return this.sourceAttachmentPath;
}
public IPath getSourceAttachmentRootPath() {
return this.sourceAttachmentRootPath;
}
public IBuildpathElement getReferencingEntry() {
return this.referencingElement;
}
@Override
public boolean isExported() {
return this.isExported;
}
@Override
public int hashCode() {
return this.type.hashCode() ^ this.path.hashCode();
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof BuildpathElement) {
final BuildpathElement other= (BuildpathElement) obj;
return (this.type == other.type
&& this.isExported == other.isExported()
&& this.path.equals(other.getPath())
&& Objects.equals(this.sourceAttachmentPath, other.sourceAttachmentPath)
&& Objects.equals(getSourceAttachmentRootPath(), other.sourceAttachmentRootPath)
&& BuildpathsUtils.equalPatterns(this.inclusionPatterns, other.getInclusionPatterns())
&& BuildpathsUtils.equalPatterns(this.exclusionPatterns, other.getExclusionPatterns())
&& Objects.equals(this.specificOutputPath, other.specificOutputPath)
&& this.extraAttributes.equals(other.extraAttributes) );
}
return false;
}
@Override
public String toString() {
final ObjectUtils.ToStringBuilder sb= new ObjectUtils.ToStringBuilder("BuildpathElement"); //$NON-NLS-1$
sb.append(" ["); //$NON-NLS-1$
sb.append(this.type.getName());
sb.append("]:"); //$NON-NLS-1$
sb.append(getPath().toString());
sb.addProp("including", getInclusionPatterns()); //$NON-NLS-1$
sb.addProp("excluding", getExclusionPatterns()); //$NON-NLS-1$
if (getSourceAttachmentPath() != null) {
sb.addProp("sourcePath", getSourceAttachmentPath().toString()); //$NON-NLS-1$
if (getSourceAttachmentRootPath() != null) {
sb.append(':');
sb.append(getSourceAttachmentRootPath().toString());
}
}
if (getOutputPath() != null) {
sb.addProp("outputPath", getOutputPath()); //$NON-NLS-1$
}
sb.addProp("isExported", this.isExported);
final ImList<IBuildpathAttribute> attributes= getExtraAttributes();
if (!attributes.isEmpty()) {
sb.addProp("extraAttributes", attributes); //$NON-NLS-1$
}
return sb.toString();
}
}