Source code: org/apache/tapestry/AbstractComponent.java
1 /* $$ Clover has instrumented this file $$ */// Copyright 2004 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.util.Collection;
18 import java.util.Collections;
19 import java.util.HashMap;
20 import java.util.HashSet;
21 import java.util.Iterator;
22 import java.util.List;
23 import java.util.Map;
24
25 import ognl.OgnlRuntime;
26
27 import org.apache.hivemind.ApplicationRuntimeException;
28 import org.apache.hivemind.ClassResolver;
29 import org.apache.hivemind.Messages;
30 import org.apache.hivemind.impl.BaseLocatable;
31 import org.apache.hivemind.util.PropertyAdaptor;
32 import org.apache.hivemind.util.PropertyUtils;
33 import org.apache.tapestry.bean.BeanProvider;
34 import org.apache.tapestry.bean.BeanProviderPropertyAccessor;
35 import org.apache.tapestry.engine.IPageLoader;
36 import org.apache.tapestry.event.ChangeObserver;
37 import org.apache.tapestry.event.PageDetachListener;
38 import org.apache.tapestry.event.PageEvent;
39 import org.apache.tapestry.event.PageRenderListener;
40 import org.apache.tapestry.event.PageValidateListener;
41 import org.apache.tapestry.listener.ListenerMap;
42 import org.apache.tapestry.param.ParameterManager;
43 import org.apache.tapestry.spec.IComponentSpecification;
44 import org.apache.tapestry.util.prop.OgnlUtils;
45
46 /**
47 * Abstract base class implementing the {@link IComponent}interface.
48 *
49 * @author Howard Lewis Ship
50 */
51
52 public abstract class AbstractComponent extends BaseLocatable implements IComponent
53 {public static com.cortexeb.tools.clover.d __CLOVER_0_0 = com.cortexeb.tools.clover.aq.getRecorder(new char[] {67,58,92,119,111,114,107,115,112,97,99,101,92,106,97,107,97,114,116,97,45,116,97,112,101,115,116,114,121,92,102,114,97,109,101,119,111,114,107,92,116,97,114,103,101,116,92,99,108,111,118,101,114,45,100,98},1097019445706L);
54 /**
55 * Used to check that subclasses invoke this implementation of prepareForRender().
56 *
57 * @see Tapestry#checkMethodInvocation(Object, String, Object)
58 * @since 3.0
59 */
60 private final static String PREPAREFORRENDER_METHOD_ID = "AbstractComponent.prepareForRender()";
61
62 /**
63 * Used to check that subclasses invoke this implementation of cleanupAfterRender().
64 *
65 * @see Tapestry#checkMethodInvocation(Object, String, Object)
66 * @since 3.0
67 */
68
69 private final static String CLEANUPAFTERRENDER_METHOD_ID = "AbstractComponent.cleanupAfterRender()";
70
71 static
72 {
73 // Register the BeanProviderHelper to provide access to the
74 // beans of a bean provider as named properties.
75
76 __CLOVER_0_0.S[10690]++;OgnlRuntime.setPropertyAccessor(IBeanProvider.class, new BeanProviderPropertyAccessor());
77 }
78
79 /**
80 * The specification used to originally build the component.
81 */
82
83 private IComponentSpecification _specification;
84
85 /**
86 * The page that contains the component, possibly itself (if the component is in fact, a page).
87 */
88
89 private IPage _page;
90
91 /**
92 * The component which contains the component. This will only be null if the component is
93 * actually a page.
94 */
95
96 private IComponent _container;
97
98 /**
99 * The simple id of this component.
100 */
101
102 private String _id;
103
104 /**
105 * The fully qualified id of this component. This is calculated the first time it is needed,
106 * then cached for later.
107 */
108
109 private String _idPath;
110
111 private static final int MAP_SIZE = 5;
112
113 /**
114 * A {@link Map}of all bindings (for which there isn't a corresponding JavaBeans property); the
115 * keys are the names of formal and informal parameters.
116 */
117
118 private Map _bindings;
119
120 private Map _components;
121
122 private static final int BODY_INIT_SIZE = 5;
123
124 private INamespace _namespace;
125
126 /**
127 * Used in place of JDK 1.3's Collections.EMPTY_MAP (which is not available in JDK 1.2).
128 */
129
130 private static final Map EMPTY_MAP = Collections.unmodifiableMap(new HashMap(1));
131
132 /**
133 * The number of {@link IRender}objects in the body of this component.
134 */
135
136 private int _bodyCount = 0;
137
138 /**
139 * An aray of elements in the body of this component.
140 */
141
142 private IRender[] _body;
143
144 /**
145 * The components' asset map.
146 */
147
148 private Map _assets;
149
150 /**
151 * A mapping that allows public instance methods to be dressed up as {@link IActionListener}
152 * listener objects.
153 *
154 * @since 1.0.2
155 */
156
157 private ListenerMap _listeners;
158
159 /**
160 * A bean provider; these are lazily created as needed.
161 *
162 * @since 1.0.4
163 */
164
165 private IBeanProvider _beans;
166
167 /**
168 * Manages setting and clearing parameter properties for the component.
169 *
170 * @since 2.0.3
171 */
172
173 private ParameterManager _parameterManager;
174
175 /**
176 * Provides access to localized Strings for this component.
177 *
178 * @since 2.0.4
179 */
180
181 private Messages _strings;
182
183 public void addAsset(String name, IAsset asset)
184 {try { __CLOVER_0_0.M[2650]++;
185 __CLOVER_0_0.S[10691]++;if ((((_assets == null) && (++__CLOVER_0_0.CT[1838] != 0)) || (++__CLOVER_0_0.CF[1838] == 0))){
186 __CLOVER_0_0.S[10692]++;_assets = new HashMap(MAP_SIZE);}
187
188 __CLOVER_0_0.S[10693]++;_assets.put(name, asset);
189 } finally { }}
190
191 public void addComponent(IComponent component)
192 {try { __CLOVER_0_0.M[2651]++;
193 __CLOVER_0_0.S[10694]++;if ((((_components == null) && (++__CLOVER_0_0.CT[1839] != 0)) || (++__CLOVER_0_0.CF[1839] == 0))){
194 __CLOVER_0_0.S[10695]++;_components = new HashMap(MAP_SIZE);}
195
196 __CLOVER_0_0.S[10696]++;_components.put(component.getId(), component);
197 } finally { }}
198
199 /**
200 * Adds an element (which may be static text or a component) as a body element of this
201 * component. Such elements are rendered by {@link #renderBody(IMarkupWriter, IRequestCycle)}.
202 *
203 * @since 2.2
204 */
205
206 public void addBody(IRender element)
207 {try { __CLOVER_0_0.M[2652]++;
208 // Should check the specification to see if this component
209 // allows body. Curently, this is checked by the component
210 // in render(), which is silly.
211
212 __CLOVER_0_0.S[10697]++;if ((((_body == null) && (++__CLOVER_0_0.CT[1840] != 0)) || (++__CLOVER_0_0.CF[1840] == 0))){
213 {
214 __CLOVER_0_0.S[10698]++;_body = new IRender[BODY_INIT_SIZE];
215 __CLOVER_0_0.S[10699]++;_body[0] = element;
216
217 __CLOVER_0_0.S[10700]++;_bodyCount = 1;
218 __CLOVER_0_0.S[10701]++;return;
219 }}
220
221 // No more room? Make the array bigger.
222
223 __CLOVER_0_0.S[10702]++;if ((((_bodyCount == _body.length) && (++__CLOVER_0_0.CT[1841] != 0)) || (++__CLOVER_0_0.CF[1841] == 0))){
224 {
225 __CLOVER_0_0.S[10703]++;IRender[] newWrapped;
226
227 __CLOVER_0_0.S[10704]++;newWrapped = new IRender[_body.length * 2];
228
229 __CLOVER_0_0.S[10705]++;System.arraycopy(_body, 0, newWrapped, 0, _bodyCount);
230
231 __CLOVER_0_0.S[10706]++;_body = newWrapped;
232 }}
233
234 __CLOVER_0_0.S[10707]++;_body[_bodyCount++] = element;
235 } finally { }}
236
237 /**
238 * Registers this component as a listener of the page if it implements
239 * {@link org.apache.tapestry.event.PageDetachListener}or
240 * {@link org.apache.tapestry.event.PageRenderListener}.
241 * <p>
242 * Invokes {@link #finishLoad()}. Subclasses may overide as needed, but must invoke this
243 * implementation. {@link BaseComponent}loads its HTML template.
244 */
245
246 public void finishLoad(IRequestCycle cycle, IPageLoader loader,
247 IComponentSpecification specification)
248 {try { __CLOVER_0_0.M[2653]++;
249 __CLOVER_0_0.S[10708]++;if ((((this instanceof PageDetachListener) && (++__CLOVER_0_0.CT[1842] != 0)) || (++__CLOVER_0_0.CF[1842] == 0))){
250 __CLOVER_0_0.S[10709]++;_page.addPageDetachListener((PageDetachListener) this);}
251
252 __CLOVER_0_0.S[10710]++;if ((((this instanceof PageRenderListener) && (++__CLOVER_0_0.CT[1843] != 0)) || (++__CLOVER_0_0.CF[1843] == 0))){
253 __CLOVER_0_0.S[10711]++;_page.addPageRenderListener((PageRenderListener) this);}
254
255 __CLOVER_0_0.S[10712]++;if ((((this instanceof PageValidateListener) && (++__CLOVER_0_0.CT[1844] != 0)) || (++__CLOVER_0_0.CF[1844] == 0))){
256 __CLOVER_0_0.S[10713]++;_page.addPageValidateListener((PageValidateListener) this);}
257
258 __CLOVER_0_0.S[10714]++;finishLoad();
259 } finally { }}
260
261 /**
262 * Converts informal parameters into additional attributes on the curently open tag.
263 * <p>
264 * Invoked from subclasses to allow additional attributes to be specified within a tag (this
265 * works best when there is a one-to-one corespondence between an {@link IComponent}and a HTML
266 * element.
267 * <p>
268 * Iterates through the bindings for this component. Filters out bindings when the name matches
269 * a formal parameter (as of 1.0.5, informal bindings are weeded out at page load / template
270 * load time, if they match a formal parameter, or a specificied reserved name). For the most
271 * part, all the bindings here are either informal parameter, or formal parameter without a
272 * corresponding JavaBeans property.
273 * <p>
274 * For each acceptible key, the value is extracted using {@link IBinding#getObject()}. If the
275 * value is null, no attribute is written.
276 * <p>
277 * If the value is an instance of {@link IAsset}, then {@link IAsset#buildURL(IRequestCycle)}
278 * is invoked to convert the asset to a URL.
279 * <p>
280 * Finally, {@link IMarkupWriter#attribute(String,String)}is invoked with the value (or the
281 * URL).
282 * <p>
283 * The most common use for informal parameters is to support the HTML class attribute (for use
284 * with cascading style sheets) and to specify JavaScript event handlers.
285 * <p>
286 * Components are only required to generate attributes on the result phase; this can be skipped
287 * during the rewind phase.
288 */
289
290 protected void renderInformalParameters(IMarkupWriter writer, IRequestCycle cycle)
291 {try { __CLOVER_0_0.M[2654]++;
292 __CLOVER_0_0.S[10715]++;String attribute;
293
294 __CLOVER_0_0.S[10716]++;if ((((_bindings == null) && (++__CLOVER_0_0.CT[1845] != 0)) || (++__CLOVER_0_0.CF[1845] == 0))){
295 __CLOVER_0_0.S[10717]++;return;}
296
297 __CLOVER_0_0.S[10718]++;Iterator i = _bindings.entrySet().iterator();
298
299 __CLOVER_0_0.S[10719]++;while ((((i.hasNext()) && (++__CLOVER_0_0.CT[1846] != 0)) || (++__CLOVER_0_0.CF[1846] == 0))){
300 {
301 __CLOVER_0_0.S[10720]++;Map.Entry entry = (Map.Entry) i.next();
302 __CLOVER_0_0.S[10721]++;String name = (String) entry.getKey();
303
304 __CLOVER_0_0.S[10722]++;IBinding binding = (IBinding) entry.getValue();
305
306 __CLOVER_0_0.S[10723]++;Object value = binding.getObject();
307 __CLOVER_0_0.S[10724]++;if ((((value == null) && (++__CLOVER_0_0.CT[1847] != 0)) || (++__CLOVER_0_0.CF[1847] == 0))){
308 __CLOVER_0_0.S[10725]++;continue;}
309
310 __CLOVER_0_0.S[10726]++;if ((((value instanceof IAsset) && (++__CLOVER_0_0.CT[1848] != 0)) || (++__CLOVER_0_0.CF[1848] == 0))){
311 {
312 __CLOVER_0_0.S[10727]++;IAsset asset = (IAsset) value;
313
314 // Get the URL of the asset and insert that.
315
316 __CLOVER_0_0.S[10728]++;attribute = asset.buildURL(cycle);
317 }}
318 else{
319 __CLOVER_0_0.S[10729]++;attribute = value.toString();}
320
321 __CLOVER_0_0.S[10730]++;writer.attribute(name, attribute);
322 }}
323
324 } finally { }}
325
326 /**
327 * Returns an object used to resolve classes.
328 *
329 * @since 3.0
330 */
331 private ClassResolver getClassResolver()
332 {try { __CLOVER_0_0.M[2655]++;
333 __CLOVER_0_0.S[10731]++;return getPage().getEngine().getClassResolver();
334 } finally { }}
335
336 /**
337 * Returns the named binding, or null if it doesn't exist.
338 * <p>
339 * This method looks for a JavaBeans property with an appropriate name, of type {@link IBinding}.
340 * The property should be named <code><i>name</i>Binding</code>. If it exists and is both
341 * readable and writable, then it is accessor method is invoked. Components which implement such
342 * methods can access their own binding through their instance variables instead of invoking
343 * this method, a performance optimization.
344 *
345 * @see #setBinding(String,IBinding)
346 */
347
348 public IBinding getBinding(String name)
349 {try { __CLOVER_0_0.M[2656]++;
350 __CLOVER_0_0.S[10732]++;String bindingPropertyName = name + Tapestry.PARAMETER_PROPERTY_NAME_SUFFIX;
351
352 __CLOVER_0_0.S[10733]++;if ((((PropertyUtils.isReadable(this, bindingPropertyName)
353 && PropertyUtils.getPropertyType(this, bindingPropertyName).equals(IBinding.class)) && (++__CLOVER_0_0.CT[1849] != 0)) || (++__CLOVER_0_0.CF[1849] == 0))){
354 {
355 __CLOVER_0_0.S[10734]++;return (IBinding) PropertyUtils.read(this, bindingPropertyName);
356 }}
357
358 __CLOVER_0_0.S[10735]++;if ((((_bindings == null) && (++__CLOVER_0_0.CT[1850] != 0)) || (++__CLOVER_0_0.CF[1850] == 0))){
359 __CLOVER_0_0.S[10736]++;return null;}
360
361 __CLOVER_0_0.S[10737]++;return (IBinding) _bindings.get(name);
362 } finally { }}
363
364 /**
365 * Return's the page's change observer. In practical terms, this will be an
366 * {@link org.apache.tapestry.engine.IPageRecorder}.
367 *
368 * @see IPage#getChangeObserver()
369 * @deprecated To be removed in 3.1; use {@link IPage#getChangeObserver()}.
370 */
371
372 public ChangeObserver getChangeObserver()
373 {try { __CLOVER_0_0.M[2657]++;
374 __CLOVER_0_0.S[10738]++;return _page.getChangeObserver();
375 } finally { }}
376
377 public IComponent getComponent(String id)
378 {try { __CLOVER_0_0.M[2658]++;
379 __CLOVER_0_0.S[10739]++;IComponent result = null;
380
381 __CLOVER_0_0.S[10740]++;if ((((_components != null) && (++__CLOVER_0_0.CT[1851] != 0)) || (++__CLOVER_0_0.CF[1851] == 0))){
382 __CLOVER_0_0.S[10741]++;result = (IComponent) _components.get(id);}
383
384 __CLOVER_0_0.S[10742]++;if ((((result == null) && (++__CLOVER_0_0.CT[1852] != 0)) || (++__CLOVER_0_0.CF[1852] == 0))){
385 __CLOVER_0_0.S[10743]++;throw new ApplicationRuntimeException(Tapestry.format("no-such-component", this, id),
386 this, null, null);}
387
388 __CLOVER_0_0.S[10744]++;return result;
389 } finally { }}
390
391 public IComponent getContainer()
392 {try { __CLOVER_0_0.M[2659]++;
393 __CLOVER_0_0.S[10745]++;return _container;
394 } finally { }}
395
396 public void setContainer(IComponent value)
397 {try { __CLOVER_0_0.M[2660]++;
398 __CLOVER_0_0.S[10746]++;if ((((_container != null) && (++__CLOVER_0_0.CT[1853] != 0)) || (++__CLOVER_0_0.CF[1853] == 0))){
399 __CLOVER_0_0.S[10747]++;throw new ApplicationRuntimeException(Tapestry
400 .getMessage("AbstractComponent.attempt-to-change-container"));}
401
402 __CLOVER_0_0.S[10748]++;_container = value;
403 } finally { }}
404
405 /**
406 * Returns the name of the page, a slash, and this component's id path. Pages are different,
407 * they simply return their name.
408 *
409 * @see #getIdPath()
410 */
411
412 public String getExtendedId()
413 {try { __CLOVER_0_0.M[2661]++;
414 __CLOVER_0_0.S[10749]++;if ((((_page == null) && (++__CLOVER_0_0.CT[1854] != 0)) || (++__CLOVER_0_0.CF[1854] == 0))){
415 __CLOVER_0_0.S[10750]++;return null;}
416
417 __CLOVER_0_0.S[10751]++;return _page.getPageName() + "/" + getIdPath();
418 } finally { }}
419
420 public String getId()
421 {try { __CLOVER_0_0.M[2662]++;
422 __CLOVER_0_0.S[10752]++;return _id;
423 } finally { }}
424
425 public void setId(String value)
426 {try { __CLOVER_0_0.M[2663]++;
427 __CLOVER_0_0.S[10753]++;if ((((_id != null) && (++__CLOVER_0_0.CT[1855] != 0)) || (++__CLOVER_0_0.CF[1855] == 0))){
428 __CLOVER_0_0.S[10754]++;throw new ApplicationRuntimeException(Tapestry
429 .getMessage("AbstractComponent.attempt-to-change-component-id"));}
430
431 __CLOVER_0_0.S[10755]++;_id = value;
432 } finally { }}
433
434 public String getIdPath()
435 {try { __CLOVER_0_0.M[2664]++;
436 __CLOVER_0_0.S[10756]++;String containerIdPath;
437
438 __CLOVER_0_0.S[10757]++;if ((((_container == null) && (++__CLOVER_0_0.CT[1856] != 0)) || (++__CLOVER_0_0.CF[1856] == 0))){
439 __CLOVER_0_0.S[10758]++;throw new NullPointerException(Tapestry
440 .format("AbstractComponent.null-container", this));}
441
442 __CLOVER_0_0.S[10759]++;containerIdPath = _container.getIdPath();
443
444 __CLOVER_0_0.S[10760]++;if ((((containerIdPath == null) && (++__CLOVER_0_0.CT[1857] != 0)) || (++__CLOVER_0_0.CF[1857] == 0))){
445 __CLOVER_0_0.S[10761]++;_idPath = _id;}
446 else{
447 __CLOVER_0_0.S[10762]++;_idPath = containerIdPath + "." + _id;}
448
449 __CLOVER_0_0.S[10763]++;return _idPath;
450 } finally { }}
451
452 public IPage getPage()
453 {try { __CLOVER_0_0.M[2665]++;
454 __CLOVER_0_0.S[10764]++;return _page;
455 } finally { }}
456
457 public void setPage(IPage value)
458 {try { __CLOVER_0_0.M[2666]++;
459 __CLOVER_0_0.S[10765]++;if ((((_page != null) && (++__CLOVER_0_0.CT[1858] != 0)) || (++__CLOVER_0_0.CF[1858] == 0))){
460 __CLOVER_0_0.S[10766]++;throw new ApplicationRuntimeException(Tapestry
461 .getMessage("AbstractComponent.attempt-to-change-page"));}
462
463 __CLOVER_0_0.S[10767]++;_page = value;
464 } finally { }}
465
466 public IComponentSpecification getSpecification()
467 {try { __CLOVER_0_0.M[2667]++;
468 __CLOVER_0_0.S[10768]++;return _specification;
469 } finally { }}
470
471 public void setSpecification(IComponentSpecification value)
472 {try { __CLOVER_0_0.M[2668]++;
473 __CLOVER_0_0.S[10769]++;if ((((_specification != null) && (++__CLOVER_0_0.CT[1859] != 0)) || (++__CLOVER_0_0.CF[1859] == 0))){
474 __CLOVER_0_0.S[10770]++;throw new ApplicationRuntimeException(Tapestry
475 .getMessage("AbstractComponent.attempt-to-change-spec"));}
476
477 __CLOVER_0_0.S[10771]++;_specification = value;
478 } finally { }}
479
480 /**
481 * Renders all elements wrapped by the receiver.
482 */
483
484 public void renderBody(IMarkupWriter writer, IRequestCycle cycle)
485 {try { __CLOVER_0_0.M[2669]++;
486 __CLOVER_0_0.S[10772]++;for (int i = 0; (((i < _bodyCount) && (++__CLOVER_0_0.CT[1860] != 0)) || (++__CLOVER_0_0.CF[1860] == 0)); i++){
487 __CLOVER_0_0.S[10773]++;_body[i].render(writer, cycle);}
488 } finally { }}
489
490 /**
491 * Adds the binding with the given name, replacing any existing binding with that name.
492 * <p>
493 * This method checks to see if a matching JavaBeans property (with a name of
494 * <code><i>name</i>Binding</code> and a type of {@link IBinding}) exists. If so, that
495 * property is updated. An optimized component can simply implement accessor and mutator methods
496 * and then access its bindings via its own instance variables, rather than going through {@link
497 * #getBinding(String)}.
498 * <p>
499 * Informal parameters should <em>not</em> be stored in instance variables if {@link
500 * #renderInformalParameters(IMarkupWriter, IRequestCycle)} is to be used. It relies on using
501 * the collection of bindings (to store informal parameters).
502 */
503
504 public void setBinding(String name, IBinding binding)
505 {try { __CLOVER_0_0.M[2670]++;
506 __CLOVER_0_0.S[10774]++;String bindingPropertyName = name + Tapestry.PARAMETER_PROPERTY_NAME_SUFFIX;
507
508 __CLOVER_0_0.S[10775]++;if ((((PropertyUtils.isWritable(this, bindingPropertyName)
509 && PropertyUtils.getPropertyType(this, bindingPropertyName).equals(IBinding.class)) && (++__CLOVER_0_0.CT[1861] != 0)) || (++__CLOVER_0_0.CF[1861] == 0))){
510 {
511 __CLOVER_0_0.S[10776]++;PropertyUtils.write(this, bindingPropertyName, binding);
512 __CLOVER_0_0.S[10777]++;return;
513 }}
514
515 __CLOVER_0_0.S[10778]++;if ((((_bindings == null) && (++__CLOVER_0_0.CT[1862] != 0)) || (++__CLOVER_0_0.CF[1862] == 0))){
516 __CLOVER_0_0.S[10779]++;_bindings = new HashMap(MAP_SIZE);}
517
518 __CLOVER_0_0.S[10780]++;_bindings.put(name, binding);
519 } finally { }}
520
521 public String toString()
522 {try { __CLOVER_0_0.M[2671]++;
523 __CLOVER_0_0.S[10781]++;StringBuffer buffer;
524
525 __CLOVER_0_0.S[10782]++;buffer = new StringBuffer(super.toString());
526
527 __CLOVER_0_0.S[10783]++;buffer.append('[');
528
529 __CLOVER_0_0.S[10784]++;buffer.append(getExtendedId());
530
531 __CLOVER_0_0.S[10785]++;buffer.append(']');
532
533 __CLOVER_0_0.S[10786]++;return buffer.toString();
534 } finally { }}
535
536 /**
537 * Returns an unmodifiable {@link Map}of components, keyed on component id. Never returns null,
538 * but may return an empty map. The returned map is immutable.
539 */
540
541 public Map getComponents()
542 {try { __CLOVER_0_0.M[2672]++;
543 __CLOVER_0_0.S[10787]++;if ((((_components == null) && (++__CLOVER_0_0.CT[1863] != 0)) || (++__CLOVER_0_0.CF[1863] == 0))){
544 __CLOVER_0_0.S[10788]++;return EMPTY_MAP;}
545
546 __CLOVER_0_0.S[10789]++;return Collections.unmodifiableMap(_components);
547
548 } finally { }}
549
550 public Map getAssets()
551 {try { __CLOVER_0_0.M[2673]++;
552 __CLOVER_0_0.S[10790]++;if ((((_assets == null) && (++__CLOVER_0_0.CT[1864] != 0)) || (++__CLOVER_0_0.CF[1864] == 0))){
553 __CLOVER_0_0.S[10791]++;return EMPTY_MAP;}
554
555 __CLOVER_0_0.S[10792]++;return Collections.unmodifiableMap(_assets);
556 } finally { }}
557
558 public IAsset getAsset(String name)
559 {try { __CLOVER_0_0.M[2674]++;
560 __CLOVER_0_0.S[10793]++;if ((((_assets == null) && (++__CLOVER_0_0.CT[1865] != 0)) || (++__CLOVER_0_0.CF[1865] == 0))){
561 __CLOVER_0_0.S[10794]++;return null;}
562
563 __CLOVER_0_0.S[10795]++;return (IAsset) _assets.get(name);
564 } finally { }}
565
566 public Collection getBindingNames()
567 {try { __CLOVER_0_0.M[2675]++;
568 // If no conainer, i.e. a page, then no bindings.
569
570 __CLOVER_0_0.S[10796]++;if ((((_container == null) && (++__CLOVER_0_0.CT[1866] != 0)) || (++__CLOVER_0_0.CF[1866] == 0))){
571 __CLOVER_0_0.S[10797]++;return null;}
572
573 __CLOVER_0_0.S[10798]++;HashSet result = new HashSet();
574
575 // All the informal bindings go into the bindings Map.
576
577 __CLOVER_0_0.S[10799]++;if ((((_bindings != null) && (++__CLOVER_0_0.CT[1867] != 0)) || (++__CLOVER_0_0.CF[1867] == 0))){
578 __CLOVER_0_0.S[10800]++;result.addAll(_bindings.keySet());}
579
580 // Now, iterate over the formal parameters and add the formal parameters
581 // that have a binding.
582
583 __CLOVER_0_0.S[10801]++;List names = _specification.getParameterNames();
584
585 __CLOVER_0_0.S[10802]++;int count = names.size();
586
587 __CLOVER_0_0.S[10803]++;for (int i = 0; (((i < count) && (++__CLOVER_0_0.CT[1868] != 0)) || (++__CLOVER_0_0.CF[1868] == 0)); i++){
588 {
589 __CLOVER_0_0.S[10804]++;String name = (String) names.get(i);
590
591 __CLOVER_0_0.S[10805]++;if ((((result.contains(name)) && (++__CLOVER_0_0.CT[1869] != 0)) || (++__CLOVER_0_0.CF[1869] == 0))){
592 __CLOVER_0_0.S[10806]++;continue;}
593
594 __CLOVER_0_0.S[10807]++;if ((((getBinding(name) != null) && (++__CLOVER_0_0.CT[1870] != 0)) || (++__CLOVER_0_0.CF[1870] == 0))){
595 __CLOVER_0_0.S[10808]++;result.add(name);}
596 }}
597
598 __CLOVER_0_0.S[10809]++;return result;
599 } finally { }}
600
601 /**
602 * Returns a {@link Map}of all bindings for this component. This implementation is expensive,
603 * since it has to merge the disassociated bindings (informal parameters, and parameters without
604 * a JavaBeans property) with the associated bindings (formal parameters with a JavaBeans
605 * property).
606 *
607 * @since 1.0.5
608 */
609
610 public Map getBindings()
611 {try { __CLOVER_0_0.M[2676]++;
612 __CLOVER_0_0.S[10810]++;Map result = new HashMap();
613
614 // Add any informal parameters.
615
616 __CLOVER_0_0.S[10811]++;if ((((_bindings != null) && (++__CLOVER_0_0.CT[1871] != 0)) || (++__CLOVER_0_0.CF[1871] == 0))){
617 __CLOVER_0_0.S[10812]++;result.putAll(_bindings);}
618
619 // Now work on the formal parameters
620
621 __CLOVER_0_0.S[10813]++;Iterator i = _specification.getParameterNames().iterator();
622 __CLOVER_0_0.S[10814]++;while ((((i.hasNext()) && (++__CLOVER_0_0.CT[1872] != 0)) || (++__CLOVER_0_0.CF[1872] == 0))){
623 {
624 __CLOVER_0_0.S[10815]++;String name = (String) i.next();
625
626 __CLOVER_0_0.S[10816]++;if ((((result.containsKey(name)) && (++__CLOVER_0_0.CT[1873] != 0)) || (++__CLOVER_0_0.CF[1873] == 0))){
627 __CLOVER_0_0.S[10817]++;continue;}
628
629 __CLOVER_0_0.S[10818]++;IBinding binding = getBinding(name);
630
631 __CLOVER_0_0.S[10819]++;if ((((binding != null) && (++__CLOVER_0_0.CT[1874] != 0)) || (++__CLOVER_0_0.CF[1874] == 0))){
632 __CLOVER_0_0.S[10820]++;result.put(name, binding);}
633 }}
634
635 __CLOVER_0_0.S[10821]++;return result;
636 } finally { }}
637
638 /**
639 * Returns a {@link ListenerMap}for the component. A {@link ListenerMap}contains a number of
640 * synthetic read-only properties that implement the {@link IActionListener}interface, but in
641 * fact, cause public instance methods to be invoked.
642 *
643 * @since 1.0.2
644 */
645
646 public ListenerMap getListeners()
647 {try { __CLOVER_0_0.M[2677]++;
648 __CLOVER_0_0.S[10822]++;if ((((_listeners == null) && (++__CLOVER_0_0.CT[1875] != 0)) || (++__CLOVER_0_0.CF[1875] == 0))){
649 __CLOVER_0_0.S[10823]++;_listeners = new ListenerMap(this);}
650
651 __CLOVER_0_0.S[10824]++;return _listeners;
652 } finally { }}
653
654 /**
655 * Returns the {@link IBeanProvider}for this component. This is lazily created the first time
656 * it is needed.
657 *
658 * @since 1.0.4
659 */
660
661 public IBeanProvider getBeans()
662 {try { __CLOVER_0_0.M[2678]++;
663 __CLOVER_0_0.S[10825]++;if ((((_beans == null) && (++__CLOVER_0_0.CT[1876] != 0)) || (++__CLOVER_0_0.CF[1876] == 0))){
664 __CLOVER_0_0.S[10826]++;_beans = new BeanProvider(this);}
665
666 __CLOVER_0_0.S[10827]++;return _beans;
667 } finally { }}
668
669 /**
670 * Invoked, as a convienience, from
671 * {@link #finishLoad(IRequestCycle, IPageLoader, IComponentSpecification)}. This implemenation
672 * does nothing. Subclasses may override without invoking this implementation.
673 *
674 * @since 1.0.5
675 */
676
677 protected void finishLoad()
678 {try { __CLOVER_0_0.M[2679]++;
679 } finally { }}
680
681 /**
682 * The main method used to render the component. Invokes
683 * {@link #prepareForRender(IRequestCycle)}, then
684 * {@link #renderComponent(IMarkupWriter, IRequestCycle)}.
685 * {@link #cleanupAfterRender(IRequestCycle)}is invoked in a <code>finally</code> block.
686 * <p>
687 * Subclasses should not override this method; instead they will implement
688 * {@link #renderComponent(IMarkupWriter, IRequestCycle)}.
689 *
690 * @since 2.0.3
691 */
692
693 public final void render(IMarkupWriter writer, IRequestCycle cycle)
694 {try { __CLOVER_0_0.M[2680]++;
695 __CLOVER_0_0.S[10828]++;try
696 {
697 __CLOVER_0_0.S[10829]++;Tapestry.clearMethodInvocations();
698
699 __CLOVER_0_0.S[10830]++;prepareForRender(cycle);
700
701 __CLOVER_0_0.S[10831]++;Tapestry.checkMethodInvocation(PREPAREFORRENDER_METHOD_ID, "prepareForRender()", this);
702
703 __CLOVER_0_0.S[10832]++;renderComponent(writer, cycle);
704 }
705 finally
706 {
707 __CLOVER_0_0.S[10833]++;Tapestry.clearMethodInvocations();
708
709 __CLOVER_0_0.S[10834]++;cleanupAfterRender(cycle);
710
711 __CLOVER_0_0.S[10835]++;Tapestry.checkMethodInvocation(
712 CLEANUPAFTERRENDER_METHOD_ID,
713 "cleanupAfterRender()",
714 this);
715 }
716 } finally { }}
717
718 /**
719 * Invoked by {@link #render(IMarkupWriter, IRequestCycle)}to prepare the component to render.
720 * This implementation sets JavaBeans properties from matching bound parameters. Subclasses that
721 * override this method must invoke this implementation as well.
722 *
723 * @since 2.0.3
724 */
725
726 protected void prepareForRender(IRequestCycle cycle)
727 {try { __CLOVER_0_0.M[2681]++;
728 __CLOVER_0_0.S[10836]++;Tapestry.addMethodInvocation(PREPAREFORRENDER_METHOD_ID);
729
730 __CLOVER_0_0.S[10837]++;if ((((_parameterManager == null) && (++__CLOVER_0_0.CT[1877] != 0)) || (++__CLOVER_0_0.CF[1877] == 0))){
731 {
732 // Pages inherit from this class too, but pages (by definition)
733 // never have parameters.
734
735 __CLOVER_0_0.S[10838]++;if ((((getSpecification().isPageSpecification()) && (++__CLOVER_0_0.CT[1878] != 0)) || (++__CLOVER_0_0.CF[1878] == 0))){
736 __CLOVER_0_0.S[10839]++;return;}
737
738 __CLOVER_0_0.S[10840]++;_parameterManager = new ParameterManager(this);
739 }}
740
741 __CLOVER_0_0.S[10841]++;_parameterManager.setParameters(cycle);
742 } finally { }}
743
744 /**
745 * Invoked by {@link #render(IMarkupWriter, IRequestCycle)}to actually render the component
746 * (with any parameter values already set). This is the method that subclasses must implement.
747 *
748 * @since 2.0.3
749 */
750
751 protected abstract void renderComponent(IMarkupWriter writer, IRequestCycle cycle);
752
753 /**
754 * Invoked by {@link #render(IMarkupWriter, IRequestCycle)}after the component renders, to
755 * clear any parameters back to null (or 0, or false, or whatever the correct default is).
756 * Primarily, this is used to ensure that the component doesn't hold onto any objects that could
757 * otherwise be garbage collected.
758 * <p>
759 * Subclasses may override this implementation, but must also invoke it.
760 *
761 * @since 2.0.3
762 */
763
764 protected void cleanupAfterRender(IRequestCycle cycle)
765 {try { __CLOVER_0_0.M[2682]++;
766 __CLOVER_0_0.S[10842]++;Tapestry.addMethodInvocation(CLEANUPAFTERRENDER_METHOD_ID);
767
768 __CLOVER_0_0.S[10843]++;if ((((_parameterManager != null) && (++__CLOVER_0_0.CT[1879] != 0)) || (++__CLOVER_0_0.CF[1879] == 0))){
769 __CLOVER_0_0.S[10844]++;_parameterManager.resetParameters(cycle);}
770 } finally { }}
771
772 /** @since 3.0 * */
773
774 public Messages getMessages()
775 {try { __CLOVER_0_0.M[2683]++;
776 __CLOVER_0_0.S[10845]++;if ((((_strings == null) && (++__CLOVER_0_0.CT[1880] != 0)) || (++__CLOVER_0_0.CF[1880] == 0))){
777 __CLOVER_0_0.S[10846]++;_strings = getPage().getEngine().getComponentMessagesSource().getMessages(this);}
778
779 __CLOVER_0_0.S[10847]++;return _strings;
780 } finally { }}
781
782 /**
783 * Obtains the {@link IMessages}for this component (if necessary), and gets the string from it.
784 */
785
786 public String getString(String key)
787 {try { __CLOVER_0_0.M[2684]++;
788 __CLOVER_0_0.S[10848]++;return getMessages().getMessage(key);
789 } finally { }}
790
791 public String getMessage(String key)
792 {try { __CLOVER_0_0.M[2685]++;
793 // Invoke the deprecated implementation (for code coverage reasons).
794 // In 3.1, remove getString() and move its implementation
795 // here.
796
797 __CLOVER_0_0.S[10849]++;return getString(key);
798 } finally { }}
799
800 /**
801 * Formats a message string, using
802 * {@link IMessages#format(java.lang.String, java.lang.Object[])}.
803 *
804 * @param key
805 * the key used to obtain a localized pattern using {@link #getString(String)}
806 * @param arguments
807 * passed to the formatter
808 * @since 2.2
809 * @deprecated To be removed in 3.1. Use {@link #format(String, Object[])}instead.
810 */
811
812 public String formatString(String key, Object[] arguments)
813 {try { __CLOVER_0_0.M[2686]++;
814 __CLOVER_0_0.S[10850]++;return getMessages().format(key, arguments);
815 } finally { }}
816
817 /**
818 * Formats a localized message string, using
819 * {@link IMessages#format(java.lang.String, java.lang.Object[])}.
820 *
821 * @param key
822 * the key used to obtain a localized pattern using {@link #getString(String)}
823 * @param arguments
824 * passed to the formatter
825 * @since 3.0
826 */
827
828 public String format(String key, Object[] arguments)
829 {try { __CLOVER_0_0.M[2687]++;
830 // SOP: New name invokes deprecated method (consistency and
831 // code coverage); in 3.1 we move the implementation here.
832
833 __CLOVER_0_0.S[10851]++;return formatString(key, arguments);
834 } finally { }}
835
836 /**
837 * Convienience method for invoking {@link IMessages#format(String, Object[])}
838 *
839 * @since 2.2
840 * @deprecated To be removed in 3.1. Use {@link #format(String, Object)}instead.
841 */
842
843 public String formatString(String key, Object argument)
844 {try { __CLOVER_0_0.M[2688]++;
845 __CLOVER_0_0.S[10852]++;return getMessages().format(key, argument);
846 } finally { }}
847
848 /**
849 * Convienience method for invoking {@link IMessages#format(String, Object)}
850 *
851 * @since 3.0
852 */
853
854 public String format(String key, Object argument)
855 {try { __CLOVER_0_0.M[2689]++;
856 __CLOVER_0_0.S[10853]++;return formatString(key, argument);
857 } finally { }}
858
859 /**
860 * Convienience method for invoking {@link IMessages#format(String, Object, Object)}.
861 *
862 * @since 2.2
863 * @deprecated To be removed in 3.1. Use {@link #format(String, Object, Object)}instead.
864 */
865
866 public String formatString(String key, Object argument1, Object argument2)
867 {try { __CLOVER_0_0.M[2690]++;
868 __CLOVER_0_0.S[10854]++;return getMessages().format(key, argument1, argument2);
869 } finally { }}
870
871 /**
872 * Convienience method for invoking {@link IMessages#format(String, Object, Object)}.
873 *
874 * @since 3.0
875 */
876
877 public String format(String key, Object argument1, Object argument2)
878 {try { __CLOVER_0_0.M[2691]++;
879 __CLOVER_0_0.S[10855]++;return formatString(key, argument1, argument2);
880 } finally { }}
881
882 /**
883 * Convienience method for {@link IMessages#format(String, Object, Object, Object)}.
884 *
885 * @since 2.2
886 * @deprecated To be removed in 3.1. Use {@link #format(String, Object, Object, Object)}
887 * instead.
888 */
889
890 public String formatString(String key, Object argument1, Object argument2, Object argument3)
891 {try { __CLOVER_0_0.M[2692]++;
892 __CLOVER_0_0.S[10856]++;return getMessages().format(key, argument1, argument2, argument3);
893 } finally { }}
894
895 /**
896 * Convienience method for {@link IMessages#format(String, Object, Object, Object)}.
897 *
898 * @since 3.0
899 */
900
901 public String format(String key, Object argument1, Object argument2, Object argument3)
902 {try { __CLOVER_0_0.M[2693]++;
903 __CLOVER_0_0.S[10857]++;return formatString(key, argument1, argument2, argument3);
904 } finally { }}
905
906 public INamespace getNamespace()
907 {try { __CLOVER_0_0.M[2694]++;
908 __CLOVER_0_0.S[10858]++;return _namespace;
909 } finally { }}
910
911 public void setNamespace(INamespace namespace)
912 {try { __CLOVER_0_0.M[2695]++;
913 __CLOVER_0_0.S[10859]++;_namespace = namespace;
914 } finally { }}
915
916 /**
917 * Returns the body of the component, the element (which may be static HTML or components) that
918 * the component immediately wraps. May return null. Do not modify the returned array. The array
919 * may be padded with nulls.
920 *
921 * @since 2.3
922 * @see #getBodyCount()
923 */
924
925 public IRender[] getBody()
926 {try { __CLOVER_0_0.M[2696]++;
927 __CLOVER_0_0.S[10860]++;return _body;
928 } finally { }}
929
930 /**
931 * Returns the active number of elements in the the body, which may be zero.
932 *
933 * @since 2.3
934 * @see #getBody()
935 */
936
937 public int getBodyCount()
938 {try { __CLOVER_0_0.M[2697]++;
939 __CLOVER_0_0.S[10861]++;return _bodyCount;
940 } finally { }}
941
942 /**
943 * Empty implementation of
944 * {@link org.apache.tapestry.event.PageRenderListener#pageEndRender(PageEvent)}. This allows
945 * classes to implement {@link org.apache.tapestry.event.PageRenderListener}and only implement
946 * the {@link org.apache.tapestry.event.PageRenderListener#pageBeginRender(PageEvent)}method.
947 *
948 * @since 3.0
949 */
950
951 public void pageEndRender(PageEvent event)
952 {try { __CLOVER_0_0.M[2698]++;
953 } finally { }}
954
955 /**
956 * Sets a property of a component.
957 *
958 * @see IComponent
959 * @since 3.0
960 */
961 public void setProperty(String propertyName, Object value)
962 {try { __CLOVER_0_0.M[2699]++;
963 __CLOVER_0_0.S[10862]++;OgnlUtils.set(propertyName, this, value);
964 } finally { }}
965
966 /**
967 * Gets a property of a component.
968 *
969 * @see IComponent
970 * @since 3.0
971 */
972 public Object getProperty(String propertyName)
973 {try { __CLOVER_0_0.M[2700]++;
974 __CLOVER_0_0.S[10863]++;return OgnlUtils.get(propertyName, this);
975 } finally { }}
976 }