/* (non-Javadoc)
   * @see org.eclipse.jetty.websocket.AbstractExtension#onFrame(byte, byte, org.eclipse.jetty.io.Buffer)
   */
  @Override
  public void onFrame(byte flags, byte opcode, Buffer buffer) {
    if (getConnection().isControl(opcode) || !isFlag(flags, 1)) {
      super.onFrame(flags, opcode, buffer);
      return;
    }

    if (buffer.array() == null) buffer = buffer.asMutableBuffer();

    int length = 0xff & buffer.get();
    if (length >= 0x7e) {
      int b = (length == 0x7f) ? 8 : 2;
      length = 0;
      while (b-- > 0) length = 0x100 * length + (0xff & buffer.get());
    }

    // TODO check a max framesize

    _inflater.setInput(buffer.array(), buffer.getIndex(), buffer.length());
    ByteArrayBuffer buf = new ByteArrayBuffer(length);
    try {
      while (_inflater.getRemaining() > 0) {
        int inflated = _inflater.inflate(buf.array(), buf.putIndex(), buf.space());
        if (inflated == 0) throw new DataFormatException("insufficient data");
        buf.setPutIndex(buf.putIndex() + inflated);
      }

      super.onFrame(clearFlag(flags, 1), opcode, buf);
    } catch (DataFormatException e) {
      LOG.warn(e);
      getConnection().close(WebSocketConnectionRFC6455.CLOSE_BAD_PAYLOAD, e.toString());
    }
  }
  @Override
  public Extension newInstance(ExtensionConfig config) {
    if (config == null) {
      return null;
    }

    String name = config.getName();
    if (StringUtil.isBlank(name)) {
      return null;
    }

    Class<? extends Extension> extClass = getExtension(name);
    if (extClass == null) {
      return null;
    }

    try {
      Extension ext = extClass.newInstance();
      if (ext instanceof AbstractExtension) {
        AbstractExtension aext = (AbstractExtension) ext;
        aext.setConfig(config);
        aext.setPolicy(policy);
        aext.setBufferPool(bufferPool);
      }
      return ext;
    } catch (InstantiationException | IllegalAccessException e) {
      throw new WebSocketException("Cannot instantiate extension: " + extClass, e);
    }
  }
  private AbstractExtensionWrapper getCache(Class<AbstractExtension<?>> cls)
      throws StartException, InstantiationException, IllegalAccessException, IOException {
    String id = cls.getName().substring(27);
    // File cache = Application.getResource("tmp/extensioncache/" + id +
    // ".json");
    // AbstractExtensionWrapper cached = JSonStorage.restoreFrom(cache,
    // true, (byte[]) null, new TypeRef<AbstractExtensionWrapper>() {

    AbstractExtensionWrapper cached = cache.get(id);

    int v = AbstractExtension.readVersion(cls);
    if (cached != null) {
      cached._setClazz(cls);
      if (cached.getVersion() != v
          || !cached.getLng().equals(_JDT.getLanguage())
          || cached._getSettings() == null) {
        // update cache
        cached = null;
      }
    }
    if (cached == null) {
      Log.L.info("Update Cache " + cache);
      cached = AbstractExtensionWrapper.create(id, cls);
      cache.put(id, cached);
      cacheChanged = true;
    } else {
      cached._setClazz(cls);
    }
    return cached;
  }
  /* (non-Javadoc)
   * @see org.eclipse.jetty.websocket.AbstractExtension#addFrame(byte, byte, byte[], int, int)
   */
  @Override
  public void addFrame(byte flags, byte opcode, byte[] content, int offset, int length)
      throws IOException {
    if (getConnection().isControl(opcode) || length < _minLength) {
      super.addFrame(clearFlag(flags, 1), opcode, content, offset, length);
      return;
    }

    // prepare the uncompressed input
    _deflater.reset();
    _deflater.setInput(content, offset, length);
    _deflater.finish();

    // prepare the output buffer
    byte[] out = new byte[length];
    int out_offset = 0;

    // write the uncompressed length
    if (length > 0xffff) {
      out[out_offset++] = 0x7f;
      out[out_offset++] = (byte) 0;
      out[out_offset++] = (byte) 0;
      out[out_offset++] = (byte) 0;
      out[out_offset++] = (byte) 0;
      out[out_offset++] = (byte) ((length >> 24) & 0xff);
      out[out_offset++] = (byte) ((length >> 16) & 0xff);
      out[out_offset++] = (byte) ((length >> 8) & 0xff);
      out[out_offset++] = (byte) (length & 0xff);
    } else if (length >= 0x7e) {
      out[out_offset++] = 0x7e;
      out[out_offset++] = (byte) (length >> 8);
      out[out_offset++] = (byte) (length & 0xff);
    } else {
      out[out_offset++] = (byte) (length & 0x7f);
    }

    int l = _deflater.deflate(out, out_offset, length - out_offset);

    if (_deflater.finished()) super.addFrame(setFlag(flags, 1), opcode, out, 0, l + out_offset);
    else super.addFrame(clearFlag(flags, 1), opcode, content, offset, length);
  }
 @Override
 public void destroy() {
   tcFuture.cancel(true);
   tuFuture.cancel(true);
   super.destroy();
 }