package eu.stratosphere.sopremo.operator; import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import eu.stratosphere.api.common.Plan; import eu.stratosphere.api.common.operators.GenericDataSink; import eu.stratosphere.sopremo.AbstractSopremoType; import eu.stratosphere.sopremo.EvaluationContext; import eu.stratosphere.sopremo.SopremoEnvironment; import eu.stratosphere.sopremo.io.Sink; import eu.stratosphere.sopremo.packages.DefaultTypeRegistry; import eu.stratosphere.sopremo.packages.ITypeRegistry; import eu.stratosphere.sopremo.serialization.SopremoRecordLayout; /** * Encapsulate a complete query in Sopremo and translates it to a Pact {@link Plan}. */ public class SopremoPlan extends AbstractSopremoType implements Serializable { private static final long serialVersionUID = 5702832506916907827L; private final SopremoModule module; private EvaluationContext context = new EvaluationContext(); private List<String> requiredPackages = new ArrayList<String>(); private SopremoRecordLayout layout; private ITypeRegistry typeRegistry = new DefaultTypeRegistry(); public SopremoPlan() { this.module = new SopremoModule(0, 0); } public SopremoPlan(Sink... sinks) { this(); for (final Sink sink : sinks) this.module.addInternalOutput(sink); } public void addRequiredPackage(final String packageName) { this.requiredPackages.add(packageName); } /* * (non-Javadoc) * @see eu.stratosphere.sopremo.ISopremoType#appendAsString(java.lang.Appendable) */ @Override public void appendAsString(final Appendable appendable) throws IOException { this.module.appendAsString(appendable); } /** * Converts the Sopremo module to a Pact {@link Plan}. * * @return the converted Pact plan */ public Plan asPactPlan() { final Collection<GenericDataSink> sinks = this.checkForSinks(this.assemblePact()); return new PlanWithSopremoPostPass(this.layout, this.typeRegistry, sinks); } /** * Assembles the Pacts of the contained Sopremo operators and returns a list * of all Pact sinks. These sinks may either be directly a {@link GenericDataSink} or an unconnected * {@link eu.stratosphere.api.common.operators.Operator}. * * @return a list of Pact sinks */ public Collection<eu.stratosphere.api.common.operators.Operator> assemblePact() { final ElementarySopremoModule elementaryModule = this.module.asElementary(); this.layout = SopremoRecordLayout.create(elementaryModule.getSchema().getKeyExpressions()); SopremoEnvironment.getInstance().setLayout(this.layout); return elementaryModule.assemblePact(); } @Override public boolean equals(final Object obj) { if (this == obj) return true; if (obj == null) return false; if (this.getClass() != obj.getClass()) return false; final SopremoPlan other = (SopremoPlan) obj; return this.module.equals(other.module); } /** * Returns the evaluation context of this plan. * * @return the evaluation context */ public EvaluationContext getCompilationContext() { return this.context; } /** * Returns all operators that are either (internal) {@link Sink}s or * included in the reference graph. * * @return all operators in this module */ public Iterable<? extends Operator<?>> getContainedOperators() { return this.module.getReachableNodes(); } public SopremoRecordLayout getLayout() { return this.layout; } /** * Returns the requiredPackages. * * @return the requiredPackages */ public List<String> getRequiredPackages() { return this.requiredPackages; } public List<Sink> getSinks() { return this.module.getInternalOutputNodes(); } /** * Returns the typeRegistry. * * @return the typeRegistry */ public ITypeRegistry getTypeRegistry() { return this.typeRegistry; } public List<Operator<?>> getUnmatchingOperators(final SopremoPlan other) { return this.module.getUnmatchingNodes(other.module); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + this.module.hashCode(); return result; } /** * Sets the evaluation context of this plan. * * @param context * the evaluation context */ public void setContext(final EvaluationContext context) { if (context == null) throw new NullPointerException("context must not be null"); this.context = context; } /** * Sets the requiredPackages to the specified value. * * @param packageNames * the packageNames to set */ public void setRequiredPackages(final List<String> packageNames) { if (packageNames == null) throw new NullPointerException("requiredPackages must not be null"); this.requiredPackages = packageNames; } public void setSinks(final List<Sink> sinks) { for (final Sink sink : sinks) this.module.addInternalOutput(sink); } public void setSinks(final Sink... sinks) { this.setSinks(Arrays.asList(sinks)); } /** * Sets the typeRegistry to the specified value. * * @param typeRegistry * the typeRegistry to set */ public void setTypeRegistry(ITypeRegistry typeRegistry) { if (typeRegistry == null) throw new NullPointerException("typeRegistry must not be null"); this.typeRegistry = typeRegistry; } /** * Checks if all contracts are {@link GenericDataSink}s. */ @SuppressWarnings({ "unchecked", "rawtypes" }) private Collection<GenericDataSink> checkForSinks( final Collection<eu.stratosphere.api.common.operators.Operator> contracts) { for (final eu.stratosphere.api.common.operators.Operator contract : contracts) if (!GenericDataSink.class.isInstance(contract)) throw new IllegalStateException("Operator without connected sink detected " + contract); return (Collection) contracts; } }