content: /*
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements.  See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership.  The ASF licenses this file
   * to you 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 com.alibaba.jstorm.flux.model;
  
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  import java.util.*;
  
  /**
   * Bean represenation of a topology.
   *
   * It consists of the following:
   *   1. The topology name
   *   2. A `java.util.Map` representing the `backtype.storm.config` for the topology
   *   3. A list of spout definitions
   *   4. A list of bolt definitions
   *   5. A list of stream definitions that define the flow between spouts and bolts.
   *
   */
  public class TopologyDef {
      private static Logger LOG = LoggerFactory.getLogger(TopologyDef.class);
  
      private String name;
      private Map<String, BeanDef> componentMap = new LinkedHashMap<String, BeanDef>(); // not required
      private List<IncludeDef> includes; // not required
      private Map<String, Object> config = new HashMap<String, Object>();
  
      // a "topology source" is a class that can produce a `StormTopology` thrift object.
      private TopologySourceDef topologySource;
  
      // the following are required if we're defining a core storm topology DAG in YAML, etc.
      private Map<String, BoltDef> boltMap = new LinkedHashMap<String, BoltDef>();
      private Map<String, SpoutDef> spoutMap = new LinkedHashMap<String, SpoutDef>();
      private List<StreamDef> streams = new ArrayList<StreamDef>();
  
  
      public String getName() {
          return name;
      }
  
      public void setName(String name) {
          this.name = name;
      }
  
      public void setName(String name, boolean override){
          if(this.name == null || override){
              this.name = name;
          } else {
              LOG.warn("Ignoring attempt to set property 'name' with override == false.");
          }
      }
  
      public List<SpoutDef> getSpouts() {
          ArrayList<SpoutDef> retval = new ArrayList<SpoutDef>();
          retval.addAll(this.spoutMap.values());
          return retval;
      }
  
      public void setSpouts(List<SpoutDef> spouts) {
          this.spoutMap = new LinkedHashMap<String, SpoutDef>();
          for(SpoutDef spout : spouts){
              this.spoutMap.put(spout.getId(), spout);
          }
      }
  
      public List<BoltDef> getBolts() {
          ArrayList<BoltDef> retval = new ArrayList<BoltDef>();
          retval.addAll(this.boltMap.values());
          return retval;
      }
  
      public void setBolts(List<BoltDef> bolts) {
          this.boltMap = new LinkedHashMap<String, BoltDef>();
          for(BoltDef bolt : bolts){
              this.boltMap.put(bolt.getId(), bolt);
          }
      }
  
      public List<StreamDef> getStreams() {
          return streams;
      }
  
      public void setStreams(List<StreamDef> streams) {
          this.streams = streams;
      }
  
      public Map<String, Object> getConfig() {
          return config;
      }
  
      public void setConfig(Map<String, Object> config) {
          this.config = config;
      }
  
      public List<BeanDef> getComponents() {
          ArrayList<BeanDef> retval = new ArrayList<BeanDef>();
          retval.addAll(this.componentMap.values());
          return retval;
      }
  
      public void setComponents(List<BeanDef> components) {
          this.componentMap = new LinkedHashMap<String, BeanDef>();
          for(BeanDef component : components){
              this.componentMap.put(component.getId(), component);
          }
      }
  
      public List<IncludeDef> getIncludes() {
          return includes;
      }
  
      public void setIncludes(List<IncludeDef> includes) {
          this.includes = includes;
      }
  
      // utility methods
      public int parallelismForBolt(String boltId){
          return this.boltMap.get(boltId).getParallelism();
      }
  
      public BoltDef getBoltDef(String id){
          return this.boltMap.get(id);
      }
  
      public SpoutDef getSpoutDef(String id){
          return this.spoutMap.get(id);
      }
  
      public BeanDef getComponent(String id){
          return this.componentMap.get(id);
      }
  
      // used by includes implementation
      public void addAllBolts(List<BoltDef> bolts, boolean override){
          for(BoltDef bolt : bolts){
              String id = bolt.getId();
              if(this.boltMap.get(id) == null || override) {
                  this.boltMap.put(bolt.getId(), bolt);
              } else {
                  LOG.warn("Ignoring attempt to create bolt '{}' with override == false.", id);
              }
          }
      }
  
      public void addAllSpouts(List<SpoutDef> spouts, boolean override){
          for(SpoutDef spout : spouts){
              String id = spout.getId();
              if(this.spoutMap.get(id) == null || override) {
                  this.spoutMap.put(spout.getId(), spout);
              } else {
                  LOG.warn("Ignoring attempt to create spout '{}' with override == false.", id);
              }
          }
      }
  
      public void addAllComponents(List<BeanDef> components, boolean override) {
          for(BeanDef bean : components){
              String id = bean.getId();
              if(this.componentMap.get(id) == null || override) {
                  this.componentMap.put(bean.getId(), bean);
              } else {
                  LOG.warn("Ignoring attempt to create component '{}' with override == false.", id);
              }
          }
      }
  
      public void addAllStreams(List<StreamDef> streams, boolean override) {
          //TODO figure out how we want to deal with overrides. Users may want to add streams even when overriding other
          // properties. For now we just add them blindly which could lead to a potentially invalid topology.
          this.streams.addAll(streams);
      }
  
      public TopologySourceDef getTopologySource() {
          return topologySource;
      }
  
      public void setTopologySource(TopologySourceDef topologySource) {
          this.topologySource = topologySource;
      }
  
      public boolean isDslTopology(){
          return this.topologySource == null;
      }
  
  
      public boolean validate(){
          boolean hasSpouts = this.spoutMap != null && this.spoutMap.size() > 0;
          boolean hasBolts = this.boltMap != null && this.boltMap.size() > 0;
          boolean hasStreams = this.streams != null && this.streams.size() > 0;
          boolean hasSpoutsBoltsStreams = hasStreams && hasBolts && hasSpouts;
          // you cant define a topologySource and a DSL topology at the same time...
          if (!isDslTopology() && ((hasSpouts || hasBolts || hasStreams))) {
              return false;
          }
          if(isDslTopology() && (hasSpouts && hasBolts && hasStreams)) {
              return true;
          }
          return true;
      }
  }
  