1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.jasper.runtime;
19
20 import javax.servlet.ServletConfig;
21 import javax.servlet.jsp.JspException;
22 import javax.servlet.jsp.tagext.Tag;
23
24 import org.apache.AnnotationProcessor;
25 import org.apache.jasper.Constants;
26 import org.apache.juli.logging.Log;
27 import org.apache.juli.logging.LogFactory;
28
29 /**
30 * Pool of tag handlers that can be reused.
31 *
32 * @author Jan Luehe
33 */
34 public class TagHandlerPool {
35
36 private Tag[] handlers;
37
38 public static String OPTION_TAGPOOL="tagpoolClassName";
39 public static String OPTION_MAXSIZE="tagpoolMaxSize";
40
41 private Log log = LogFactory.getLog(TagHandlerPool.class);
42
43 // index of next available tag handler
44 private int current;
45 protected AnnotationProcessor annotationProcessor = null;
46
47 public static TagHandlerPool getTagHandlerPool( ServletConfig config) {
48 TagHandlerPool result=null;
49
50 String tpClassName=getOption( config, OPTION_TAGPOOL, null);
51 if( tpClassName != null ) {
52 try {
53 Class c=Class.forName( tpClassName );
54 result=(TagHandlerPool)c.newInstance();
55 } catch (Exception e) {
56 e.printStackTrace();
57 result=null;
58 }
59 }
60 if( result==null ) result=new TagHandlerPool();
61 result.init(config);
62
63 return result;
64 }
65
66 protected void init( ServletConfig config ) {
67 int maxSize=-1;
68 String maxSizeS=getOption(config, OPTION_MAXSIZE, null);
69 if( maxSizeS != null ) {
70 try {
71 maxSize=Integer.parseInt(maxSizeS);
72 } catch( Exception ex) {
73 maxSize=-1;
74 }
75 }
76 if( maxSize <0 ) {
77 maxSize=Constants.MAX_POOL_SIZE;
78 }
79 this.handlers = new Tag[maxSize];
80 this.current = -1;
81 this.annotationProcessor =
82 (AnnotationProcessor) config.getServletContext().getAttribute(AnnotationProcessor.class.getName());
83 }
84
85 /**
86 * Constructs a tag handler pool with the default capacity.
87 */
88 public TagHandlerPool() {
89 // Nothing - jasper generated servlets call the other constructor,
90 // this should be used in future + init .
91 }
92
93 /**
94 * Constructs a tag handler pool with the given capacity.
95 *
96 * @param capacity Tag handler pool capacity
97 * @deprecated Use static getTagHandlerPool
98 */
99 public TagHandlerPool(int capacity) {
100 this.handlers = new Tag[capacity];
101 this.current = -1;
102 }
103
104 /**
105 * Gets the next available tag handler from this tag handler pool,
106 * instantiating one if this tag handler pool is empty.
107 *
108 * @param handlerClass Tag handler class
109 *
110 * @return Reused or newly instantiated tag handler
111 *
112 * @throws JspException if a tag handler cannot be instantiated
113 */
114 public Tag get(Class handlerClass) throws JspException {
115 Tag handler = null;
116 synchronized( this ) {
117 if (current >= 0) {
118 handler = handlers[current--];
119 return handler;
120 }
121 }
122
123 // Out of sync block - there is no need for other threads to
124 // wait for us to construct a tag for this thread.
125 try {
126 Tag instance = (Tag) handlerClass.newInstance();
127 AnnotationHelper.postConstruct(annotationProcessor, instance);
128 return instance;
129 } catch (Exception e) {
130 throw new JspException(e.getMessage(), e);
131 }
132 }
133
134 /**
135 * Adds the given tag handler to this tag handler pool, unless this tag
136 * handler pool has already reached its capacity, in which case the tag
137 * handler's release() method is called.
138 *
139 * @param handler Tag handler to add to this tag handler pool
140 */
141 public void reuse(Tag handler) {
142 synchronized( this ) {
143 if (current < (handlers.length - 1)) {
144 handlers[++current] = handler;
145 return;
146 }
147 }
148 // There is no need for other threads to wait for us to release
149 handler.release();
150 if (annotationProcessor != null) {
151 try {
152 AnnotationHelper.preDestroy(annotationProcessor, handler);
153 } catch (Exception e) {
154 log.warn("Error processing preDestroy on tag instance of "
155 + handler.getClass().getName(), e);
156 }
157 }
158 }
159
160 /**
161 * Calls the release() method of all available tag handlers in this tag
162 * handler pool.
163 */
164 public synchronized void release() {
165 for (int i = current; i >= 0; i--) {
166 handlers[i].release();
167 if (annotationProcessor != null) {
168 try {
169 AnnotationHelper.preDestroy(annotationProcessor, handlers[i]);
170 } catch (Exception e) {
171 log.warn("Error processing preDestroy on tag instance of "
172 + handlers[i].getClass().getName(), e);
173 }
174 }
175 }
176 }
177
178 protected static String getOption( ServletConfig config, String name, String defaultV) {
179 if( config == null ) return defaultV;
180
181 String value=config.getInitParameter(name);
182 if( value != null ) return value;
183 if( config.getServletContext() ==null )
184 return defaultV;
185 value=config.getServletContext().getInitParameter(name);
186 if( value!=null ) return value;
187 return defaultV;
188 }
189
190 }
191