<commit_before>/**
 *
 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either 
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public 
 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 * 
 **/
package lucee.runtime; 

import java.net.URL;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Stack;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.Servlet;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.JspEngineInfo;

import lucee.commons.io.SystemUtil;
import lucee.commons.io.log.Log;
import lucee.commons.io.log.LogUtil;
import lucee.commons.io.res.util.ResourceUtil;
import lucee.commons.lang.SizeOf;
import lucee.commons.lang.SystemOut;
import lucee.runtime.config.ConfigImpl;
import lucee.runtime.config.ConfigWeb;
import lucee.runtime.config.ConfigWebImpl;
import lucee.runtime.engine.CFMLEngineImpl;
import lucee.runtime.engine.ThreadLocalPageContext;
import lucee.runtime.exp.Abort;
import lucee.runtime.exp.PageException;
import lucee.runtime.exp.PageExceptionImpl;
import lucee.runtime.exp.RequestTimeoutException;
import lucee.runtime.functions.string.Hash;
import lucee.runtime.lock.LockManager;
import lucee.runtime.op.Caster;
import lucee.runtime.query.QueryCache;
import lucee.runtime.type.Array;
import lucee.runtime.type.ArrayImpl;
import lucee.runtime.type.Struct;
import lucee.runtime.type.StructImpl;
import lucee.runtime.type.dt.DateTimeImpl;
import lucee.runtime.type.scope.LocalNotSupportedScope;
import lucee.runtime.type.scope.ScopeContext;
import lucee.runtime.type.util.ArrayUtil;
import lucee.runtime.type.util.KeyConstants;
import lucee.runtime.type.util.ListUtil;

/**
 * implements a JSP Factory, this class produce JSP Compatible PageContext Object
 * this object holds also the must interfaces to coldfusion specified functionlity
 */
public final class CFMLFactoryImpl extends CFMLFactory {
	
	private static JspEngineInfo info=new JspEngineInfoImpl("1.0");
	private ConfigWebImpl config;
	Stack<PageContext> pcs=new Stack<PageContext>();
    private final Map<Integer,PageContextImpl> runningPcs=new ConcurrentHashMap<Integer, PageContextImpl>();
    int idCounter=1;
    private ScopeContext scopeContext=new ScopeContext(this);
    private HttpServlet servlet;
	private URL url=null;
	private CFMLEngineImpl engine;

	/**
	 * constructor of the JspFactory
	 * @param config Lucee specified Configuration
	 * @param compiler CFML compiler
	 * @param engine
	 */
	public CFMLFactoryImpl(CFMLEngineImpl engine) {
		this.engine=engine; 
	}
    
    /**
     * reset the PageContexes
     */
    public void resetPageContext() {
        SystemOut.printDate(config.getOutWriter(),"Reset "+pcs.size()+" Unused PageContexts");
        synchronized(pcs) {
            pcs.clear();
        }
        
        Iterator<PageContextImpl> it = runningPcs.values().iterator();
        while(it.hasNext()){
        	it.next().reset();
        }
    }
    
	@Override
	public javax.servlet.jsp.PageContext getPageContext(
		Servlet servlet,
		ServletRequest req,
		ServletResponse rsp,
		String errorPageURL,
		boolean needsSession,
		int bufferSize,
		boolean autoflush) {
			return getPageContextImpl((HttpServlet)servlet,(HttpServletRequest)req,(HttpServletResponse)rsp,errorPageURL,needsSession,bufferSize,autoflush,true,false);
	}
	
	/**
	 * similar to getPageContext Method but return the concrete implementation of the lucee PageCOntext
	 * and take the HTTP Version of the Servlet Objects
	 * @param servlet
	 * @param req
	 * @param rsp
	 * @param errorPageURL
	 * @param needsSession
	 * @param bufferSize
	 * @param autoflush
	 * @return return the page<context
	 */
	public PageContext getLuceePageContext(
	HttpServlet servlet,
	HttpServletRequest req,
	HttpServletResponse rsp,
        String errorPageURL,
		boolean needsSession,
		int bufferSize,
		boolean autoflush)  {
        //runningCount++;
        return getPageContextImpl(servlet, req, rsp, errorPageURL, needsSession, bufferSize, autoflush,true,false);
	}
	
	public PageContextImpl getPageContextImpl(
			HttpServlet servlet,
			HttpServletRequest req,
			HttpServletResponse rsp,
		        String errorPageURL,
				boolean needsSession,
				int bufferSize,
				boolean autoflush,boolean registerPageContext2Thread,boolean isChild)  {
		        //runningCount++;
				PageContextImpl pc;
        		synchronized (pcs) {
		            if(pcs.isEmpty()) pc=new PageContextImpl(scopeContext,config,idCounter++,servlet);
		            else pc=((PageContextImpl)pcs.pop());
		            runningPcs.put(Integer.valueOf(pc.getId()),pc);
		            this.servlet=servlet;
		            if(registerPageContext2Thread)ThreadLocalPageContext.register(pc);
		    		
		        }
		        pc.initialize(servlet,req,rsp,errorPageURL,needsSession,bufferSize,autoflush,isChild);
		        return pc;
			}

    @Override
	public void releasePageContext(javax.servlet.jsp.PageContext pc) {
		releaseLuceePageContext((PageContext)pc);
	}
	
	/**
	 * Similar to the releasePageContext Method, but take lucee PageContext as entry
	 * @param pc
	 */
	public void releaseLuceePageContext(PageContext pc) {
		if(pc.getId()<0)return;
        pc.release();
        ThreadLocalPageContext.release();
        //if(!pc.hasFamily()){
			    runningPcs.remove(Integer.valueOf(pc.getId()));
	            
	            if(pcs.size()<100 && ((PageContextImpl)pc).getStopPosition()==null)// not more than 100 PCs
	            	pcs.push(pc);
	            //SystemOut.printDate(config.getOutWriter(),"Release: (id:"+pc.getId()+";running-requests:"+config.getThreadQueue().size()+";)");
	        
       /*}
        else {
        	 SystemOut.printDate(config.getOutWriter(),"Unlink: ("+pc.getId()+")");
        }*/
	}
    
    /**
	 * check timeout of all running threads, downgrade also priority from all thread run longer than 10 seconds
	 */
	public void checkTimeout() {
		if(!engine.allowRequestTimeout())return;
		//synchronized (runningPcs) {
            //int len=runningPcs.size();
			Iterator<Entry<Integer, PageContextImpl>> it = runningPcs.entrySet().iterator();
            PageContextImpl pc;
            //Collection.Key key;
            Entry<Integer, PageContextImpl> e;
            while(it.hasNext()) {
            	e = it.next();
            	pc=e.getValue();
                
                long timeout=pc.getRequestTimeout();
                if(pc.getStartTime()+timeout<System.currentTimeMillis()) {
                    terminate(pc);
                    it.remove();
                }
                // after 10 seconds downgrade priority of the thread
                else if(pc.getStartTime()+10000<System.currentTimeMillis() && pc.getThread().getPriority()!=Thread.MIN_PRIORITY) {
                    Log log = config.getLog("requesttimeout");
                    if(log!=null)log.log(Log.LEVEL_WARN,"controler","downgrade priority of the a thread at "+getPath(pc));
                    try {
                    	pc.getThread().setPriority(Thread.MIN_PRIORITY);
                    }
                    catch(Throwable t) {}
                }
            }
        //}
	}
	
	public static void terminate(PageContextImpl pc) {
		Log log = ((ConfigImpl)pc.getConfig()).getLog("requesttimeout");
        
		String strLocks="";
		try{
			LockManager manager = pc.getConfig().getLockManager();
	        String[] locks = manager.getOpenLockNames();
	        if(!ArrayUtil.isEmpty(locks)) 
	        	strLocks=" open locks at this time ("+ListUtil.arrayToList(locks, ", ")+").";
	        //LockManagerImpl.unlockAll(pc.getId());
		}
		catch(Throwable t){}
        if(log!=null)LogUtil.log(log,Log.LEVEL_ERROR,"controler",
        		"stop thread ("+pc.getId()+") because run into a timeout "+getPath(pc)+"."+strLocks,pc.getThread().getStackTrace());
        
        // then we release the pagecontext
        pc.getConfig().getThreadQueue().exit(pc);
        SystemUtil.stop(pc,new RequestTimeoutException(pc.getThread(),"request ("+getPath(pc)+":"+pc.getId()+") has run into a timeout ("+(pc.getRequestTimeout()/1000)+" seconds) and has been stopped."+strLocks),log);
	}

	private static String getPath(PageContext pc) {
		try {
			String base=ResourceUtil.getResource(pc, pc.getBasePageSource()).getAbsolutePath();
			String current=ResourceUtil.getResource(pc, pc.getCurrentPageSource()).getAbsolutePath();
			if(base.equals(current)) return "path: "+base;
			return "path: "+base+" ("+current+")";
		}
		catch(Throwable t) {
			return "(fail to retrieve path:"+t.getClass().getName()+":"+t.getMessage()+")";
		}
	}
	
	@Override
	public JspEngineInfo getEngineInfo() {
		return info;
	}<commit_msg>log stop thread<commit_after>/**
 *
 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either 
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public 
 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 * 
 **/
package lucee.runtime; 

import java.net.URL;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Stack;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.Servlet;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.JspEngineInfo;

import lucee.commons.io.SystemUtil;
import lucee.commons.io.log.Log;
import lucee.commons.io.log.LogUtil;
import lucee.commons.io.res.util.ResourceUtil;
import lucee.commons.lang.SizeOf;
import lucee.commons.lang.SystemOut;
import lucee.runtime.config.ConfigImpl;
import lucee.runtime.config.ConfigWeb;
import lucee.runtime.config.ConfigWebImpl;
import lucee.runtime.engine.CFMLEngineImpl;
import lucee.runtime.engine.ThreadLocalPageContext;
import lucee.runtime.exp.Abort;
import lucee.runtime.exp.PageException;
import lucee.runtime.exp.PageExceptionImpl;
import lucee.runtime.exp.RequestTimeoutException;
import lucee.runtime.functions.string.Hash;
import lucee.runtime.lock.LockManager;
import lucee.runtime.op.Caster;
import lucee.runtime.query.QueryCache;
import lucee.runtime.type.Array;
import lucee.runtime.type.ArrayImpl;
import lucee.runtime.type.Struct;
import lucee.runtime.type.StructImpl;
import lucee.runtime.type.dt.DateTimeImpl;
import lucee.runtime.type.scope.LocalNotSupportedScope;
import lucee.runtime.type.scope.ScopeContext;
import lucee.runtime.type.util.ArrayUtil;
import lucee.runtime.type.util.KeyConstants;
import lucee.runtime.type.util.ListUtil;

/**
 * implements a JSP Factory, this class produce JSP Compatible PageContext Object
 * this object holds also the must interfaces to coldfusion specified functionlity
 */
public final class CFMLFactoryImpl extends CFMLFactory {
	
	private static JspEngineInfo info=new JspEngineInfoImpl("1.0");
	private ConfigWebImpl config;
	Stack<PageContext> pcs=new Stack<PageContext>();
    private final Map<Integer,PageContextImpl> runningPcs=new ConcurrentHashMap<Integer, PageContextImpl>();
    int idCounter=1;
    private ScopeContext scopeContext=new ScopeContext(this);
    private HttpServlet servlet;
	private URL url=null;
	private CFMLEngineImpl engine;

	/**
	 * constructor of the JspFactory
	 * @param config Lucee specified Configuration
	 * @param compiler CFML compiler
	 * @param engine
	 */
	public CFMLFactoryImpl(CFMLEngineImpl engine) {
		this.engine=engine; 
	}
    
    /**
     * reset the PageContexes
     */
    public void resetPageContext() {
        SystemOut.printDate(config.getOutWriter(),"Reset "+pcs.size()+" Unused PageContexts");
        synchronized(pcs) {
            pcs.clear();
        }
        
        Iterator<PageContextImpl> it = runningPcs.values().iterator();
        while(it.hasNext()){
        	it.next().reset();
        }
    }
    
	@Override
	public javax.servlet.jsp.PageContext getPageContext(
		Servlet servlet,
		ServletRequest req,
		ServletResponse rsp,
		String errorPageURL,
		boolean needsSession,
		int bufferSize,
		boolean autoflush) {
			return getPageContextImpl((HttpServlet)servlet,(HttpServletRequest)req,(HttpServletResponse)rsp,errorPageURL,needsSession,bufferSize,autoflush,true,false);
	}
	
	/**
	 * similar to getPageContext Method but return the concrete implementation of the lucee PageCOntext
	 * and take the HTTP Version of the Servlet Objects
	 * @param servlet
	 * @param req
	 * @param rsp
	 * @param errorPageURL
	 * @param needsSession
	 * @param bufferSize
	 * @param autoflush
	 * @return return the page<context
	 */
	public PageContext getLuceePageContext(
	HttpServlet servlet,
	HttpServletRequest req,
	HttpServletResponse rsp,
        String errorPageURL,
		boolean needsSession,
		int bufferSize,
		boolean autoflush)  {
        //runningCount++;
        return getPageContextImpl(servlet, req, rsp, errorPageURL, needsSession, bufferSize, autoflush,true,false);
	}
	
	public PageContextImpl getPageContextImpl(
			HttpServlet servlet,
			HttpServletRequest req,
			HttpServletResponse rsp,
		        String errorPageURL,
				boolean needsSession,
				int bufferSize,
				boolean autoflush,boolean registerPageContext2Thread,boolean isChild)  {
		        //runningCount++;
				PageContextImpl pc;
        		synchronized (pcs) {
		            if(pcs.isEmpty()) pc=new PageContextImpl(scopeContext,config,idCounter++,servlet);
		            else pc=((PageContextImpl)pcs.pop());
		            runningPcs.put(Integer.valueOf(pc.getId()),pc);
		            this.servlet=servlet;
		            if(registerPageContext2Thread)ThreadLocalPageContext.register(pc);
		    		
		        }
		        pc.initialize(servlet,req,rsp,errorPageURL,needsSession,bufferSize,autoflush,isChild);
		        return pc;
			}

    @Override
	public void releasePageContext(javax.servlet.jsp.PageContext pc) {
		releaseLuceePageContext((PageContext)pc);
	}
	
	/**
	 * Similar to the releasePageContext Method, but take lucee PageContext as entry
	 * @param pc
	 */
	public void releaseLuceePageContext(PageContext pc) {
		if(pc.getId()<0)return;
        pc.release();
        ThreadLocalPageContext.release();
        //if(!pc.hasFamily()){
			    runningPcs.remove(Integer.valueOf(pc.getId()));
	            
	            if(pcs.size()<100 && ((PageContextImpl)pc).getStopPosition()==null)// not more than 100 PCs
	            	pcs.push(pc);
	            //SystemOut.printDate(config.getOutWriter(),"Release: (id:"+pc.getId()+";running-requests:"+config.getThreadQueue().size()+";)");
	        
       /*}
        else {
        	 SystemOut.printDate(config.getOutWriter(),"Unlink: ("+pc.getId()+")");
        }*/
	}
    
    /**
	 * check timeout of all running threads, downgrade also priority from all thread run longer than 10 seconds
	 */
	public void checkTimeout() {
		if(!engine.allowRequestTimeout())return;
		//synchronized (runningPcs) {
            //int len=runningPcs.size();
			Iterator<Entry<Integer, PageContextImpl>> it = runningPcs.entrySet().iterator();
            PageContextImpl pc;
            //Collection.Key key;
            Entry<Integer, PageContextImpl> e;
            while(it.hasNext()) {
            	e = it.next();
            	pc=e.getValue();
                
                long timeout=pc.getRequestTimeout();
                if(pc.getStartTime()+timeout<System.currentTimeMillis()) {
                    terminate(pc);
                    it.remove();
                }
                // after 10 seconds downgrade priority of the thread
                else if(pc.getStartTime()+10000<System.currentTimeMillis() && pc.getThread().getPriority()!=Thread.MIN_PRIORITY) {
                    Log log = config.getLog("requesttimeout");
                    if(log!=null)log.log(Log.LEVEL_WARN,"controler","downgrade priority of the a thread at "+getPath(pc));
                    try {
                    	pc.getThread().setPriority(Thread.MIN_PRIORITY);
                    }
                    catch(Throwable t) {}
                }
            }
        //}
	}
	
	public static void terminate(PageContextImpl pc) {
		Log log = ((ConfigImpl)pc.getConfig()).getLog("requesttimeout");
        
		
        if(log!=null)LogUtil.log(log,Log.LEVEL_ERROR,"controler",
        		"stop thread ("+pc.getId()+") because run into a timeout "+getPath(pc)+"."+getLocks(pc),pc.getThread().getStackTrace());
        
        // then we release the pagecontext
        pc.getConfig().getThreadQueue().exit(pc);
        SystemUtil.stop(pc,createRequestTimeoutException(pc),log);
	}

	private static String getLocks(PageContext pc) {
		String strLocks="";
		try{
			LockManager manager = pc.getConfig().getLockManager();
	        String[] locks = manager.getOpenLockNames();
	        if(!ArrayUtil.isEmpty(locks)) 
	        	strLocks=" open locks at this time ("+ListUtil.arrayToList(locks, ", ")+").";
	        //LockManagerImpl.unlockAll(pc.getId());
		}
		catch(Throwable t){}
		return strLocks;
	}

	public static RequestTimeoutException createRequestTimeoutException(PageContext pc) {
		return new RequestTimeoutException(pc.getThread(),"request ("+getPath(pc)+":"+pc.getId()+") has run into a timeout ("+(pc.getRequestTimeout()/1000)+" seconds) and has been stopped."+getLocks(pc));
	}

	private static String getPath(PageContext pc) {
		try {
			String base=ResourceUtil.getResource(pc, pc.getBasePageSource()).getAbsolutePath();
			String current=ResourceUtil.getResource(pc, pc.getCurrentPageSource()).getAbsolutePath();
			if(base.equals(current)) return "path: "+base;
			return "path: "+base+" ("+current+")";
		}
		catch(Throwable t) {
			return "(fail to retrieve path:"+t.getClass().getName()+":"+t.getMessage()+")";
		}
	}
	
	@Override
	public JspEngineInfo getEngineInfo() {
		return info;
	}
{'fraction_non_alphanumeric': 0.11381174864822301, 'fraction_numerical': 0.0032547640296078533, 'mean_word_length': 3.397506925207756, 'pattern_counts': {'":': 4, '<': 31, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5627203', 'n_tokens_mistral': 5848, 'n_tokens_neox': 5520, 'n_words': 1254}