/* * Copyright (c) 2007-2010 Concurrent, Inc. All Rights Reserved. * * Project and contact information: http://www.cascading.org/ * * This file is part of the Cascading project. * * Cascading is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Cascading is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Cascading. If not, see <http://www.gnu.org/licenses/>. */ package cascading.flow; import java.io.Serializable; import java.util.HashSet; import java.util.Map; import java.util.Set; import cascading.tuple.Fields; import cascading.tuple.TupleEntry; /** Class Scope is an internal representation of the linkages between operations. */ public class Scope implements Serializable { /** Enum Kind */ static public enum Kind { TAP, EACH, EVERY, GROUP; } /** Field name */ private String name; /** Field kind */ private Kind kind; /** Field remainderFields */ private Fields remainderFields; /** Field argumentSelector */ private Fields argumentFields; /** Field declaredFields */ private Fields declaredFields; // fields declared by the operation /** Field isGroupBy */ private boolean isGroupBy; /** Field groupingSelectors */ private Map<String, Fields> groupingSelectors; /** Field sortingSelectors */ private Map<String, Fields> sortingSelectors; /** Field outGroupingSelector */ private Fields outGroupingSelector; /** Field outGroupingFields */ private Fields outGroupingFields; // all key fields /** Field outValuesSelector */ private Fields outValuesSelector; /** Field outValuesFields */ private Fields outValuesFields; // all value fields, includes keys /** Field argumentsEntry */ private transient TupleEntry argumentsEntry; // caches entry /** Field declaredEntry */ private transient TupleEntry declaredEntry; // caches entry /** Default constructor. */ public Scope() { } /** * Copy constructor * * @param scope of type Scope */ public Scope( Scope scope ) { this.name = scope.getName(); copyFields( scope ); } /** * Tap constructor * * @param outFields of type Fields */ public Scope( Fields outFields ) { this.kind = Kind.TAP; if( outFields == null ) throw new IllegalArgumentException( "fields may not be null" ); this.outGroupingFields = outFields; this.outValuesFields = outFields; } /** * Constructor Scope creates a new Scope instance. Used by classes Each and Every. * * @param name of type String * @param kind of type Kind * @param remainderFields of type Fields * @param argumentFields of type Fields * @param declaredFields of type Fields * @param outGroupingFields of type Fields * @param outValuesFields of type Fields */ public Scope( String name, Kind kind, Fields remainderFields, Fields argumentFields, Fields declaredFields, Fields outGroupingFields, Fields outValuesFields ) { this.name = name; this.kind = kind; this.remainderFields = remainderFields; this.argumentFields = argumentFields; this.declaredFields = declaredFields; if( outGroupingFields == null ) throw new IllegalArgumentException( "grouping may not be null" ); if( outValuesFields == null ) throw new IllegalArgumentException( "values may not be null" ); if( kind == Kind.EACH ) { this.outGroupingFields = Fields.asDeclaration( outGroupingFields ); this.outValuesSelector = outValuesFields; this.outValuesFields = Fields.asDeclaration( outValuesFields ); } else if( kind == Kind.EVERY ) { this.outGroupingSelector = outGroupingFields; this.outGroupingFields = Fields.asDeclaration( outGroupingFields ); this.outValuesFields = outValuesFields; } else { throw new IllegalArgumentException( "may not use the constructor for kind: " + kind ); } } /** * Constructor Scope creates a new Scope instance. Used by the Group class. * * @param name of type String * @param declaredFields of type Fields * @param outGroupingFields of type Fields * @param groupingSelectors of type Map<String, Fields> * @param sortingSelectors of type Fields * @param outValuesFields of type Fields * @param isGroupBy of type boolean */ public Scope( String name, Fields declaredFields, Fields outGroupingFields, Map<String, Fields> groupingSelectors, Map<String, Fields> sortingSelectors, Fields outValuesFields, boolean isGroupBy ) { this.name = name; this.kind = Kind.GROUP; this.isGroupBy = isGroupBy; if( groupingSelectors == null ) throw new IllegalArgumentException( "grouping may not be null" ); if( outValuesFields == null ) throw new IllegalArgumentException( "values may not be null" ); this.declaredFields = declaredFields; this.outGroupingFields = outGroupingFields; this.groupingSelectors = groupingSelectors; this.sortingSelectors = sortingSelectors; // null ok this.outValuesFields = outValuesFields; } /** * Constructor Scope creates a new Scope instance. * * @param name of type String */ public Scope( String name ) { this.name = name; } /** * Method isGroup returns true if this Scope object represents a Group. * * @return the group (type boolean) of this Scope object. */ public boolean isGroup() { return kind == Kind.GROUP; } /** * Method isEach returns true if this Scope object represents an Each. * * @return the each (type boolean) of this Scope object. */ public boolean isEach() { return kind == Kind.EACH; } /** * Method isEvery returns true if this Scope object represents an Every. * * @return the every (type boolean) of this Scope object. */ public boolean isEvery() { return kind == Kind.EVERY; } /** * Method isTap returns true if this Scope object represents a Tap. * * @return the tap (type boolean) of this Scope object. */ public boolean isTap() { return kind == Kind.TAP; } /** * Method getName returns the name of this Scope object. * * @return the name (type String) of this Scope object. */ public String getName() { return name; } /** * Method setName sets the name of this Scope object. * * @param name the name of this Scope object. */ public void setName( String name ) { this.name = name; } /** * Method getRemainderFields returns the remainderFields of this Scope object. * * @return the remainderFields (type Fields) of this Scope object. */ public Fields getRemainderFields() { return remainderFields; } /** * Method getArgumentSelector returns the argumentSelector of this Scope object. * * @return the argumentSelector (type Fields) of this Scope object. */ public Fields getArgumentFields() { return argumentFields; } /** * Method getArguments returns the arguments of this Scope object. * * @return the arguments (type Fields) of this Scope object. */ public Fields getArguments() { return Fields.asDeclaration( argumentFields ); } /** * Method getArgumentsEntry returns the argumentsEntry of this Scope object. * * @return the argumentsEntry (type TupleEntry) of this Scope object. */ public TupleEntry getArgumentsEntry() { if( argumentsEntry != null ) return argumentsEntry; argumentsEntry = new TupleEntry( getArguments(), true ); return argumentsEntry; } /** * Method getArgumentsEntry returns a cached {@link TupleEntry} for the declared arguments of this scope. * * @param input of type TupleEntry * @return TupleEntry */ public TupleEntry getArgumentsEntry( TupleEntry input ) { TupleEntry entry = getArgumentsEntry(); entry.setTuple( input.selectTuple( getArgumentFields() ) ); return entry; } /** * Method getDeclaredFields returns the declaredFields of this Scope object. * * @return the declaredFields (type Fields) of this Scope object. */ public Fields getDeclaredFields() { return declaredFields; } /** * Method getDeclaredEntry returns the declaredEntry of this Scope object. * * @return the declaredEntry (type TupleEntry) of this Scope object. */ public TupleEntry getDeclaredEntry() { if( declaredEntry != null ) return declaredEntry; declaredEntry = new TupleEntry( getDeclaredFields() ); return declaredEntry; } /** * Method getGroupingSelectors returns the groupingSelectors of this Scope object. * * @return the groupingSelectors (type Map<String, Fields>) of this Scope object. */ public Map<String, Fields> getGroupingSelectors() { return groupingSelectors; } /** * Method getSortingSelectors returns the sortingSelectors of this Scope object. * * @return the sortingSelectors (type Map<String, Fields>) of this Scope object. */ public Map<String, Fields> getSortingSelectors() { return sortingSelectors; } /** * Method getOutGroupingSelector returns the outGroupingSelector of this Scope object. * * @return the outGroupingSelector (type Fields) of this Scope object. */ public Fields getOutGroupingSelector() { return outGroupingSelector; } /** * Method getOutGroupingFields returns the outGroupingFields of this Scope object. * * @return the outGroupingFields (type Fields) of this Scope object. */ public Fields getOutGroupingFields() { if( kind != Kind.GROUP ) return outGroupingFields; Fields first = groupingSelectors.values().iterator().next(); if( groupingSelectors.size() == 1 || isGroup() && isGroupBy ) return first; // if given by user if( outGroupingFields != null ) return outGroupingFields; // if all have the same names, then use for grouping Set<Fields> set = new HashSet<Fields>( groupingSelectors.values() ); if( set.size() == 1 ) return first; return Fields.size( first.size() ); } /** * Method getOutValuesSelector returns the outValuesSelector of this Scope object. * * @return the outValuesSelector (type Fields) of this Scope object. */ public Fields getOutValuesSelector() { return outValuesSelector; } /** * Method getOutValuesFields returns the outValuesFields of this Scope object. * * @return the outValuesFields (type Fields) of this Scope object. */ public Fields getOutValuesFields() { return outValuesFields; } /** * Method copyFields copies the given Scope instance fields to this instance. * * @param scope of type Scope */ public void copyFields( Scope scope ) { this.kind = scope.kind; this.isGroupBy = scope.isGroupBy; this.remainderFields = scope.remainderFields; this.argumentFields = scope.argumentFields; this.declaredFields = scope.declaredFields; this.groupingSelectors = scope.groupingSelectors; this.sortingSelectors = scope.sortingSelectors; this.outGroupingSelector = scope.outGroupingSelector; this.outGroupingFields = scope.outGroupingFields; this.outValuesSelector = scope.outValuesSelector; this.outValuesFields = scope.outValuesFields; } @Override public String toString() { if( getOutValuesFields() == null ) return ""; // endpipes StringBuffer buffer = new StringBuffer(); if( groupingSelectors != null && !groupingSelectors.isEmpty() ) { for( String name : groupingSelectors.keySet() ) { if( buffer.length() != 0 ) buffer.append( "," ); buffer.append( name ).append( groupingSelectors.get( name ).printVerbose() ); } buffer.append( "\n" ); } if( outGroupingFields != null ) buffer.append( getOutGroupingFields().printVerbose() ).append( "\n" ); buffer.append( getOutValuesFields().printVerbose() ); return buffer.toString(); } }