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 }