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 }