blob: 4d4c29d4d57160a9e361dfdb7a18b00a752ff62e [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.buildpath.core;
import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullAssert;
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.NonNull;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
import org.eclipse.statet.jcommons.lang.ObjectUtils;
@NonNullByDefault
public class BasicBuildpathElement implements BuildpathElement {
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 @Nullable ImList<IPath> inclusionPatterns;
private volatile @Nullable ImList<String> fullInclusionPatterns;
private final @Nullable ImList<IPath> exclusionPatterns;
private volatile @Nullable 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 @Nullable 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 @Nullable IPath sourceAttachmentRootPath;
/**
* See {@link BuildpathElement#getReferencingEntry()}
*/
private final @Nullable BuildpathElement referencingElement;
/**
* Specific output location (for this source entry)
*/
private final @Nullable IPath specificOutputPath;
/**
* The export flag
*/
private final boolean isExported;
/**
* The extra attributes
*/
private final ImList<BuildpathAttribute> extraAttributes;
/**
* Creates a class path entry of the specified kind with the given path.
*/
public BasicBuildpathElement(final BuildpathElementType type,
final IPath path, final @Nullable ImList<IPath> inclusionPatterns, final @Nullable ImList<IPath> exclusionPatterns,
final @Nullable IPath sourceAttachmentPath, final @Nullable IPath sourceAttachmentRootPath,
final @Nullable IPath specificOutputLocation,
final @Nullable BuildpathElement referencingEntry,
final boolean isExported,
final @Nullable ImList<BuildpathAttribute> extraAttributes) {
this.type= nonNullAssert(type);
this.path= nonNullAssert(path);
this.inclusionPatterns= inclusionPatterns;
this.fullInclusionPatterns= UNINITIALIZED_PATTERNS;
this.exclusionPatterns= exclusionPatterns;
this.fullExclusionPatterns= UNINITIALIZED_PATTERNS;
this.referencingElement= referencingEntry;
this.sourceAttachmentPath= sourceAttachmentPath;
this.sourceAttachmentRootPath= sourceAttachmentRootPath;
this.specificOutputPath= specificOutputLocation;
this.isExported= isExported;
this.extraAttributes= (extraAttributes != null) ? extraAttributes : ImCollections.<BuildpathAttribute>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 @Nullable ImList<IPath> getInclusionPatterns() {
return this.inclusionPatterns;
}
@Override
public final @Nullable ImList<IPath> getExclusionPatterns() {
return this.exclusionPatterns;
}
private @Nullable ImList<String> createFullPatterns(final @Nullable ImList<IPath> patterns) {
if (patterns == null || patterns.isEmpty()) {
return null;
}
final int length= patterns.size();
final String[] fullPatterns= new @NonNull 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 @Nullable ImList<String> getFullInclusionPatterns() {
ImList<String> patterns= this.fullInclusionPatterns;
if (patterns == UNINITIALIZED_PATTERNS) {
patterns= this.fullInclusionPatterns= createFullPatterns(this.inclusionPatterns);
}
return patterns;
}
public @Nullable ImList<String> getFullExclusionPatterns() {
ImList<String> patterns= this.fullExclusionPatterns;
if (patterns == UNINITIALIZED_PATTERNS) {
patterns= this.fullExclusionPatterns= createFullPatterns(this.exclusionPatterns);
}
return patterns;
}
@Override
public @Nullable IPath getOutputPath() {
return this.specificOutputPath;
}
@Override
public ImList<BuildpathAttribute> getExtraAttributes() {
return this.extraAttributes;
}
public @Nullable BuildpathAttribute getAttribute(final String name) {
for (final BuildpathAttribute attribute : this.extraAttributes) {
if (attribute.getName().equals(name)) {
return attribute;
}
}
return null;
}
@Override
public @Nullable IPath getSourceAttachmentPath() {
return this.sourceAttachmentPath;
}
public @Nullable IPath getSourceAttachmentRootPath() {
return this.sourceAttachmentRootPath;
}
public @Nullable BuildpathElement 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 @Nullable Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof BasicBuildpathElement) {
final BasicBuildpathElement other= (BasicBuildpathElement)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)
&& BuildpathUtils.equalPatterns(this.inclusionPatterns, other.getInclusionPatterns())
&& BuildpathUtils.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("BasicBuildpathElement"); //$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$
sb.addProp("sourcePath", getSourceAttachmentPath()); //$NON-NLS-1$
{ final IPath rootPath= getSourceAttachmentRootPath();
if (rootPath != null) {
sb.append(':');
sb.append(rootPath.toString());
}
}
sb.addProp("outputPath", getOutputPath()); //$NON-NLS-1$
sb.addProp("isExported", this.isExported);
final ImList<BuildpathAttribute> attributes= getExtraAttributes();
if (!attributes.isEmpty()) {
sb.addProp("extraAttributes", attributes); //$NON-NLS-1$
}
return sb.toString();
}
}