Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
TurbinePullService |
|
| 3.35;3,35 | ||||
TurbinePullService$ToolData |
|
| 3.35;3,35 |
1 | package org.apache.turbine.services.pull; | |
2 | ||
3 | ||
4 | /* | |
5 | * Licensed to the Apache Software Foundation (ASF) under one | |
6 | * or more contributor license agreements. See the NOTICE file | |
7 | * distributed with this work for additional information | |
8 | * regarding copyright ownership. The ASF licenses this file | |
9 | * to you under the Apache License, Version 2.0 (the | |
10 | * "License"); you may not use this file except in compliance | |
11 | * with the License. You may obtain a copy of the License at | |
12 | * | |
13 | * http://www.apache.org/licenses/LICENSE-2.0 | |
14 | * | |
15 | * Unless required by applicable law or agreed to in writing, | |
16 | * software distributed under the License is distributed on an | |
17 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
18 | * KIND, either express or implied. See the License for the | |
19 | * specific language governing permissions and limitations | |
20 | * under the License. | |
21 | */ | |
22 | ||
23 | ||
24 | import java.util.ArrayList; | |
25 | import java.util.Iterator; | |
26 | import java.util.List; | |
27 | ||
28 | import org.apache.commons.configuration2.Configuration; | |
29 | import org.apache.fulcrum.pool.PoolService; | |
30 | import org.apache.fulcrum.security.model.turbine.TurbineUserManager; | |
31 | import org.apache.logging.log4j.LogManager; | |
32 | import org.apache.logging.log4j.Logger; | |
33 | import org.apache.turbine.Turbine; | |
34 | import org.apache.turbine.annotation.AnnotationProcessor; | |
35 | import org.apache.turbine.om.security.User; | |
36 | import org.apache.turbine.pipeline.PipelineData; | |
37 | import org.apache.turbine.services.InitializationException; | |
38 | import org.apache.turbine.services.TurbineBaseService; | |
39 | import org.apache.turbine.services.TurbineServices; | |
40 | import org.apache.turbine.services.velocity.VelocityService; | |
41 | import org.apache.turbine.util.RunData; | |
42 | import org.apache.velocity.context.Context; | |
43 | ||
44 | /** | |
45 | * This is the concrete implementation of the Turbine | |
46 | * Pull Service. | |
47 | * <p> | |
48 | * These are tools that are placed in the context by the service | |
49 | * These tools will be made available to all your | |
50 | * templates. You list the tools in the following way: | |
51 | * </p> | |
52 | * <pre> | |
53 | * tool.<scope>.<id> = <classname> | |
54 | * | |
55 | * <scope> is the tool scope: global, request, session, | |
56 | * authorized or persistent (see below for more details) | |
57 | * <id> is the name of the tool in the context | |
58 | * | |
59 | * You can configure the tools in this way: | |
60 | * tool.<id>.<parameter> = <value> | |
61 | * | |
62 | * So if you find "global", "request", "session" or "persistent" as second | |
63 | * part, it is a configuration to put a tool into the toolbox, else it is a | |
64 | * tool specific configuration. | |
65 | * | |
66 | * For example: | |
67 | * | |
68 | * tool.global.ui = org.apache.turbine.util.pull.UIManager | |
69 | * tool.global.mm = org.apache.turbine.util.pull.MessageManager | |
70 | * tool.request.link = org.apache.turbine.services.pull.tools.TemplateLink | |
71 | * tool.request.page = org.apache.turbine.util.template.TemplatePageAttributes | |
72 | * | |
73 | * Then: | |
74 | * | |
75 | * tool.ui.skin = default | |
76 | * | |
77 | * configures the value of "skin" for the "ui" tool. | |
78 | * | |
79 | * Tools are accessible in all templates by the <id> given | |
80 | * to the tool. So for the above listings the UIManager would | |
81 | * be available as $ui, the MessageManager as $mm, the TemplateLink | |
82 | * as $link and the TemplatePageAttributes as $page. | |
83 | * | |
84 | * You should avoid using tool names called "global", "request", | |
85 | * "session" or "persistent" because of clashes with the possible Scopes. | |
86 | * | |
87 | * Scopes: | |
88 | * | |
89 | * global: tool is instantiated once and that instance is available | |
90 | * to all templates for all requests. Tool must be threadsafe. | |
91 | * | |
92 | * request: tool is instantiated once for each request (although the | |
93 | * PoolService is used to recycle instances). Tool need not | |
94 | * be threadsafe. | |
95 | * | |
96 | * session: tool is instantiated once for each user session, and is | |
97 | * stored in the session. These tools do not need to be | |
98 | * threadsafe. | |
99 | * | |
100 | * authorized: tool is instantiated once for each user session once the | |
101 | * user logs in. After this, it is a normal session tool. | |
102 | * | |
103 | * persistent: tool is instantitated once for each user session once | |
104 | * the user logs in and is is stored in the user's permanent | |
105 | * hashtable. | |
106 | * This means for a logged in user the tool will be persisted | |
107 | * in the user's objectdata. Tool should be Serializable. These | |
108 | * tools do not need to be threadsafe. | |
109 | * <b>persistent scope tools are deprecated in 2.3</b> | |
110 | * | |
111 | * Defaults: none | |
112 | * </pre> | |
113 | * | |
114 | * @author <a href="mailto:jvanzyl@periapt.com">Jason van Zyl</a> | |
115 | * @author <a href="mailto:sean@informage.net">Sean Legassick</a> | |
116 | * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a> | |
117 | * @author <a href="mailto:quintonm@bellsouth.net">Quinton McCombs</a> | |
118 | * @author <a href="mailto:peter@courcoux.biz">Peter Courcoux</a> | |
119 | * @version $Id: TurbinePullService.java 1854797 2019-03-04 20:41:39Z tv $ | |
120 | */ | |
121 | 99 | public class TurbinePullService |
122 | extends TurbineBaseService | |
123 | implements PullService | |
124 | { | |
125 | /** Logging */ | |
126 | 99 | private static Logger log = LogManager.getLogger(TurbinePullService.class); |
127 | ||
128 | /** Reference to the pool service */ | |
129 | 99 | private PoolService pool = null; |
130 | ||
131 | /** Reference to the templating (nee Velocity) service */ | |
132 | 99 | private VelocityService velocity = null; |
133 | ||
134 | /** | |
135 | * This is the container for the global web application | |
136 | * tools that are used in conjunction with the | |
137 | * Turbine Pull Model. All the global tools will be placed | |
138 | * in this Context and be made accessible inside | |
139 | * templates via the tool name specified in the TR.props | |
140 | * file. | |
141 | */ | |
142 | private Context globalContext; | |
143 | ||
144 | /** | |
145 | * This inner class is used in the lists below to store the | |
146 | * tool name and class for each of request, session and persistent | |
147 | * tools | |
148 | */ | |
149 | private static class ToolData | |
150 | { | |
151 | String toolName; | |
152 | String toolClassName; | |
153 | Class<ApplicationTool> toolClass; | |
154 | ||
155 | public ToolData(String toolName, String toolClassName, Class<ApplicationTool> toolClass) | |
156 | 420 | { |
157 | 420 | this.toolName = toolName; |
158 | 420 | this.toolClassName = toolClassName; |
159 | 420 | this.toolClass = toolClass; |
160 | 420 | } |
161 | } | |
162 | ||
163 | /** Internal list of global tools */ | |
164 | private List<ToolData> globalTools; | |
165 | ||
166 | /** Internal list of request tools */ | |
167 | private List<ToolData> requestTools; | |
168 | ||
169 | /** Internal list of session tools */ | |
170 | private List<ToolData> sessionTools; | |
171 | ||
172 | /** Internal list of authorized tools */ | |
173 | private List<ToolData> authorizedTools; | |
174 | ||
175 | /** Internal list of persistent tools */ | |
176 | private List<ToolData> persistentTools; | |
177 | ||
178 | /** Directory where application tool resources are stored.*/ | |
179 | private String resourcesDirectory; | |
180 | ||
181 | /** Should we refresh the application tools on a per request basis? */ | |
182 | 99 | private boolean refreshToolsPerRequest = false; |
183 | ||
184 | /** | |
185 | * Called the first time the Service is used. | |
186 | */ | |
187 | @Override | |
188 | public void init() | |
189 | throws InitializationException | |
190 | { | |
191 | try | |
192 | { | |
193 | 120 | pool = (PoolService)TurbineServices.getInstance().getService(PoolService.ROLE); |
194 | ||
195 | 120 | if (pool == null) |
196 | { | |
197 | 0 | throw new InitializationException("Pull Service requires" |
198 | + " configured Pool Service!"); | |
199 | } | |
200 | ||
201 | 120 | initPullService(); |
202 | // Make sure to setInit(true) because Tools may | |
203 | // make calls back to the TurbinePull static methods | |
204 | // which causes an init loop. | |
205 | 120 | setInit(true); |
206 | ||
207 | // Do _NOT_ move this before the setInit(true) | |
208 | 120 | velocity = (VelocityService)TurbineServices.getInstance().getService(VelocityService.SERVICE_NAME); |
209 | ||
210 | 87 | if (velocity != null) |
211 | { | |
212 | 87 | initPullTools(); |
213 | } | |
214 | else | |
215 | { | |
216 | 0 | log.info("Velocity Service not configured, skipping pull tools!"); |
217 | } | |
218 | } | |
219 | 33 | catch (Exception e) |
220 | { | |
221 | 33 | throw new InitializationException("TurbinePullService failed to initialize", e); |
222 | 87 | } |
223 | 87 | } |
224 | ||
225 | /** | |
226 | * Initialize the pull service | |
227 | * | |
228 | * @throws Exception A problem happened when starting up | |
229 | */ | |
230 | private void initPullService() | |
231 | throws Exception | |
232 | { | |
233 | // This is the per-service configuration, prefixed with services.PullService | |
234 | 120 | Configuration conf = getConfiguration(); |
235 | ||
236 | // Get the resources directory that is specificed | |
237 | // in the TR.props or default to "resources", relative to the webapp. | |
238 | 120 | resourcesDirectory = conf.getString( |
239 | TOOL_RESOURCES_DIR_KEY, | |
240 | TOOL_RESOURCES_DIR_DEFAULT); | |
241 | ||
242 | // Should we refresh the tool box on a per | |
243 | // request basis. | |
244 | 120 | refreshToolsPerRequest = |
245 | 120 | conf.getBoolean( |
246 | TOOLS_PER_REQUEST_REFRESH_KEY, | |
247 | TOOLS_PER_REQUEST_REFRESH_DEFAULT); | |
248 | ||
249 | // Log the fact that the application tool box will | |
250 | // be refreshed on a per request basis. | |
251 | 120 | if (refreshToolsPerRequest) |
252 | { | |
253 | 93 | log.info("Pull Model tools will be refreshed on a per request basis."); |
254 | } | |
255 | 120 | } |
256 | ||
257 | /** | |
258 | * Initialize the pull tools. At this point, the | |
259 | * service must be marked as initialized, because the | |
260 | * tools may call the methods of this service via the | |
261 | * static facade class TurbinePull. | |
262 | * | |
263 | * @throws Exception A problem happened when starting up | |
264 | */ | |
265 | private void initPullTools() | |
266 | throws Exception | |
267 | { | |
268 | // And for reasons I never really fully understood, | |
269 | // the tools directive is toplevel without the service | |
270 | // prefix. This is brain-damaged but for legacy reasons we | |
271 | // keep this. So this is the global turbine configuration: | |
272 | 87 | Configuration conf = Turbine.getConfiguration(); |
273 | ||
274 | // Grab each list of tools that are to be used (for global scope, | |
275 | // request scope, authorized scope, session scope and persistent | |
276 | // scope tools). They are specified respectively in the TR.props | |
277 | // like this: | |
278 | // | |
279 | // tool.global.ui = org.apache.turbine.util.pull.UIManager | |
280 | // tool.global.mm = org.apache.turbine.util.pull.MessageManager | |
281 | // | |
282 | // tool.request.link = org.apache.turbine.services.pull.tools.TemplateLink | |
283 | // | |
284 | // tool.session.basket = org.sample.util.ShoppingBasket; | |
285 | // | |
286 | // tool.persistent.ui = org.apache.turbine.services.pull.util.PersistentUIManager | |
287 | ||
288 | 87 | log.debug("Global Tools:"); |
289 | 87 | globalTools = getTools(conf.subset(GLOBAL_TOOL)); |
290 | 87 | log.debug("Request Tools:"); |
291 | 87 | requestTools = getTools(conf.subset(REQUEST_TOOL)); |
292 | 87 | log.debug("Session Tools:"); |
293 | 87 | sessionTools = getTools(conf.subset(SESSION_TOOL)); |
294 | 87 | log.debug("Authorized Tools:"); |
295 | 87 | authorizedTools = getTools(conf.subset(AUTHORIZED_TOOL)); |
296 | 87 | log.debug("Persistent Tools:"); |
297 | 87 | persistentTools = getTools(conf.subset(PERSISTENT_TOOL)); |
298 | ||
299 | // Create and populate the global context right now | |
300 | ||
301 | // This is unholy, because it entwines the VelocityService and | |
302 | // the Pull Service even further. However, there isn't much we can | |
303 | // do for the 2.3 release. Expect this to go post-2.3 | |
304 | 87 | globalContext = velocity.getNewContext(); |
305 | ||
306 | 87 | populateWithGlobalTools(globalContext); |
307 | 87 | } |
308 | ||
309 | /** | |
310 | * Retrieve the tool names and classes for the tools defined | |
311 | * in the configuration file with the prefix given. | |
312 | * | |
313 | * @param toolConfig The part of the configuration describing some tools | |
314 | */ | |
315 | @SuppressWarnings("unchecked") | |
316 | private List<ToolData> getTools(Configuration toolConfig) | |
317 | { | |
318 | 435 | List<ToolData> tools = new ArrayList<ToolData>(); |
319 | ||
320 | // There might not be any tools for this prefix | |
321 | // so return an empty list. | |
322 | 435 | if (toolConfig == null) |
323 | { | |
324 | 0 | return tools; |
325 | } | |
326 | ||
327 | 435 | for (Iterator<String> it = toolConfig.getKeys(); it.hasNext();) |
328 | { | |
329 | 420 | String toolName = it.next(); |
330 | 420 | String toolClassName = toolConfig.getString(toolName); |
331 | ||
332 | try | |
333 | { | |
334 | // Create an instance of the tool class. | |
335 | 420 | Class<ApplicationTool> toolClass = (Class<ApplicationTool>) Class.forName(toolClassName); |
336 | ||
337 | // Add the tool to the list being built. | |
338 | 420 | tools.add(new ToolData(toolName, toolClassName, toolClass)); |
339 | ||
340 | 420 | log.info("Tool {} to add to the context as '${}'", toolClassName, toolName); |
341 | } | |
342 | 0 | catch (NoClassDefFoundError | ClassNotFoundException e) |
343 | { | |
344 | 0 | log.error("Cannot instantiate tool class {}", toolClassName, e); |
345 | 420 | } |
346 | 420 | } |
347 | ||
348 | 435 | return tools; |
349 | } | |
350 | ||
351 | /** | |
352 | * Return the Context which contains all global tools that | |
353 | * are to be used in conjunction with the Turbine | |
354 | * Pull Model. The tools are refreshed every time the | |
355 | * global Context is pulled. | |
356 | */ | |
357 | @Override | |
358 | public Context getGlobalContext() | |
359 | { | |
360 | 30 | if (refreshToolsPerRequest) |
361 | { | |
362 | 30 | refreshGlobalTools(); |
363 | } | |
364 | 30 | return globalContext; |
365 | } | |
366 | ||
367 | /** | |
368 | * Populate the given context with all request, session, authorized | |
369 | * and persistent scope tools (it is assumed that the context | |
370 | * already wraps the global context, and thus already contains | |
371 | * the global tools). | |
372 | * | |
373 | * @param context a Velocity Context to populate | |
374 | * @param data a RunData object for request specific data | |
375 | */ | |
376 | @Override | |
377 | public void populateContext(Context context, RunData data) | |
378 | { | |
379 | 0 | populateWithRequestTools(context, data); |
380 | ||
381 | // session tools (whether session-only or persistent are | |
382 | // very similar, so the same method is used - the | |
383 | // boolean parameter indicates whether get/setPerm is to be used | |
384 | // rather than get/setTemp) | |
385 | ||
386 | // | |
387 | // Session Tool start right at the session once the user has been set | |
388 | // while persistent and authorized Tools are started when the user has | |
389 | // logged in | |
390 | // | |
391 | 0 | User user = data.getUser(); |
392 | ||
393 | // Note: Session tools are currently lost after the login action | |
394 | // because the anonymous user is replaced the the real user object. | |
395 | // We should either store the session pull tools in the session or | |
396 | // make Turbine.loginAction() copy the session pull tools into the | |
397 | // new user object. | |
398 | 0 | populateWithSessionTools(sessionTools, context, data, user); |
399 | ||
400 | TurbineUserManager userManager = | |
401 | (TurbineUserManager)TurbineServices | |
402 | 0 | .getInstance() |
403 | 0 | .getService(TurbineUserManager.ROLE); |
404 | ||
405 | 0 | if (!userManager.isAnonymousUser(user) && user.hasLoggedIn()) |
406 | { | |
407 | 0 | populateWithSessionTools(authorizedTools, context, data, user); |
408 | 0 | populateWithPermTools(persistentTools, context, data, user); |
409 | } | |
410 | 0 | } |
411 | ||
412 | /** | |
413 | * Populate the given context with all request, session, authorized | |
414 | * and persistent scope tools (it is assumed that the context | |
415 | * already wraps the global context, and thus already contains | |
416 | * the global tools). | |
417 | * | |
418 | * @param context a Velocity Context to populate | |
419 | * @param pipelineData a PipelineData object for request specific data | |
420 | */ | |
421 | @Override | |
422 | public void populateContext(Context context, PipelineData pipelineData) | |
423 | { | |
424 | 27 | RunData data = pipelineData.getRunData(); |
425 | ||
426 | 27 | populateWithRequestTools(context, pipelineData); |
427 | // session tools (whether session-only or persistent are | |
428 | // very similar, so the same method is used - the | |
429 | // boolean parameter indicates whether get/setPerm is to be used | |
430 | // rather than get/setTemp) | |
431 | ||
432 | // | |
433 | // Session Tool start right at the session once the user has been set | |
434 | // while persistent and authorized Tools are started when the user has | |
435 | // logged in | |
436 | // | |
437 | 27 | User user = data.getUser(); |
438 | ||
439 | // Note: Session tools are currently lost after the login action | |
440 | // because the anonymous user is replaced the the real user object. | |
441 | // We should either store the session pull tools in the session or | |
442 | // make Turbine.loginAction() copy the session pull tools into the | |
443 | // new user object. | |
444 | 27 | populateWithSessionTools(sessionTools, context, data, user); |
445 | ||
446 | TurbineUserManager userManager = | |
447 | (TurbineUserManager)TurbineServices | |
448 | 27 | .getInstance() |
449 | 27 | .getService(TurbineUserManager.ROLE); |
450 | ||
451 | 27 | if (!userManager.isAnonymousUser(user) && user.hasLoggedIn()) |
452 | { | |
453 | 6 | populateWithSessionTools(authorizedTools, context, data, user); |
454 | 6 | populateWithPermTools(persistentTools, context, pipelineData, user); |
455 | } | |
456 | 27 | } |
457 | ||
458 | /** | |
459 | * Populate the given context with the global tools | |
460 | * | |
461 | * @param context a Velocity Context to populate | |
462 | */ | |
463 | private void populateWithGlobalTools(Context context) | |
464 | { | |
465 | 87 | for (ToolData toolData : globalTools) |
466 | { | |
467 | try | |
468 | { | |
469 | 60 | Object tool = toolData.toolClass.newInstance(); |
470 | ||
471 | // global tools are init'd with a null data parameter | |
472 | 60 | initTool(tool, null); |
473 | ||
474 | // put the tool in the context | |
475 | 60 | context.put(toolData.toolName, tool); |
476 | } | |
477 | 0 | catch (Exception e) |
478 | { | |
479 | 0 | log.error("Could not instantiate global tool {} from a {} object", |
480 | toolData.toolName, toolData.toolClassName, e); | |
481 | 60 | } |
482 | 60 | } |
483 | 87 | } |
484 | ||
485 | /** | |
486 | * Populate the given context with the request-scope tools | |
487 | * | |
488 | * @param context a Velocity Context to populate | |
489 | * @param data a RunData or PipelineData instance | |
490 | */ | |
491 | private void populateWithRequestTools(Context context, Object data) | |
492 | { | |
493 | // Iterate the tools | |
494 | 27 | for (ToolData toolData : requestTools) |
495 | { | |
496 | try | |
497 | { | |
498 | // Fetch Object through the Pool. | |
499 | 135 | Object tool = pool.getInstance(toolData.toolClass); |
500 | ||
501 | // request tools are init'd with a RunData object | |
502 | 135 | initTool(tool, data); |
503 | ||
504 | // put the tool in the context | |
505 | 135 | context.put(toolData.toolName, tool); |
506 | } | |
507 | 0 | catch (Exception e) |
508 | { | |
509 | 0 | log.error("Could not instantiate request tool {} from a {} object", |
510 | toolData.toolName, toolData.toolClassName, e); | |
511 | 135 | } |
512 | 135 | } |
513 | 27 | } |
514 | ||
515 | /** | |
516 | * Populate the given context with the session-scoped tools. | |
517 | * | |
518 | * @param tools The list of tools with which to populate the session. | |
519 | * @param context The context to populate. | |
520 | * @param data The current RunData object | |
521 | * @param user The <code>User</code> object whose storage to | |
522 | * retrieve the tool from. | |
523 | */ | |
524 | private void populateWithSessionTools(List<ToolData> tools, Context context, | |
525 | RunData data, User user) | |
526 | { | |
527 | // Iterate the tools | |
528 | 33 | for (ToolData toolData : tools) |
529 | { | |
530 | try | |
531 | { | |
532 | // ensure that tool is created only once for a user | |
533 | // by synchronizing against the user object | |
534 | 27 | synchronized (data.getSession()) |
535 | { | |
536 | // first try and fetch the tool from the user's | |
537 | // hashmap | |
538 | 27 | Object tool = data.getSession().getAttribute( |
539 | SESSION_TOOLS_ATTRIBUTE_PREFIX | |
540 | + toolData.toolClassName); | |
541 | ||
542 | 27 | if (tool == null) |
543 | { | |
544 | // if not there, an instance must be fetched from | |
545 | // the pool | |
546 | 27 | tool = pool.getInstance(toolData.toolClass); |
547 | ||
548 | // session tools are init'd with the User object | |
549 | 27 | initTool(tool, user); |
550 | } | |
551 | ||
552 | // *NOT* else | |
553 | 27 | if(tool != null) |
554 | { | |
555 | // store the newly created tool in the session | |
556 | 54 | data.getSession().setAttribute( |
557 | SESSION_TOOLS_ATTRIBUTE_PREFIX | |
558 | 27 | + tool.getClass().getName(), tool); |
559 | ||
560 | // This is a semantics change. In the old | |
561 | // Turbine, Session tools were initialized and | |
562 | // then refreshed every time they were pulled | |
563 | // into the context if "refreshToolsPerRequest" | |
564 | // was wanted. | |
565 | // | |
566 | // RunDataApplicationTools now have a parameter | |
567 | // for refresh. If it is not refreshed immediately | |
568 | // after init(), the parameter value will be undefined | |
569 | // until the 2nd run. So we refresh all the session | |
570 | // tools on every run, even if we just init'ed it. | |
571 | // | |
572 | ||
573 | 27 | if (refreshToolsPerRequest) |
574 | { | |
575 | 27 | refreshTool(tool, data); |
576 | } | |
577 | ||
578 | // put the tool in the context | |
579 | 27 | log.debug("Adding {} to ctx as {}", tool, toolData.toolName); |
580 | 27 | context.put(toolData.toolName, tool); |
581 | } | |
582 | else | |
583 | { | |
584 | 0 | log.info("Tool {} was null, skipping it.", toolData.toolName); |
585 | } | |
586 | 27 | } |
587 | } | |
588 | 0 | catch (Exception e) |
589 | { | |
590 | 0 | log.error("Could not instantiate session tool {} from a {} object", |
591 | toolData.toolName, toolData.toolClassName, e); | |
592 | 27 | } |
593 | 27 | } |
594 | 33 | } |
595 | ||
596 | /** | |
597 | * Populate the given context with the perm-scoped tools. | |
598 | * | |
599 | * @param tools The list of tools with which to populate the | |
600 | * session. | |
601 | * @param context The context to populate. | |
602 | * @param data The current RunData or PipelineData object | |
603 | * @param user The <code>User</code> object whose storage to | |
604 | * retrieve the tool from. | |
605 | */ | |
606 | private void populateWithPermTools(List<ToolData> tools, Context context, | |
607 | Object data, User user) | |
608 | { | |
609 | // Iterate the tools | |
610 | 6 | for (ToolData toolData : tools) |
611 | { | |
612 | try | |
613 | { | |
614 | // ensure that tool is created only once for a user | |
615 | // by synchronizing against the user object | |
616 | 0 | synchronized (user) |
617 | { | |
618 | // first try and fetch the tool from the user's | |
619 | // hashtable | |
620 | 0 | Object tool = user.getPerm(toolData.toolClassName); |
621 | ||
622 | 0 | if (tool == null) |
623 | { | |
624 | // if not there, an instance must be fetched from | |
625 | // the pool | |
626 | 0 | tool = pool.getInstance(toolData.toolClass); |
627 | ||
628 | // session tools are init'd with the User object | |
629 | 0 | initTool(tool, user); |
630 | ||
631 | // store the newly created tool in the user's hashtable | |
632 | 0 | user.setPerm(toolData.toolClassName, tool); |
633 | } | |
634 | ||
635 | // *NOT* else | |
636 | 0 | if (tool != null) |
637 | { | |
638 | // This is a semantics change. In the old | |
639 | // Turbine, Session tools were initialized and | |
640 | // then refreshed every time they were pulled | |
641 | // into the context if "refreshToolsPerRequest" | |
642 | // was wanted. | |
643 | // | |
644 | // RunDataApplicationTools now have a parameter | |
645 | // for refresh. If it is not refreshed immediately | |
646 | // after init(), the parameter value will be undefined | |
647 | // until the 2nd run. So we refresh all the session | |
648 | // tools on every run, even if we just init'ed it. | |
649 | // | |
650 | ||
651 | 0 | if (refreshToolsPerRequest) |
652 | { | |
653 | 0 | refreshTool(tool, data); |
654 | } | |
655 | ||
656 | // put the tool in the context | |
657 | 0 | log.debug("Adding {} to ctx as {}", tool, toolData.toolName); |
658 | 0 | log.warn("Persistent scope tools are deprecated."); |
659 | 0 | context.put(toolData.toolName, tool); |
660 | } | |
661 | else | |
662 | { | |
663 | 0 | log.info("Tool {} was null, skipping it.", toolData.toolName); |
664 | } | |
665 | 0 | } |
666 | } | |
667 | 0 | catch (Exception e) |
668 | { | |
669 | 0 | log.error("Could not instantiate perm tool {} from a {} object", |
670 | toolData.toolName, toolData.toolClassName, e); | |
671 | 0 | } |
672 | 0 | } |
673 | 6 | } |
674 | ||
675 | ||
676 | ||
677 | /** | |
678 | * Return the absolute path to the resources directory | |
679 | * used by the application tools. | |
680 | * | |
681 | * @return the absolute path of the resources directory | |
682 | */ | |
683 | @Override | |
684 | public String getAbsolutePathToResourcesDirectory() | |
685 | { | |
686 | 0 | return Turbine.getRealPath(resourcesDirectory); |
687 | } | |
688 | ||
689 | /** | |
690 | * Return the resources directory. This is | |
691 | * relative to the web context. | |
692 | * | |
693 | * @return the relative path of the resources directory | |
694 | */ | |
695 | @Override | |
696 | public String getResourcesDirectory() | |
697 | { | |
698 | 60 | return resourcesDirectory; |
699 | } | |
700 | ||
701 | /** | |
702 | * Refresh the global tools. We can | |
703 | * only refresh those tools that adhere to | |
704 | * ApplicationTool interface because we | |
705 | * know those types of tools have a refresh | |
706 | * method. | |
707 | */ | |
708 | private void refreshGlobalTools() | |
709 | { | |
710 | 30 | if (globalTools != null) |
711 | { | |
712 | 30 | for (ToolData toolData : globalTools) |
713 | { | |
714 | 30 | Object tool = globalContext.get(toolData.toolName); |
715 | 30 | refreshTool(tool, null); |
716 | 30 | } |
717 | } | |
718 | 30 | } |
719 | ||
720 | /** | |
721 | * Release the request-scope tool instances in the | |
722 | * given Context back to the pool | |
723 | * | |
724 | * @param context the Velocity Context to release tools from | |
725 | */ | |
726 | @Override | |
727 | public void releaseTools(Context context) | |
728 | { | |
729 | // only the request tools can be released - other scoped | |
730 | // tools will have continuing references to them | |
731 | 6 | releaseTools(context, requestTools); |
732 | 6 | } |
733 | ||
734 | /** | |
735 | * Release the given list of tools from the context back | |
736 | * to the pool | |
737 | * | |
738 | * @param context the Context containing the tools | |
739 | * @param tools a List of ToolData objects | |
740 | */ | |
741 | private void releaseTools(Context context, List<ToolData> tools) | |
742 | { | |
743 | 6 | if (tools != null) |
744 | { | |
745 | 6 | for (ToolData toolData : tools) |
746 | { | |
747 | 30 | Object tool = context.remove(toolData.toolName); |
748 | ||
749 | 30 | if (tool != null) |
750 | { | |
751 | 30 | pool.putInstance(tool); |
752 | } | |
753 | 30 | } |
754 | } | |
755 | 6 | } |
756 | ||
757 | /** | |
758 | * Initialized a given Tool with the passed init Object | |
759 | * | |
760 | * @param tool A Tool Object | |
761 | * @param param The Init Parameter | |
762 | * | |
763 | * @throws Exception If anything went wrong. | |
764 | */ | |
765 | private void initTool(Object tool, Object param) | |
766 | throws Exception | |
767 | { | |
768 | 222 | AnnotationProcessor.process(tool); |
769 | ||
770 | 222 | if (param instanceof PipelineData) |
771 | { | |
772 | 135 | if (tool instanceof PipelineDataApplicationTool) |
773 | { | |
774 | 0 | ((PipelineDataApplicationTool) tool).init(param); |
775 | } | |
776 | 135 | else if (tool instanceof RunDataApplicationTool) |
777 | { | |
778 | 0 | RunData data = getRunData((PipelineData)param); |
779 | 0 | ((RunDataApplicationTool) tool).init(data); |
780 | 0 | } |
781 | 135 | else if (tool instanceof ApplicationTool) |
782 | { | |
783 | 135 | RunData data = getRunData((PipelineData)param); |
784 | 135 | ((ApplicationTool) tool).init(data); |
785 | 135 | } |
786 | } | |
787 | else | |
788 | { | |
789 | 87 | if (tool instanceof PipelineDataApplicationTool) |
790 | { | |
791 | 0 | ((PipelineDataApplicationTool) tool).init(param); |
792 | } | |
793 | 87 | else if (tool instanceof RunDataApplicationTool) |
794 | { | |
795 | 0 | ((RunDataApplicationTool) tool).init(param); |
796 | } | |
797 | 87 | else if (tool instanceof ApplicationTool) |
798 | { | |
799 | 87 | ((ApplicationTool) tool).init(param); |
800 | } | |
801 | } | |
802 | 222 | } |
803 | ||
804 | /** | |
805 | * Refresh a given Tool. | |
806 | * | |
807 | * @param tool A Tool Object | |
808 | * @param pipelineData The current RunData Object | |
809 | */ | |
810 | private void refreshTool(Object tool, Object dataObject) | |
811 | { | |
812 | 57 | RunData data = null; |
813 | 57 | PipelineData pipelineData = null; |
814 | 57 | if (dataObject instanceof PipelineData) |
815 | { | |
816 | 27 | pipelineData = (PipelineData)dataObject; |
817 | 27 | data = pipelineData.getRunData(); |
818 | 27 | if (tool instanceof PipelineDataApplicationTool) |
819 | { | |
820 | 0 | ((PipelineDataApplicationTool) tool).refresh(pipelineData); |
821 | } | |
822 | } | |
823 | 57 | if (tool instanceof ApplicationTool) |
824 | { | |
825 | 57 | ((ApplicationTool) tool).refresh(); |
826 | } | |
827 | 0 | else if (tool instanceof RunDataApplicationTool) |
828 | { | |
829 | 0 | ((RunDataApplicationTool) tool).refresh(data); |
830 | } | |
831 | 57 | } |
832 | ||
833 | private RunData getRunData(PipelineData pipelineData) | |
834 | { | |
835 | 135 | if (!(pipelineData instanceof RunData)) |
836 | { | |
837 | 0 | throw new RuntimeException("Can't cast to rundata from pipeline data."); |
838 | } | |
839 | 135 | return (RunData)pipelineData; |
840 | } | |
841 | } |