package railo.runtime.tag;

import java.util.HashMap;
import java.util.Map;
import java.util.Stack;

import javax.servlet.jsp.tagext.Tag;

import railo.commons.lang.ClassUtil;
import railo.runtime.config.ConfigWeb;
import railo.runtime.exp.ExpressionException;
import railo.runtime.exp.PageException;
import railo.runtime.op.Caster;

// TODO kann man nicht auf context ebene

/**
 * Pool to Handle Tags
 */
public final class TagHandlerPool {
	private Map<String,Stack<Tag>> map=new HashMap<String,Stack<Tag>>();
	private ConfigWeb config;
	
	public TagHandlerPool(ConfigWeb config) { 
		this.config=config;
	}

	/**
	 * return a tag to use from a class
	 * @param tagClass
	 * @return Tag
	 * @throws PageException
	 */
	public Tag use(String tagClass) throws PageException {
		Stack<Tag> stack = getStack(tagClass);
		synchronized (stack) {
			if(!stack.isEmpty()){
	        	Tag tag=stack.pop();
	        	if(tag!=null) return tag;
	        }
		}
		return loadTag(tagClass);
	}

	/**
	 * free a tag for reusing
	 * @param tag
	 * @throws ExpressionException
	 */
	public synchronized void reuse(Tag tag) {
		tag.release();
		Stack<Tag> stack = getStack(tag.getClass().getName());
		synchronized (stack) {
			stack.add(tag);
		}
	}
	
	
	private Tag loadTag(String tagClass) throws PageException {
		try {
			Class<Tag> clazz = ClassUtil.loadClass(config.getClassLoader(),tagClass);
			return clazz.newInstance();
		} 
		catch (Exception e) {
			throw Caster.toPageException(e);
		}
	}

	private Stack<Tag> getStack(String tagClass) {
		synchronized (map) {
			Stack<Tag> stack = map.get(tagClass);
	        if(stack==null) {
				stack=new Stack<Tag>();
				map.put(tagClass,stack);
			}
	        return stack;
		}
	}

	public void reset() {
		map.clear();
	}
}
@@ -86,21 +86,143 @@
 va.util.
-Stack
+Queue;%0Aimport java.util.Stack;%0Aimport java.util.concurrent.ConcurrentHashMap;%0Aimport java.util.concurrent.ConcurrentLinkedQueue
 ;%0A%0Aimpor
@@ -567,16 +567,30 @@
 private 
+ConcurrentHash
 Map%3CStri
@@ -588,29 +588,29 @@
 hMap%3CString,
-Stack
+Queue
 %3CTag%3E%3E map=n
@@ -612,16 +612,26 @@
 map=new 
+Concurrent
 HashMap%3C
@@ -637,21 +637,21 @@
 %3CString,
-Stack
+Queue
 %3CTag%3E%3E()
@@ -922,35 +922,35 @@
 %7B%0A%09%09
-Stack
+Queue
 %3CTag%3E 
-stack
+queue
  = get
-Stack
+Queue
 (tag
@@ -963,96 +963,33 @@
 ;%0A%09%09
-synchronized (stack) %7B%0A%09%09%09if(!stack.isEmpty())%7B%0A%09        %09Tag tag=stack.pop
+Tag tag = queue.poll
 ();%0A%09
-        
 %09if(
@@ -1015,23 +1015,8 @@
 ag;%0A
-%09        %7D%0A%09%09%7D%0A
 %09%09re
@@ -1135,29 +1135,16 @@
 %09public 
-synchronized 
 void reu
@@ -1180,35 +1180,35 @@
 ;%0A%09%09
-Stack
+Queue
 %3CTag%3E 
-stack
+queue
  = get
-Stack
+Queue
 (tag
@@ -1237,39 +1237,13 @@
 ;%0A%09%09
-synchronized (stack) %7B%0A%09%09%09stack
+queue
 .add
@@ -1249,20 +1249,16 @@
 d(tag);%0A
-%09%09%7D%0A
 %09%7D%0A%09%0A%09%0A%09
@@ -1515,21 +1515,21 @@
 private 
-Stack
+Queue
 %3CTag%3E ge
@@ -1529,21 +1529,21 @@
 Tag%3E get
-Stack
+Queue
 (String 
@@ -1560,48 +1560,24 @@
 %7B%0A%09%09
-synchronized (map) %7B%0A%09%09%09Stack
+Queue
 %3CTag%3E 
-stack
+queue
  = m
@@ -1593,18 +1593,101 @@
 gClass);
+// doing get before, do avoid constructing ConcurrentLinkedQueue Object all the time
 %0A
-%09
         
@@ -1693,111 +1693,195 @@
  if(
-stack=
+queue!
 =null) 
-%7B%0A%09%09%09%09stack=new Stack%3CTag%3E();%0A%09%09%09%09map.put(tagClass,stack);%0A%09%09%09%7D%0A%09        return stack;%0A%09%09%7D
+return queue;%0A        Queue%3CTag%3E nq,oq;%0A        oq=map.putIfAbsent(tagClass, nq=new ConcurrentLinkedQueue%3CTag%3E());%0A        if(oq!=null) return oq;%0A        return nq;%0A        
 %0A%09%7D%0A

improve tag pool by switching from synchronized blocks to concurrent classes