001/*
002 * Copyright (c) 2007-2022 The Cascading Authors. All Rights Reserved.
003 *
004 * Project and contact information: https://cascading.wensel.net/
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.nested.core.aggregate;
022
023import java.beans.ConstructorProperties;
024import java.io.Serializable;
025
026import cascading.nested.core.NestedAggregate;
027import cascading.operation.SerFunction;
028import cascading.tuple.Fields;
029import cascading.tuple.Tuple;
030import cascading.tuple.type.CoercibleType;
031
032/**
033 * Class SimpleNestedAggregate provides a simple extensible implementation of {@link NestedAggregate}.
034 *
035 * @param <Node>
036 */
037public class SimpleNestedAggregate<Node> implements NestedAggregate<Node, SimpleNestedAggregate.AggregateContext<Node>>
038  {
039  public interface AggregateContext<Node> extends Serializable
040    {
041    void aggregate( Node node );
042
043    Tuple complete();
044
045    void reset();
046    }
047
048  protected Fields fieldDeclaration;
049  protected SerFunction<CoercibleType<Node>, AggregateContext<Node>> factory;
050
051  /**
052   * Create a new instance of SimpleNestedAggregate.
053   * <p>
054   * The factory parameter provides new instances of {@link AggregateContext}.
055   *
056   * @param fieldDeclaration the fields this aggregate returns
057   * @param factory          a supplier for new AggregateContext instances
058   */
059  @ConstructorProperties({"fieldDeclaration", "factory"})
060  public SimpleNestedAggregate( Fields fieldDeclaration, SerFunction<CoercibleType<Node>, SimpleNestedAggregate.AggregateContext<Node>> factory )
061    {
062    this.fieldDeclaration = fieldDeclaration;
063    this.factory = factory;
064    }
065
066  /**
067   * Create a new instance of SimpleNestedAggregate without a factory
068   * <p>
069   * The factory parameter provides new instances of {@link AggregateContext}.
070   *
071   * @param fieldDeclaration the fields this aggregate returns
072   */
073  @ConstructorProperties({"fieldDeclaration"})
074  protected SimpleNestedAggregate( Fields fieldDeclaration )
075    {
076    this.fieldDeclaration = fieldDeclaration;
077    }
078
079  /**
080   * Create a new instance of SimpleNestedAggregate without a factory
081   * <p>
082   * The factory parameter provides new instances of {@link AggregateContext}.
083   */
084  protected SimpleNestedAggregate()
085    {
086    }
087
088  protected void setFactory( SerFunction<CoercibleType<Node>, AggregateContext<Node>> factory )
089    {
090    this.factory = factory;
091    }
092
093  @Override
094  public Fields getFieldDeclaration()
095    {
096    return fieldDeclaration;
097    }
098
099  protected SimpleNestedAggregate<Node> setFieldDeclaration( Fields fieldDeclaration )
100    {
101    this.fieldDeclaration = fieldDeclaration;
102    return this;
103    }
104
105  @Override
106  public AggregateContext<Node> createContext( CoercibleType<Node> nestedCoercibleType )
107    {
108    if( factory == null )
109      throw new IllegalStateException( "factory is required" );
110
111    return factory.apply( nestedCoercibleType );
112    }
113
114  @Override
115  public void aggregate( AggregateContext<Node> context, Node node )
116    {
117    context.aggregate( node );
118    }
119
120  @Override
121  public Tuple complete( AggregateContext<Node> context )
122    {
123    return context.complete();
124    }
125
126  @Override
127  public AggregateContext<Node> resetContext( AggregateContext<Node> context )
128    {
129    context.reset();
130
131    return context;
132    }
133  }