/*****************************************************************************
* Copyright (c) 2006-2013, Cloudsmith Inc.
* The code, documentation and other materials contained herein have been
* licensed under the Eclipse Public License - v 1.0 by the copyright holder
* listed above, as the Initial Contributor under such license. The text of
* such license is available at www.eclipse.org.
*****************************************************************************/
package org.eclipse.buckminster.core.cspec.model;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import org.eclipse.buckminster.core.cspec.IAttributeFilter;
import org.eclipse.buckminster.core.cspec.IGroup;
import org.eclipse.buckminster.core.cspec.PathGroup;
import org.eclipse.buckminster.core.cspec.builder.AttributeBuilder;
import org.eclipse.buckminster.core.cspec.builder.CSpecBuilder;
import org.eclipse.buckminster.core.cspec.builder.GroupBuilder;
import org.eclipse.buckminster.core.internal.actor.PerformManager;
import org.eclipse.buckminster.core.metadata.MissingComponentException;
import org.eclipse.buckminster.core.metadata.WorkspaceInfo;
import org.eclipse.buckminster.core.metadata.model.IModelCache;
import org.eclipse.buckminster.sax.Utils;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
/**
* @author Thomas Hallgren
*/
public class Group extends TopLevelAttribute implements IGroup {
public static final String ATTR_REBASE = "rebase"; //$NON-NLS-1$
/**
* Rebase all paths that, when resolved, are paths prefixed by newBase
*
* @param newBase
* The base to use as replacement
* @param paths
* The path groups to rebase
* @return A new set of path groups
* @throws CoreException
*/
public static PathGroup[] rebase(IPath newBase, PathGroup[] pathGroups) throws CoreException {
if (newBase == null)
return pathGroups;
HashMap<IPath, ArrayList<IPath>> bld = new HashMap<IPath, ArrayList<IPath>>();
for (PathGroup pathGroup : pathGroups) {
IPath currentBase = pathGroup.getBase();
IPath[] paths = pathGroup.getPaths();
if (paths.length == 0)
addPathGroup(bld, newBase, currentBase, null);
else {
for (IPath path : paths)
addPathGroup(bld, newBase, currentBase, path);
}
}
ArrayList<PathGroup> newPathGroups = new ArrayList<PathGroup>();
for (Map.Entry<IPath, ArrayList<IPath>> entry : bld.entrySet()) {
ArrayList<IPath> paths = entry.getValue();
newPathGroups.add(new PathGroup(entry.getKey(), paths.toArray(new IPath[paths.size()])));
}
return newPathGroups.toArray(new PathGroup[newPathGroups.size()]);
}
private static void addPathGroup(HashMap<IPath, ArrayList<IPath>> bld, IPath newBase, IPath currentBase, IPath path) {
IPath base;
IPath absolute = currentBase;
if (path != null)
absolute = absolute.append(path);
if (newBase.isPrefixOf(absolute)) {
base = newBase;
path = absolute.removeFirstSegments(newBase.segmentCount()).setDevice(null);
} else
base = currentBase;
ArrayList<IPath> group = bld.get(base);
if (group == null) {
group = new ArrayList<IPath>();
bld.put(base, group);
}
if (path != null)
group.add(path);
}
private final List<Prerequisite> prerequisites;
private final IPath prerequisiteRebase;
public Group(GroupBuilder builder) {
super(builder);
prerequisiteRebase = builder.getPrerequisiteRebase();
prerequisites = Utils.createUnmodifiableList(builder.getPrerequisiteList());
}
@Override
public IPath getPrerequisiteRebase() {
return prerequisiteRebase;
}
@Override
public List<Prerequisite> getPrerequisites(Stack<IAttributeFilter> filters) {
if (filters == null || filters.size() == 0 || prerequisites.size() == 0)
return prerequisites;
ArrayList<Prerequisite> matched = new ArrayList<Prerequisite>(prerequisites.size());
for (Prerequisite pq : prerequisites) {
String cname = pq.getComponentName();
if (cname == null)
cname = getCSpec().getName();
String attr = pq.getAttribute();
boolean isMatch = false;
for (IAttributeFilter filter : filters) {
if (filter.isMatch(cname, attr)) {
isMatch = true;
break;
}
}
if (isMatch)
matched.add(pq);
}
return matched.size() == prerequisites.size() ? prerequisites : matched;
}
@Override
public boolean isEnabled(IModelCache ctx) throws CoreException {
if (!super.isEnabled(ctx))
return false;
// Return true if at least one of the prerequisites are enabled
//
CSpec cspec = getCSpec();
int idx = prerequisites.size();
if (idx == 0)
return true;
while (--idx >= 0)
if (prerequisites.get(idx).isEnabled(ctx, cspec))
return true;
return false;
}
@Override
public boolean isProducedByActions(IModelCache ctx) throws CoreException {
CSpec cspec = getCSpec();
int idx = prerequisites.size();
while (--idx >= 0) {
Prerequisite pq = prerequisites.get(idx);
try {
Attribute attr = pq.getReferencedAttribute(cspec, ctx);
if (attr != null && attr.isProducedByActions(ctx))
return true;
} catch (MissingComponentException e) {
return !WorkspaceInfo.getGenerators(new ComponentRequest(pq.getComponentName(), pq.getComponentType(), null)).isEmpty();
}
}
return false;
}
@Override
protected void addAttributes(AttributesImpl attrs) {
super.addAttributes(attrs);
IPath prereqsRebase = getPrerequisiteRebase();
if (prereqsRebase != null)
Utils.addAttribute(attrs, ATTR_REBASE, prereqsRebase.toPortableString());
}
@Override
protected AttributeBuilder createAttributeBuilder(CSpecBuilder cspecBuilder) {
return cspecBuilder.createGroupBuilder();
}
@Override
protected void emitElements(ContentHandler handler, String namespace, String prefix) throws SAXException {
super.emitElements(handler, namespace, prefix);
for (Prerequisite pr : getPrerequisites())
pr.toSax(handler, namespace, prefix, pr.getDefaultTag());
}
@Override
protected PathGroup[] internalGetPathGroups(IModelCache ctx, Map<String, ? extends Object> local, Stack<IAttributeFilter> filters)
throws CoreException {
IPath prereqRebase = getPrerequisiteRebase();
if (prereqRebase != null) {
prereqRebase = PerformManager.expandPath(local, prereqRebase);
if (!prereqRebase.isAbsolute())
prereqRebase = getCSpec().getComponentLocation().append(prereqRebase);
}
CSpec cspec = getCSpec();
ArrayList<PathGroup> bld = new ArrayList<PathGroup>();
for (Prerequisite pr : getPrerequisites(filters)) {
if (!pr.isContributor())
continue;
Attribute ag = pr.getReferencedAttribute(cspec, ctx);
if (ag == null)
continue;
PathGroup[] pathGroups;
if (pr.isPatternFilter()) {
if (filters == null)
filters = new Stack<IAttributeFilter>();
filters.push(pr);
pathGroups = ag.getPathGroups(ctx, filters);
filters.pop();
} else
pathGroups = ag.getPathGroups(ctx, filters);
if (!pr.isExternal() && prereqRebase != null)
pathGroups = rebase(prereqRebase, pathGroups);
for (PathGroup path : pathGroups) {
if (!bld.contains(path))
bld.add(path);
}
}
return bld.toArray(new PathGroup[bld.size()]);
}
}