package org.bundlemaker.core.spi.analysis; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.bundlemaker.core.analysis.AnalysisModelException; import org.bundlemaker.core.analysis.IArtifactSelector; import org.bundlemaker.core.analysis.IBundleMakerArtifact; import org.bundlemaker.core.analysis.IDependency; import org.bundlemaker.core.analysis.IRootArtifact; import org.bundlemaker.core.analysis.selectors.DefaultArtifactSelector; import org.bundlemaker.core.internal.api.resource.IModifiableModularizedSystem; import org.bundlemaker.core.internal.transformation.AddArtifactsTransformation; import org.bundlemaker.core.internal.transformation.RemoveArtifactsTransformation; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import com.google.gson.JsonElement; /** * <p> * </p> * * @author Gerd Wütherich (gerd@gerd-wuetherich.de) */ public abstract class AbstractArtifactContainer extends AbstractArtifact { /** - */ private Collection<IBundleMakerArtifact> _children; /** - */ private Map<IBundleMakerArtifact, IDependency> _aggregatedDependenciesTo; /** - */ private Map<IBundleMakerArtifact, IDependency> _aggregatedDependenciesFrom; /** - */ private List<IDependency> _allCoreDependenciesTo; /** - */ private List<IDependency> _allCoreDependenciesFrom; /** - */ private List<IReferencedArtifact> _allReferencedArtifacts; /** - */ private List<IReferencingArtifact> _allReferencingArtifacts; /** * <p> * Creates a new instance of type {@link AbstractArtifactContainer}. * </p> * * @param type * @param name */ public AbstractArtifactContainer(String name) { super(name); // initialize children _children = new ArrayList<IBundleMakerArtifact>(); } /** * {@inheritDoc} */ public IBundleMakerArtifact getChild(String path) { // assert not null Assert.isNotNull(path); // String[] splittedString = path.split("\\|"); // return getChild(splittedString); } /** * {@inheritDoc} */ public IBundleMakerArtifact getChild(IPath path) { return getChild(path.segments()); } /** * <p> * </p> * * @param path * @return */ public boolean hasChild(String path) { return getChild(path) != null; } /** * {@inheritDoc} */ @Override public String getUniquePathIdentifier() { return getName(); } /** * {@inheritDoc} */ @Override public IPath getFullPath() { // if (hasParent() && !(getParent() instanceof IRootArtifact)) { // IPath path = getParent().getFullPath(); return path.append(getUniquePathIdentifier()); } else { // return new Path(getUniquePathIdentifier()); } } /** * <p> * </p> * * @param splittedString * @return */ private IBundleMakerArtifact getChild(String[] splittedString) { // assert not null Assert.isNotNull(splittedString); // if segment count == 0 -> return null if (splittedString.length == 0) { return null; } // if segment count = 1 -> return matching direct child else if (splittedString.length == 1) { return getDirectChild(splittedString[0]); } // else call recursive else { // get the direct child IBundleMakerArtifact directChild = getDirectChild(splittedString[0]); // recurse if (directChild != null) { // if (directChild instanceof AbstractArtifactContainer) { String[] newArray = new String[splittedString.length - 1]; System.arraycopy(splittedString, 1, newArray, 0, newArray.length); return ((AbstractArtifactContainer) directChild).getChild(newArray); } // support for "non-AbstractArtifactContainer" IArtifacts else { StringBuilder builder = new StringBuilder(); for (int i = 1; i < splittedString.length; i++) { builder.append(splittedString[i]); if (i + 1 < splittedString.length) { builder.append("|"); } } return directChild.getChild(builder.toString()); } } } // return null return null; } /**************************************************************************************************/ /** * <p> * </p> * * @return */ @Override public List<IReferencingArtifact> getContainedReferencingArtifacts() { // initializeCaches(); // return _allReferencingArtifacts; } /** * <p> * </p> * * @return */ @Override public List<IReferencedArtifact> getContainedReferencedArtifacts() { // initializeCaches(); // return _allReferencedArtifacts; } /** * {@inheritDoc} */ @Override public Collection<IDependency> getDependenciesFrom() { // initializeCaches(); // return the core dependencies return _allCoreDependenciesFrom; } /** * {@inheritDoc} */ @Override public IDependency getDependencyFrom(IBundleMakerArtifact artifact) { // 'aggregated' dependency if (!aggregatedDependenciesFrom().containsKey(artifact)) { // create new dependency Dependency dependency = new Dependency(artifact, this, false); // store dependency aggregatedDependenciesFrom().put(artifact, dependency); } // Dependency dependency = (Dependency) aggregatedDependenciesFrom().get(artifact); // if (!dependency.isInitialized()) { for (IDependency reference : getDependenciesFrom()) { if (artifact.contains(reference.getFrom())) { ((Dependency) dependency).addDependency(reference); } } dependency.setInitialized(); } // if (dependency != null && dependency.getWeight() > 0) { return dependency; } else { return null; } } /** * {@inheritDoc} */ @Override public Collection<IDependency> getDependenciesFrom(Collection<? extends IBundleMakerArtifact> artifacts) { // List<IDependency> result = new LinkedList<IDependency>(); // for (IBundleMakerArtifact artifact : artifacts) { IDependency dependency = getDependencyFrom(artifact); if (dependency != null) { result.add(dependency); } } // return result; } /** * {@inheritDoc} */ @Override public Collection<IDependency> getDependenciesFrom(IBundleMakerArtifact... artifacts) { return getDependenciesFrom(Arrays.asList(artifacts)); } /** * {@inheritDoc} */ @Override public Collection<IDependency> getDependenciesTo() { // initializeCaches(); // return the core dependencies return _allCoreDependenciesTo; } /** * {@inheritDoc} */ @Override public IDependency getDependencyTo(IBundleMakerArtifact artifact) { // 'aggregated' dependency if (!aggregatedDependenciesTo().containsKey(artifact)) { // store dependency aggregatedDependenciesTo().put(artifact, new Dependency(this, artifact, false)); } // Dependency dependency = (Dependency) aggregatedDependenciesTo().get(artifact); // initialize dependency if (!dependency.isInitialized()) { // for (IDependency reference : getDependenciesTo()) { if (artifact.contains(reference.getTo())) { ((Dependency) dependency).addDependency(reference); } } // dependency.setInitialized(); } // if (dependency != null && dependency.getWeight() > 0) { return dependency; } else { return null; } } /** * {@inheritDoc} */ @Override public Collection<IDependency> getDependenciesTo(Collection<? extends IBundleMakerArtifact> artifacts) { // List<IDependency> result = new LinkedList<IDependency>(); // for (IBundleMakerArtifact artifact : artifacts) { IDependency dependency = getDependencyTo(artifact); if (dependency != null) { result.add(dependency); } } // return result; } /** * {@inheritDoc} */ @Override public Collection<IDependency> getDependenciesTo(IBundleMakerArtifact... artifacts) { return getDependenciesTo(Arrays.asList(artifacts)); } /** * {@inheritDoc} */ public void invalidateCaches() { super.invalidateCaches(); // if (_allCoreDependenciesFrom != null) { _allCoreDependenciesFrom.clear(); _allCoreDependenciesFrom = null; } // if (_allCoreDependenciesTo != null) { _allCoreDependenciesTo.clear(); _allCoreDependenciesTo = null; } // if (_aggregatedDependenciesTo != null) { for (IDependency dependency : _aggregatedDependenciesTo.values()) { ((Dependency) dependency).clearDependencies(); } } // if (_aggregatedDependenciesFrom != null) { for (IDependency dependency : _aggregatedDependenciesFrom.values()) { ((Dependency) dependency).clearDependencies(); } } } /********************************************************************************************************/ /** * <p> * </p> * * @param artifact */ protected abstract void onRemoveArtifact(IBundleMakerArtifact artifact); /** * {@inheritDoc} */ public void removeFromParent() { if (this.getParent() != null) { this.getParent().removeArtifact(this); } } /** * {@inheritDoc} */ @Override public boolean hasParent() { return getParent() != null; } @Override public void setParent(IBundleMakerArtifact parent) { super.setParent(parent); getRoot(); } /** * {@inheritDoc} */ @Override public final boolean containsTypesOrResources() { // return result return containsTypes() || containsResources(); } /** * {@inheritDoc} */ @Override public boolean containsTypes() { // return 'true' if any child contains (or is) a type for (IBundleMakerArtifact artifact : getChildren()) { if (((IBundleMakerArtifact) artifact).containsTypes()) { return true; } } // otherwise return false return false; } /** * {@inheritDoc} */ @Override public boolean containsResources() { // return 'true' if any child contains (or is) a resource for (IBundleMakerArtifact artifact : getChildren()) { if (((IBundleMakerArtifact) artifact).containsResources()) { return true; } } // otherwise return false return false; } /** * {@inheritDoc} */ @Override public final boolean canAdd(IBundleMakerArtifact artifact) { if (artifact == null) { return false; } if (this.equals(artifact)) { return false; } if (!((IBundleMakerArtifact) artifact).getRoot().equals(this.getRoot())) { return false; } return handleCanAdd(artifact) == null; } /** * {@inheritDoc} */ @Override public final void addArtifact(IBundleMakerArtifact artifact) { // asserts Assert.isNotNull(artifact); // assertCanAdd(artifact); // addArtifacts(new DefaultArtifactSelector(artifact)); } /** * {@inheritDoc} */ @Override public void addArtifacts(List<? extends IBundleMakerArtifact> artifacts) { // assert not null Assert.isNotNull(artifacts); // for (IBundleMakerArtifact artifact : artifacts) { assertCanAdd(artifact); } // addArtifacts(new DefaultArtifactSelector(artifacts)); } /** * {@inheritDoc} */ @Override public void addArtifacts(IArtifactSelector artifactSelector) { // AddArtifactsTransformation transformation = new AddArtifactsTransformation(this, artifactSelector); // ((IModifiableModularizedSystem) getModularizedSystem()).applyTransformations(null, transformation); } /** * {@inheritDoc} */ @Override public final boolean removeArtifact(IBundleMakerArtifact artifact) { Assert.isNotNull(artifact); // remove artifacts removeArtifacts(new DefaultArtifactSelector(artifact)); // return true; } /** * {@inheritDoc} */ @Override public void removeArtifacts(List<? extends IBundleMakerArtifact> artifacts) { // assert not null Assert.isNotNull(artifacts); // remove artifacts removeArtifacts(new DefaultArtifactSelector(artifacts)); } /** * {@inheritDoc} */ @Override public void removeArtifacts(IArtifactSelector artifactSelector) { // assert not null Assert.isNotNull(artifactSelector); // get the json configuration JsonElement jsonConfiguration = new RemoveArtifactsTransformation.Configuration(this, artifactSelector).toJsonTree(); // get the list of artifacts List<? extends IBundleMakerArtifact> bundleMakerArtifacts = artifactSelector.getBundleMakerArtifacts(); // add the artifacts for (IBundleMakerArtifact artifact : artifactSelector.getBundleMakerArtifacts()) { Assert.isTrue(canRemove(artifact)); } // for (IBundleMakerArtifact artifact : bundleMakerArtifacts) { onRemoveArtifact(artifact); } // add the transformation getModularizedSystem().getTransformations().add( new RemoveArtifactsTransformation(jsonConfiguration)); } /** * <p> * </p> * * @param artifact */ public final void internalAddArtifact(IBundleMakerArtifact artifact) { // assert not null Assert.isNotNull(artifact); Assert.isTrue(!artifact.isAncestorOf(this)); Assert.isTrue(!artifact.equals(this)); // if the artifact has a parent, it has to be removed if (artifact.getParent() != null) { ((AbstractArtifactContainer) artifact.getParent()).internalRemoveArtifact(artifact); } // call super if (!_children.contains(artifact)) { _children.add(artifact); } AbstractArtifact modifiableArtifact = (AbstractArtifact) artifact; modifiableArtifact.setParent(this); } /** * <p> * </p> * * @param artifact */ public final void internalRemoveArtifact(IBundleMakerArtifact artifact) { // assert not null Assert.isNotNull(artifact); // set parent to null if (artifact.getParent() != null) { ((AbstractArtifact) artifact).setParent(null); } // call super _children.remove(artifact); } /** * {@inheritDoc} */ @Override public boolean contains(final IBundleMakerArtifact artifact) { return this.isAncestorOf(artifact); } /** * {@inheritDoc} */ @Override public Collection<IBundleMakerArtifact> getChildren() { return Collections.unmodifiableCollection(new LinkedList<IBundleMakerArtifact>(_children)); } /** * {@inheritDoc} */ @Override @SuppressWarnings("unchecked") public <T extends IBundleMakerArtifact> Collection<T> getChildren(Class<T> clazz) { // Assert.isNotNull(clazz); // List<T> result = new ArrayList<T>(); // for (IBundleMakerArtifact child : _children) { if (clazz.isAssignableFrom(child.getClass())) { result.add((T) child); } } // return Collections.unmodifiableCollection(result); } /** * <p> * </p> * * @param artifact * @return */ protected String handleCanAdd(IBundleMakerArtifact artifact) { return null; } /** * <p> * </p> * * @param artifact * @deprecated use canAdd and Assert.isTrue() instead */ @Deprecated public void assertCanAdd(IBundleMakerArtifact artifact) { // if (artifact == null) { throw new AnalysisModelException("Can not add 'null' to " + this); } if (artifact == this) { throw new AnalysisModelException("Can not artifact to itself. " + this); } // String canAddMessage = handleCanAdd(artifact); // if (canAddMessage != null) { throw new AnalysisModelException("Can not add " + artifact + " to " + this + ":\n" + canAddMessage); } } /** * <p> * </p> * * @param artifact * @return */ protected String handleCanRemove(IBundleMakerArtifact artifact) { return null; } /** * {@inheritDoc} */ @Override public final boolean canRemove(IBundleMakerArtifact artifact) { if (artifact == null) { return false; } if (this.equals(artifact)) { return false; } if (!((IBundleMakerArtifact) artifact).getRoot().equals(this.getRoot())) { return false; } if (!isAncestorOf(artifact)) { return false; } return handleCanRemove(artifact) == null; } /** * <p> * </p> * * @param identifier * @return */ private IBundleMakerArtifact getDirectChild(String identifier) { // assert not null Assert.isNotNull(identifier); // IBundleMakerArtifact result = null; // step 1a: search for the qualified name for (IBundleMakerArtifact artifact : getChildren()) { // check the qualified name if (identifier.equals(artifact.getQualifiedName())) { // check if null... if (result == null) { result = artifact; } // ... else throw exception else { throw new RuntimeException(String.format("Ambigous identifier '%s' [%s, %s]", result, getQualifiedName(), getChildren())); } } } // step 1b: if (result != null) { return result; } // step 2: search for the simple name for (IBundleMakerArtifact artifact : getChildren()) { // check the qualified name if (identifier.equals(artifact.getName())) { // check if null... if (result == null) { result = artifact; } // ... else throw exception else { // TODO throw new RuntimeException(String.format("Ambigous identifier '%s' [%s, %s]", result, result.toString(), artifact.toString())); } } } // return result return result; } /** * <p> * </p> * * @return */ public Collection<IBundleMakerArtifact> getModifiableChildrenCollection() { return _children; } /** * <p> * </p> * */ public void initializeCaches() { // super.initializeCaches(); // if (_allCoreDependenciesTo == null || _allReferencingArtifacts == null || _allCoreDependenciesFrom == null || _allReferencedArtifacts == null) { // _allReferencingArtifacts = new ArrayList<IReferencingArtifact>(); _allReferencedArtifacts = new ArrayList<IReferencedArtifact>(); _allCoreDependenciesTo = new ArrayList<IDependency>(); _allCoreDependenciesFrom = new ArrayList<IDependency>(); // add core dependencies if (this instanceof IReferencingArtifact) { _allReferencingArtifacts.add(((IReferencingArtifact) this)); _allCoreDependenciesTo.addAll(((IReferencingArtifact) this).getDependenciesTo()); } // add core dependencies if (this instanceof IReferencedArtifact) { _allReferencedArtifacts.add((IReferencedArtifact) this); _allCoreDependenciesFrom.addAll(((IReferencedArtifact) this).getDependenciesFrom()); } // for (IBundleMakerArtifact child : _children) { // call recursive... _allCoreDependenciesTo.addAll(child.getDependenciesTo()); _allCoreDependenciesFrom.addAll(child.getDependenciesFrom()); _allReferencingArtifacts.addAll(child.getContainedReferencingArtifacts()); _allReferencedArtifacts.addAll(child.getContainedReferencedArtifacts()); } } } /** * <p> * </p> * * @return */ private Map<IBundleMakerArtifact, IDependency> aggregatedDependenciesTo() { // if (_aggregatedDependenciesTo == null) { _aggregatedDependenciesTo = new HashMap<IBundleMakerArtifact, IDependency>(); } // return _aggregatedDependenciesTo; } /** * <p> * </p> * * @return */ private Map<IBundleMakerArtifact, IDependency> aggregatedDependenciesFrom() { // if (_aggregatedDependenciesFrom == null) { _aggregatedDependenciesFrom = new HashMap<IBundleMakerArtifact, IDependency>(); } // return _aggregatedDependenciesFrom; } }