/*******************************************************************************
* Copyright (c) 2005, 2007 committers of openArchitectureWare and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* committers of openArchitectureWare - initial API and implementation
*******************************************************************************/
package org.eclipse.emf.mwe.core.container;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.emf.mwe.core.ConfigurationException;
import org.eclipse.emf.mwe.core.WorkflowComponent;
import org.eclipse.emf.mwe.core.WorkflowComponentWithID;
import org.eclipse.emf.mwe.core.WorkflowContext;
import org.eclipse.emf.mwe.core.ao.AbstractWorkflowAdvice;
import org.eclipse.emf.mwe.core.config.FeatureComponent;
import org.eclipse.emf.mwe.core.issues.Issues;
import org.eclipse.emf.mwe.core.lib.Mwe2Bridge;
import org.eclipse.emf.mwe.core.monitor.ProgressMonitor;
import org.eclipse.emf.mwe.internal.core.Workflow;
import org.eclipse.emf.mwe.internal.core.ast.parser.Location;
import org.eclipse.emf.mwe.internal.core.util.ComponentPrinter;
import org.eclipse.emf.mwe2.runtime.workflow.IWorkflowComponent;
import org.eclipse.emf.mwe2.runtime.workflow.IWorkflowContext;
/**
* A composite <tt>WorkflowComponent</tt>.
*
*/
public class CompositeComponent implements WorkflowComponentWithID, IWorkflowComponent {
private static final String COMPONENT_NAME = "Composite component";
protected static final Log log = LogFactory.getLog(CompositeComponent.class);
private final String name;
private String resource;
private Location location;
private Location ownLocation;
private CompositeComponent container;
public CompositeComponent(final String name) {
this.name = name;
}
/** All components aggregated by this composite */
protected List<WorkflowComponent> components = new ArrayList<WorkflowComponent>();
private String id;
/**
* Returns a list of aggregated components.
*
* @return list of components
*/
public List<WorkflowComponent> getComponents() {
return components;
}
public String getId() {
return id;
}
public void setId(final String id) {
this.id = id;
}
public String getLogMessage() {
return "CompositeComponent " + (id != null ? id : "");
}
/**
* Dispatches the invocation to all aggregated components.
*/
public void invoke(final WorkflowContext ctx, final ProgressMonitor monitor, final Issues issues) {
internalInvoke(ctx, monitor, issues);
}
private void internalInvoke(final WorkflowContext model, final ProgressMonitor monitor, final Issues issues) {
for (final WorkflowComponent comp : components) {
if ((monitor != null) && monitor.isCanceled()) {
return;
}
if ((!(comp instanceof AbstractWorkflowAdvice))) {
comp.setContainer(this);
if (monitor != null) {
monitor.preTask(comp, model);
}
log.info(ComponentPrinter.getString(comp));
comp.invoke(model, monitor, issues);
if (monitor != null) {
monitor.postTask(comp, model);
}
}
}
}
public void checkConfiguration(final Issues issues) throws ConfigurationException {
for (final WorkflowComponent comp : components) {
if (comp instanceof AbstractWorkflowAdvice) {
final AbstractWorkflowAdvice advice = (AbstractWorkflowAdvice) comp;
final String adviceTargetID = advice.getAdviceTarget();
if (adviceTargetID == null) {
issues.addError(advice, "No 'adviceTarget' given.");
continue;
}
// log.info("Weaving Advice: " +
// ComponentPrinter.getString(comp));
final Collection<WorkflowComponent> targetComponents = findComponentByID(adviceTargetID);
if (targetComponents.size() == 0) {
issues.addWarning(advice, "No component with ID '" + adviceTargetID + "' found.");
}
if (targetComponents.size() > 1) {
issues.addWarning(advice, "More than on component with ID '" + adviceTargetID + "' found.");
}
if (needsToWeave(comp, issues)) {
for (final WorkflowComponent c : targetComponents) {
((AbstractWorkflowAdvice) comp).weave(c, issues);
}
}
}
}
for (final WorkflowComponent comp : components) {
if ((!(comp instanceof AbstractWorkflowAdvice))) {
if (log.isDebugEnabled()) {
log.debug("Checking configuration of: " + ComponentPrinter.getString(comp));
}
comp.checkConfiguration(issues);
}
}
}
private boolean needsToWeave(final WorkflowComponent comp, final Issues issues) {
try {
WorkflowComponent current = comp;
while (current != null) {
if (current instanceof WorkflowConditional) {
final WorkflowConditional cond = (WorkflowConditional) current;
if (!cond.evaluate()) {
return false;
}
}
current = current.getContainer();
}
return true;
}
catch (final ConditionEvaluationException ex) {
issues.addError(this, ex.getMessage());
return false;
}
}
private Collection<WorkflowComponent> findComponentByID(final String adviceTargetID) {
final List<WorkflowComponent> hits = new ArrayList<WorkflowComponent>();
WorkflowComponent c = this;
while (c.getContainer() != null) {
c = c.getContainer();
}
((CompositeComponent) c).resolveComponentByID(adviceTargetID, hits);
return hits;
}
private void resolveComponentByID(final String adviceTargetID, final List<WorkflowComponent> hits) {
for (final WorkflowComponent component : components) {
if (component instanceof WorkflowComponentWithID) {
if (adviceTargetID.equals(((WorkflowComponentWithID) component).getId())) {
hits.add(component);
}
}
}
for (final WorkflowComponent component : components) {
if (component instanceof CompositeComponent) {
((CompositeComponent) component).resolveComponentByID(adviceTargetID, hits);
}
}
}
/**
* Returns the name of the component.
*
* @return name of component
*/
public String getName() {
return name;
}
/**
* Returns the filename of the workflow.
*
* @return the filename
*/
public String getResource() {
return resource;
}
/**
* Sets the filename of the workflow.
*
* @param resource
* the filename
*/
public void setResource(final String resource) {
this.resource = resource;
}
/**
* Returns the location of the entry in the parent workflow file.
*
* @see org.eclipse.emf.mwe.core.WorkflowComponent#getLocation()
*/
public Location getLocation() {
return location;
}
public void setLocation(final Location location) {
this.location = location;
}
/**
* Returns the location of the start and closing tags in the actual workflow
* file.
*
* @return the location
*/
public Location getOwnLocation() {
return ownLocation;
}
/**
* Sets the location of the start and closing tags in the actual workflow
* file.
*
* @param endLocation
* the location
*/
// locations are set from VisitorCreator by reflection
public void setOwnLocation(final Location endLocation) {
this.ownLocation = endLocation;
}
/**
* Adds a bean.
*
* @param obj
* the bean
*/
public void addBean(final Object obj) {
// noop
}
/**
* Sets the aggregated components of this composite.
*
* @param components
* Components to aggregate.
*/
public void addComponent(final WorkflowComponent component) {
components.add(component);
component.setContainer(this);
}
/**
* Sets the aggregated components of this composite.
*
* @param components
* Components to aggregate.
*/
public void addCartridge(final Workflow cartridge) {
components.add(cartridge);
cartridge.setContainer(this);
}
/**
* adds a conditionalcompositecomponent to the list of components
*
* @param comp
* the conditional component
*/
public void addIf(final IfComponent comp) {
addComponent(comp);
}
/**
* adds a feature components to the list of components
*
* @param comp
* the feature component
*/
public void addFeature(final FeatureComponent comp) {
addComponent(comp);
}
/**
* @see org.eclipse.emf.mwe.core.WorkflowComponent#getContainer()
*/
public CompositeComponent getContainer() {
return container;
}
/**
* @see org.eclipse.emf.mwe.core.WorkflowComponent#setContainer(org.eclipse.emf.mwe.core.container.CompositeComponent)
*/
public void setContainer(final CompositeComponent container) {
this.container = container;
}
/**
* Adds a workflow component.
*
* @param comp
* the component
*/
public void put(final String name, final WorkflowComponent comp) {
addComponent(comp);
}
/**
* @see org.eclipse.emf.mwe.core.WorkflowComponent#getComponentName()
*/
public String getComponentName() {
return COMPONENT_NAME;
}
private Mwe2Bridge bridge;
protected Mwe2Bridge getBridge() {
if (bridge == null)
bridge = new Mwe2Bridge(this);
return bridge;
}
public void preInvoke() {
getBridge().preInvoke();
}
public void invoke(final IWorkflowContext ctx) {
getBridge().invoke(ctx);
}
public void postInvoke() {
getBridge().postInvoke();
}
}