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