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