1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.commons.jelly.tags.threads;
17
18 import org.apache.commons.jelly.JellyContext;
19 import org.apache.commons.jelly.JellyTagException;
20 import org.apache.commons.jelly.TagSupport;
21 import org.apache.commons.jelly.XMLOutput;
22 import org.apache.commons.jelly.util.NestedRuntimeException;
23
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26
27 import java.io.FileOutputStream;
28 import java.io.IOException;
29 import java.io.UnsupportedEncodingException;
30
31 /***
32 * A tag that spawns the contained script in a separate thread. A thread
33 * can wait on another thread or another thread group to finish before starting.
34 *
35 * @author <a href="mailto:vinayc@apache.org">Vinay Chandran</a>
36 * @author <a href="mailto:jason@jhorman.org">Jason Horman</a>
37 */
38 public class ThreadTag extends TagSupport {
39 /*** The Log to which logging calls will be made. */
40 private static final Log log = LogFactory.getLog(ThreadTag.class);
41
42 /*** The current thread number. Used for default thread naming */
43 private static int threadNumber = 0;
44
45 /*** Variable to place the thread into */
46 private String var = null;
47 /*** Thread Name */
48 private String name = null;
49 /*** Thread priority, defaults to Thread.NORM_PRIORITY */
50 private int priority = Thread.NORM_PRIORITY;
51 /*** Set if the thread should be a daemon or not */
52 private boolean daemon = false;
53 /*** the destination of output */
54 private XMLOutput xmlOutput;
55 /*** Should we close the underlying output */
56 private boolean closeOutput;
57 /*** Should a new context be created */
58 private boolean newContext = false;
59 /*** Keep a reference to the thread */
60 private JellyThread thread = new JellyThread();
61
62 public ThreadTag() {
63 super();
64 }
65
66 public ThreadTag(boolean shouldTrim) {
67 super(shouldTrim);
68 }
69
70
71
72 public void doTag(final XMLOutput output) throws JellyTagException {
73 if (xmlOutput == null) {
74
75 try {
76 xmlOutput = XMLOutput.createXMLOutput(System.out);
77 }
78 catch (UnsupportedEncodingException e) {
79 throw new JellyTagException(e);
80 }
81 }
82
83
84 final JellyContext useThisContext = newContext ? context.newJellyContext() : context;
85
86
87 thread.setTarget(new Runnable() {
88 public void run() {
89 try {
90 getBody().run(useThisContext, xmlOutput);
91 if (closeOutput) {
92 xmlOutput.close();
93 }
94 else {
95 xmlOutput.flush();
96 }
97 }
98 catch (JellyTagException e) {
99
100 Throwable subException = e.getCause();
101 if (subException != null) {
102 if (subException instanceof TimeoutException) {
103 throw (TimeoutException)subException;
104 } else if (subException instanceof RequirementException) {
105 throw (RequirementException)subException;
106 }
107 }
108
109 log.error(e);
110
111
112 throw new NestedRuntimeException(e);
113 }
114 catch (Exception e) {
115 log.error(e);
116
117
118 if (e instanceof RuntimeException) {
119 throw (RuntimeException) e;
120 }
121 else {
122 throw new NestedRuntimeException(e);
123 }
124 }
125 }
126 });
127
128
129 thread.setPriority(priority);
130
131
132 if (name != null) {
133 thread.setName(name);
134 } else {
135 thread.setName("Jelly Thread #" + (threadNumber++));
136 }
137
138
139 thread.setDaemon(daemon);
140
141
142 if (var != null) {
143 context.setVariable(var, thread);
144 }
145
146
147
148
149 GroupTag gt = (GroupTag) findAncestorWithClass(GroupTag.class);
150 if (gt != null) {
151 gt.addThread(thread);
152 } else {
153
154 thread.start();
155 }
156 }
157
158 /***
159 * Sets the variable name to export, optional
160 * @param var The variable name
161 */
162 public void setVar(String var) {
163 this.var = var;
164 if (name == null) {
165 name = var;
166 }
167 }
168
169 /***
170 * Sets the name of the thread.
171 * @param name The name to set
172 */
173 public void setName(String name) {
174 this.name = name;
175 }
176
177 /***
178 * Set the threads priority. Defaults to Thread.NORM_PRIORITY
179 */
180 public void setPriority(int priority) {
181 this.priority = priority;
182 }
183
184 /***
185 * Sets the thread to be a daemon thread if true
186 */
187 public void setDaemon(boolean daemon) {
188 this.daemon = daemon;
189 }
190
191 /***
192 * Sets the destination of output
193 */
194 public void setXmlOutput(XMLOutput xmlOutput) {
195 this.closeOutput = false;
196 this.xmlOutput = xmlOutput;
197 }
198
199 /***
200 * Set the file which is generated from the output
201 * @param name The output file name
202 */
203 public void setFile(String name) throws IOException {
204 this.closeOutput = true;
205 setXmlOutput(XMLOutput.createXMLOutput(new FileOutputStream(name)));
206 }
207
208 /***
209 * Should a new context be created for this thread?
210 */
211 public void setNewContext(boolean newContext) {
212 this.newContext = newContext;
213 }
214
215 /***
216 * Get the thread instance
217 * @return The thread
218 */
219 public Thread getThread() {
220 return thread;
221 }
222 }