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  }