Package com.sissi.server.exchange.impl

Source Code of com.sissi.server.exchange.impl.BridgeExchangerContext$NothingExchanger

package com.sissi.server.exchange.impl;

import java.io.Closeable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.mongodb.BasicDBObjectBuilder;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.WriteConcern;
import com.sissi.commons.Trace;
import com.sissi.commons.apache.IOUtil;
import com.sissi.config.Dictionary;
import com.sissi.config.MongoConfig;
import com.sissi.config.impl.MongoUtils;
import com.sissi.pipeline.Transfer;
import com.sissi.pipeline.TransferBuffer;
import com.sissi.resource.ResourceCounter;
import com.sissi.server.exchange.Exchanger;
import com.sissi.server.exchange.ExchangerContext;
import com.sissi.server.exchange.Terminal;
import com.sissi.thread.Runner;
import com.sissi.thread.impl.ExecuteInterval;

/**
* 索引策略: {"host":1},{"date":1}
*
* @author kim 2013年12月22日
*/
public class BridgeExchangerContext implements ExchangerContext {

  private final String date = "date";

  private final Log log = LogFactory.getLog(this.getClass());

  /**
   * {"host":1}
   */
  private final DBObject filter = BasicDBObjectBuilder.start(Dictionary.FIELD_HOST, 1).get();

  private final Map<String, Exchanger> exchangers = new ConcurrentHashMap<String, Exchanger>();

  private final ResourceCounter resourceCounter;

  private final MongoConfig config;

  private final ExecuteInterval interval;

  private final long timeout;

  public BridgeExchangerContext(long timeout, Runner runner, ExecuteInterval interval, MongoConfig config, ResourceCounter resourceCounter) {
    super();
    this.timeout = timeout;
    this.interval = interval;
    this.config = config.reset();
    this.resourceCounter = resourceCounter;
    runner.executor(1, new Timeout());
  }

  @Override
  public Exchanger wait(String host, boolean cascade, Transfer transfer) {
    BridgeExchanger exchanger = new BridgeExchanger(host, cascade, transfer);
    if (MongoUtils.success(this.config.collection().save(this.build(host, true), WriteConcern.SAFE))) {
      this.exchangers.put(host, exchanger);
    }
    return exchanger;
  }

  @Override
  public Exchanger activate(String host) {
    if (MongoUtils.success(this.config.collection().remove(this.build(host, false), WriteConcern.SAFE))) {
      // Double check 4 multi thread
      Exchanger exchanger = this.exchangers.remove(host);
      return exchanger != null ? exchanger : new NothingExchanger(host);
    }
    return new NothingExchanger(host);
  }

  @Override
  public boolean exists(String host) {
    return this.config.collection().findOne(this.build(host, false)) != null;
  }

  /**
   * {"host":host,"date":Xxx}
   *
   * @param host
   * @param date
   * @return
   */
  private DBObject build(String host, boolean date) {
    BasicDBObjectBuilder builder = BasicDBObjectBuilder.start(Dictionary.FIELD_HOST, host);
    if (date) {
      builder.add(this.date, System.currentTimeMillis());
    }
    return builder.get();
  }

  /**
   * 终止发起方在超时时间内尚未激活的Exchanger
   *
   * @author kim 2014年4月20日
   */
  private class Timeout implements Runnable {

    private final long sleep = BridgeExchangerContext.this.interval.convert(TimeUnit.MILLISECONDS);

    private final String resource = Timeout.class.getSimpleName();

    @Override
    public void run() {
      try {
        BridgeExchangerContext.this.resourceCounter.increment(this.resource);
        while (true) {
          try {
            this.timeout();
            Thread.sleep(this.sleep);
          } catch (Exception e) {
            log.error(e.toString());
            Trace.trace(log, e);
          }
        }
      } finally {
        BridgeExchangerContext.this.resourceCounter.decrement(this.resource);
      }
    }

    private Timeout timeout() {
      try (DBCursor cursor = BridgeExchangerContext.this.config.collection().find(BasicDBObjectBuilder.start(BridgeExchangerContext.this.date, BasicDBObjectBuilder.start("$lt", System.currentTimeMillis() - BridgeExchangerContext.this.timeout).get()).get(), BridgeExchangerContext.this.filter)) {
        while (cursor.hasNext()) {
          Exchanger exchanger = BridgeExchangerContext.this.activate(MongoUtils.asString(DBObject.class.cast(cursor.next()), Dictionary.FIELD_HOST));
          // Double check 4 multi thread
          if (exchanger != null) {
            BridgeExchangerContext.this.log.warn("Timeout socks: " + exchanger.host());
            exchanger.close(Terminal.ALL);
          }
        }
      }
      return this;
    }
  }

  private class BridgeExchanger implements Exchanger {

    private final Transfer target;

    /**
     * 是否允许关闭Target
     */
    private final boolean cascade;

    private final String host;

    private Closeable source;

    /**
     * @param host
     * @param cascade 是否允许关闭Target
     * @param target 接收方
     */
    private BridgeExchanger(String host, boolean cascade, Transfer target) {
      this.host = host;
      this.cascade = cascade;
      this.target = target;
    }

    public String host() {
      return this.host;
    }

    public BridgeExchanger source(Closeable source) {
      this.source = source;
      return this;
    }

    @Override
    public BridgeExchanger write(TransferBuffer buffer) {
      this.target.transfer(buffer);
      return this;
    }

    @Override
    public BridgeExchanger close(Terminal terminal) {
      switch (terminal) {
      case ALL:
        return this.close(Terminal.SOURCE).close(Terminal.TARGET);
      case SOURCE:
        return this.close(this.source);
      case TARGET:
        return this.cascade ? this.close(this.target) : this;
      }
      return this;
    }

    /**
     * 无论是否成功都将隐式激活(Activate)
     *
     * @param closer
     * @return
     */
    private BridgeExchanger close(Closeable closer) {
      try {
        IOUtil.closeQuietly(closer);
      } catch (Exception e) {
        BridgeExchangerContext.this.log.warn(e.toString());
        Trace.trace(BridgeExchangerContext.this.log, e);
      } finally {
        BridgeExchangerContext.this.activate(this.host);
      }
      return this;
    }
  }

  private final class NothingExchanger implements Exchanger {

    private final String host;

    public NothingExchanger(String host) {
      super();
      this.host = host;
    }

    @Override
    public String host() {
      return this.host;
    }

    @Override
    public NothingExchanger source(Closeable source) {
      return this;
    }

    @Override
    public NothingExchanger write(TransferBuffer buffer) {
      BridgeExchangerContext.this.log.info("Nothing on " + this.host + ", please check");
      return this;
    }

    @Override
    public NothingExchanger close(Terminal terminal) {
      return this;
    }
  }
}
TOP

Related Classes of com.sissi.server.exchange.impl.BridgeExchangerContext$NothingExchanger

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.