    001/*
    002 * Copyright (c) 2007-2017 Xplenty, Inc. All Rights Reserved.
    003 *
    004 * Project and contact information: http://www.cascading.org/
    005 *
    006 * This file is part of the Cascading project.
    007 *
    008 * Licensed under the Apache License, Version 2.0 (the "License");
    009 * you may not use this file except in compliance with the License.
    010 * You may obtain a copy of the License at
    011 *
    012 *     http://www.apache.org/licenses/LICENSE-2.0
    013 *
    014 * Unless required by applicable law or agreed to in writing, software
    015 * distributed under the License is distributed on an "AS IS" BASIS,
    016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    017 * See the License for the specific language governing permissions and
    018 * limitations under the License.
    019 */
    020
    021package cascading.flow.planner.rule;
    022
    023import cascading.flow.planner.iso.expression.ExpressionGraph;
    024
    025/**
    026 * A RuleExpression describes where a {@link cascading.flow.planner.rule.Rule} is applied in an element graph. Where
    027 * a Rule can be a {@link cascading.flow.planner.rule.RuleAssert}, {@link cascading.flow.planner.rule.RuleTransformer},
    028 * or {@link cascading.flow.planner.rule.partitioner.ExpressionRulePartitioner}.
    029 * <p/>
    030 * To pin down how a Rule behaves and where, a RuleExpression relies on the
    031 * {@link cascading.flow.planner.iso.expression.ExpressionGraph} class, where an ExpressionGraph is an actual graph
    032 * of {@link cascading.flow.planner.iso.expression.ElementExpression} nodes and
    033 * {@link cascading.flow.planner.iso.expression.ScopeExpression} edges.
    034 * <p/>
    035 * This expression graph is analogous to a text Regular Expression. A regular expression is used to match a sub-set
    036 * of text in a string. This enables efficient string replacement and parsing.
    037 * <p/>
    038 * The expression graph is used to match a smaller graph inside a larger one so that the larger graph can be
    039 * manipulated. As in a regular expression, elements of the captured graph can be addressed and used.
    040 * <p/>
    041 * The simplest application is to use a single ExpressionGraph to match a portion of a larger graph. Once found,
    042 * the calling rule can fire. Most commonly this is useful for the RuleAssert rule that looks for a given structure,
    043 * and if founds throws an error pinpointing the element in the graph that violates the assertion rule.
    044 * <p/>
    045 * The second application is to have one ExpressionGraph identify distinguished elements in a larger graph, and
    046 * remove them. This is called graph contraction. The structure of the original graph is retained where possible.
    047 * Think of this as hiding elements in the larger graph so that a second ExpressionGraph can be applied to look
    048 * for a sub-graph.
    049 * <p/>
    050 * If the second sub-graph is found, the calling Rule can execute. This most commonly used to partition a graph into
    051 * smaller graphs. For example, any sub-graph with source Taps and a single sink Group (Pipe) is a process Node (Mapper).
    052 * <p/>
    053 * The third application is similar to the second. An ExpressionGraph is used to create a contracted graph of only
    054 * distinguished elements. The second ExpressionGraph finds a sub-graph in the contracted graph. This contracted
    055 * sub-graph is then isolated and all hidden elements are restored within the bounds of the sub-graph.
    056 * <p/>
    057 * Finally a third ExpressionGraph is used to identify a location within the new sub-graph so the Rule can execute.
    058 * This is most commonly used to perform transformations within a graph. For example, to insert a temporary Tap into
    059 * the full assembly element graph to force boundaries between MapReduce jobs.
    060 */
    061public class RuleExpression
    062  {
    063  protected final ExpressionGraph contractionExpression;
    064  protected final ExpressionGraph contractedMatchExpression;
    065  protected final ExpressionGraph matchExpression;
    066
    067  public RuleExpression( ExpressionGraph matchExpression )
    068    {
    069    this.contractionExpression = null;
    070    this.contractedMatchExpression = null;
    071    this.matchExpression = matchExpression;
    072
    073    verify();
    074    }
    075
    076  public RuleExpression( ExpressionGraph contractionExpression, ExpressionGraph matchExpression )
    077    {
    078    this.contractionExpression = contractionExpression;
    079    this.contractedMatchExpression = null;
    080    this.matchExpression = matchExpression;
    081
    082    verify();
    083    }
    084
    085  public RuleExpression( ExpressionGraph contractionExpression, ExpressionGraph contractedMatchExpression, ExpressionGraph matchExpression )
    086    {
    087    this.contractionExpression = contractionExpression;
    088    this.contractedMatchExpression = contractedMatchExpression;
    089    this.matchExpression = matchExpression;
    090
    091    verify();
    092    }
    093
    094  private void verify()
    095    {
    096    // test for
    097    // constraction removes
    098    // contractedMatch
    099    // matchExpression inserts
    100    }
    101
    102  public String getExpressionName()
    103    {
    104    return getClass().getSimpleName().replaceAll( "^(.*)[]A-Z][a-z]*Rule$", "$1" );
    105    }
    106
    107  public ExpressionGraph getContractionExpression()
    108    {
    109    return contractionExpression;
    110    }
    111
    112  public ExpressionGraph getContractedMatchExpression()
    113    {
    114    return contractedMatchExpression;
    115    }
    116
    117  public ExpressionGraph getMatchExpression()
    118    {
    119    return matchExpression;
    120    }
    121  }