content: /*
   * Copyright 1999-2012 Alibaba Group.
   *  
   * 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 com.alibaba.cobar;
  
  import java.util.Map;
  import java.util.concurrent.locks.ReentrantLock;
  
  import com.alibaba.cobar.config.model.DataSourceConfig;
  import com.alibaba.cobar.config.model.QuarantineConfig;
  import com.alibaba.cobar.config.model.SchemaConfig;
  import com.alibaba.cobar.config.model.SystemConfig;
  import com.alibaba.cobar.config.model.UserConfig;
  import com.alibaba.cobar.mysql.MySQLDataNode;
  import com.alibaba.cobar.util.TimeUtil;
  
  /**
   * @author xianmao.hexm
   */
  public class CobarConfig {
      private static final int RELOAD = 1;
      private static final int ROLLBACK = 2;
  
      private volatile SystemConfig system;
      private volatile CobarCluster cluster;
      private volatile CobarCluster _cluster;
      private volatile QuarantineConfig quarantine;
      private volatile QuarantineConfig _quarantine;
      private volatile Map<String, UserConfig> users;
      private volatile Map<String, UserConfig> _users;
      private volatile Map<String, SchemaConfig> schemas;
      private volatile Map<String, SchemaConfig> _schemas;
      private volatile Map<String, MySQLDataNode> dataNodes;
      private volatile Map<String, MySQLDataNode> _dataNodes;
      private volatile Map<String, DataSourceConfig> dataSources;
      private volatile Map<String, DataSourceConfig> _dataSources;
      private long reloadTime;
      private long rollbackTime;
      private int status;
      private final ReentrantLock lock;
  
      public CobarConfig() {
          ConfigInitializer confInit = new ConfigInitializer();
          this.system = confInit.getSystem();
          this.users = confInit.getUsers();
          this.schemas = confInit.getSchemas();
          this.dataSources = confInit.getDataSources();
          this.dataNodes = confInit.getDataNodes();
          this.quarantine = confInit.getQuarantine();
          this.cluster = confInit.getCluster();
  
          this.reloadTime = TimeUtil.currentTimeMillis();
          this.rollbackTime = -1L;
          this.status = RELOAD;
          this.lock = new ReentrantLock();
      }
  
      public SystemConfig getSystem() {
          return system;
      }
  
      public Map<String, UserConfig> getUsers() {
          return users;
      }
  
      public Map<String, UserConfig> getBackupUsers() {
          return _users;
      }
  
      public Map<String, SchemaConfig> getSchemas() {
          return schemas;
      }
  
      public Map<String, SchemaConfig> getBackupSchemas() {
          return _schemas;
      }
  
      public Map<String, MySQLDataNode> getDataNodes() {
          return dataNodes;
      }
  
      public Map<String, MySQLDataNode> getBackupDataNodes() {
          return _dataNodes;
      }
  
      public Map<String, DataSourceConfig> getDataSources() {
          return dataSources;
      }
  
      public Map<String, DataSourceConfig> getBackupDataSources() {
          return _dataSources;
      }
  
      public CobarCluster getCluster() {
          return cluster;
      }
  
      public CobarCluster getBackupCluster() {
          return _cluster;
      }
  
      public QuarantineConfig getQuarantine() {
          return quarantine;
      }
  
      public QuarantineConfig getBackupQuarantine() {
          return _quarantine;
      }
  
      public ReentrantLock getLock() {
          return lock;
      }
  
      public long getReloadTime() {
          return reloadTime;
      }
  
      public long getRollbackTime() {
          return rollbackTime;
      }
  
      public void reload(Map<String, UserConfig> users, Map<String, SchemaConfig> schemas,
                         Map<String, MySQLDataNode> dataNodes, Map<String, DataSourceConfig> dataSources,
                         CobarCluster cluster, QuarantineConfig quarantine) {
          apply(users, schemas, dataNodes, dataSources, cluster, quarantine);
          this.reloadTime = TimeUtil.currentTimeMillis();
          this.status = RELOAD;
      }
  
      public boolean canRollback() {
          if (_users == null || _schemas == null || _dataNodes == null || _dataSources == null || _cluster == null
              || _quarantine == null || status == ROLLBACK) {
              return false;
          } else {
              return true;
          }
      }
  
      public void rollback(Map<String, UserConfig> users, Map<String, SchemaConfig> schemas,
                           Map<String, MySQLDataNode> dataNodes, Map<String, DataSourceConfig> dataSources,
                           CobarCluster cluster, QuarantineConfig quarantine) {
          apply(users, schemas, dataNodes, dataSources, cluster, quarantine);
          this.rollbackTime = TimeUtil.currentTimeMillis();
          this.status = ROLLBACK;
      }
  
      private void apply(Map<String, UserConfig> users, Map<String, SchemaConfig> schemas,
                         Map<String, MySQLDataNode> dataNodes, Map<String, DataSourceConfig> dataSources,
                         CobarCluster cluster, QuarantineConfig quarantine) {
          final ReentrantLock lock = this.lock;
          lock.lock();
          try {
              // stop mysql heartbeat
              Map<String, MySQLDataNode> oldDataNodes = this.dataNodes;
              if (oldDataNodes != null) {
                  for (MySQLDataNode n : oldDataNodes.values()) {
                      if (n != null) {
                          n.stopHeartbeat();
                      }
                  }
              }
              // stop cobar heartbeat
              CobarCluster oldCluster = this.cluster;
              if (oldCluster != null) {
                  Map<String, CobarNode> nodes = oldCluster.getNodes();
                  for (CobarNode n : nodes.values()) {
                      if (n != null) {
                          n.stopHeartbeat();
                      }
                  }
              }
              this._users = this.users;
              this._schemas = this.schemas;
              this._dataNodes = this.dataNodes;
              this._dataSources = this.dataSources;
              this._cluster = this.cluster;
              this._quarantine = this.quarantine;
  
              // start mysql heartbeat
              if (dataNodes != null) {
                  for (MySQLDataNode n : dataNodes.values()) {
                      if (n != null) {
                          n.startHeartbeat();
                      }
                  }
              }
              // start cobar heartbeat
              if (cluster != null) {
                  Map<String, CobarNode> nodes = cluster.getNodes();
                  for (CobarNode n : nodes.values()) {
                      if (n != null) {
                          n.startHeartbeat();
                      }
                  }
              }
              this.users = users;
              this.schemas = schemas;
              this.dataNodes = dataNodes;
              this.dataSources = dataSources;
              this.cluster = cluster;
              this.quarantine = quarantine;
          } finally {
              lock.unlock();
          }
      }
  
  }
  