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.tag;
020
021import java.util.Queue;
022import java.util.concurrent.ConcurrentHashMap;
023import java.util.concurrent.ConcurrentLinkedQueue;
024
025import javax.servlet.jsp.tagext.Tag;
026
027import lucee.commons.lang.ClassUtil;
028import lucee.runtime.config.ConfigWeb;
029import lucee.runtime.exp.ExpressionException;
030import lucee.runtime.exp.PageException;
031import lucee.runtime.op.Caster;
032
033// TODO kann man nicht auf context ebene
034
035/**
036 * Pool to Handle Tags
037 */
038public final class TagHandlerPool {
039        private ConcurrentHashMap<String,Queue<Tag>> map=new ConcurrentHashMap<String,Queue<Tag>>();
040        private ConfigWeb config;
041        
042        public TagHandlerPool(ConfigWeb config) { 
043                this.config=config;
044        }
045
046        /**
047         * return a tag to use from a class
048         * @param tagClass
049         * @return Tag
050         * @throws PageException
051         */
052        public Tag use(String tagClass) throws PageException {
053                Queue<Tag> queue = getQueue(tagClass);
054                Tag tag = queue.poll();
055                if(tag!=null) return tag;
056                return loadTag(tagClass);
057        }
058
059        /**
060         * free a tag for reusing
061         * @param tag
062         * @throws ExpressionException
063         */
064        public void reuse(Tag tag) {
065                tag.release();
066                Queue<Tag> queue = getQueue(tag.getClass().getName());
067                queue.add(tag);
068        }
069        
070        
071        private Tag loadTag(String tagClass) throws PageException {
072                try {
073                        Class<Tag> clazz = ClassUtil.loadClass(config.getClassLoader(),tagClass);
074                        return clazz.newInstance();
075                } 
076                catch (Exception e) {
077                        throw Caster.toPageException(e);
078                }
079        }
080
081        private Queue<Tag> getQueue(String tagClass) {
082                Queue<Tag> queue = map.get(tagClass);// doing get before, do avoid constructing ConcurrentLinkedQueue Object all the time
083        if(queue!=null) return queue;
084        Queue<Tag> nq,oq;
085        oq=map.putIfAbsent(tagClass, nq=new ConcurrentLinkedQueue<Tag>());
086        if(oq!=null) return oq;
087        return nq;
088        
089        }
090
091        public void reset() {
092                map.clear();
093        }
094}