Exemple #1
0
/**
 * Index
 *
 * @author william.liangf
 */
public class Index {
  // 日志输出
  private static final Logger logger = LoggerFactory.getLogger(Index.class);

  @Autowired private HttpServletRequest request;

  @Autowired private ProviderService providerService;

  @Autowired private ConsumerService consumerService;

  public void execute(Context context) {
    Set<String> applications = new HashSet<String>();
    Set<String> services = new HashSet<String>();
    List<Provider> pList = new ArrayList<Provider>();
    try {
      pList = providerService.findAll();
    } catch (Exception e) {
      logger.error(e.getMessage(), e);
    }
    for (Provider p : pList) {
      applications.add(p.getApplication());
      services.add(p.getService());
    }
    List<Consumer> cList = new ArrayList<Consumer>();
    try {
      cList = consumerService.findAll();
    } catch (Exception e) {
      logger.error(e.getMessage(), e);
    }
    for (Consumer c : cList) {
      applications.add(c.getApplication());
      services.add(c.getService());
    }
    context.put("rootContextPath", new RootContextPath(request.getContextPath()));
    context.put("services", services.size());
    context.put("providers", pList.size());
    context.put("consumers", cList.size());
    context.put("applications", applications.size());
  }
}
/**
 * @author li
 * @version 1 (2014年12月22日 下午2:26:18)
 * @since Java7
 */
public class AbstractRedisRegistry extends FailbackRegistry {
  private static final Logger logger = LoggerFactory.getLogger(AbstractRedisRegistry.class);

  private final ScheduledExecutorService expireExecutor =
      Executors.newScheduledThreadPool(1, new NamedThreadFactory("DubboRegistryExpireTimer", true));

  private final ScheduledFuture<?> expireFuture;

  private final String root;

  private final Map<String, JedisPool> jedisPools = new ConcurrentHashMap<String, JedisPool>();

  private final ConcurrentMap<String, RedisRegistryNotifier> notifiers =
      new ConcurrentHashMap<String, RedisRegistryNotifier>();

  private int reconnectPeriod;

  private final int expirePeriod;

  private volatile boolean admin = false;

  private boolean replicate;

  public AbstractRedisRegistry(URL url) {
    super(url);
    RedisRegistryUtil.assertNotAnyHost(url);
    GenericObjectPoolConfig config = RedisRegistryUtil.genericObjectPoolConfig(url);
    List<String> addresses = RedisRegistryUtil.getAddresses(url);

    for (String address : addresses) {
      JedisPool jedisPool = RedisRegistryUtil.initJedisPoolAndCheck(url, config, address);
      jedisPools.put(address, jedisPool);
    }

    this.replicate = RedisRegistryUtil.getReplicate(url);
    this.reconnectPeriod =
        url.getParameter(
            Constants.REGISTRY_RECONNECT_PERIOD_KEY, Constants.DEFAULT_REGISTRY_RECONNECT_PERIOD);
    this.root = RedisRegistryUtil.getGroup(url);
    this.expirePeriod =
        url.getParameter(Constants.SESSION_TIMEOUT_KEY, Constants.DEFAULT_SESSION_TIMEOUT);
    this.expireFuture =
        expireExecutor.scheduleWithFixedDelay(
            new Runnable() {
              public void run() {
                try {
                  deferExpired(); // 延长过期时间
                } catch (Throwable t) { // 防御性容错
                  logger.error(
                      "Unexpected exception occur at defer expire time, cause: " + t.getMessage(),
                      t);
                }
              }
            },
            expirePeriod / 2,
            expirePeriod / 2,
            TimeUnit.MILLISECONDS);
  }

  private void deferExpired() {
    for (Map.Entry<String, JedisPool> entry : jedisPools.entrySet()) {
      JedisPool jedisPool = entry.getValue();
      try {
        Jedis jedis = jedisPool.getResource();
        try {
          RedisRegistryUtil.publishToJedis(jedis, getRegistered(), root, expirePeriod);
          if (admin) {
            clean(jedis);
          }
          if (!replicate) {
            break; //  如果服务器端已同步数据,只需写入单台机器
          }
        } finally {
          jedisPool.returnResource(jedis);
        }
      } catch (Throwable t) {
        logger.warn(
            "Failed to write provider heartbeat to redis registry. registry: "
                + entry.getKey()
                + ", cause: "
                + t.getMessage(),
            t);
      }
    }
  }

  // 监控中心负责删除过期脏数据
  private void clean(Jedis jedis) {
    RedisRegistryUtil.clean(jedis, root);
  }

  public boolean isAvailable() {
    for (JedisPool jedisPool : jedisPools.values()) {
      try {
        Jedis jedis = jedisPool.getResource();
        try {
          if (jedis.isConnected()) {
            return true; // 至少需单台机器可用
          }
        } finally {
          jedisPool.returnResource(jedis);
        }
      } catch (Throwable t) {
      }
    }
    return false;
  }

  public void destroy() {
    super.destroy();
    try {
      expireFuture.cancel(true);
    } catch (Throwable t) {
      logger.warn(t.getMessage(), t);
    }
    try {
      for (RedisRegistryNotifier notifier : notifiers.values()) {
        notifier.shutdown();
      }
    } catch (Throwable t) {
      logger.warn(t.getMessage(), t);
    }
    for (Map.Entry<String, JedisPool> entry : jedisPools.entrySet()) {
      JedisPool jedisPool = entry.getValue();
      try {
        jedisPool.destroy();
      } catch (Throwable t) {
        logger.warn(
            "Failed to destroy the redis registry client. registry: "
                + entry.getKey()
                + ", cause: "
                + t.getMessage(),
            t);
      }
    }
  }

  public void doRegister(URL url) {
    String key = RedisRegistryUtil.toCategoryPath(url, root);
    String value = url.toFullString();
    String expire = String.valueOf(System.currentTimeMillis() + expirePeriod);
    boolean success = false;
    RpcException exception = null;
    for (Map.Entry<String, JedisPool> entry : jedisPools.entrySet()) {
      JedisPool jedisPool = entry.getValue();
      try {
        Jedis jedis = jedisPool.getResource();
        try {
          jedis.hset(key, value, expire);
          jedis.publish(key, Constants.REGISTER);
          success = true;
          if (!replicate) {
            break; //  如果服务器端已同步数据,只需写入单台机器
          }
        } finally {
          jedisPool.returnResource(jedis);
        }
      } catch (Throwable t) {
        exception =
            new RpcException(
                "Failed to register service to redis registry. registry: "
                    + entry.getKey()
                    + ", service: "
                    + url
                    + ", cause: "
                    + t.getMessage(),
                t);
      }
    }
    if (exception != null) {
      if (success) {
        logger.warn(exception.getMessage(), exception);
      } else {
        throw exception;
      }
    }
  }

  public void doUnregister(URL url) {
    String key = RedisRegistryUtil.toCategoryPath(url, root);
    String value = url.toFullString();
    RpcException exception = null;
    boolean success = false;
    for (Map.Entry<String, JedisPool> entry : jedisPools.entrySet()) {
      JedisPool jedisPool = entry.getValue();
      try {
        Jedis jedis = jedisPool.getResource();
        try {
          jedis.hdel(key, value);
          jedis.publish(key, Constants.UNREGISTER);
          success = true;
          if (!replicate) {
            break; //  如果服务器端已同步数据,只需写入单台机器
          }
        } finally {
          jedisPool.returnResource(jedis);
        }
      } catch (Throwable t) {
        exception =
            new RpcException(
                "Failed to unregister service to redis registry. registry: "
                    + entry.getKey()
                    + ", service: "
                    + url
                    + ", cause: "
                    + t.getMessage(),
                t);
      }
    }
    if (exception != null) {
      if (success) {
        logger.warn(exception.getMessage(), exception);
      } else {
        throw exception;
      }
    }
  }

  public void doSubscribe(final URL url, final NotifyListener listener) {
    String service = RedisRegistryUtil.toServicePath(url, root);
    RedisRegistryNotifier notifier = notifiers.get(service);
    if (notifier == null) {
      RedisRegistryNotifier newNotifier = new RedisRegistryNotifier(service, this);
      notifiers.putIfAbsent(service, newNotifier);
      notifier = notifiers.get(service);
      if (notifier == newNotifier) {
        notifier.start();
      }
    }
    boolean success = false;
    RpcException exception = null;
    for (Map.Entry<String, JedisPool> entry : jedisPools.entrySet()) {
      JedisPool jedisPool = entry.getValue();
      try {
        Jedis jedis = jedisPool.getResource();
        try {
          if (service.endsWith(Constants.ANY_VALUE)) {
            admin = true;
            Set<String> keys = jedis.keys(service);
            if (keys != null && keys.size() > 0) {
              Map<String, Set<String>> serviceKeys = RedisRegistryUtil.getServiceKeys(keys, root);
              for (Set<String> sk : serviceKeys.values()) {
                doNotify(jedis, sk, url, Arrays.asList(listener));
              }
            }
          } else {
            doNotify(
                jedis,
                jedis.keys(service + Constants.PATH_SEPARATOR + Constants.ANY_VALUE),
                url,
                Arrays.asList(listener));
          }
          success = true;
          break; // 只需读一个服务器的数据
        } finally {
          jedisPool.returnResource(jedis);
        }
      } catch (Throwable t) { // 尝试下一个服务器
        exception =
            new RpcException(
                "Failed to subscribe service from redis registry. registry: "
                    + entry.getKey()
                    + ", service: "
                    + url
                    + ", cause: "
                    + t.getMessage(),
                t);
      }
    }
    if (exception != null) {
      if (success) {
        logger.warn(exception.getMessage(), exception);
      } else {
        throw exception;
      }
    }
  }

  public void doNotify(Jedis jedis, String key) {
    for (Map.Entry<URL, Set<NotifyListener>> entry :
        new HashMap<URL, Set<NotifyListener>>(getSubscribed()).entrySet()) {
      doNotify(
          jedis, Arrays.asList(key), entry.getKey(), new HashSet<NotifyListener>(entry.getValue()));
    }
  }

  private void doNotify(
      Jedis jedis, Collection<String> keys, URL url, Collection<NotifyListener> listeners) {
    if (keys == null || keys.size() == 0 || listeners == null || listeners.size() == 0) {
      return;
    }
    long now = System.currentTimeMillis();
    List<URL> result = new ArrayList<URL>();
    List<String> categories =
        Arrays.asList(url.getParameter(Constants.CATEGORY_KEY, new String[0]));
    String consumerService = url.getServiceInterface();
    for (String key : keys) {
      if (!Constants.ANY_VALUE.equals(consumerService)) {
        String prvoiderService = RedisRegistryUtil.toServiceName(key, root);
        if (!prvoiderService.equals(consumerService)) {
          continue;
        }
      }
      String category = RedisRegistryUtil.toCategoryName(key);
      if (!categories.contains(Constants.ANY_VALUE) && !categories.contains(category)) {
        continue;
      }

      Map<String, String> values = jedis.hgetAll(key);
      List<URL> urls = RedisRegistryUtil.getUrlsForDoNotify(url, now, values);

      if (urls.isEmpty()) {
        urls.add(RedisRegistryUtil.setUrlProperties(url, key, category, root));
      }
      result.addAll(urls);
      if (logger.isWarnEnabled()) {
        logger.warn("redis notify: " + key + " = " + urls);
      }
    }
    if (result == null || result.size() == 0) {
      return;
    }
    for (NotifyListener listener : listeners) {
      notify(url, listener, result);
    }
  }

  public void doUnsubscribe(URL url, NotifyListener listener) {
    // do nothing
  }

  public Map<String, JedisPool> getJedisPools() {
    return jedisPools;
  }

  public int getReconnectPeriod() {
    return reconnectPeriod;
  }
}
Exemple #3
0
/**
 * GenericImplInvokerFilter
 *
 * @author william.liangf
 */
@Activate(group = Constants.CONSUMER, value = Constants.GENERIC_KEY, order = 20000)
public class GenericImplFilter implements Filter {

  private static final Logger logger = LoggerFactory.getLogger(GenericImplFilter.class);

  private static final Class<?>[] GENERIC_PARAMETER_TYPES =
      new Class<?>[] {String.class, String[].class, Object[].class};

  public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
    String generic = invoker.getUrl().getParameter(Constants.GENERIC_KEY);
    if (ProtocolUtils.isGeneric(generic)
        && !Constants.$INVOKE.equals(invocation.getMethodName())
        && invocation instanceof RpcInvocation) {
      RpcInvocation invocation2 = (RpcInvocation) invocation;
      String methodName = invocation2.getMethodName();
      Class<?>[] parameterTypes = invocation2.getParameterTypes();
      Object[] arguments = invocation2.getArguments();

      String[] types = new String[parameterTypes.length];
      for (int i = 0; i < parameterTypes.length; i++) {
        types[i] = ReflectUtils.getName(parameterTypes[i]);
      }
      Object[] args = PojoUtils.generalize(arguments);

      invocation2.setMethodName(Constants.$INVOKE);
      invocation2.setParameterTypes(GENERIC_PARAMETER_TYPES);
      invocation2.setArguments(new Object[] {methodName, types, args});
      Result result = invoker.invoke(invocation2);

      if (!result.hasException()) {
        Object value = result.getValue();
        try {
          Method method = invoker.getInterface().getMethod(methodName, parameterTypes);
          return new RpcResult(
              PojoUtils.realize(value, method.getReturnType(), method.getGenericReturnType()));
        } catch (NoSuchMethodException e) {
          throw new RpcException(e.getMessage(), e);
        }
      } else if (result.getException() instanceof GenericException) {
        GenericException exception = (GenericException) result.getException();
        try {
          String className = exception.getExceptionClass();
          Class<?> clazz = ReflectUtils.forName(className);
          Throwable targetException = null;
          Throwable lastException = null;
          try {
            targetException = (Throwable) clazz.newInstance();
          } catch (Throwable e) {
            lastException = e;
            for (Constructor<?> constructor : clazz.getConstructors()) {
              try {
                targetException =
                    (Throwable)
                        constructor.newInstance(new Object[constructor.getParameterTypes().length]);
                break;
              } catch (Throwable e1) {
                lastException = e1;
              }
            }
          }
          if (targetException != null) {
            try {
              Field field = Throwable.class.getDeclaredField("detailMessage");
              if (!field.isAccessible()) {
                field.setAccessible(true);
              }
              field.set(targetException, exception.getExceptionMessage());
            } catch (Throwable e) {
              logger.warn(e.getMessage(), e);
            }
            result = new RpcResult(targetException);
          } else if (lastException != null) {
            throw lastException;
          }
        } catch (Throwable e) {
          throw new RpcException(
              "Can not deserialize exception "
                  + exception.getExceptionClass()
                  + ", message: "
                  + exception.getExceptionMessage(),
              e);
        }
      }
      return result;
    }

    if (invocation.getMethodName().equals(Constants.$INVOKE)
        && invocation.getArguments() != null
        && invocation.getArguments().length == 3
        && ProtocolUtils.isGeneric(generic)) {

      if (ProtocolUtils.isJavaGenericSerialization(generic)) {
        Object[] args = (Object[]) invocation.getArguments()[2];

        for (Object arg : args) {
          if (!(byte[].class == arg.getClass())) {
            error(arg.getClass().getName());
          }
        }
      }

      ((RpcInvocation) invocation)
          .setAttachment(
              Constants.GENERIC_KEY, invoker.getUrl().getParameter(Constants.GENERIC_KEY));
    }
    return invoker.invoke(invocation);
  }

  private void error(String type) throws RpcException {
    throw new RpcException(
        new StringBuilder(32)
            .append("Generic serialization [")
            .append(Constants.GENERIC_SERIALIZATION_NATIVE_JAVA)
            .append("] only support message type ")
            .append(byte[].class)
            .append(" and your message type is ")
            .append(type)
            .toString());
  }
}
Exemple #4
0
/**
 * ExchangeCodec.
 *
 * @author qianlei
 * @author william.liangf
 */
public class ExchangeCodec extends TelnetCodec {

  private static final Logger logger = LoggerFactory.getLogger(ExchangeCodec.class);

  // header length.
  protected static final int HEADER_LENGTH = 16;

  // magic header.
  protected static final short MAGIC = (short) 0xdabb;

  protected static final byte MAGIC_HIGH = Bytes.short2bytes(MAGIC)[0];

  protected static final byte MAGIC_LOW = Bytes.short2bytes(MAGIC)[1];

  // message flag.
  protected static final byte FLAG_REQUEST = (byte) 0x80;

  protected static final byte FLAG_TWOWAY = (byte) 0x40;

  protected static final byte FLAG_EVENT = (byte) 0x20;

  protected static final int SERIALIZATION_MASK = 0x1f;

  public Short getMagicCode() {
    return MAGIC;
  }

  public void encode(Channel channel, ChannelBuffer buffer, Object msg) throws IOException {
    if (msg instanceof Request) {
      encodeRequest(channel, buffer, (Request) msg);
    } else if (msg instanceof Response) {
      encodeResponse(channel, buffer, (Response) msg);
    } else {
      super.encode(channel, buffer, msg);
    }

    // TODO modified by lishen
    //        System.out.println(">>>>>>>>>>>>>>>>>>>>>> the resulting byte size of encoding is " +
    // buffer.readableBytes());
    if (logger.isTraceEnabled()) {
      logger.trace("the resulting byte size of encoding is " + buffer.readableBytes());
    }
  }

  public Object decode(Channel channel, ChannelBuffer buffer) throws IOException {
    int readable = buffer.readableBytes();
    byte[] header = new byte[Math.min(readable, HEADER_LENGTH)];
    buffer.readBytes(header);
    return decode(channel, buffer, readable, header);
  }

  protected Object decode(Channel channel, ChannelBuffer buffer, int readable, byte[] header)
      throws IOException {
    // check magic number.
    if (readable > 0 && header[0] != MAGIC_HIGH || readable > 1 && header[1] != MAGIC_LOW) {
      int length = header.length;
      if (header.length < readable) {
        header = Bytes.copyOf(header, readable);
        buffer.readBytes(header, length, readable - length);
      }
      for (int i = 1; i < header.length - 1; i++) {
        if (header[i] == MAGIC_HIGH && header[i + 1] == MAGIC_LOW) {
          buffer.readerIndex(buffer.readerIndex() - header.length + i);
          header = Bytes.copyOf(header, i);
          break;
        }
      }
      return super.decode(channel, buffer, readable, header);
    }
    // check length.
    if (readable < HEADER_LENGTH) {
      return DecodeResult.NEED_MORE_INPUT;
    }

    // get data length.
    int len = Bytes.bytes2int(header, 12);
    checkPayload(channel, len);

    int tt = len + HEADER_LENGTH;
    if (readable < tt) {
      return DecodeResult.NEED_MORE_INPUT;
    }

    // limit input stream.
    ChannelBufferInputStream is = new ChannelBufferInputStream(buffer, len);

    try {
      return decodeBody(channel, is, header);
    } finally {
      if (is.available() > 0) {
        try {
          if (logger.isWarnEnabled()) {
            logger.warn("Skip input stream " + is.available());
          }
          StreamUtils.skipUnusedStream(is);
        } catch (IOException e) {
          logger.warn(e.getMessage(), e);
        }
      }
    }
  }

  protected Object decodeBody(Channel channel, InputStream is, byte[] header) throws IOException {
    byte flag = header[2], proto = (byte) (flag & SERIALIZATION_MASK);
    Serialization s = CodecSupport.getSerialization(channel.getUrl(), proto);
    ObjectInput in = s.deserialize(channel.getUrl(), is);
    // get request id.
    long id = Bytes.bytes2long(header, 4);
    if ((flag & FLAG_REQUEST) == 0) {
      // decode response.
      Response res = new Response(id);
      if ((flag & FLAG_EVENT) != 0) {
        res.setEvent(Response.HEARTBEAT_EVENT);
      }
      // get status.
      byte status = header[3];
      res.setStatus(status);
      if (status == Response.OK) {
        try {
          Object data;
          if (res.isHeartbeat()) {
            data = decodeHeartbeatData(channel, in);
          } else if (res.isEvent()) {
            data = decodeEventData(channel, in);
          } else {
            data = decodeResponseData(channel, in, getRequestData(id));
          }
          res.setResult(data);
        } catch (Throwable t) {
          res.setStatus(Response.CLIENT_ERROR);
          res.setErrorMessage(StringUtils.toString(t));
        }
      } else {
        res.setErrorMessage(in.readUTF());
      }
      return res;
    } else {
      // decode request.
      Request req = new Request(id);
      req.setVersion("2.0.0");
      req.setTwoWay((flag & FLAG_TWOWAY) != 0);
      if ((flag & FLAG_EVENT) != 0) {
        req.setEvent(Request.HEARTBEAT_EVENT);
      }
      try {
        Object data;
        if (req.isHeartbeat()) {
          data = decodeHeartbeatData(channel, in);
        } else if (req.isEvent()) {
          data = decodeEventData(channel, in);
        } else {
          data = decodeRequestData(channel, in);
        }
        req.setData(data);
      } catch (Throwable t) {
        // bad request
        req.setBroken(true);
        req.setData(t);
      }
      return req;
    }
  }

  protected Object getRequestData(long id) {
    DefaultFuture future = DefaultFuture.getFuture(id);
    if (future == null) return null;
    Request req = future.getRequest();
    if (req == null) return null;
    return req.getData();
  }

  protected void encodeRequest(Channel channel, ChannelBuffer buffer, Request req)
      throws IOException {
    Serialization serialization = getSerialization(channel);
    // header.
    byte[] header = new byte[HEADER_LENGTH];
    // set magic number.
    Bytes.short2bytes(MAGIC, header);

    // set request and serialization flag.
    header[2] = (byte) (FLAG_REQUEST | serialization.getContentTypeId());

    if (req.isTwoWay()) header[2] |= FLAG_TWOWAY;
    if (req.isEvent()) header[2] |= FLAG_EVENT;

    // set request id.
    Bytes.long2bytes(req.getId(), header, 4);

    // encode request data.
    int savedWriteIndex = buffer.writerIndex();
    buffer.writerIndex(savedWriteIndex + HEADER_LENGTH);
    ChannelBufferOutputStream bos = new ChannelBufferOutputStream(buffer);
    ObjectOutput out = serialization.serialize(channel.getUrl(), bos);
    try {
      if (req.isEvent()) {
        encodeEventData(channel, out, req.getData());
      } else {
        encodeRequestData(channel, out, req.getData());
      }
      out.flushBuffer();
    } finally {
      // modified by lishen
      if (out instanceof Cleanable) {
        ((Cleanable) out).cleanup();
      }
    }

    bos.flush();
    bos.close();
    int len = bos.writtenBytes();
    checkPayload(channel, len);
    Bytes.int2bytes(len, header, 12);

    // write
    buffer.writerIndex(savedWriteIndex);
    buffer.writeBytes(header); // write header.
    buffer.writerIndex(savedWriteIndex + HEADER_LENGTH + len);
  }

  protected void encodeResponse(Channel channel, ChannelBuffer buffer, Response res)
      throws IOException {
    try {
      Serialization serialization = getSerialization(channel);
      // header.
      byte[] header = new byte[HEADER_LENGTH];
      // set magic number.
      Bytes.short2bytes(MAGIC, header);
      // set request and serialization flag.
      header[2] = serialization.getContentTypeId();
      if (res.isHeartbeat()) header[2] |= FLAG_EVENT;
      // set response status.
      byte status = res.getStatus();
      header[3] = status;
      // set request id.
      Bytes.long2bytes(res.getId(), header, 4);

      int savedWriteIndex = buffer.writerIndex();
      buffer.writerIndex(savedWriteIndex + HEADER_LENGTH);
      ChannelBufferOutputStream bos = new ChannelBufferOutputStream(buffer);
      ObjectOutput out = serialization.serialize(channel.getUrl(), bos);
      try {
        // encode response data or error message.
        if (status == Response.OK) {
          if (res.isHeartbeat()) {
            encodeHeartbeatData(channel, out, res.getResult());
          } else {
            encodeResponseData(channel, out, res.getResult());
          }
        } else out.writeUTF(res.getErrorMessage());
        out.flushBuffer();
      } finally {
        // modified by lishen
        if (out instanceof Cleanable) {
          ((Cleanable) out).cleanup();
        }
      }

      bos.flush();
      bos.close();

      int len = bos.writtenBytes();
      checkPayload(channel, len);
      Bytes.int2bytes(len, header, 12);
      // write
      buffer.writerIndex(savedWriteIndex);
      buffer.writeBytes(header); // write header.
      buffer.writerIndex(savedWriteIndex + HEADER_LENGTH + len);
    } catch (Throwable t) {
      // 发送失败信息给Consumer,否则Consumer只能等超时了
      if (!res.isEvent() && res.getStatus() != Response.BAD_RESPONSE) {
        try {
          // FIXME 在Codec中打印出错日志?在IoHanndler的caught中统一处理?
          logger.warn(
              "Fail to encode response: "
                  + res
                  + ", send bad_response info instead, cause: "
                  + t.getMessage(),
              t);

          Response r = new Response(res.getId(), res.getVersion());
          r.setStatus(Response.BAD_RESPONSE);
          r.setErrorMessage(
              "Failed to send response: " + res + ", cause: " + StringUtils.toString(t));
          channel.send(r);

          return;
        } catch (RemotingException e) {
          logger.warn(
              "Failed to send bad_response info back: " + res + ", cause: " + e.getMessage(), e);
        }
      }

      // 重新抛出收到的异常
      if (t instanceof IOException) {
        throw (IOException) t;
      } else if (t instanceof RuntimeException) {
        throw (RuntimeException) t;
      } else if (t instanceof Error) {
        throw (Error) t;
      } else {
        throw new RuntimeException(t.getMessage(), t);
      }
    }
  }

  @Override
  protected Object decodeData(ObjectInput in) throws IOException {
    return decodeRequestData(in);
  }

  @Deprecated
  protected Object decodeHeartbeatData(ObjectInput in) throws IOException {
    try {
      return in.readObject();
    } catch (ClassNotFoundException e) {
      throw new IOException(StringUtils.toString("Read object failed.", e));
    }
  }

  protected Object decodeRequestData(ObjectInput in) throws IOException {
    try {
      return in.readObject();
    } catch (ClassNotFoundException e) {
      throw new IOException(StringUtils.toString("Read object failed.", e));
    }
  }

  protected Object decodeResponseData(ObjectInput in) throws IOException {
    try {
      return in.readObject();
    } catch (ClassNotFoundException e) {
      throw new IOException(StringUtils.toString("Read object failed.", e));
    }
  }

  @Override
  protected void encodeData(ObjectOutput out, Object data) throws IOException {
    encodeRequestData(out, data);
  }

  private void encodeEventData(ObjectOutput out, Object data) throws IOException {
    out.writeObject(data);
  }

  @Deprecated
  protected void encodeHeartbeatData(ObjectOutput out, Object data) throws IOException {
    encodeEventData(out, data);
  }

  protected void encodeRequestData(ObjectOutput out, Object data) throws IOException {
    out.writeObject(data);
  }

  protected void encodeResponseData(ObjectOutput out, Object data) throws IOException {
    out.writeObject(data);
  }

  @Override
  protected Object decodeData(Channel channel, ObjectInput in) throws IOException {
    return decodeRequestData(channel, in);
  }

  protected Object decodeEventData(Channel channel, ObjectInput in) throws IOException {
    try {
      return in.readObject();
    } catch (ClassNotFoundException e) {
      throw new IOException(StringUtils.toString("Read object failed.", e));
    }
  }

  @Deprecated
  protected Object decodeHeartbeatData(Channel channel, ObjectInput in) throws IOException {
    try {
      return in.readObject();
    } catch (ClassNotFoundException e) {
      throw new IOException(StringUtils.toString("Read object failed.", e));
    }
  }

  protected Object decodeRequestData(Channel channel, ObjectInput in) throws IOException {
    return decodeRequestData(in);
  }

  protected Object decodeResponseData(Channel channel, ObjectInput in) throws IOException {
    return decodeResponseData(in);
  }

  protected Object decodeResponseData(Channel channel, ObjectInput in, Object requestData)
      throws IOException {
    return decodeResponseData(channel, in);
  }

  @Override
  protected void encodeData(Channel channel, ObjectOutput out, Object data) throws IOException {
    encodeRequestData(channel, out, data);
  }

  private void encodeEventData(Channel channel, ObjectOutput out, Object data) throws IOException {
    encodeEventData(out, data);
  }

  @Deprecated
  protected void encodeHeartbeatData(Channel channel, ObjectOutput out, Object data)
      throws IOException {
    encodeHeartbeatData(out, data);
  }

  protected void encodeRequestData(Channel channel, ObjectOutput out, Object data)
      throws IOException {
    encodeRequestData(out, data);
  }

  protected void encodeResponseData(Channel channel, ObjectOutput out, Object data)
      throws IOException {
    encodeResponseData(out, data);
  }
}
/**
 * 包装的一个chanelhandler 提供线程池给子类调度用 具体操作可以看子类的覆盖 适配
 *
 * @author wuzl
 */
public class WrappedChannelHandler implements ChannelHandlerDelegate {

  protected static final Logger logger = LoggerFactory.getLogger(WrappedChannelHandler.class);
  // 初始化共享的线程池
  protected static final ExecutorService SHARED_EXECUTOR =
      Executors.newCachedThreadPool(new NamedThreadFactory("DubboSharedHandler", true));
  // 对象独自的线程池
  protected final ExecutorService executor;

  protected final ChannelHandler handler;

  protected final URL url;

  public WrappedChannelHandler(ChannelHandler handler, URL url) {
    this.handler = handler;
    this.url = url;
    // 从扩展实现中初始化线程池
    executor =
        (ExecutorService)
            ExtensionLoader.getExtensionLoader(ThreadPool.class)
                .getAdaptiveExtension()
                .getExecutor(url);

    String componentKey = Constants.EXECUTOR_SERVICE_COMPONENT_KEY;
    if (Constants.CONSUMER_SIDE.equalsIgnoreCase(url.getParameter(Constants.SIDE_KEY))) {
      componentKey = Constants.CONSUMER_SIDE;
    }
    DataStore dataStore = ExtensionLoader.getExtensionLoader(DataStore.class).getDefaultExtension();
    dataStore.put(componentKey, Integer.toString(url.getPort()), executor); // 保存起来
  }

  public void close() {
    try {
      if (executor instanceof ExecutorService) {
        ((ExecutorService) executor).shutdown();
      }
    } catch (Throwable t) {
      logger.warn("fail to destroy thread pool of server: " + t.getMessage(), t);
    }
  }

  public void connected(Channel channel) throws RemotingException {
    handler.connected(channel);
  }

  public void disconnected(Channel channel) throws RemotingException {
    handler.disconnected(channel);
  }

  public void sent(Channel channel, Object message) throws RemotingException {
    handler.sent(channel, message);
  }

  public void received(Channel channel, Object message) throws RemotingException {
    handler.received(channel, message);
  }

  public void caught(Channel channel, Throwable exception) throws RemotingException {
    handler.caught(channel, exception);
  }

  public ExecutorService getExecutor() {
    return executor;
  }

  public ChannelHandler getHandler() {
    if (handler instanceof ChannelHandlerDelegate) {
      return ((ChannelHandlerDelegate) handler).getHandler();
    } else {
      return handler;
    }
  }

  public URL getUrl() {
    return url;
  }
}
Exemple #6
0
public class RedisTemplate {
  private static final Logger logger = LoggerFactory.getLogger(RedisTemplate.class);

  private ShardedJedisPool masterShardedJedisPool;

  public void setMasterShardedJedisPool(ShardedJedisPool masterShardedJedisPool) {
    this.masterShardedJedisPool = masterShardedJedisPool;
  }

  public void setSlaveShardedJedisPool(ShardedJedisPool slaveShardedJedisPool) {
    this.slaveShardedJedisPool = slaveShardedJedisPool;
  }

  private ShardedJedisPool slaveShardedJedisPool;

  /**
   * 设置一个key的过期时间(单位:秒)
   *
   * @param key key值
   * @param seconds 多少秒后过期
   * @return 1:设置了过期时间 0:没有设置过期时间/不能设置过期时间
   */
  public long expire(String key, int seconds) {
    if (key == null || key.equals("")) {
      return 0;
    }

    ShardedJedis shardedJedis = null;
    try {
      shardedJedis = masterShardedJedisPool.getResource();
      return shardedJedis.expire(key, seconds);
    } catch (Exception ex) {
      logger.error("EXPIRE error[key=" + key + " seconds=" + seconds + "]" + ex.getMessage(), ex);
    } finally {
      returnResource(shardedJedis);
    }
    return 0;
  }

  /**
   * 设置一个key在某个时间点过期
   *
   * @param key key值
   * @param unixTimestamp unix时间戳,从1970-01-01 00:00:00开始到现在的秒数
   * @return 1:设置了过期时间 0:没有设置过期时间/不能设置过期时间
   */
  public long expireAt(String key, int unixTimestamp) {
    if (key == null || key.equals("")) {
      return 0;
    }

    ShardedJedis shardedJedis = null;
    try {
      shardedJedis = masterShardedJedisPool.getResource();
      return shardedJedis.expireAt(key, unixTimestamp);
    } catch (Exception ex) {
      logger.error(
          "EXPIRE error[key=" + key + " unixTimestamp=" + unixTimestamp + "]" + ex.getMessage(),
          ex);
    } finally {
      returnResource(shardedJedis);
    }
    return 0;
  }

  /**
   * 截断一个List
   *
   * @param key 列表key
   * @param start 开始位置 从0开始
   * @param end 结束位置
   * @return 状态码
   */
  public String trimList(String key, long start, long end) {
    if (key == null || key.equals("")) {
      return "-";
    }
    ShardedJedis shardedJedis = null;
    try {
      shardedJedis = slaveShardedJedisPool.getResource();
      return shardedJedis.ltrim(key, start, end);
    } catch (Exception ex) {
      logger.error(
          "LTRIM 出错[key=" + key + " start=" + start + " end=" + end + "]" + ex.getMessage(), ex);
    } finally {
      returnResource(shardedJedis);
    }
    return "-";
  }

  /**
   * 检查Set长度
   *
   * @param key
   * @return
   */
  public long countSet(String key) {
    if (key == null) {
      return 0;
    }
    ShardedJedis shardedJedis = null;
    try {
      shardedJedis = slaveShardedJedisPool.getResource();
      return shardedJedis.scard(key);
    } catch (Exception ex) {
      logger.error("countSet error.", ex);
    } finally {
      returnResource(shardedJedis);
    }
    return 0;
  }

  /**
   * 添加到Set中(同时设置过期时间)
   *
   * @param key key值
   * @param seconds 过期时间 单位s
   * @param value
   * @return
   */
  public boolean addSet(String key, int seconds, String... value) {
    boolean result = addSet(key, value);
    if (result) {
      long i = expire(key, seconds);
      return i == 1;
    }
    return false;
  }

  /**
   * 添加到Set中
   *
   * @param key
   * @param value
   * @return
   */
  public boolean addSet(String key, String... value) {
    if (key == null || value == null) {
      return false;
    }
    ShardedJedis shardedJedis = null;
    try {
      shardedJedis = masterShardedJedisPool.getResource();
      shardedJedis.sadd(key, value);
      return true;
    } catch (Exception ex) {
      logger.error("setList error.", ex);
    } finally {
      returnResource(shardedJedis);
    }
    return false;
  }

  /**
   * @param key
   * @param value
   * @return 判断值是否包含在set中
   */
  public boolean containsInSet(String key, String value) {
    if (key == null || value == null) {
      return false;
    }
    ShardedJedis shardedJedis = null;
    try {
      shardedJedis = slaveShardedJedisPool.getResource();
      return shardedJedis.sismember(key, value);
    } catch (Exception ex) {
      logger.error("setList error.", ex);
    } finally {
      returnResource(shardedJedis);
    }
    return false;
  }

  /**
   * 获取Set
   *
   * @param key
   * @return
   */
  public Set<String> getSet(String key) {
    ShardedJedis shardedJedis = null;
    try {
      shardedJedis = slaveShardedJedisPool.getResource();
      return shardedJedis.smembers(key);
    } catch (Exception ex) {
      logger.error("getList error.", ex);
    } finally {
      returnResource(shardedJedis);
    }
    return null;
  }

  /**
   * 从set中删除value
   *
   * @param key
   * @return
   */
  public boolean removeSetValue(String key, String... value) {
    ShardedJedis shardedJedis = null;
    try {
      shardedJedis = masterShardedJedisPool.getResource();
      shardedJedis.srem(key, value);
      return true;
    } catch (Exception ex) {
      logger.error("getList error.", ex);
    } finally {
      returnResource(shardedJedis);
    }
    return false;
  }

  /**
   * 从list中删除value 默认count 1
   *
   * @param key
   * @param values 值list
   * @return
   */
  public int removeListValue(String key, List<String> values) {
    return removeListValue(key, 1, values);
  }

  /**
   * 从list中删除value
   *
   * @param key
   * @param count
   * @param values 值list
   * @return
   */
  public int removeListValue(String key, long count, List<String> values) {
    int result = 0;
    if (values != null && values.size() > 0) {
      for (String value : values) {
        if (removeListValue(key, count, value)) {
          result++;
        }
      }
    }
    return result;
  }

  /**
   * 从list中删除value
   *
   * @param key
   * @param count 要删除个数
   * @param value
   * @return
   */
  public boolean removeListValue(String key, long count, String value) {
    ShardedJedis shardedJedis = null;
    try {
      shardedJedis = masterShardedJedisPool.getResource();
      shardedJedis.lrem(key, count, value);
      return true;
    } catch (Exception ex) {
      logger.error("getList error.", ex);
      ;
    } finally {
      returnResource(shardedJedis);
    }
    return false;
  }

  /**
   * 截取List
   *
   * @param key
   * @param start 起始位置
   * @param end 结束位置
   * @return
   */
  public List<String> rangeList(String key, long start, long end) {
    if (key == null || key.equals("")) {
      return null;
    }
    ShardedJedis shardedJedis = null;
    try {
      shardedJedis = slaveShardedJedisPool.getResource();
      return shardedJedis.lrange(key, start, end);
    } catch (Exception ex) {
      logger.error(
          "rangeList 出错[key=" + key + " start=" + start + " end=" + end + "]" + ex.getMessage(),
          ex);
    } finally {
      returnResource(shardedJedis);
    }
    return null;
  }

  /**
   * 检查List长度
   *
   * @param key
   * @return
   */
  public long countList(String key) {
    if (key == null) {
      return 0;
    }
    ShardedJedis shardedJedis = null;
    try {
      shardedJedis = slaveShardedJedisPool.getResource();
      return shardedJedis.llen(key);
    } catch (Exception ex) {
      logger.error("countList error.", ex);
    } finally {
      returnResource(shardedJedis);
    }
    return 0;
  }

  /**
   * 添加到List中(同时设置过期时间)
   *
   * @param key key值
   * @param seconds 过期时间 单位s
   * @param value
   * @return
   */
  public boolean addList(String key, int seconds, String... value) {
    boolean result = addList(key, value);
    if (result) {
      long i = expire(key, seconds);
      return i == 1;
    }
    return false;
  }

  /**
   * 添加到List
   *
   * @param key
   * @param value
   * @return
   */
  public boolean addList(String key, String... value) {
    if (key == null || value == null) {
      return false;
    }
    ShardedJedis shardedJedis = null;
    try {
      shardedJedis = masterShardedJedisPool.getResource();
      shardedJedis.lpush(key, value);
      return true;
    } catch (Exception ex) {
      logger.error("setList error.", ex);
    } finally {
      returnResource(shardedJedis);
    }
    return false;
  }

  /**
   * 添加到List(只新增)
   *
   * @param key
   * @param value
   * @return
   */
  public boolean addList(String key, List<String> list) {
    if (key == null || list == null || list.size() == 0) {
      return false;
    }
    for (String value : list) {
      addList(key, value);
    }
    return true;
  }

  /**
   * 获取List
   *
   * @param key
   * @return
   */
  public List<String> getList(String key) {
    ShardedJedis shardedJedis = null;
    try {
      shardedJedis = slaveShardedJedisPool.getResource();
      return shardedJedis.lrange(key, 0, -1);
    } catch (Exception ex) {
      logger.error("getList error.", ex);
    } finally {
      returnResource(shardedJedis);
    }
    return null;
  }

  /**
   * 设置HashSet对象
   *
   * @param domain 域名
   * @param key 键值
   * @param value Json String or String value
   * @return
   */
  public boolean setHSet(String domain, String key, String value) {
    if (value == null) return false;
    ShardedJedis shardedJedis = null;
    try {
      shardedJedis = masterShardedJedisPool.getResource();
      shardedJedis.hset(domain, key, value);
      return true;
    } catch (Exception ex) {
      logger.error("setHSet error.", ex);
    } finally {
      returnResource(shardedJedis);
    }
    return false;
  }

  /**
   * 获得HashSet对象
   *
   * @param domain 域名
   * @param key 键值
   * @return Json String or String value
   */
  public String getHSet(String domain, String key) {
    ShardedJedis shardedJedis = null;
    try {
      shardedJedis = slaveShardedJedisPool.getResource();
      return shardedJedis.hget(domain, key);
    } catch (Exception ex) {
      logger.error("getHSet error.", ex);
    } finally {
      returnResource(shardedJedis);
    }
    return null;
  }

  /**
   * 删除HashSet对象
   *
   * @param domain 域名
   * @param key 键值
   * @return 删除的记录数
   */
  public long delHSet(String domain, String key) {
    ShardedJedis shardedJedis = null;
    long count = 0;
    try {
      shardedJedis = masterShardedJedisPool.getResource();
      count = shardedJedis.hdel(domain, key);
    } catch (Exception ex) {
      logger.error("delHSet error.", ex);
    } finally {
      returnResource(shardedJedis);
    }
    return count;
  }

  /**
   * 删除HashSet对象
   *
   * @param domain 域名
   * @param key 键值
   * @return 删除的记录数
   */
  public long delHSet(String domain, String... key) {
    ShardedJedis shardedJedis = null;
    long count = 0;
    try {
      shardedJedis = masterShardedJedisPool.getResource();
      count = shardedJedis.hdel(domain, key);
    } catch (Exception ex) {
      logger.error("delHSet error.", ex);
    } finally {
      returnResource(shardedJedis);
    }
    return count;
  }

  /**
   * 判断key是否存在
   *
   * @param domain 域名
   * @param key 键值
   * @return
   */
  public boolean existsHSet(String domain, String key) {
    ShardedJedis shardedJedis = null;
    boolean isExist = false;
    try {
      shardedJedis = slaveShardedJedisPool.getResource();
      isExist = shardedJedis.hexists(domain, key);
    } catch (Exception ex) {
      logger.error("existsHSet error.", ex);
    } finally {
      returnResource(shardedJedis);
    }
    return isExist;
  }

  /**
   * 全局扫描hset
   *
   * @param match field匹配模式
   * @return
   */
  public List<Map.Entry<String, String>> scanHSet(String domain, String match) {
    ShardedJedis shardedJedis = null;
    try {
      int cursor = 0;
      shardedJedis = slaveShardedJedisPool.getResource();
      ScanParams scanParams = new ScanParams();
      scanParams.match(match);
      Jedis jedis = shardedJedis.getShard(domain);
      ScanResult<Map.Entry<String, String>> scanResult;
      List<Map.Entry<String, String>> list = new ArrayList<Map.Entry<String, String>>();
      do {
        scanResult = jedis.hscan(domain, String.valueOf(cursor), scanParams);
        list.addAll(scanResult.getResult());
        cursor = Integer.parseInt(scanResult.getStringCursor());
      } while (cursor > 0);
      return list;
    } catch (Exception ex) {
      logger.error("scanHSet error.", ex);
    } finally {
      returnResource(shardedJedis);
    }
    return null;
  }

  /**
   * 返回 domain 指定的哈希集中所有字段的value值
   *
   * @param domain
   * @return
   */
  public List<String> hvals(String domain) {
    ShardedJedis shardedJedis = null;
    List<String> retList = null;
    try {
      shardedJedis = slaveShardedJedisPool.getResource();
      retList = shardedJedis.hvals(domain);
    } catch (Exception ex) {
      logger.error("hvals error.", ex);
    } finally {
      returnResource(shardedJedis);
    }
    return retList;
  }

  /**
   * 返回 domain 指定的哈希集中所有字段的key值
   *
   * @param domain
   * @return
   */
  public Set<String> hkeys(String domain) {
    ShardedJedis shardedJedis = null;
    Set<String> retList = null;
    try {
      shardedJedis = slaveShardedJedisPool.getResource();
      retList = shardedJedis.hkeys(domain);
    } catch (Exception ex) {
      logger.error("hkeys error.", ex);
    } finally {
      returnResource(shardedJedis);
    }
    return retList;
  }

  /**
   * 返回 domain 指定的哈希key值总数
   *
   * @param domain
   * @return
   */
  public long lenHset(String domain) {
    ShardedJedis shardedJedis = null;
    long retList = 0;
    try {
      shardedJedis = slaveShardedJedisPool.getResource();
      retList = shardedJedis.hlen(domain);
    } catch (Exception ex) {
      logger.error("hkeys error.", ex);
    } finally {
      returnResource(shardedJedis);
    }
    return retList;
  }

  /**
   * 设置排序集合
   *
   * @param key
   * @param score
   * @param value
   * @return
   */
  public boolean setSortedSet(String key, long score, String value) {
    ShardedJedis shardedJedis = null;
    try {
      shardedJedis = masterShardedJedisPool.getResource();
      shardedJedis.zadd(key, score, value);
      return true;
    } catch (Exception ex) {
      logger.error("setSortedSet error.", ex);
    } finally {
      returnResource(shardedJedis);
    }
    return false;
  }

  /**
   * 获得排序集合
   *
   * @param key
   * @param startScore
   * @param endScore
   * @param orderByDesc
   * @return
   */
  public Set<String> getSoredSet(String key, long startScore, long endScore, boolean orderByDesc) {
    ShardedJedis shardedJedis = null;
    try {
      shardedJedis = slaveShardedJedisPool.getResource();
      if (orderByDesc) {
        return shardedJedis.zrevrangeByScore(key, endScore, startScore);
      } else {
        return shardedJedis.zrangeByScore(key, startScore, endScore);
      }
    } catch (Exception ex) {
      logger.error("getSoredSet error.", ex);
    } finally {
      returnResource(shardedJedis);
    }
    return null;
  }

  /**
   * 计算排序长度
   *
   * @param key
   * @param startScore
   * @param endScore
   * @return
   */
  public long countSoredSet(String key, long startScore, long endScore) {
    ShardedJedis shardedJedis = null;
    try {
      shardedJedis = slaveShardedJedisPool.getResource();
      Long count = shardedJedis.zcount(key, startScore, endScore);
      return count == null ? 0L : count;
    } catch (Exception ex) {
      logger.error("countSoredSet error.", ex);
    } finally {
      returnResource(shardedJedis);
    }
    return 0L;
  }

  /**
   * 删除排序集合
   *
   * @param key
   * @param value
   * @return
   */
  public boolean delSortedSet(String key, String value) {
    ShardedJedis shardedJedis = null;
    try {
      shardedJedis = masterShardedJedisPool.getResource();
      long count = shardedJedis.zrem(key, value);
      return count > 0;
    } catch (Exception ex) {
      logger.error("delSortedSet error.", ex);
    } finally {
      returnResource(shardedJedis);
    }
    return false;
  }

  /**
   * 获得排序集合
   *
   * @param key
   * @param startRange
   * @param endRange
   * @param orderByDesc
   * @return
   */
  public Set<String> getSoredSetByRange(
      String key, int startRange, int endRange, boolean orderByDesc) {
    ShardedJedis shardedJedis = null;
    try {
      shardedJedis = slaveShardedJedisPool.getResource();
      if (orderByDesc) {
        return shardedJedis.zrevrange(key, startRange, endRange);
      } else {
        return shardedJedis.zrange(key, startRange, endRange);
      }
    } catch (Exception ex) {
      logger.error("getSoredSetByRange error.", ex);
    } finally {
      returnResource(shardedJedis);
    }
    return null;
  }

  /**
   * 获得排序打分
   *
   * @param key
   * @return
   */
  public Double getScore(String key, String member) {
    ShardedJedis shardedJedis = null;
    try {
      shardedJedis = slaveShardedJedisPool.getResource();
      return shardedJedis.zscore(key, member);
    } catch (Exception ex) {
      logger.error("getSoredSet error.", ex);
    } finally {
      returnResource(shardedJedis);
    }
    return null;
  }

  public boolean set(String key, String value, int second) {
    ShardedJedis shardedJedis = null;
    try {
      shardedJedis = masterShardedJedisPool.getResource();
      shardedJedis.setex(key, second, value);
      return true;
    } catch (Exception ex) {
      logger.error("set error.", ex);
    } finally {
      returnResource(shardedJedis);
    }
    return false;
  }

  public boolean set(String key, String value) {
    ShardedJedis shardedJedis = null;
    try {
      shardedJedis = masterShardedJedisPool.getResource();
      shardedJedis.set(key, value);
      return true;
    } catch (Exception ex) {
      logger.error("set error.", ex);
    } finally {
      returnResource(shardedJedis);
    }
    return false;
  }

  public String get(String key) {
    ShardedJedis shardedJedis = null;
    try {
      shardedJedis = slaveShardedJedisPool.getResource();
      return shardedJedis.get(key);
    } catch (Exception ex) {
      logger.error("get error.", ex);
      return null;
    } finally {
      returnResource(shardedJedis);
    }
  }

  public boolean del(String key) {
    ShardedJedis shardedJedis = null;
    try {
      shardedJedis = masterShardedJedisPool.getResource();
      shardedJedis.del(key);
      return true;
    } catch (Exception ex) {
      logger.error("del error.", ex);

    } finally {
      returnResource(shardedJedis);
    }
    return false;
  }

  public long incr(String key) {
    ShardedJedis shardedJedis = null;
    try {
      shardedJedis = masterShardedJedisPool.getResource();
      return shardedJedis.incr(key);
    } catch (Exception ex) {
      logger.error("incr error.", ex);
    } finally {
      returnResource(shardedJedis);
    }
    return 0;
  }

  public long decr(String key) {
    ShardedJedis shardedJedis = null;
    try {
      shardedJedis = masterShardedJedisPool.getResource();
      return shardedJedis.decr(key);
    } catch (Exception ex) {
      logger.error("incr error.", ex);
    } finally {
      returnResource(shardedJedis);
    }
    return 0;
  }

  private void returnResource(ShardedJedis shardedJedis) {
    try {
      shardedJedis.close();
    } catch (Exception e) {
      logger.error("returnResource error.", e);
    }
  }
}
/**
 * MinaServer mina用的是session类似于netty的chanel
 *
 * @author qian.lei
 * @author william.liangf
 * @author ding.lid
 */
public class MinaServer extends AbstractServer {

  private static final Logger logger = LoggerFactory.getLogger(MinaServer.class);

  private SocketAcceptor acceptor;

  public MinaServer(URL url, ChannelHandler handler) throws RemotingException {
    super(
        url,
        ChannelHandlers.wrap(handler, ExecutorUtil.setThreadName(url, SERVER_THREAD_POOL_NAME)));
  }

  @Override
  protected void doOpen() throws Throwable {
    // set thread pool.
    acceptor =
        new SocketAcceptor(
            getUrl().getPositiveParameter(Constants.IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS),
            Executors.newCachedThreadPool(new NamedThreadFactory("MinaServerWorker", true)));
    // config
    SocketAcceptorConfig cfg = (SocketAcceptorConfig) acceptor.getDefaultConfig();
    cfg.setThreadModel(ThreadModel.MANUAL);
    // set codec.
    acceptor
        .getFilterChain()
        .addLast(
            "codec", new ProtocolCodecFilter(new MinaCodecAdapter(getCodec(), getUrl(), this)));

    acceptor.bind(getBindAddress(), new MinaHandler(getUrl(), this));
  }

  @Override
  protected void doClose() throws Throwable {
    try {
      if (acceptor != null) {
        acceptor.unbind(getBindAddress());
      }
    } catch (Throwable e) {
      logger.warn(e.getMessage(), e);
    }
  }

  public Collection<Channel> getChannels() {
    Set<IoSession> sessions = acceptor.getManagedSessions(getBindAddress());
    Collection<Channel> channels = new HashSet<Channel>();
    for (IoSession session : sessions) {
      if (session.isConnected()) {
        channels.add(MinaChannel.getOrAddChannel(session, getUrl(), this));
      }
    }
    return channels;
  }

  public Channel getChannel(InetSocketAddress remoteAddress) {
    Set<IoSession> sessions = acceptor.getManagedSessions(getBindAddress());
    for (IoSession session : sessions) {
      if (session.getRemoteAddress().equals(remoteAddress)) {
        return MinaChannel.getOrAddChannel(session, getUrl(), this);
      }
    }
    return null;
  }

  public boolean isBound() {
    return acceptor.isManaged(getBindAddress());
  }
}
/**
 * AbstractRegistry. (SPI, Prototype, ThreadSafe)
 *
 * @author chao.liuc
 * @author william.liangf
 */
public abstract class AbstractRegistry implements Registry {

  // 日志输出
  protected final Logger logger = LoggerFactory.getLogger(getClass());

  // URL地址分隔符,用于文件缓存中,服务提供者URL分隔
  private static final char URL_SEPARATOR = ' ';

  // URL地址分隔正则表达式,用于解析文件缓存中服务提供者URL列表
  private static final String URL_SPLIT = "\\s+";

  private URL registryUrl;

  // 本地磁盘缓存文件
  private File file;

  // 本地磁盘缓存,其中特殊的key值.registies记录注册中心列表,其它均为notified服务提供者列表
  private final Properties properties = new Properties();

  // 文件缓存定时写入
  private final ExecutorService registryCacheExecutor =
      Executors.newFixedThreadPool(1, new NamedThreadFactory("DubboSaveRegistryCache", true));

  // 是否是同步保存文件
  private final boolean syncSaveFile;

  private final AtomicLong lastCacheChanged = new AtomicLong();

  private final Set<URL> registered = new ConcurrentHashSet<URL>();

  private final ConcurrentMap<URL, Set<NotifyListener>> subscribed =
      new ConcurrentHashMap<URL, Set<NotifyListener>>();

  private final ConcurrentMap<URL, Map<String, List<URL>>> notified =
      new ConcurrentHashMap<URL, Map<String, List<URL>>>();

  public AbstractRegistry(URL url) {
    setUrl(url);
    // 启动文件保存定时器
    syncSaveFile = url.getParameter(Constants.REGISTRY_FILESAVE_SYNC_KEY, false);
    String filename =
        url.getParameter(
            Constants.FILE_KEY,
            System.getProperty("user.home") + "/.dubbo/dubbo-registry-" + url.getHost() + ".cache");
    File file = null;
    if (ConfigUtils.isNotEmpty(filename)) {
      file = new File(filename);
      if (!file.exists() && file.getParentFile() != null && !file.getParentFile().exists()) {
        if (!file.getParentFile().mkdirs()) {
          throw new IllegalArgumentException(
              "Invalid registry store file "
                  + file
                  + ", cause: Failed to create directory "
                  + file.getParentFile()
                  + "!");
        }
      }
    }
    this.file = file;
    loadProperties();
    notify(url.getBackupUrls());
  }

  protected void setUrl(URL url) {
    if (url == null) {
      throw new IllegalArgumentException("registry url == null");
    }
    this.registryUrl = url;
  }

  public URL getUrl() {
    return registryUrl;
  }

  public Set<URL> getRegistered() {
    return registered;
  }

  public Map<URL, Set<NotifyListener>> getSubscribed() {
    return subscribed;
  }

  public Map<URL, Map<String, List<URL>>> getNotified() {
    return notified;
  }

  public File getCacheFile() {
    return file;
  }

  public Properties getCacheProperties() {
    return properties;
  }

  public AtomicLong getLastCacheChanged() {
    return lastCacheChanged;
  }

  private class SaveProperties implements Runnable {
    private long version;

    private SaveProperties(long version) {
      this.version = version;
    }

    public void run() {
      doSaveProperties(version);
    }
  }

  public void doSaveProperties(long version) {
    if (version < lastCacheChanged.get()) {
      return;
    }
    if (file == null) {
      return;
    }
    Properties newProperties = new Properties();
    // 保存之前先读取一遍,防止多个注册中心之间冲突
    InputStream in = null;
    try {
      if (file.exists()) {
        in = new FileInputStream(file);
        newProperties.load(in);
      }
    } catch (Throwable e) {
      logger.warn("Failed to load registry store file, cause: " + e.getMessage(), e);
    } finally {
      if (in != null) {
        try {
          in.close();
        } catch (IOException e) {
          logger.warn(e.getMessage(), e);
        }
      }
    }
    // 保存
    try {
      newProperties.putAll(properties);
      File lockfile = new File(file.getAbsolutePath() + ".lock");
      if (!lockfile.exists()) {
        lockfile.createNewFile();
      }
      RandomAccessFile raf = new RandomAccessFile(lockfile, "rw");
      try {
        FileChannel channel = raf.getChannel();
        try {
          FileLock lock = channel.tryLock();
          if (lock == null) {
            throw new IOException(
                "Can not lock the registry cache file "
                    + file.getAbsolutePath()
                    + ", ignore and retry later, maybe multi java process use the file, please config: dubbo.registry.file=xxx.properties");
          }
          // 保存
          try {
            if (!file.exists()) {
              file.createNewFile();
            }
            FileOutputStream outputFile = new FileOutputStream(file);
            try {
              newProperties.store(outputFile, "Dubbo Registry Cache");
            } finally {
              outputFile.close();
            }
          } finally {
            lock.release();
          }
        } finally {
          channel.close();
        }
      } finally {
        raf.close();
      }
    } catch (Throwable e) {
      if (version < lastCacheChanged.get()) {
        return;
      } else {
        registryCacheExecutor.execute(new SaveProperties(lastCacheChanged.incrementAndGet()));
      }
      logger.warn("Failed to save registry store file, cause: " + e.getMessage(), e);
    }
  }

  private void loadProperties() {
    if (file != null && file.exists()) {
      InputStream in = null;
      try {
        in = new FileInputStream(file);
        properties.load(in);
        if (logger.isInfoEnabled()) {
          logger.info("Load registry store file " + file + ", data: " + properties);
        }
      } catch (Throwable e) {
        logger.warn("Failed to load registry store file " + file, e);
      } finally {
        if (in != null) {
          try {
            in.close();
          } catch (IOException e) {
            logger.warn(e.getMessage(), e);
          }
        }
      }
    }
  }

  public List<URL> getCacheUrls(URL url) {
    for (Map.Entry<Object, Object> entry : properties.entrySet()) {
      String key = (String) entry.getKey();
      String value = (String) entry.getValue();
      if (key != null
          && key.length() > 0
          && key.equals(url.getServiceKey())
          && (Character.isLetter(key.charAt(0)) || key.charAt(0) == '_')
          && value != null
          && value.length() > 0) {
        String[] arr = value.trim().split(URL_SPLIT);
        List<URL> urls = new ArrayList<URL>();
        for (String u : arr) {
          urls.add(URL.valueOf(u));
        }
        return urls;
      }
    }
    return null;
  }

  public List<URL> lookup(URL url) {
    List<URL> result = new ArrayList<URL>();
    Map<String, List<URL>> notifiedUrls = getNotified().get(url);
    if (notifiedUrls != null && notifiedUrls.size() > 0) {
      for (List<URL> urls : notifiedUrls.values()) {
        for (URL u : urls) {
          if (!Constants.EMPTY_PROTOCOL.equals(u.getProtocol())) {
            result.add(u);
          }
        }
      }
    } else {
      final AtomicReference<List<URL>> reference = new AtomicReference<List<URL>>();
      NotifyListener listener =
          new NotifyListener() {
            public void notify(List<URL> urls) {
              reference.set(urls);
            }
          };
      subscribe(url, listener); // 订阅逻辑保证第一次notify后再返回
      List<URL> urls = reference.get();
      if (urls != null && urls.size() > 0) {
        for (URL u : urls) {
          if (!Constants.EMPTY_PROTOCOL.equals(u.getProtocol())) {
            result.add(u);
          }
        }
      }
    }
    return result;
  }

  public void register(URL url) {
    if (url == null) {
      throw new IllegalArgumentException("register url == null");
    }
    if (logger.isInfoEnabled()) {
      logger.info("Register: " + url);
    }
    registered.add(url);
  }

  public void unregister(URL url) {
    if (url == null) {
      throw new IllegalArgumentException("unregister url == null");
    }
    if (logger.isInfoEnabled()) {
      logger.info("Unregister: " + url);
    }
    registered.remove(url);
  }

  public void subscribe(URL url, NotifyListener listener) {
    if (url == null) {
      throw new IllegalArgumentException("subscribe url == null");
    }
    if (listener == null) {
      throw new IllegalArgumentException("subscribe listener == null");
    }
    if (logger.isInfoEnabled()) {
      logger.info("Subscribe: " + url);
    }
    Set<NotifyListener> listeners = subscribed.get(url);
    if (listeners == null) {
      subscribed.putIfAbsent(url, new ConcurrentHashSet<NotifyListener>());
      listeners = subscribed.get(url);
    }
    listeners.add(listener);
  }

  public void unsubscribe(URL url, NotifyListener listener) {
    if (url == null) {
      throw new IllegalArgumentException("unsubscribe url == null");
    }
    if (listener == null) {
      throw new IllegalArgumentException("unsubscribe listener == null");
    }
    if (logger.isInfoEnabled()) {
      logger.info("Unsubscribe: " + url);
    }
    Set<NotifyListener> listeners = subscribed.get(url);
    if (listeners != null) {
      listeners.remove(listener);
    }
  }

  protected void recover() throws Exception {
    // register
    Set<URL> recoverRegistered = new HashSet<URL>(getRegistered());
    if (!recoverRegistered.isEmpty()) {
      if (logger.isInfoEnabled()) {
        logger.info("Recover register url " + recoverRegistered);
      }
      for (URL url : recoverRegistered) {
        register(url);
      }
    }
    // subscribe
    Map<URL, Set<NotifyListener>> recoverSubscribed =
        new HashMap<URL, Set<NotifyListener>>(getSubscribed());
    if (!recoverSubscribed.isEmpty()) {
      if (logger.isInfoEnabled()) {
        logger.info("Recover subscribe url " + recoverSubscribed.keySet());
      }
      for (Map.Entry<URL, Set<NotifyListener>> entry : recoverSubscribed.entrySet()) {
        URL url = entry.getKey();
        for (NotifyListener listener : entry.getValue()) {
          subscribe(url, listener);
        }
      }
    }
  }

  protected static List<URL> filterEmpty(URL url, List<URL> urls) {
    if (urls == null || urls.size() == 0) {
      List<URL> result = new ArrayList<URL>(1);
      result.add(url.setProtocol(Constants.EMPTY_PROTOCOL));
      return result;
    }
    return urls;
  }

  protected void notify(List<URL> urls) {
    if (urls == null || urls.isEmpty()) return;

    for (Map.Entry<URL, Set<NotifyListener>> entry : getSubscribed().entrySet()) {
      URL url = entry.getKey();

      if (!UrlUtils.isMatch(url, urls.get(0))) {
        continue;
      }

      Set<NotifyListener> listeners = entry.getValue();
      if (listeners != null) {
        for (NotifyListener listener : listeners) {
          try {
            notify(url, listener, filterEmpty(url, urls));
          } catch (Throwable t) {
            logger.error(
                "Failed to notify registry event, urls: " + urls + ", cause: " + t.getMessage(), t);
          }
        }
      }
    }
  }

  protected void notify(URL url, NotifyListener listener, List<URL> urls) {
    if (url == null) {
      throw new IllegalArgumentException("notify url == null");
    }
    if (listener == null) {
      throw new IllegalArgumentException("notify listener == null");
    }
    if ((urls == null || urls.size() == 0)
        && !Constants.ANY_VALUE.equals(url.getServiceInterface())) {
      logger.warn("Ignore empty notify urls for subscribe url " + url);
      return;
    }
    if (logger.isInfoEnabled()) {
      logger.info("Notify urls for subscribe url " + url + ", urls: " + urls);
    }
    Map<String, List<URL>> result = new HashMap<String, List<URL>>();
    for (URL u : urls) {
      if (UrlUtils.isMatch(url, u)) {
        String category = u.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY);
        List<URL> categoryList = result.get(category);
        if (categoryList == null) {
          categoryList = new ArrayList<URL>();
          result.put(category, categoryList);
        }
        categoryList.add(u);
      }
    }
    if (result.size() == 0) {
      return;
    }
    Map<String, List<URL>> categoryNotified = notified.get(url);
    if (categoryNotified == null) {
      notified.putIfAbsent(url, new ConcurrentHashMap<String, List<URL>>());
      categoryNotified = notified.get(url);
    }
    for (Map.Entry<String, List<URL>> entry : result.entrySet()) {
      String category = entry.getKey();
      List<URL> categoryList = entry.getValue();
      categoryNotified.put(category, categoryList);
      saveProperties(url);
      listener.notify(categoryList);
    }
  }

  private void saveProperties(URL url) {
    if (file == null) {
      return;
    }

    try {
      StringBuilder buf = new StringBuilder();
      Map<String, List<URL>> categoryNotified = notified.get(url);
      if (categoryNotified != null) {
        for (List<URL> us : categoryNotified.values()) {
          for (URL u : us) {
            if (buf.length() > 0) {
              buf.append(URL_SEPARATOR);
            }
            buf.append(u.toFullString());
          }
        }
      }
      properties.setProperty(url.getServiceKey(), buf.toString());
      long version = lastCacheChanged.incrementAndGet();
      if (syncSaveFile) {
        doSaveProperties(version);
      } else {
        registryCacheExecutor.execute(new SaveProperties(version));
      }
    } catch (Throwable t) {
      logger.warn(t.getMessage(), t);
    }
  }

  public void destroy() {
    if (logger.isInfoEnabled()) {
      logger.info("Destroy registry:" + getUrl());
    }
    Set<URL> destroyRegistered = new HashSet<URL>(getRegistered());
    if (!destroyRegistered.isEmpty()) {
      for (URL url : new HashSet<URL>(getRegistered())) {
        if (url.getParameter(Constants.DYNAMIC_KEY, true)) {
          try {
            unregister(url);
            if (logger.isInfoEnabled()) {
              logger.info("Destroy unregister url " + url);
            }
          } catch (Throwable t) {
            logger.warn(
                "Failed to unregister url "
                    + url
                    + " to registry "
                    + getUrl()
                    + " on destroy, cause: "
                    + t.getMessage(),
                t);
          }
        }
      }
    }
    Map<URL, Set<NotifyListener>> destroySubscribed =
        new HashMap<URL, Set<NotifyListener>>(getSubscribed());
    if (!destroySubscribed.isEmpty()) {
      for (Map.Entry<URL, Set<NotifyListener>> entry : destroySubscribed.entrySet()) {
        URL url = entry.getKey();
        for (NotifyListener listener : entry.getValue()) {
          try {
            unsubscribe(url, listener);
            if (logger.isInfoEnabled()) {
              logger.info("Destroy unsubscribe url " + url);
            }
          } catch (Throwable t) {
            logger.warn(
                "Failed to unsubscribe url "
                    + url
                    + " to registry "
                    + getUrl()
                    + " on destroy, cause: "
                    + t.getMessage(),
                t);
          }
        }
      }
    }
  }

  public String toString() {
    return getUrl().toString();
  }
}
/**
 * AbstractRegistryService
 *
 * @author william.liangf
 */
public abstract class AbstractRegistryService implements RegistryService {

  // 日志输出
  protected final Logger logger = LoggerFactory.getLogger(getClass());

  // 已注册的服务
  // Map<serviceName, Map<url, queryString>>
  private final ConcurrentMap<String, List<URL>> registered =
      new ConcurrentHashMap<String, List<URL>>();

  // 已订阅的服务
  // Map<serviceName, queryString>
  private final ConcurrentMap<String, Map<String, String>> subscribed =
      new ConcurrentHashMap<String, Map<String, String>>();

  // 已通知的服务
  // Map<serviceName, Map<url, queryString>>
  private final ConcurrentMap<String, List<URL>> notified =
      new ConcurrentHashMap<String, List<URL>>();

  // 已订阅服务的监听器列表
  // Map<serviceName, List<notificationListener>>
  private final ConcurrentMap<String, List<NotifyListener>> notifyListeners =
      new ConcurrentHashMap<String, List<NotifyListener>>();

  public void register(URL url) {
    if (logger.isInfoEnabled()) {
      logger.info("Register service: " + url.getServiceKey() + ",url:" + url);
    }
    register(url.getServiceKey(), url);
  }

  public void unregister(URL url) {
    if (logger.isInfoEnabled()) {
      logger.info("Unregister service: " + url.getServiceKey() + ",url:" + url);
    }
    unregister(url.getServiceKey(), url);
  }

  public void subscribe(URL url, NotifyListener listener) {
    if (logger.isInfoEnabled()) {
      logger.info("Subscribe service: " + url.getServiceKey() + ",url:" + url);
    }
    subscribe(url.getServiceKey(), url, listener);
  }

  public void unsubscribe(URL url, NotifyListener listener) {
    if (logger.isInfoEnabled()) {
      logger.info("Unsubscribe service: " + url.getServiceKey() + ",url:" + url);
    }
    unsubscribe(url.getServiceKey(), url, listener);
  }

  public List<URL> lookup(URL url) {
    return getRegistered(url.getServiceKey());
  }

  public void register(String service, URL url) {
    if (service == null) {
      throw new IllegalArgumentException("service == null");
    }
    if (url == null) {
      throw new IllegalArgumentException("url == null");
    }
    List<URL> urls = registered.get(service);
    if (urls == null) {
      registered.putIfAbsent(service, new CopyOnWriteArrayList<URL>());
      urls = registered.get(service);
    }
    if (!urls.contains(url)) {
      urls.add(url);
    }
  }

  public void unregister(String service, URL url) {
    if (service == null) {
      throw new IllegalArgumentException("service == null");
    }
    if (url == null) {
      throw new IllegalArgumentException("url == null");
    }
    List<URL> urls = registered.get(service);
    if (urls != null) {
      URL deleteURL = null;
      for (URL u : urls) {
        if (u.toIdentityString().equals(url.toIdentityString())) {
          deleteURL = u;
          break;
        }
      }
      if (deleteURL != null) {
        urls.remove(deleteURL);
      }
    }
  }

  public void subscribe(String service, URL url, NotifyListener listener) {
    if (service == null) {
      throw new IllegalArgumentException("service == null");
    }
    if (url == null) {
      throw new IllegalArgumentException("parameters == null");
    }
    if (listener == null) {
      throw new IllegalArgumentException("listener == null");
    }
    subscribed.put(service, url.getParameters());
    addListener(service, listener);
  }

  public void unsubscribe(String service, URL url, NotifyListener listener) {
    if (service == null) {
      throw new IllegalArgumentException("service == null");
    }
    if (url == null) {
      throw new IllegalArgumentException("parameters == null");
    }
    if (listener == null) {
      throw new IllegalArgumentException("listener == null");
    }
    subscribed.remove(service);
    removeListener(service, listener);
  }

  // consumer 与 provider的 listener可以一起存储,都是根据服务名称共享
  private void addListener(final String service, final NotifyListener listener) {
    if (listener == null) {
      return;
    }
    List<NotifyListener> listeners = notifyListeners.get(service);
    if (listeners == null) {
      notifyListeners.putIfAbsent(service, new CopyOnWriteArrayList<NotifyListener>());
      listeners = notifyListeners.get(service);
    }
    if (listeners != null && !listeners.contains(listener)) {
      listeners.add(listener);
    }
  }

  private void removeListener(final String service, final NotifyListener listener) {
    if (listener == null) {
      return;
    }
    List<NotifyListener> listeners = notifyListeners.get(service);
    if (listeners != null) {
      listeners.remove(listener);
    }
  }

  private void doNotify(String service, List<URL> urls) {
    notified.put(service, urls);
    List<NotifyListener> listeners = notifyListeners.get(service);
    if (listeners != null) {
      for (NotifyListener listener : listeners) {
        try {
          notify(service, urls, listener);
        } catch (Throwable t) {
          logger.error(
              "Failed to notify registry event, service: "
                  + service
                  + ", urls: "
                  + urls
                  + ", cause: "
                  + t.getMessage(),
              t);
        }
      }
    }
  }

  protected void notify(String service, List<URL> urls, NotifyListener listener) {
    listener.notify(urls);
  }

  protected final void forbid(String service) {
    doNotify(service, new ArrayList<URL>(0));
  }

  protected final void notify(String service, List<URL> urls) {
    if (service == null || service.length() == 0 || urls == null || urls.size() == 0) {
      return;
    }
    doNotify(service, urls);
  }

  public Map<String, List<URL>> getRegistered() {
    return Collections.unmodifiableMap(registered);
  }

  public List<URL> getRegistered(String service) {
    return Collections.unmodifiableList(registered.get(service));
  }

  public Map<String, Map<String, String>> getSubscribed() {
    return Collections.unmodifiableMap(subscribed);
  }

  public Map<String, String> getSubscribed(String service) {
    return subscribed.get(service);
  }

  public Map<String, List<URL>> getNotified() {
    return Collections.unmodifiableMap(notified);
  }

  public List<URL> getNotified(String service) {
    return Collections.unmodifiableList(notified.get(service));
  }

  public Map<String, List<NotifyListener>> getListeners() {
    return Collections.unmodifiableMap(notifyListeners);
  }
}