|
|||||||||||||||||||
30 day Evaluation License registered to hlship@comcast.net Your 30 day evaluation period has expired. Please visit http://www.cenqua.com to obtain a licensed version of Clover | |||||||||||||||||||
Source file | Conditionals | Statements | Methods | TOTAL | |||||||||||||||
Tapestry.java | 60.5% | 52.8% | 63% | 56.1% |
|
1 | // Copyright 2004, 2005 The Apache Software Foundation | |
2 | // | |
3 | // Licensed under the Apache License, Version 2.0 (the "License"); | |
4 | // you may not use this file except in compliance with the License. | |
5 | // You may obtain a copy of the License at | |
6 | // | |
7 | // http://www.apache.org/licenses/LICENSE-2.0 | |
8 | // | |
9 | // Unless required by applicable law or agreed to in writing, software | |
10 | // distributed under the License is distributed on an "AS IS" BASIS, | |
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 | // See the License for the specific language governing permissions and | |
13 | // limitations under the License. | |
14 | ||
15 | package org.apache.tapestry; | |
16 | ||
17 | import java.io.IOException; | |
18 | import java.io.InputStream; | |
19 | import java.text.MessageFormat; | |
20 | import java.util.ArrayList; | |
21 | import java.util.Collection; | |
22 | import java.util.HashMap; | |
23 | import java.util.Iterator; | |
24 | import java.util.List; | |
25 | import java.util.Locale; | |
26 | import java.util.Map; | |
27 | import java.util.Properties; | |
28 | import java.util.ResourceBundle; | |
29 | import java.util.Set; | |
30 | ||
31 | import org.apache.hivemind.ApplicationRuntimeException; | |
32 | import org.apache.hivemind.HiveMind; | |
33 | import org.apache.hivemind.Location; | |
34 | import org.apache.hivemind.service.ClassFabUtils; | |
35 | import org.apache.tapestry.event.ChangeObserver; | |
36 | import org.apache.tapestry.event.ObservedChangeEvent; | |
37 | import org.apache.tapestry.services.ServiceConstants; | |
38 | import org.apache.tapestry.spec.IComponentSpecification; | |
39 | import org.apache.tapestry.util.StringSplitter; | |
40 | ||
41 | /** | |
42 | * A placeholder for a number of (static) methods that don't belong elsewhere, as well as a global | |
43 | * location for static constants. | |
44 | * | |
45 | * @since 1.0.1 | |
46 | * @author Howard Lewis Ship | |
47 | */ | |
48 | ||
49 | public final class Tapestry | |
50 | { | |
51 | /** | |
52 | * The name ("action") of a service that allows behavior to be associated with an | |
53 | * {@link IAction} component, such as {@link org.apache.tapestry.link.ActionLink }or | |
54 | * {@link org.apache.tapestry.form.Form}. | |
55 | * <p> | |
56 | * This service is used with actions that are tied to the dynamic state of the page, and which | |
57 | * require a rewind of the page. | |
58 | */ | |
59 | ||
60 | public final static String ACTION_SERVICE = "action"; | |
61 | ||
62 | /** | |
63 | * The name ("direct") of a service that allows stateless behavior for an {@link | |
64 | * org.apache.tapestry.link.DirectLink} component. | |
65 | * <p> | |
66 | * This service rolls back the state of the page but doesn't rewind the the dynamic state of the | |
67 | * page the was the action service does, which is more efficient but less powerful. | |
68 | * <p> | |
69 | * An array of String parameters may be included with the service URL; these will be made | |
70 | * available to the {@link org.apache.tapestry.link.DirectLink} component's listener. | |
71 | */ | |
72 | ||
73 | public final static String DIRECT_SERVICE = "direct"; | |
74 | ||
75 | /** | |
76 | * The name ("external") of a service that a allows {@link IExternalPage} to be selected. | |
77 | * Associated with a {@link org.apache.tapestry.link.ExternalLink} component. | |
78 | * <p> | |
79 | * This service enables {@link IExternalPage}s to be accessed via a URL. External pages may be | |
80 | * booked marked using their URL for future reference. | |
81 | * <p> | |
82 | * An array of Object parameters may be included with the service URL; these will be passed to | |
83 | * the {@link IExternalPage#activateExternalPage(Object[], IRequestCycle)} method. | |
84 | */ | |
85 | ||
86 | public final static String EXTERNAL_SERVICE = "external"; | |
87 | ||
88 | /** | |
89 | * The name ("page") of a service that allows a new page to be selected. Associated with a | |
90 | * {@link org.apache.tapestry.link.PageLink} component. | |
91 | * <p> | |
92 | * The service requires a single parameter: the name of the target page. | |
93 | */ | |
94 | ||
95 | public final static String PAGE_SERVICE = "page"; | |
96 | ||
97 | /** | |
98 | * The name ("home") of a service that jumps to the home page. A stand-in for when no service is | |
99 | * provided, which is typically the entrypoint to the application. | |
100 | */ | |
101 | ||
102 | public final static String HOME_SERVICE = "home"; | |
103 | ||
104 | /** | |
105 | * The name ("restart") of a service that invalidates the session and restarts the application. | |
106 | * Typically used just to recover from an exception. | |
107 | */ | |
108 | ||
109 | public static final String RESTART_SERVICE = "restart"; | |
110 | ||
111 | /** | |
112 | * The name ("asset") of a service used to access internal assets. | |
113 | */ | |
114 | ||
115 | public static final String ASSET_SERVICE = "asset"; | |
116 | ||
117 | /** | |
118 | * The name ("reset") of a service used to clear cached template and specification data and | |
119 | * remove all pooled pages. This is only used when debugging as a quick way to clear the out | |
120 | * cached data, to allow updated versions of specifications and templates to be loaded (without | |
121 | * stopping and restarting the servlet container). | |
122 | * <p> | |
123 | * This service is only available if the Java system property | |
124 | * <code>org.apache.tapestry.enable-reset-service</code> is set to <code>true</code>. | |
125 | */ | |
126 | ||
127 | public static final String RESET_SERVICE = "reset"; | |
128 | ||
129 | /** | |
130 | * Query parameter that identfies the service for the request. | |
131 | * | |
132 | * @since 1.0.3 | |
133 | * @deprecated To be removed in 4.1. Use | |
134 | * {@link org.apache.tapestry.services.ServiceConstants#SERVICE} instead. | |
135 | */ | |
136 | ||
137 | public static final String SERVICE_QUERY_PARAMETER_NAME = ServiceConstants.SERVICE; | |
138 | ||
139 | /** | |
140 | * The query parameter for application specific parameters to the service (this is used with the | |
141 | * direct service). Each of these values is encoded with | |
142 | * {@link java.net.URLEncoder#encode(String)} before being added to the URL. Multiple values are | |
143 | * handle by repeatedly establishing key/value pairs (this is a change from behavior in 2.1 and | |
144 | * earlier). | |
145 | * | |
146 | * @since 1.0.3 | |
147 | * @deprecated To be removed in 4.1. Use | |
148 | * {@link org.apache.tapestry.services.ServiceConstants#PARAMETER} instead. | |
149 | */ | |
150 | ||
151 | public static final String PARAMETERS_QUERY_PARAMETER_NAME = ServiceConstants.PARAMETER; | |
152 | ||
153 | /** | |
154 | * Property name used to get the extension used for templates. This may be set in the page or | |
155 | * component specification, or in the page (or component's) immediate container (library or | |
156 | * application specification). Unlike most properties, value isn't inherited all the way up the | |
157 | * chain. The default template extension is "html". | |
158 | * | |
159 | * @since 3.0 | |
160 | */ | |
161 | ||
162 | public static final String TEMPLATE_EXTENSION_PROPERTY = "org.apache.tapestry.template-extension"; | |
163 | ||
164 | /** | |
165 | * The name of an {@link org.apache.tapestry.IRequestCycle} attribute in which the currently | |
166 | * rendering {@link org.apache.tapestry.components.ILinkComponent} is stored. Link components do | |
167 | * not nest. | |
168 | */ | |
169 | ||
170 | public static final String LINK_COMPONENT_ATTRIBUTE_NAME = "org.apache.tapestry.active-link-component"; | |
171 | ||
172 | /** | |
173 | * Suffix appended to a parameter name to form the name of a property that stores the binding | |
174 | * for the parameter. | |
175 | * | |
176 | * @since 3.0 | |
177 | */ | |
178 | ||
179 | public static final String PARAMETER_PROPERTY_NAME_SUFFIX = "Binding"; | |
180 | ||
181 | /** | |
182 | * Key used to obtain an extension from the application specification. The extension, if it | |
183 | * exists, implements {@link org.apache.tapestry.request.IRequestDecoder}. | |
184 | * | |
185 | * @since 2.2 | |
186 | */ | |
187 | ||
188 | public static final String REQUEST_DECODER_EXTENSION_NAME = "org.apache.tapestry.request-decoder"; | |
189 | ||
190 | /** | |
191 | * Name of optional application extension for the multipart decoder used by the application. The | |
192 | * extension must implement {@link org.apache.tapestry.multipart.IMultipartDecoder} (and is | |
193 | * generally a configured instance of | |
194 | * {@link org.apache.tapestry.multipart.DefaultMultipartDecoder}). | |
195 | * | |
196 | * @since 3.0 | |
197 | */ | |
198 | ||
199 | public static final String MULTIPART_DECODER_EXTENSION_NAME = "org.apache.tapestry.multipart-decoder"; | |
200 | ||
201 | /** | |
202 | * Method id used to check that {@link IPage#validate(IRequestCycle)} is invoked. | |
203 | * | |
204 | * @see #checkMethodInvocation(Object, String, Object) | |
205 | * @since 3.0 | |
206 | */ | |
207 | ||
208 | public static final String ABSTRACTPAGE_VALIDATE_METHOD_ID = "AbstractPage.validate()"; | |
209 | ||
210 | /** | |
211 | * Method id used to check that {@link IPage#detach()} is invoked. | |
212 | * | |
213 | * @see #checkMethodInvocation(Object, String, Object) | |
214 | * @since 3.0 | |
215 | */ | |
216 | ||
217 | public static final String ABSTRACTPAGE_DETACH_METHOD_ID = "AbstractPage.detach()"; | |
218 | ||
219 | /** | |
220 | * Regular expression defining a simple property name. Used by several different parsers. Simple | |
221 | * property names match Java variable names; a leading letter (or underscore), followed by | |
222 | * letters, numbers and underscores. | |
223 | * | |
224 | * @since 3.0 | |
225 | */ | |
226 | ||
227 | public static final String SIMPLE_PROPERTY_NAME_PATTERN = "^_?[a-zA-Z]\\w*$"; | |
228 | ||
229 | /** | |
230 | * Name of an application extension used as a factory for | |
231 | * {@link org.apache.tapestry.engine.IMonitor}instances. The extension must implement | |
232 | * {@link org.apache.tapestry.engine.IMonitorFactory}. | |
233 | * | |
234 | * @since 3.0 | |
235 | */ | |
236 | ||
237 | public static final String MONITOR_FACTORY_EXTENSION_NAME = "org.apache.tapestry.monitor-factory"; | |
238 | ||
239 | /** | |
240 | * Class name of an {@link ognl.TypeConverter}implementing class to use as a type converter for | |
241 | * {@link org.apache.tapestry.binding.ExpressionBinding} | |
242 | */ | |
243 | public static final String OGNL_TYPE_CONVERTER = "org.apache.tapestry.ognl-type-converter"; | |
244 | ||
245 | /** | |
246 | * Prevent instantiation. | |
247 | */ | |
248 | ||
249 | 0 | private Tapestry() |
250 | { | |
251 | } | |
252 | ||
253 | /** | |
254 | * The version of the framework; this is updated for major releases. | |
255 | */ | |
256 | ||
257 | public static final String VERSION = readVersion(); | |
258 | ||
259 | /** | |
260 | * Contains strings loaded from TapestryStrings.properties. | |
261 | * | |
262 | * @since 1.0.8 | |
263 | */ | |
264 | ||
265 | private static ResourceBundle _strings; | |
266 | ||
267 | /** | |
268 | * A {@link Map}that links Locale names (as in {@link Locale#toString()}to {@link Locale} | |
269 | * instances. This prevents needless duplication of Locales. | |
270 | */ | |
271 | ||
272 | private static final Map _localeMap = new HashMap(); | |
273 | ||
274 | static | |
275 | { | |
276 | 1 | Locale[] locales = Locale.getAvailableLocales(); |
277 | 1 | for (int i = 0; i < locales.length; i++) |
278 | { | |
279 | 132 | _localeMap.put(locales[i].toString(), locales[i]); |
280 | } | |
281 | } | |
282 | ||
283 | /** | |
284 | * Used for tracking if a particular super-class method has been invoked. | |
285 | */ | |
286 | ||
287 | private static final ThreadLocal _invokedMethodIds = new ThreadLocal(); | |
288 | ||
289 | /** | |
290 | * Copys all informal {@link IBinding bindings}from a source component to the destination | |
291 | * component. Informal bindings are bindings for informal parameters. This will overwrite | |
292 | * parameters (formal or informal) in the destination component if there is a naming conflict. | |
293 | */ | |
294 | ||
295 | 0 | public static void copyInformalBindings(IComponent source, IComponent destination) |
296 | { | |
297 | 0 | Collection names = source.getBindingNames(); |
298 | ||
299 | 0 | if (names == null) |
300 | 0 | return; |
301 | ||
302 | 0 | IComponentSpecification specification = source.getSpecification(); |
303 | 0 | Iterator i = names.iterator(); |
304 | ||
305 | 0 | while (i.hasNext()) |
306 | { | |
307 | 0 | String name = (String) i.next(); |
308 | ||
309 | // If not a formal parameter, then copy it over. | |
310 | ||
311 | 0 | if (specification.getParameter(name) == null) |
312 | { | |
313 | 0 | IBinding binding = source.getBinding(name); |
314 | ||
315 | 0 | destination.setBinding(name, binding); |
316 | } | |
317 | } | |
318 | } | |
319 | ||
320 | /** | |
321 | * Gets the {@link Locale}for the given string, which is the result of | |
322 | * {@link Locale#toString()}. If no such locale is already registered, a new instance is | |
323 | * created, registered and returned. | |
324 | */ | |
325 | ||
326 | 0 | public static Locale getLocale(String s) |
327 | { | |
328 | 0 | Locale result = null; |
329 | ||
330 | 0 | synchronized (_localeMap) |
331 | { | |
332 | 0 | result = (Locale) _localeMap.get(s); |
333 | } | |
334 | ||
335 | 0 | if (result == null) |
336 | { | |
337 | 0 | StringSplitter splitter = new StringSplitter('_'); |
338 | 0 | String[] terms = splitter.splitToArray(s); |
339 | ||
340 | 0 | switch (terms.length) |
341 | { | |
342 | 0 | case 1: |
343 | ||
344 | 0 | result = new Locale(terms[0], ""); |
345 | 0 | break; |
346 | ||
347 | 0 | case 2: |
348 | ||
349 | 0 | result = new Locale(terms[0], terms[1]); |
350 | 0 | break; |
351 | ||
352 | 0 | case 3: |
353 | ||
354 | 0 | result = new Locale(terms[0], terms[1], terms[2]); |
355 | 0 | break; |
356 | ||
357 | 0 | default: |
358 | ||
359 | 0 | throw new IllegalArgumentException("Unable to convert '" + s + "' to a Locale."); |
360 | } | |
361 | ||
362 | 0 | synchronized (_localeMap) |
363 | { | |
364 | 0 | _localeMap.put(s, result); |
365 | } | |
366 | ||
367 | } | |
368 | ||
369 | 0 | return result; |
370 | ||
371 | } | |
372 | ||
373 | /** | |
374 | * Closes the stream (if not null), ignoring any {@link IOException}thrown. | |
375 | * | |
376 | * @since 1.0.2 | |
377 | */ | |
378 | ||
379 | 162 | public static void close(InputStream stream) |
380 | { | |
381 | 162 | if (stream != null) |
382 | { | |
383 | 162 | try |
384 | { | |
385 | 162 | stream.close(); |
386 | } | |
387 | catch (IOException ex) | |
388 | { | |
389 | // Ignore. | |
390 | } | |
391 | } | |
392 | } | |
393 | ||
394 | /** | |
395 | * Gets a string from the TapestryStrings resource bundle. The string in the bundle is treated | |
396 | * as a pattern for {@link MessageFormat#format(java.lang.String, java.lang.Object[])}. | |
397 | * | |
398 | * @since 1.0.8 | |
399 | */ | |
400 | ||
401 | 28 | public static String format(String key, Object[] args) |
402 | { | |
403 | 28 | if (_strings == null) |
404 | 1 | _strings = ResourceBundle.getBundle("org.apache.tapestry.TapestryStrings"); |
405 | ||
406 | 28 | String pattern = _strings.getString(key); |
407 | ||
408 | 28 | if (args == null) |
409 | 12 | return pattern; |
410 | ||
411 | 16 | return MessageFormat.format(pattern, args); |
412 | } | |
413 | ||
414 | /** | |
415 | * Convienience method for invoking {@link #format(String, Object[])}. | |
416 | * | |
417 | * @since 3.0 | |
418 | */ | |
419 | ||
420 | 12 | public static String getMessage(String key) |
421 | { | |
422 | 12 | return format(key, null); |
423 | } | |
424 | ||
425 | /** | |
426 | * Convienience method for invoking {@link #format(String, Object[])}. | |
427 | * | |
428 | * @since 3.0 | |
429 | */ | |
430 | ||
431 | 4 | public static String format(String key, Object arg) |
432 | { | |
433 | 4 | return format(key, new Object[] |
434 | { arg }); | |
435 | } | |
436 | ||
437 | /** | |
438 | * Convienience method for invoking {@link #format(String, Object[])}. | |
439 | * | |
440 | * @since 3.0 | |
441 | */ | |
442 | ||
443 | 9 | public static String format(String key, Object arg1, Object arg2) |
444 | { | |
445 | 9 | return format(key, new Object[] |
446 | { arg1, arg2 }); | |
447 | } | |
448 | ||
449 | /** | |
450 | * Convienience method for invoking {@link #format(String, Object[])}. | |
451 | * | |
452 | * @since 3.0 | |
453 | */ | |
454 | ||
455 | 3 | public static String format(String key, Object arg1, Object arg2, Object arg3) |
456 | { | |
457 | 3 | return format(key, new Object[] |
458 | { arg1, arg2, arg3 }); | |
459 | } | |
460 | ||
461 | private static final String UNKNOWN_VERSION = "Unknown"; | |
462 | ||
463 | /** | |
464 | * Invoked when the class is initialized to read the current version file. | |
465 | */ | |
466 | ||
467 | 1 | private static final String readVersion() |
468 | { | |
469 | 1 | Properties props = new Properties(); |
470 | ||
471 | 1 | try |
472 | { | |
473 | 1 | InputStream in = Tapestry.class.getResourceAsStream("version.properties"); |
474 | ||
475 | 1 | if (in == null) |
476 | 0 | return UNKNOWN_VERSION; |
477 | ||
478 | 1 | props.load(in); |
479 | ||
480 | 1 | in.close(); |
481 | ||
482 | 1 | return props.getProperty("project.version", UNKNOWN_VERSION); |
483 | } | |
484 | catch (IOException ex) | |
485 | { | |
486 | 0 | return UNKNOWN_VERSION; |
487 | } | |
488 | ||
489 | } | |
490 | ||
491 | /** | |
492 | * Returns the size of a collection, or zero if the collection is null. | |
493 | * | |
494 | * @since 2.2 | |
495 | */ | |
496 | ||
497 | 2209 | public static int size(Collection c) |
498 | { | |
499 | 2209 | if (c == null) |
500 | 1 | return 0; |
501 | ||
502 | 2208 | return c.size(); |
503 | } | |
504 | ||
505 | /** | |
506 | * Returns the length of the array, or 0 if the array is null. | |
507 | * | |
508 | * @since 2.2 | |
509 | */ | |
510 | ||
511 | 289 | public static int size(Object[] array) |
512 | { | |
513 | 289 | if (array == null) |
514 | 52 | return 0; |
515 | ||
516 | 237 | return array.length; |
517 | } | |
518 | ||
519 | /** | |
520 | * Returns true if the Map is null or empty. | |
521 | * | |
522 | * @since 3.0 | |
523 | */ | |
524 | ||
525 | 0 | public static boolean isEmpty(Map map) |
526 | { | |
527 | 0 | return map == null || map.isEmpty(); |
528 | } | |
529 | ||
530 | /** | |
531 | * Returns true if the Collection is null or empty. | |
532 | * | |
533 | * @since 3.0 | |
534 | */ | |
535 | ||
536 | 77 | public static boolean isEmpty(Collection c) |
537 | { | |
538 | 77 | return c == null || c.isEmpty(); |
539 | } | |
540 | ||
541 | /** | |
542 | * Converts a {@link Map} to an even-sized array of key/value pairs. This may be useful when | |
543 | * using a Map as service parameters (with {@link org.apache.tapestry.link.DirectLink}. | |
544 | * Assuming the keys and values are simple objects (String, Boolean, Integer, etc.), then the | |
545 | * representation as an array will encode more efficiently (via | |
546 | * {@link org.apache.tapestry.util.io.DataSqueezerImpl} than serializing the Map and its | |
547 | * contents. | |
548 | * | |
549 | * @return the array of keys and values, or null if the input Map is null or empty | |
550 | * @since 2.2 | |
551 | */ | |
552 | ||
553 | 0 | public static Object[] convertMapToArray(Map map) |
554 | { | |
555 | 0 | if (isEmpty(map)) |
556 | 0 | return null; |
557 | ||
558 | 0 | Set entries = map.entrySet(); |
559 | ||
560 | 0 | Object[] result = new Object[2 * entries.size()]; |
561 | 0 | int x = 0; |
562 | ||
563 | 0 | Iterator i = entries.iterator(); |
564 | 0 | while (i.hasNext()) |
565 | { | |
566 | 0 | Map.Entry entry = (Map.Entry) i.next(); |
567 | ||
568 | 0 | result[x++] = entry.getKey(); |
569 | 0 | result[x++] = entry.getValue(); |
570 | } | |
571 | ||
572 | 0 | return result; |
573 | } | |
574 | ||
575 | /** | |
576 | * Converts an even-sized array of objects back into a {@link Map}. | |
577 | * | |
578 | * @see #convertMapToArray(Map) | |
579 | * @return a Map, or null if the array is null or empty | |
580 | * @since 2.2 | |
581 | */ | |
582 | ||
583 | 107 | public static Map convertArrayToMap(Object[] array) |
584 | { | |
585 | 107 | if (array == null || array.length == 0) |
586 | 25 | return null; |
587 | ||
588 | 82 | if (array.length % 2 != 0) |
589 | 0 | throw new IllegalArgumentException(getMessage("Tapestry.even-sized-array")); |
590 | ||
591 | 82 | Map result = new HashMap(); |
592 | ||
593 | 82 | int x = 0; |
594 | 82 | while (x < array.length) |
595 | { | |
596 | 181 | Object key = array[x++]; |
597 | 181 | Object value = array[x++]; |
598 | ||
599 | 181 | result.put(key, value); |
600 | } | |
601 | ||
602 | 82 | return result; |
603 | } | |
604 | ||
605 | /** | |
606 | * Given a Class, creates a presentable name for the class, even if the class is a scalar type | |
607 | * or Array type. | |
608 | * | |
609 | * @since 3.0 | |
610 | * @deprecated To be removed in 4.1. | |
611 | */ | |
612 | ||
613 | 6 | public static String getClassName(Class subject) |
614 | { | |
615 | 6 | return ClassFabUtils.getJavaClassName(subject); |
616 | } | |
617 | ||
618 | /** | |
619 | * Creates an exception indicating the binding value is null. | |
620 | * | |
621 | * @since 3.0 | |
622 | */ | |
623 | ||
624 | 0 | public static BindingException createNullBindingException(IBinding binding) |
625 | { | |
626 | 0 | return new BindingException(getMessage("null-value-for-binding"), binding); |
627 | } | |
628 | ||
629 | /** @since 3.0 * */ | |
630 | ||
631 | 0 | public static ApplicationRuntimeException createNoSuchComponentException(IComponent component, |
632 | String id, Location location) | |
633 | { | |
634 | 0 | return new ApplicationRuntimeException(format("no-such-component", component |
635 | .getExtendedId(), id), component, location, null); | |
636 | } | |
637 | ||
638 | /** @since 3.0 * */ | |
639 | ||
640 | 2 | public static BindingException createRequiredParameterException(IComponent component, |
641 | String parameterName) | |
642 | { | |
643 | 2 | return new BindingException(format("required-parameter", parameterName, component |
644 | .getExtendedId()), component, null, component.getBinding(parameterName), null); | |
645 | } | |
646 | ||
647 | /** @since 3.0 * */ | |
648 | ||
649 | 0 | public static ApplicationRuntimeException createRenderOnlyPropertyException( |
650 | IComponent component, String propertyName) | |
651 | { | |
652 | 0 | return new ApplicationRuntimeException(format( |
653 | "render-only-property", | |
654 | propertyName, | |
655 | component.getExtendedId()), component, null, null); | |
656 | } | |
657 | ||
658 | /** | |
659 | * Clears the list of method invocations. | |
660 | * | |
661 | * @see #checkMethodInvocation(Object, String, Object) | |
662 | * @since 3.0 | |
663 | */ | |
664 | ||
665 | 376 | public static void clearMethodInvocations() |
666 | { | |
667 | 376 | _invokedMethodIds.set(null); |
668 | } | |
669 | ||
670 | /** | |
671 | * Adds a method invocation to the list of invocations. This is done in a super-class | |
672 | * implementations. | |
673 | * | |
674 | * @see #checkMethodInvocation(Object, String, Object) | |
675 | * @since 3.0 | |
676 | */ | |
677 | ||
678 | 382 | public static void addMethodInvocation(Object methodId) |
679 | { | |
680 | 382 | List methodIds = (List) _invokedMethodIds.get(); |
681 | ||
682 | 382 | if (methodIds == null) |
683 | { | |
684 | 376 | methodIds = new ArrayList(); |
685 | 376 | _invokedMethodIds.set(methodIds); |
686 | } | |
687 | ||
688 | 382 | methodIds.add(methodId); |
689 | } | |
690 | ||
691 | /** | |
692 | * Checks to see if a particular method has been invoked. The method is identified by a methodId | |
693 | * (usually a String). The methodName and object are used to create an error message. | |
694 | * <p> | |
695 | * The caller should invoke {@link #clearMethodInvocations()}, then invoke a method on the | |
696 | * object. The super-class implementation should invoke {@link #addMethodInvocation(Object)} to | |
697 | * indicate that it was, in fact, invoked. The caller then invokes this method to validate that | |
698 | * the super-class implementation was invoked. | |
699 | * <p> | |
700 | * The list of method invocations is stored in a {@link ThreadLocal} variable. | |
701 | * | |
702 | * @since 3.0 | |
703 | */ | |
704 | ||
705 | 372 | public static void checkMethodInvocation(Object methodId, String methodName, Object object) |
706 | { | |
707 | 372 | List methodIds = (List) _invokedMethodIds.get(); |
708 | ||
709 | 372 | if (methodIds != null && methodIds.contains(methodId)) |
710 | 371 | return; |
711 | ||
712 | 1 | throw new ApplicationRuntimeException(Tapestry.format( |
713 | "Tapestry.missing-method-invocation", | |
714 | object.getClass().getName(), | |
715 | methodName)); | |
716 | } | |
717 | ||
718 | /** | |
719 | * Method used by pages and components to send notifications about property changes. | |
720 | * | |
721 | * @param component | |
722 | * the component containing the property | |
723 | * @param propertyName | |
724 | * the name of the property which changed | |
725 | * @param newValue | |
726 | * the new value for the property | |
727 | * @since 3.0 | |
728 | */ | |
729 | 31 | public static void fireObservedChange(IComponent component, String propertyName, Object newValue) |
730 | { | |
731 | 31 | ChangeObserver observer = component.getPage().getChangeObserver(); |
732 | ||
733 | 31 | if (observer == null) |
734 | 11 | return; |
735 | ||
736 | 20 | ObservedChangeEvent event = new ObservedChangeEvent(component, propertyName, newValue); |
737 | ||
738 | 20 | observer.observeChange(event); |
739 | } | |
740 | ||
741 | /** | |
742 | * Returns true if the input is null or contains only whitespace. | |
743 | * <p> | |
744 | * Note: Yes, you'd think we'd use <code>StringUtils</code>, but with the change in names and | |
745 | * behavior between releases, it is smarter to just implement our own little method! | |
746 | * | |
747 | * @since 3.0 | |
748 | * @deprecated To be removed in Tapestry 4.1. Use {@link HiveMind#isBlank(java.lang.String)} | |
749 | * instead. | |
750 | */ | |
751 | ||
752 | 0 | public static boolean isBlank(String input) |
753 | { | |
754 | 0 | return HiveMind.isBlank(input); |
755 | } | |
756 | ||
757 | /** | |
758 | * Returns true if the input is not null and not empty (or only whitespace). | |
759 | * | |
760 | * @since 3.0 | |
761 | * @deprecated To be removed in Tapestry 4.1. Use {@link HiveMind#isNonBlank(java.lang.String)} | |
762 | * instead. | |
763 | */ | |
764 | ||
765 | 0 | public static boolean isNonBlank(String input) |
766 | { | |
767 | 0 | return HiveMind.isNonBlank(input); |
768 | } | |
769 | } |
|