package nginx.clojure.clj; import static nginx.clojure.MiniConstants.NGX_HTTP_CLOJURE_HEADERSO_STATUS_OFFSET; import static nginx.clojure.MiniConstants.NGX_HTTP_CLOJURE_REQ_HEADERS_OUT_OFFSET; import static nginx.clojure.NginxClojureRT.fetchNGXInt; import static nginx.clojure.NginxClojureRT.pushNGXInt; import java.io.IOException; import java.util.Iterator; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import clojure.lang.IMapEntry; import clojure.lang.IPersistentCollection; import clojure.lang.IPersistentMap; import clojure.lang.ISeq; import nginx.clojure.ChannelCloseAdapter; import nginx.clojure.NginxChainWrappedInputStream; import nginx.clojure.NginxFilterRequest; import nginx.clojure.NginxHandler; public class LazyFilterRequestMap extends LazyRequestMap implements NginxFilterRequest, Cloneable { /** * native ngx_chain_t */ protected long c; protected NginxChainWrappedInputStream body; /** * native headers_out */ protected long ho; protected LazyHeaderMap responseHeaders; protected LazyFilterRequestMap origin; protected final static Map<Long, LazyFilterRequestMap> bodyFilterRequests = new ConcurrentHashMap<Long, LazyFilterRequestMap>(); protected final static ChannelCloseAdapter<Long> bodyFilterRequestsCleaner = new ChannelCloseAdapter<Long>() { @Override public void onClose(Long r) throws IOException { bodyFilterRequests.remove(r); } }; public static LazyFilterRequestMap cloneExisted(long r, long c) { LazyFilterRequestMap req = bodyFilterRequests.get(r); LazyFilterRequestMap creq = null; if (req != null) { try { creq = (LazyFilterRequestMap) req.clone(); creq.array = null; creq.origin = req; creq.c = c; if (c > 0) { creq.body = new NginxChainWrappedInputStream(creq, c); } else { creq.body = null; } } catch (CloneNotSupportedException e) { e.printStackTrace();//should never happen } catch (IOException e) { e.printStackTrace();//should never happen } } return creq; } public LazyFilterRequestMap(NginxHandler handler, long r, long c) { super(handler, r); this.c = c; this.ho = r + NGX_HTTP_CLOJURE_REQ_HEADERS_OUT_OFFSET; responseHeaders = new LazyHeaderMap(r, true); if (c > 0) { //body filter request try { body = new NginxChainWrappedInputStream(this, c); } catch (IOException e) { throw new RuntimeException("can not build body r:" + r +", c=" + c, e); } bodyFilterRequests.put(r, this); this.addListener(r, bodyFilterRequestsCleaner); } } /* (non-Javadoc) * @see nginx.clojure.clj.LazyRequestMap#reset(long, nginx.clojure.clj.NginxClojureHandler) */ @Override public void reset(long r, NginxClojureHandler handler) { if (origin == null) { super.reset(r, handler); } else { throw new UnsupportedOperationException("cloned filter request should not be reset!"); } } @Override public int responseStatus() { return fetchNGXInt(ho + NGX_HTTP_CLOJURE_HEADERSO_STATUS_OFFSET); } public LazyFilterRequestMap responseStatus(int status) { pushNGXInt(ho + NGX_HTTP_CLOJURE_HEADERSO_STATUS_OFFSET, status ); return this; } @Override public Map<String, Object> responseHeaders() { return responseHeaders; } /* (non-Javadoc) * @see nginx.clojure.clj.LazyRequestMap#prefetchAll() */ @Override public void prefetchAll() { if (origin == null) { super.prefetchAll(); } if (body != null) { try { body.prefetchNativeData(); } catch (IOException e) { throw new RuntimeException("can not prefetch native data", e); } } } /* (non-Javadoc) * @see nginx.clojure.clj.LazyRequestMap#index(java.lang.Object) */ @Override protected int index(Object key) { if (origin == null) { return super.index(key); } return origin.index(key); } /* (non-Javadoc) * @see nginx.clojure.clj.LazyRequestMap#iterator() */ @Override public Iterator iterator() { if (origin == null) { return super.iterator(); } return origin.iterator(); } @Override public IMapEntry entryAt(Object key) { if (origin == null) { return super.entryAt(key); } return origin.entryAt(key); } @Override public int count() { if (origin == null) { return super.count(); } return origin.count(); } /* (non-Javadoc) * @see nginx.clojure.clj.LazyRequestMap#cons(java.lang.Object) */ @Override public IPersistentCollection cons(Object o) { if (origin == null) { return super.cons(o); } return origin.cons(o); } /* (non-Javadoc) * @see nginx.clojure.clj.LazyRequestMap#seq() */ @Override public ISeq seq() { if (origin == null) { return super.seq(); } return origin.seq(); } /* (non-Javadoc) * @see nginx.clojure.clj.LazyRequestMap#element(int) */ @Override protected Object element(int i) { if (origin == null) { return super.element(i); } return origin.element(i); } /* (non-Javadoc) * @see nginx.clojure.clj.LazyRequestMap#valAt(java.lang.Object) */ @Override public Object valAt(Object key) { if (origin == null) { return super.valAt(key); } return origin.valAt(key); } /* (non-Javadoc) * @see nginx.clojure.clj.LazyRequestMap#valAt(java.lang.Object, java.lang.Object) */ @Override public Object valAt(Object key, Object notFound) { if (origin == null) { return super.valAt(key, notFound); } return origin.valAt(key, notFound); } /* (non-Javadoc) * @see nginx.clojure.clj.LazyRequestMap#assoc(java.lang.Object, java.lang.Object) */ @Override public IPersistentMap assoc(Object key, Object val) { if (origin == null) { return super.assoc(key, val); } return origin.assoc(key, val); } /* (non-Javadoc) * @see nginx.clojure.clj.LazyRequestMap#assocEx(java.lang.Object, java.lang.Object) */ @Override public IPersistentMap assocEx(Object key, Object val) { if (origin == null) { return super.assocEx(key, val); } return origin.assocEx(key, val); } /* (non-Javadoc) * @see nginx.clojure.clj.LazyRequestMap#without(java.lang.Object) */ @Override public IPersistentMap without(Object key) { if (origin == null) { return super.without(key); } return origin.without(key); } @Override public void tagReleased() { this.released = true; this.channel = null; if (listeners != null) { listeners.clear(); } // if (origin == null) { // System.arraycopy(default_request_array, 0, array, 0, default_request_array.length); // validLen = default_request_array.length; // if (array.length > validLen) { // Stack.fillNull(array, validLen, array.length - validLen); // } // } // ((NginxClojureHandler)handler).returnToRequestPool(this); } }