001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019package lucee.runtime.thread; 020 021import java.io.ByteArrayOutputStream; 022import java.io.Serializable; 023import java.util.ConcurrentModificationException; 024import java.util.Iterator; 025import java.util.Map.Entry; 026 027import javax.servlet.http.HttpServletRequest; 028 029import lucee.commons.io.DevNullOutputStream; 030import lucee.commons.io.log.Log; 031import lucee.commons.io.log.LogUtil; 032import lucee.commons.lang.ExceptionUtil; 033import lucee.commons.lang.Pair; 034import lucee.runtime.Page; 035import lucee.runtime.PageContext; 036import lucee.runtime.PageContextImpl; 037import lucee.runtime.PageSourceImpl; 038import lucee.runtime.config.Config; 039import lucee.runtime.config.ConfigImpl; 040import lucee.runtime.config.ConfigWeb; 041import lucee.runtime.config.ConfigWebImpl; 042import lucee.runtime.engine.ThreadLocalPageContext; 043import lucee.runtime.exp.Abort; 044import lucee.runtime.exp.PageException; 045import lucee.runtime.net.http.HttpServletResponseDummy; 046import lucee.runtime.net.http.HttpUtil; 047import lucee.runtime.net.http.ReqRspUtil; 048import lucee.runtime.op.Caster; 049import lucee.runtime.op.Duplicator; 050import lucee.runtime.type.Collection; 051import lucee.runtime.type.Collection.Key; 052import lucee.runtime.type.KeyImpl; 053import lucee.runtime.type.Struct; 054import lucee.runtime.type.StructImpl; 055import lucee.runtime.type.scope.Argument; 056import lucee.runtime.type.scope.ArgumentThreadImpl; 057import lucee.runtime.type.scope.Local; 058import lucee.runtime.type.scope.LocalImpl; 059import lucee.runtime.type.scope.Threads; 060import lucee.runtime.type.scope.Undefined; 061 062public class ChildThreadImpl extends ChildThread implements Serializable { 063 064 private static final long serialVersionUID = -8902836175312356628L; 065 066 private static final Collection.Key KEY_ATTRIBUTES = KeyImpl.intern("attributes"); 067 068 //private static final Set EMPTY = new HashSet(); 069 070 private int threadIndex; 071 private PageContextImpl parent; 072 PageContextImpl pc =null; 073 private String tagName; 074 private long start; 075 private Threads scope; 076 077 // accesible from scope 078 Struct content=new StructImpl(); 079 Struct catchBlock; 080 boolean terminated; 081 boolean completed; 082 ByteArrayOutputStream output; 083 084 085 // only used for type daemon 086 private Page page; 087 088 // only used for type task, demon attrs are not Serializable 089 private Struct attrs; 090 private SerializableCookie[] cookies; 091 private String serverName; 092 private String queryString; 093 private Pair[] parameters; 094 private String requestURI; 095 private Pair[] headers; 096 private Struct attributes; 097 private String template; 098 private long requestTimeout; 099 100 private boolean serializable; 101 102 String contentType; 103 104 String contentEncoding; 105 106 107 public ChildThreadImpl(PageContextImpl parent,Page page, String tagName,int threadIndex, Struct attrs, boolean serializable) { 108 this.serializable=serializable; 109 this.tagName=tagName; 110 this.threadIndex=threadIndex; 111 start=System.currentTimeMillis(); 112 if(attrs==null) this.attrs=new StructImpl(); 113 else this.attrs=attrs; 114 115 if(!serializable){ 116 this.page=page; 117 if(parent!=null){ 118 output = new ByteArrayOutputStream(); 119 try{ 120 this.parent=ThreadUtil.clonePageContext(parent, output,false,false,true); 121 } 122 catch(ConcurrentModificationException e){// MUST search for:hhlhgiug 123 this.parent=ThreadUtil.clonePageContext(parent, output,false,false,true); 124 } 125 //this.parent=parent; 126 } 127 } 128 else { 129 this.template=page.getPageSource().getFullRealpath(); 130 HttpServletRequest req = parent.getHttpServletRequest(); 131 serverName=req.getServerName(); 132 queryString=ReqRspUtil.getQueryString(req); 133 cookies=SerializableCookie.toSerializableCookie(ReqRspUtil.getCookies(req,parent.getWebCharset())); 134 parameters=HttpUtil.cloneParameters(req); 135 requestURI=req.getRequestURI(); 136 headers=HttpUtil.cloneHeaders(req); 137 attributes=HttpUtil.getAttributesAsStruct(req); 138 requestTimeout=parent.getRequestTimeout(); 139 // MUST here ist sill a mutch state values missing 140 } 141 } 142 143 public PageContext getPageContext(){ 144 return pc; 145 } 146 147 148 public void run() { 149 execute(null); 150 } 151 public PageException execute(Config config) { 152 PageContext oldPc = ThreadLocalPageContext.get(); 153 154 Page p=page; 155 156 if(parent!=null){ 157 pc=parent; 158 ThreadLocalPageContext.register(pc); 159 } 160 else { 161 ConfigWebImpl cwi; 162 try { 163 cwi = (ConfigWebImpl)config; 164 DevNullOutputStream os = DevNullOutputStream.DEV_NULL_OUTPUT_STREAM; 165 pc=ThreadUtil.createPageContext(cwi, os, serverName, requestURI, queryString, SerializableCookie.toCookies(cookies), headers, parameters, attributes); 166 pc.setRequestTimeout(requestTimeout); 167 p=PageSourceImpl.loadPage(pc, cwi.getPageSources(oldPc==null?pc:oldPc,null, template, false,false,true)); 168 //p=cwi.getPageSources(oldPc,null, template, false,false,true).loadPage(cwi); 169 } catch (PageException e) { 170 return e; 171 } 172 pc.addPageSource(p.getPageSource(), true); 173 } 174 pc.setThreadScope("thread", new ThreadsImpl(this)); 175 pc.setThread(Thread.currentThread()); 176 177 //String encodings = pc.getHttpServletRequest().getHeader("Accept-Encoding"); 178 179 Undefined undefined=pc.us(); 180 181 Argument newArgs=new ArgumentThreadImpl((Struct) Duplicator.duplicate(attrs,false)); 182 LocalImpl newLocal=pc.getScopeFactory().getLocalInstance(); 183 //Key[] keys = attrs.keys(); 184 Iterator<Entry<Key, Object>> it = attrs.entryIterator(); 185 Entry<Key, Object> e; 186 while(it.hasNext()){ 187 e = it.next(); 188 newArgs.setEL(e.getKey(),e.getValue()); 189 } 190 191 newLocal.setEL(KEY_ATTRIBUTES, newArgs); 192 193 Argument oldArgs=pc.argumentsScope(); 194 Local oldLocal=pc.localScope(); 195 196 int oldMode=undefined.setMode(Undefined.MODE_LOCAL_OR_ARGUMENTS_ALWAYS); 197 pc.setFunctionScopes(newLocal,newArgs); 198 199 try { 200 p.threadCall(pc, threadIndex); 201 } 202 catch (Throwable t) { 203 ExceptionUtil.rethrowIfNecessary(t); 204 if(!Abort.isSilentAbort(t)) { 205 ConfigWeb c = pc.getConfig(); 206 if(c instanceof ConfigImpl) { 207 ConfigImpl ci=(ConfigImpl) c; 208 Log log = ci.getLog("thread"); 209 if(log!=null)LogUtil.log(log,Log.LEVEL_ERROR,this.getName(), t); 210 } 211 PageException pe = Caster.toPageException(t); 212 if(!serializable)catchBlock=pe.getCatchBlock(pc); 213 return pe; 214 } 215 } 216 finally { 217 completed=true; 218 pc.setFunctionScopes(oldLocal,oldArgs); 219 undefined.setMode(oldMode); 220 //pc.getScopeFactory().recycle(newArgs); 221 pc.getScopeFactory().recycle(newLocal); 222 223 if(pc.getHttpServletResponse() instanceof HttpServletResponseDummy) { 224 HttpServletResponseDummy rsp=(HttpServletResponseDummy) pc.getHttpServletResponse(); 225 pc.flush(); 226 contentType=rsp.getContentType(); 227 Pair<String,Object>[] _headers = rsp.getHeaders(); 228 if(_headers!=null)for(int i=0;i<_headers.length;i++){ 229 if(_headers[i].getName().equalsIgnoreCase("Content-Encoding")) 230 contentEncoding=Caster.toString(_headers[i].getValue(),null); 231 } 232 } 233 234 ((ConfigImpl)pc.getConfig()).getFactory().releasePageContext(pc); 235 pc=null; 236 if(oldPc!=null)ThreadLocalPageContext.register(oldPc); 237 } 238 return null; 239 } 240 241 @Override 242 public String getTagName() { 243 return tagName; 244 } 245 246 @Override 247 public long getStartTime() { 248 return start; 249 } 250 251 public Threads getThreadScope() { 252 if(scope==null) scope=new ThreadsImpl(this); 253 return scope; 254 } 255 256 public void terminated() { 257 terminated=true; 258 } 259 260 /** 261 * @return the pageSource 262 */ 263 public String getTemplate() { 264 return template; 265 } 266 267 268}