Package co.cask.tigon.api.flow

Source Code of co.cask.tigon.api.flow.FlowletDefinition

/*
* Copyright © 2014 Cask Data, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/

package co.cask.tigon.api.flow;

import co.cask.tigon.api.flow.flowlet.Flowlet;
import co.cask.tigon.api.flow.flowlet.FlowletSpecification;
import co.cask.tigon.internal.flowlet.DefaultFlowletSpecification;
import co.cask.tigon.internal.io.Schema;
import co.cask.tigon.internal.io.SchemaGenerator;
import co.cask.tigon.internal.io.UnsupportedTypeException;
import co.cask.tigon.internal.lang.Reflections;
import co.cask.tigon.internal.specification.OutputEmitterFieldExtractor;
import co.cask.tigon.internal.specification.ProcessMethodExtractor;
import co.cask.tigon.internal.specification.PropertyFieldExtractor;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.reflect.TypeToken;

import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
* Class defining the definition for a flowlet.
*/
public final class FlowletDefinition {
  public static final String DEFAULT_OUTPUT = "queue";
  public static final String ANY_INPUT = "";

  private final FlowletSpecification flowletSpec;
  private int instances;

  private final transient Map<String, Set<Type>> inputTypes;
  private final transient Map<String, Set<Type>> outputTypes;
  private Map<String, Set<Schema>> inputs;
  private Map<String, Set<Schema>> outputs;

  FlowletDefinition(String flowletName, Flowlet flowlet, int instances) {
    FlowletSpecification flowletSpec = flowlet.configure();

    this.instances = instances;

    Map<String, Set<Type>> inputTypes = Maps.newHashMap();
    Map<String, Set<Type>> outputTypes = Maps.newHashMap();
    Map<String, String> properties = Maps.newHashMap(flowletSpec.getProperties());
    Reflections.visit(flowlet, TypeToken.of(flowlet.getClass()),
                      new PropertyFieldExtractor(properties),
                      new OutputEmitterFieldExtractor(outputTypes),
                      new ProcessMethodExtractor(inputTypes));

    this.inputTypes = immutableCopyOf(inputTypes);
    this.outputTypes = immutableCopyOf(outputTypes);
    this.flowletSpec = new DefaultFlowletSpecification(flowlet.getClass().getName(),
                                                       flowletName == null ? flowletSpec.getName() : flowletName,
                                                       flowletSpec.getDescription(), flowletSpec.getFailurePolicy(),
                                                       properties, flowletSpec.getResources(),
                                                       flowletSpec.getMaxInstances());
  }

  /**
   * Creates a definition from a copy and overrides the number of instances.
   * @param definition definition to copy from
   * @param instances new number of instances
   */
  public FlowletDefinition(FlowletDefinition definition, int instances) {
    this(definition);
    this.instances = instances;
  }

  /**
   * Creates a definition from a copy and overrides the stream connection.
   * @param definition definition to copy from
   * @param oldStreamInput stream connection to override
   * @param newStreamInput new value for input stream
   */
  public FlowletDefinition(FlowletDefinition definition, String oldStreamInput, String newStreamInput) {
    this(definition);

    // Changing what is going to be serialized and stored in MDS: intputs

    Set<Schema> schemas = inputs.get(oldStreamInput);
    if (schemas == null) {
      // This is fine: stream name was not in set in @ProcessInput, so no need to change it, as the change will
      // be reflected in Flow spec in flowlet connections
      return;
    }

    Schema streamSchema = null;
    Set<Schema> changedSchemas = Sets.newLinkedHashSet();
    for (Schema schema : schemas) {
      changedSchemas.add(schema);
    }

    // Removing schema from set under old name (removing the whole set if nothing is left there)
    if (changedSchemas.isEmpty()) {
      inputs.remove(oldStreamInput);
    } else {
      inputs.put(oldStreamInput, changedSchemas);
    }

    // Adding schema to the set under new name (creating set if not exists)
    Set<Schema> newSchemas =
      inputs.containsKey(newStreamInput) ? inputs.get(newStreamInput) : Sets.<Schema>newLinkedHashSet();
    newSchemas.add(streamSchema);
    inputs.put(newStreamInput, newSchemas);
  }

  private FlowletDefinition(FlowletDefinition definition) {
    this.flowletSpec = definition.flowletSpec;
    this.instances = definition.instances;
    this.inputTypes = definition.inputTypes;
    this.outputTypes = definition.outputTypes;
    this.inputs = definition.inputs;
    this.outputs = definition.outputs;
  }

  /**
   * @return Specification of Flowlet
   */
  public FlowletSpecification getFlowletSpec() {
    return flowletSpec;
  }

  /**
   * @return Number of instances configured for this flowlet.
   */
  public int getInstances() {
    return instances;
  }

  /**
   * @return Mapping of name to the method types for processing inputs.
   */
  public Map<String, Set<Schema>> getInputs() {
    Preconditions.checkState(inputs != null, "Input schemas not yet generated.");
    return inputs;
  }

  /**
   * @return Mapping from name of {@link co.cask.tigon.api.flow.flowlet.OutputEmitter} to actual emitters.
   */
  public Map<String, Set<Schema>> getOutputs() {
    Preconditions.checkState(outputs != null, "Output schemas not yet generated.");
    return outputs;
  }

  /**
   * Generate schemas for all input and output types with the given {@link SchemaGenerator}.
   * @param generator The {@link SchemaGenerator} for generating type schema.
   */
  public void generateSchema(SchemaGenerator generator) throws UnsupportedTypeException {
    if (inputs == null && outputs == null && inputTypes != null && outputTypes != null) {
      // Generate both inputs and outputs before making this visible
      Map<String, Set<Schema>> inputs = generateSchema(generator, inputTypes);
      Map<String, Set<Schema>> outputs = generateSchema(generator, outputTypes);

      this.inputs = inputs;
      this.outputs = outputs;
    }
  }

  private Map<String, Set<Schema>> generateSchema(SchemaGenerator generator, Map<String, Set<Type>> types)
                                                  throws UnsupportedTypeException {
    Map<String, Set<Schema>> result = new HashMap<String, Set<Schema>>();
    for (Map.Entry<String, Set<Type>> entry : types.entrySet()) {
      ImmutableSet.Builder<Schema> schemas = ImmutableSet.builder();
      for (Type type : entry.getValue()) {
        schemas.add(generator.generate(type));
      }
      result.put(entry.getKey(), schemas.build());
    }
    return result;
  }

  private <K, V> Map<K, Set<V>> immutableCopyOf(Map<K, Set<V>> map) {
    Map<K, Set<V>> result = new HashMap<K, Set<V>>();
    for (Map.Entry<K, Set<V>> entry : map.entrySet()) {
      result.put(entry.getKey(), ImmutableSet.copyOf(entry.getValue()));
    }
    return result;
  }
}
TOP

Related Classes of co.cask.tigon.api.flow.FlowletDefinition

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.