Package nginx.clojure.clj

Source Code of nginx.clojure.clj.LazyRequestMap$ArrayMapSeq

/**
*  Copyright (C) Zhang,Yuexiang (xfeep)
*
*/
package nginx.clojure.clj;

import static nginx.clojure.MiniConstants.BODY_FETCHER;
import static nginx.clojure.MiniConstants.CHARACTER_ENCODING_FETCHER;
import static nginx.clojure.MiniConstants.CONTENT_TYPE_FETCHER;
import static nginx.clojure.MiniConstants.DEFAULT_ENCODING;
import static nginx.clojure.MiniConstants.QUERY_STRING_FETCHER;
import static nginx.clojure.MiniConstants.REMOTE_ADDR_FETCHER;
import static nginx.clojure.MiniConstants.SCHEME_FETCHER;
import static nginx.clojure.MiniConstants.SERVER_NAME_FETCHER;
import static nginx.clojure.MiniConstants.SERVER_PORT_FETCHER;
import static nginx.clojure.MiniConstants.URI_FETCHER;
import static nginx.clojure.clj.Constants.BODY;
import static nginx.clojure.clj.Constants.CHARACTER_ENCODING;
import static nginx.clojure.clj.Constants.CONTENT_TYPE;
import static nginx.clojure.clj.Constants.HEADERS;
import static nginx.clojure.clj.Constants.HEADER_FETCHER;
import static nginx.clojure.clj.Constants.QUERY_STRING;
import static nginx.clojure.clj.Constants.REMOTE_ADDR;
import static nginx.clojure.clj.Constants.REQUEST_METHOD;
import static nginx.clojure.clj.Constants.REQUEST_METHOD_FETCHER;
import static nginx.clojure.clj.Constants.SCHEME;
import static nginx.clojure.clj.Constants.SERVER_NAME;
import static nginx.clojure.clj.Constants.SERVER_PORT;
import static nginx.clojure.clj.Constants.URI;

import java.util.Iterator;
import java.util.Map;

import nginx.clojure.ChannelListener;
import nginx.clojure.NginxClojureRT;
import nginx.clojure.NginxHandler;
import nginx.clojure.NginxRequest;
import nginx.clojure.NginxHttpServerChannel;
import nginx.clojure.RequestVarFetcher;
import clojure.lang.AFn;
import clojure.lang.ASeq;
import clojure.lang.Counted;
import clojure.lang.IMapEntry;
import clojure.lang.IPersistentCollection;
import clojure.lang.IPersistentMap;
import clojure.lang.IPersistentVector;
import clojure.lang.ISeq;
import clojure.lang.MapEntry;
import clojure.lang.Obj;
import clojure.lang.RT;
import clojure.lang.Util;

public   class LazyRequestMap extends AFn  implements NginxRequest, IPersistentMap {
 
  protected long r;
  protected Object[] array;
  protected NginxHandler handler;
  protected NginxHttpServerChannel channel;
  protected byte[] hijackTag;
  protected volatile boolean released = false;
 
  public final static LazyRequestMap EMPTY_MAP = new LazyRequestMap(null, 0, null, new Object[0]);
 
  private final  static ChannelListener<LazyRequestMap> requestListener  = new  ChannelListener<LazyRequestMap> (){
    @Override
    public void onClose(LazyRequestMap data) {
      data.released = true;
    }
   
    @Override
    public void onConnect(long status, LazyRequestMap data) {
    }
  };
 
  public LazyRequestMap(NginxHandler handler, long r, byte[] hijackTag, Object[] array) {
    this.handler = handler;
    this.r = r;
    this.array = array;
    this.hijackTag = hijackTag;
    if (r != 0) {
      NginxClojureRT.ngx_http_cleanup_add(r, requestListener, this);
    }
  }
 
  @SuppressWarnings("unchecked")
  public LazyRequestMap(NginxHandler handler, long r) {
    //TODO: SSL_CLIENT_CERT
    this(handler, r, new byte[]{0}, new Object[] {
        URI, URI_FETCHER,
        BODY, BODY_FETCHER,
        HEADERS, HEADER_FETCHER,
       
        SERVER_PORT,SERVER_PORT_FETCHER,
        SERVER_NAME, SERVER_NAME_FETCHER,
        REMOTE_ADDR, REMOTE_ADDR_FETCHER,
       
        QUERY_STRING, QUERY_STRING_FETCHER,
        SCHEME, SCHEME_FETCHER,
        REQUEST_METHOD, REQUEST_METHOD_FETCHER,
        CONTENT_TYPE, CONTENT_TYPE_FETCHER,
        CHARACTER_ENCODING, CHARACTER_ENCODING_FETCHER,
    });
  }
 
  public void prefetchAll() {
    int len = count();
    for (int i = 0; i < len; i++) {
      element(i*2);
    }
  }
 
 
  protected int index(Object key) {
    for (int i = 0; i < array.length; i+=2){
      if (key == array[i]) {
        return i;
      }
    }
    return -1;
  }
 

  @Override
  public Iterator iterator() {
    return new Iterator<MapEntry>() {
     
      int i = 0;

      @Override
      public boolean hasNext() {
        return i < array.length -2;
      }

      @Override
      public MapEntry next() {
        return new MapEntry(array[i++], array[i++]);
      }

      @Override
      public void remove() {
        throw Util.runtimeException("remove not supported");
      }
    };
  }

  @Override
  public IMapEntry entryAt(Object key) {
    Object v = valAt(key);
    if (v == null) {
      return null;
    }
    return new MapEntry(key, v);
  }

  @Override
  public int count() {
    return array.length/2;
  }

  @Override
  public IPersistentCollection cons(Object o) {
    if (o instanceof Map.Entry) {
      Map.Entry e = (Map.Entry) o;

      return assoc(e.getKey(), e.getValue());
    } else if (o instanceof IPersistentVector) {
      IPersistentVector v = (IPersistentVector) o;
      if (v.count() != 2)
        throw new IllegalArgumentException(
            "Vector arg to map conj must be a pair");
      return assoc(v.nth(0), v.nth(1));
    }

    IPersistentMap ret = this;
    for (ISeq es = RT.seq(o); es != null; es = es.next()) {
      Map.Entry e = (Map.Entry) es.first();
      ret = ret.assoc(e.getKey(), e.getValue());
    }
    return ret;
  }

  @Override
  public IPersistentCollection empty() {
    return EMPTY_MAP;
  }

  @Override
  public boolean equiv(Object o) {
    return o == this;
  }

 
  static class ArrayMapSeq extends ASeq implements Counted{
    final int i;
    final LazyRequestMap reqMap;

    ArrayMapSeq(LazyRequestMap reqMap, int i){
      this.reqMap = reqMap;
      this.i = i;
    }

    public ArrayMapSeq(IPersistentMap meta, LazyRequestMap reqMap, int i){
      super(meta);
      this.reqMap = reqMap;
      this.i = i;
    }

    public Object first(){
      return new MapEntry(reqMap.array[i],reqMap.element(i));
    }

    public ISeq next(){
      if(i + 2 < reqMap.array.length)
        return new ArrayMapSeq(reqMap, i + 2);
      return null;
    }

    public int count(){
      return (reqMap.array.length - i) / 2;
    }

    public Obj withMeta(IPersistentMap meta){
      return new ArrayMapSeq(meta, reqMap, i);
    }
  }
 
  @Override
  public ISeq seq() {
    return new ArrayMapSeq(this, 0);
  }

  protected Object element(int i) {
    Object o = array[i+1];
    if (o instanceof RequestVarFetcher) {
      if (Thread.currentThread() != NginxClojureRT.NGINX_MAIN_THREAD) {
        throw new IllegalAccessError("fetching lazy value of " + array[i] + " in LazyRequestMap can only be called in main thread, please pre-access it in main thread OR call LazyRequestMap.prefetchAll() first in main thread");
      }
      RequestVarFetcher rf = (RequestVarFetcher) o;
      array[i+1] = null;
      Object rt = rf.fetch(r, DEFAULT_ENCODING);
      array[i+1] = rt;
//      System.out.println("LazyRequestMap, key=" + rt);
      return rt;
    }
//    System.out.println("LazyRequestMap, key=" + array[i] + ", val=" + o);
    return o;
  }
 
  @Override
  public Object valAt(Object key) {
    int i = index(key);
    if (i == -1) {
      return null;
    }
    return element(i);
  }

  @Override
  public Object valAt(Object key, Object notFound) {
    Object val = valAt(key);
    return val == null ? notFound : val;
  }

  @Override
  public IPersistentMap assoc(Object key, Object val) {
    int i = index(key);
    if (i != -1) {
      array[i+1] = val;
      return this;
    }
    Object[] newArray = new Object[array.length + 2];
    System.arraycopy(array, 0, newArray, 0, array.length);
    newArray[array.length] = key;
    newArray[array.length+1] = val;
    return new LazyRequestMap(handler, r,  this.hijackTag, newArray);
  }

  @Override
  public IPersistentMap assocEx(Object key, Object val) {
    Object old = valAt(key);
    if (old != null) {
       throw Util.runtimeException("Key already present");
    }
    return assoc(key, val);
  }

  @Override
  public IPersistentMap without(Object key) {
    int i = index(key);
    if (i == -1) {
      return this;
    }else {
      if (array.length == 2) {
        return EMPTY_MAP;
      }
      Object[] newArray = new Object[array.length - 2];
      if (i > 0) {
        System.arraycopy(array, 0, newArray, 0, i);
      }
      System.arraycopy(array, i + 2, newArray, i, array.length - i - 2);
      return new LazyRequestMap(handler, r , this.hijackTag, newArray);
    }
  }
 
  public long nativeRequest() {
    return r;
  }

  @Override
  public boolean containsKey(Object key) {
    return index(key) != -1;
  }
 
  @Override
  public Object invoke(Object key) {
    return valAt(key);
  }
 
  @Override
  public Object invoke(Object key, Object notFound) {
    return valAt(key, notFound);
  }

 
  @Override
  public NginxHandler handler() {
    return handler;
  }
 
  @Override
  public NginxHttpServerChannel channel() {
    if (hijackTag == null || hijackTag[0] == 0) {
      NginxClojureRT.UNSAFE.throwException(new IllegalAccessException("not hijacked!"));
    }
    return channel;
  }

  @Override
  public boolean isHijacked() {
    return hijackTag != null && hijackTag[0] == 1;
  }

  @Override
  public boolean isReleased() {
    return released;
  }

}
TOP

Related Classes of nginx.clojure.clj.LazyRequestMap$ArrayMapSeq

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.