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 java.util.Enumeration;
21 import java.util.Vector;
22
23 import javax.servlet.ServletConfig;
24 import javax.servlet.jsp.JspException;
25 import javax.servlet.jsp.tagext.Tag;
26
27 import org.apache.jasper.Constants;
28
29 /**
30 * Thread-local based pool of tag handlers that can be reused.
31 *
32 * @author Jan Luehe
33 * @author Costin Manolache
34 */
35 public class PerThreadTagHandlerPool extends TagHandlerPool {
36
37 private int maxSize;
38
39 // For cleanup
40 private Vector perThreadDataVector;
41
42 private ThreadLocal perThread;
43
44 private static class PerThreadData {
45 Tag handlers[];
46 int current;
47 }
48
49 /**
50 * Constructs a tag handler pool with the default capacity.
51 */
52 public PerThreadTagHandlerPool() {
53 super();
54 perThreadDataVector = new Vector();
55 }
56
57 protected void init(ServletConfig config) {
58 maxSize = Constants.MAX_POOL_SIZE;
59 String maxSizeS = getOption(config, OPTION_MAXSIZE, null);
60 if (maxSizeS != null) {
61 maxSize = Integer.parseInt(maxSizeS);
62 if (maxSize < 0) {
63 maxSize = Constants.MAX_POOL_SIZE;
64 }
65 }
66
67 perThread = new ThreadLocal() {
68 protected Object initialValue() {
69 PerThreadData ptd = new PerThreadData();
70 ptd.handlers = new Tag[maxSize];
71 ptd.current = -1;
72 perThreadDataVector.addElement(ptd);
73 return ptd;
74 }
75 };
76 }
77
78 /**
79 * Gets the next available tag handler from this tag handler pool,
80 * instantiating one if this tag handler pool is empty.
81 *
82 * @param handlerClass Tag handler class
83 *
84 * @return Reused or newly instantiated tag handler
85 *
86 * @throws JspException if a tag handler cannot be instantiated
87 */
88 public Tag get(Class handlerClass) throws JspException {
89 PerThreadData ptd = (PerThreadData)perThread.get();
90 if(ptd.current >=0 ) {
91 return ptd.handlers[ptd.current--];
92 } else {
93 try {
94 return (Tag) handlerClass.newInstance();
95 } catch (Exception e) {
96 throw new JspException(e.getMessage(), e);
97 }
98 }
99 }
100
101 /**
102 * Adds the given tag handler to this tag handler pool, unless this tag
103 * handler pool has already reached its capacity, in which case the tag
104 * handler's release() method is called.
105 *
106 * @param handler Tag handler to add to this tag handler pool
107 */
108 public void reuse(Tag handler) {
109 PerThreadData ptd=(PerThreadData)perThread.get();
110 if (ptd.current < (ptd.handlers.length - 1)) {
111 ptd.handlers[++ptd.current] = handler;
112 } else {
113 handler.release();
114 }
115 }
116
117 /**
118 * Calls the release() method of all tag handlers in this tag handler pool.
119 */
120 public void release() {
121 Enumeration enumeration = perThreadDataVector.elements();
122 while (enumeration.hasMoreElements()) {
123 PerThreadData ptd = (PerThreadData)enumeration.nextElement();
124 if (ptd.handlers != null) {
125 for (int i=ptd.current; i>=0; i--) {
126 if (ptd.handlers[i] != null) {
127 ptd.handlers[i].release();
128 }
129 }
130 }
131 }
132 }
133 }
134