|
|||||||||||||||||||
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover | |||||||||||||||||||
Source file | Conditionals | Statements | Methods | TOTAL | |||||||||||||||
AbstractComponent.java | 75% | 89% | 93.2% | 86.2% |
|
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.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 org.apache.hivemind.ApplicationRuntimeException;
|
|
26 |
import org.apache.hivemind.Messages;
|
|
27 |
import org.apache.hivemind.impl.BaseLocatable;
|
|
28 |
import org.apache.hivemind.util.Defense;
|
|
29 |
import org.apache.hivemind.util.PropertyUtils;
|
|
30 |
import org.apache.tapestry.bean.BeanProvider;
|
|
31 |
import org.apache.tapestry.engine.IPageLoader;
|
|
32 |
import org.apache.tapestry.event.PageEvent;
|
|
33 |
import org.apache.tapestry.listener.ListenerMap;
|
|
34 |
import org.apache.tapestry.spec.IComponentSpecification;
|
|
35 |
|
|
36 |
/**
|
|
37 |
* Abstract base class implementing the {@link IComponent}interface.
|
|
38 |
*
|
|
39 |
* @author Howard Lewis Ship
|
|
40 |
*/
|
|
41 |
|
|
42 |
public abstract class AbstractComponent extends BaseLocatable implements IComponent |
|
43 |
{ |
|
44 |
/**
|
|
45 |
* The page that contains the component, possibly itself (if the component is in fact, a page).
|
|
46 |
*/
|
|
47 |
|
|
48 |
private IPage _page;
|
|
49 |
|
|
50 |
/**
|
|
51 |
* The component which contains the component. This will only be null if the component is
|
|
52 |
* actually a page.
|
|
53 |
*/
|
|
54 |
|
|
55 |
private IComponent _container;
|
|
56 |
|
|
57 |
/**
|
|
58 |
* The simple id of this component.
|
|
59 |
*/
|
|
60 |
|
|
61 |
private String _id;
|
|
62 |
|
|
63 |
/**
|
|
64 |
* The fully qualified id of this component. This is calculated the first time it is needed,
|
|
65 |
* then cached for later.
|
|
66 |
*/
|
|
67 |
|
|
68 |
private String _idPath;
|
|
69 |
|
|
70 |
private static final int MAP_SIZE = 5; |
|
71 |
|
|
72 |
/**
|
|
73 |
* A {@link Map}of all bindings (for which there isn't a corresponding JavaBeans property); the
|
|
74 |
* keys are the names of formal and informal parameters.
|
|
75 |
*/
|
|
76 |
|
|
77 |
private Map _bindings;
|
|
78 |
|
|
79 |
private Map _components;
|
|
80 |
|
|
81 |
private static final int BODY_INIT_SIZE = 5; |
|
82 |
|
|
83 |
private INamespace _namespace;
|
|
84 |
|
|
85 |
/**
|
|
86 |
* Used in place of JDK 1.3's Collections.EMPTY_MAP (which is not available in JDK 1.2).
|
|
87 |
*/
|
|
88 |
|
|
89 |
private static final Map EMPTY_MAP = Collections.unmodifiableMap(new HashMap(1)); |
|
90 |
|
|
91 |
/**
|
|
92 |
* The number of {@link IRender}objects in the body of this component.
|
|
93 |
*/
|
|
94 |
|
|
95 |
private int _bodyCount = 0; |
|
96 |
|
|
97 |
/**
|
|
98 |
* An aray of elements in the body of this component.
|
|
99 |
*/
|
|
100 |
|
|
101 |
private IRender[] _body;
|
|
102 |
|
|
103 |
/**
|
|
104 |
* The components' asset map.
|
|
105 |
*/
|
|
106 |
|
|
107 |
private Map _assets;
|
|
108 |
|
|
109 |
/**
|
|
110 |
* A mapping that allows public instance methods to be dressed up as {@link IActionListener}
|
|
111 |
* listener objects.
|
|
112 |
*
|
|
113 |
* @since 1.0.2
|
|
114 |
*/
|
|
115 |
|
|
116 |
private ListenerMap _listeners;
|
|
117 |
|
|
118 |
/**
|
|
119 |
* A bean provider; these are lazily created as needed.
|
|
120 |
*
|
|
121 |
* @since 1.0.4
|
|
122 |
*/
|
|
123 |
|
|
124 |
private IBeanProvider _beans;
|
|
125 |
|
|
126 |
/**
|
|
127 |
* Returns true if the component is currently rendering.
|
|
128 |
*
|
|
129 |
* @see #prepareForRender(IRequestCycle)
|
|
130 |
* @see #cleanupAfterRender(IRequestCycle)
|
|
131 |
* @since 4.0
|
|
132 |
*/
|
|
133 |
|
|
134 |
private boolean _rendering; |
|
135 |
|
|
136 |
/**
|
|
137 |
* @since 4.0
|
|
138 |
*/
|
|
139 |
|
|
140 |
private boolean _active; |
|
141 |
|
|
142 | 60 |
public void addAsset(String name, IAsset asset) |
143 |
{ |
|
144 | 60 |
Defense.notNull(name, "name");
|
145 | 60 |
Defense.notNull(asset, "asset");
|
146 |
|
|
147 | 60 |
checkActiveLock(); |
148 |
|
|
149 | 60 |
if (_assets == null) |
150 | 56 |
_assets = new HashMap(MAP_SIZE);
|
151 |
|
|
152 | 60 |
_assets.put(name, asset); |
153 |
} |
|
154 |
|
|
155 | 1024 |
public void addComponent(IComponent component) |
156 |
{ |
|
157 | 1024 |
Defense.notNull(component, "component");
|
158 |
|
|
159 | 1024 |
checkActiveLock(); |
160 |
|
|
161 | 1024 |
if (_components == null) |
162 | 219 |
_components = new HashMap(MAP_SIZE);
|
163 |
|
|
164 | 1024 |
_components.put(component.getId(), component); |
165 |
} |
|
166 |
|
|
167 |
/**
|
|
168 |
* Adds an element (which may be static text or a component) as a body element of this
|
|
169 |
* component. Such elements are rendered by {@link #renderBody(IMarkupWriter, IRequestCycle)}.
|
|
170 |
*
|
|
171 |
* @since 2.2
|
|
172 |
*/
|
|
173 |
|
|
174 | 1871 |
public void addBody(IRender element) |
175 |
{ |
|
176 | 1871 |
Defense.notNull(element, "element");
|
177 |
|
|
178 |
// TODO: Tweak the ordering of operations inside the PageLoader so that this
|
|
179 |
// check is allowable. Currently, the component is entering active state
|
|
180 |
// before it loads its template.
|
|
181 |
|
|
182 |
// checkActiveLock();
|
|
183 |
|
|
184 |
// Should check the specification to see if this component
|
|
185 |
// allows body. Curently, this is checked by the component
|
|
186 |
// in render(), which is silly.
|
|
187 |
|
|
188 | 1871 |
if (_body == null) |
189 |
{ |
|
190 | 521 |
_body = new IRender[BODY_INIT_SIZE];
|
191 | 521 |
_body[0] = element; |
192 |
|
|
193 | 521 |
_bodyCount = 1; |
194 | 521 |
return;
|
195 |
} |
|
196 |
|
|
197 |
// No more room? Make the array bigger.
|
|
198 |
|
|
199 | 1350 |
if (_bodyCount == _body.length)
|
200 |
{ |
|
201 | 110 |
IRender[] newWrapped; |
202 |
|
|
203 | 110 |
newWrapped = new IRender[_body.length * 2];
|
204 |
|
|
205 | 110 |
System.arraycopy(_body, 0, newWrapped, 0, _bodyCount); |
206 |
|
|
207 | 110 |
_body = newWrapped; |
208 |
} |
|
209 |
|
|
210 | 1350 |
_body[_bodyCount++] = element; |
211 |
} |
|
212 |
|
|
213 |
/**
|
|
214 |
* Invokes {@link #finishLoad()}. Subclasses may overide as needed, but must invoke this
|
|
215 |
* implementation. {@link BaseComponent}loads its HTML template.
|
|
216 |
*/
|
|
217 |
|
|
218 | 1151 |
public void finishLoad(IRequestCycle cycle, IPageLoader loader, |
219 |
IComponentSpecification specification) |
|
220 |
{ |
|
221 | 1151 |
finishLoad(); |
222 |
} |
|
223 |
|
|
224 |
/**
|
|
225 |
* Converts informal parameters into additional attributes on the curently open tag.
|
|
226 |
* <p>
|
|
227 |
* Invoked from subclasses to allow additional attributes to be specified within a tag (this
|
|
228 |
* works best when there is a one-to-one corespondence between an {@link IComponent}and a HTML
|
|
229 |
* element.
|
|
230 |
* <p>
|
|
231 |
* Iterates through the bindings for this component. Filters out bindings for formal parameters.
|
|
232 |
* <p>
|
|
233 |
* For each acceptible key, the value is extracted using {@link IBinding#getObject()}. If the
|
|
234 |
* value is null, no attribute is written.
|
|
235 |
* <p>
|
|
236 |
* If the value is an instance of {@link IAsset}, then {@link IAsset#buildURL(IRequestCycle)}
|
|
237 |
* is invoked to convert the asset to a URL.
|
|
238 |
* <p>
|
|
239 |
* Finally, {@link IMarkupWriter#attribute(String,String)}is invoked with the value (or the
|
|
240 |
* URL).
|
|
241 |
* <p>
|
|
242 |
* The most common use for informal parameters is to support the HTML class attribute (for use
|
|
243 |
* with cascading style sheets) and to specify JavaScript event handlers.
|
|
244 |
* <p>
|
|
245 |
* Components are only required to generate attributes on the result phase; this can be skipped
|
|
246 |
* during the rewind phase.
|
|
247 |
*/
|
|
248 |
|
|
249 | 1772 |
protected void renderInformalParameters(IMarkupWriter writer, IRequestCycle cycle) |
250 |
{ |
|
251 | 1772 |
String attribute; |
252 |
|
|
253 | 1772 |
if (_bindings == null) |
254 | 98 |
return;
|
255 |
|
|
256 | 1674 |
Iterator i = _bindings.entrySet().iterator(); |
257 |
|
|
258 | 1674 |
while (i.hasNext())
|
259 |
{ |
|
260 | 4765 |
Map.Entry entry = (Map.Entry) i.next(); |
261 | 4765 |
String name = (String) entry.getKey(); |
262 |
|
|
263 | 4765 |
if (isFormalParameter(name))
|
264 | 4676 |
continue;
|
265 |
|
|
266 | 89 |
IBinding binding = (IBinding) entry.getValue(); |
267 |
|
|
268 | 89 |
Object value = binding.getObject(); |
269 | 89 |
if (value == null) |
270 | 0 |
continue;
|
271 |
|
|
272 | 89 |
if (value instanceof IAsset) |
273 |
{ |
|
274 | 0 |
IAsset asset = (IAsset) value; |
275 |
|
|
276 |
// Get the URL of the asset and insert that.
|
|
277 |
|
|
278 | 0 |
attribute = asset.buildURL(cycle); |
279 |
} |
|
280 |
else
|
|
281 | 89 |
attribute = value.toString(); |
282 |
|
|
283 | 89 |
writer.attribute(name, attribute); |
284 |
} |
|
285 |
|
|
286 |
} |
|
287 |
|
|
288 |
/** @since 4.0 */
|
|
289 | 4765 |
private boolean isFormalParameter(String name) |
290 |
{ |
|
291 | 4765 |
Defense.notNull(name, "name");
|
292 |
|
|
293 | 4765 |
return getSpecification().getParameter(name) != null; |
294 |
} |
|
295 |
|
|
296 |
/**
|
|
297 |
* Returns the named binding, or null if it doesn't exist.
|
|
298 |
* <p>
|
|
299 |
* In Tapestry 3.0, it was possible to force a binding to be stored in a component property by
|
|
300 |
* defining a concrete or abstract property named "nameBinding" of type {@link IBinding}. This
|
|
301 |
* has been removed in release 4.0 and bindings are always stored inside a Map of the component.
|
|
302 |
*
|
|
303 |
* @see #setBinding(String,IBinding)
|
|
304 |
*/
|
|
305 |
|
|
306 | 21921 |
public IBinding getBinding(String name)
|
307 |
{ |
|
308 | 21921 |
Defense.notNull(name, "name");
|
309 |
|
|
310 | 21921 |
if (_bindings == null) |
311 | 748 |
return null; |
312 |
|
|
313 | 21173 |
return (IBinding) _bindings.get(name);
|
314 |
} |
|
315 |
|
|
316 |
/**
|
|
317 |
* Returns true if the specified parameter is bound.
|
|
318 |
*
|
|
319 |
* @since 4.0
|
|
320 |
*/
|
|
321 |
|
|
322 | 190 |
public boolean isParameterBound(String parameterName) |
323 |
{ |
|
324 | 190 |
Defense.notNull(parameterName, "parameterName");
|
325 |
|
|
326 | 190 |
return _bindings != null && _bindings.containsKey(parameterName); |
327 |
} |
|
328 |
|
|
329 | 776 |
public IComponent getComponent(String id)
|
330 |
{ |
|
331 | 776 |
Defense.notNull(id, "id");
|
332 |
|
|
333 | 776 |
IComponent result = null;
|
334 |
|
|
335 | 776 |
if (_components != null) |
336 | 776 |
result = (IComponent) _components.get(id); |
337 |
|
|
338 | 776 |
if (result == null) |
339 | 0 |
throw new ApplicationRuntimeException(Tapestry.format("no-such-component", this, id), |
340 |
this, null, null); |
|
341 |
|
|
342 | 776 |
return result;
|
343 |
} |
|
344 |
|
|
345 | 34 |
public IComponent getContainer()
|
346 |
{ |
|
347 | 34 |
return _container;
|
348 |
} |
|
349 |
|
|
350 | 1027 |
public void setContainer(IComponent value) |
351 |
{ |
|
352 | 1027 |
checkActiveLock(); |
353 |
|
|
354 | 1027 |
if (_container != null) |
355 | 0 |
throw new ApplicationRuntimeException(Tapestry |
356 |
.getMessage("AbstractComponent.attempt-to-change-container"));
|
|
357 |
|
|
358 | 1027 |
_container = value; |
359 |
} |
|
360 |
|
|
361 |
/**
|
|
362 |
* Returns the name of the page, a slash, and this component's id path. Pages are different,
|
|
363 |
* they override this method to simply return their page name.
|
|
364 |
*
|
|
365 |
* @see #getIdPath()
|
|
366 |
*/
|
|
367 |
|
|
368 | 196 |
public String getExtendedId()
|
369 |
{ |
|
370 | 196 |
if (_page == null) |
371 | 37 |
return null; |
372 |
|
|
373 | 159 |
return _page.getPageName() + "/" + getIdPath(); |
374 |
} |
|
375 |
|
|
376 | 1192 |
public String getId()
|
377 |
{ |
|
378 | 1192 |
return _id;
|
379 |
} |
|
380 |
|
|
381 | 1027 |
public void setId(String value) |
382 |
{ |
|
383 | 1027 |
if (_id != null) |
384 | 0 |
throw new ApplicationRuntimeException(Tapestry |
385 |
.getMessage("AbstractComponent.attempt-to-change-component-id"));
|
|
386 |
|
|
387 | 1027 |
_id = value; |
388 |
} |
|
389 |
|
|
390 | 283 |
public String getIdPath()
|
391 |
{ |
|
392 | 283 |
String containerIdPath; |
393 |
|
|
394 | 283 |
if (_container == null) |
395 | 0 |
throw new NullPointerException(Tapestry |
396 |
.format("AbstractComponent.null-container", this)); |
|
397 |
|
|
398 | 283 |
containerIdPath = _container.getIdPath(); |
399 |
|
|
400 | 283 |
if (containerIdPath == null) |
401 | 275 |
_idPath = _id; |
402 |
else
|
|
403 | 8 |
_idPath = containerIdPath + "." + _id;
|
404 |
|
|
405 | 283 |
return _idPath;
|
406 |
} |
|
407 |
|
|
408 | 1470 |
public IPage getPage()
|
409 |
{ |
|
410 | 1470 |
return _page;
|
411 |
} |
|
412 |
|
|
413 | 1181 |
public void setPage(IPage value) |
414 |
{ |
|
415 | 1181 |
if (_page != null) |
416 | 0 |
throw new ApplicationRuntimeException(Tapestry |
417 |
.getMessage("AbstractComponent.attempt-to-change-page"));
|
|
418 |
|
|
419 | 1181 |
_page = value; |
420 |
} |
|
421 |
|
|
422 |
/**
|
|
423 |
* Renders all elements wrapped by the receiver.
|
|
424 |
*/
|
|
425 |
|
|
426 | 2000 |
public void renderBody(IMarkupWriter writer, IRequestCycle cycle) |
427 |
{ |
|
428 | 2000 |
for (int i = 0; i < _bodyCount; i++) |
429 | 5337 |
_body[i].render(writer, cycle); |
430 |
} |
|
431 |
|
|
432 |
/**
|
|
433 |
* Adds the binding with the given name, replacing any existing binding with that name.
|
|
434 |
* <p>
|
|
435 |
*
|
|
436 |
* @see #getBinding(String)
|
|
437 |
*/
|
|
438 |
|
|
439 | 1637 |
public void setBinding(String name, IBinding binding) |
440 |
{ |
|
441 | 1637 |
Defense.notNull(name, "name");
|
442 | 1637 |
Defense.notNull(binding, "binding");
|
443 |
|
|
444 | 1637 |
if (_bindings == null) |
445 | 903 |
_bindings = new HashMap(MAP_SIZE);
|
446 |
|
|
447 | 1637 |
_bindings.put(name, binding); |
448 |
} |
|
449 |
|
|
450 | 86 |
public String toString()
|
451 |
{ |
|
452 | 86 |
StringBuffer buffer; |
453 |
|
|
454 | 86 |
buffer = new StringBuffer(super.toString()); |
455 |
|
|
456 | 86 |
buffer.append('['); |
457 |
|
|
458 | 86 |
buffer.append(getExtendedId()); |
459 |
|
|
460 | 86 |
buffer.append(']'); |
461 |
|
|
462 | 86 |
return buffer.toString();
|
463 |
} |
|
464 |
|
|
465 |
/**
|
|
466 |
* Returns an unmodifiable {@link Map}of components, keyed on component id. Never returns null,
|
|
467 |
* but may return an empty map. The returned map is immutable.
|
|
468 |
*/
|
|
469 |
|
|
470 | 2523 |
public Map getComponents()
|
471 |
{ |
|
472 | 2523 |
if (_components == null) |
473 | 1859 |
return EMPTY_MAP;
|
474 |
|
|
475 | 664 |
return Collections.unmodifiableMap(_components);
|
476 |
|
|
477 |
} |
|
478 |
|
|
479 | 32 |
public Map getAssets()
|
480 |
{ |
|
481 | 32 |
if (_assets == null) |
482 | 0 |
return EMPTY_MAP;
|
483 |
|
|
484 | 32 |
return Collections.unmodifiableMap(_assets);
|
485 |
} |
|
486 |
|
|
487 | 211 |
public IAsset getAsset(String name)
|
488 |
{ |
|
489 | 211 |
if (_assets == null) |
490 | 151 |
return null; |
491 |
|
|
492 | 60 |
return (IAsset) _assets.get(name);
|
493 |
} |
|
494 |
|
|
495 | 1 |
public Collection getBindingNames()
|
496 |
{ |
|
497 |
// If no conainer, i.e. a page, then no bindings.
|
|
498 |
|
|
499 | 1 |
if (_container == null) |
500 | 0 |
return null; |
501 |
|
|
502 | 1 |
HashSet result = new HashSet();
|
503 |
|
|
504 |
// All the informal bindings go into the bindings Map.
|
|
505 |
|
|
506 | 1 |
if (_bindings != null) |
507 | 1 |
result.addAll(_bindings.keySet()); |
508 |
|
|
509 |
// Now, iterate over the formal parameters and add the formal parameters
|
|
510 |
// that have a binding.
|
|
511 |
|
|
512 | 1 |
List names = getSpecification().getParameterNames(); |
513 |
|
|
514 | 1 |
int count = names.size();
|
515 |
|
|
516 | 1 |
for (int i = 0; i < count; i++) |
517 |
{ |
|
518 | 1 |
String name = (String) names.get(i); |
519 |
|
|
520 | 1 |
if (result.contains(name))
|
521 | 1 |
continue;
|
522 |
|
|
523 | 0 |
if (getBinding(name) != null) |
524 | 0 |
result.add(name); |
525 |
} |
|
526 |
|
|
527 | 1 |
return result;
|
528 |
} |
|
529 |
|
|
530 |
/**
|
|
531 |
* Returns an unmodifiable {@link Map}of all bindings for this component.
|
|
532 |
*
|
|
533 |
* @since 1.0.5
|
|
534 |
*/
|
|
535 |
|
|
536 | 3 |
public Map getBindings()
|
537 |
{ |
|
538 | 3 |
if (_bindings == null) |
539 | 0 |
return Collections.EMPTY_MAP;
|
540 |
|
|
541 | 3 |
return Collections.unmodifiableMap(_bindings);
|
542 |
} |
|
543 |
|
|
544 |
/**
|
|
545 |
* Returns a {@link ListenerMap} for the component. A ListenerMap contains a number of
|
|
546 |
* synthetic read-only properties that implement the {@link IActionListener}interface, but in
|
|
547 |
* fact, cause public instance methods to be invoked.
|
|
548 |
*
|
|
549 |
* @since 1.0.2
|
|
550 |
*/
|
|
551 |
|
|
552 | 34 |
public ListenerMap getListeners()
|
553 |
{ |
|
554 |
// This is what's called a violation of the Law of Demeter!
|
|
555 |
// This should probably be converted over to some kind of injection, as with
|
|
556 |
// getMessages(), etc.
|
|
557 |
|
|
558 | 34 |
if (_listeners == null) |
559 | 28 |
_listeners = getPage().getEngine().getInfrastructure().getListenerMapSource() |
560 |
.getListenerMapForObject(this);
|
|
561 |
|
|
562 | 34 |
return _listeners;
|
563 |
} |
|
564 |
|
|
565 |
/**
|
|
566 |
* Returns the {@link IBeanProvider}for this component. This is lazily created the first time
|
|
567 |
* it is needed.
|
|
568 |
*
|
|
569 |
* @since 1.0.4
|
|
570 |
*/
|
|
571 |
|
|
572 | 142 |
public IBeanProvider getBeans()
|
573 |
{ |
|
574 | 142 |
if (_beans == null) |
575 | 55 |
_beans = new BeanProvider(this); |
576 |
|
|
577 | 142 |
return _beans;
|
578 |
} |
|
579 |
|
|
580 |
/**
|
|
581 |
* Invoked, as a convienience, from
|
|
582 |
* {@link #finishLoad(IRequestCycle, IPageLoader, IComponentSpecification)}. This implemenation
|
|
583 |
* does nothing. Subclasses may override without invoking this implementation.
|
|
584 |
*
|
|
585 |
* @since 1.0.5
|
|
586 |
*/
|
|
587 |
|
|
588 | 1002 |
protected void finishLoad() |
589 |
{ |
|
590 |
} |
|
591 |
|
|
592 |
/**
|
|
593 |
* The main method used to render the component. Invokes
|
|
594 |
* {@link #prepareForRender(IRequestCycle)}, then
|
|
595 |
* {@link #renderComponent(IMarkupWriter, IRequestCycle)}.
|
|
596 |
* {@link #cleanupAfterRender(IRequestCycle)}is invoked in a <code>finally</code> block.
|
|
597 |
* <p>
|
|
598 |
* Subclasses should not override this method; instead they will implement
|
|
599 |
* {@link #renderComponent(IMarkupWriter, IRequestCycle)}.
|
|
600 |
*
|
|
601 |
* @since 2.0.3
|
|
602 |
*/
|
|
603 |
|
|
604 | 2941 |
public final void render(IMarkupWriter writer, IRequestCycle cycle) |
605 |
{ |
|
606 | 2941 |
try
|
607 |
{ |
|
608 | 2941 |
_rendering = true;
|
609 |
|
|
610 | 2941 |
prepareForRender(cycle); |
611 |
|
|
612 | 2941 |
renderComponent(writer, cycle); |
613 |
} |
|
614 |
finally
|
|
615 |
{ |
|
616 | 2941 |
_rendering = false;
|
617 |
|
|
618 | 2941 |
cleanupAfterRender(cycle); |
619 |
} |
|
620 |
} |
|
621 |
|
|
622 |
/**
|
|
623 |
* Invoked by {@link #render(IMarkupWriter, IRequestCycle)}to prepare the component to render.
|
|
624 |
* This implementation sets JavaBeans properties from matching bound parameters. This
|
|
625 |
* implementation does nothing.
|
|
626 |
*
|
|
627 |
* @since 2.0.3
|
|
628 |
*/
|
|
629 |
|
|
630 | 2853 |
protected void prepareForRender(IRequestCycle cycle) |
631 |
{ |
|
632 |
} |
|
633 |
|
|
634 |
/**
|
|
635 |
* Invoked by {@link #render(IMarkupWriter, IRequestCycle)}to actually render the component
|
|
636 |
* (with any parameter values already set). This is the method that subclasses must implement.
|
|
637 |
*
|
|
638 |
* @since 2.0.3
|
|
639 |
*/
|
|
640 |
|
|
641 |
protected abstract void renderComponent(IMarkupWriter writer, IRequestCycle cycle); |
|
642 |
|
|
643 |
/**
|
|
644 |
* Invoked by {@link #render(IMarkupWriter, IRequestCycle)}after the component renders. This
|
|
645 |
* implementation does nothing.
|
|
646 |
*
|
|
647 |
* @since 2.0.3
|
|
648 |
*/
|
|
649 |
|
|
650 | 2853 |
protected void cleanupAfterRender(IRequestCycle cycle) |
651 |
{ |
|
652 |
} |
|
653 |
|
|
654 | 1495 |
public INamespace getNamespace()
|
655 |
{ |
|
656 | 1495 |
return _namespace;
|
657 |
} |
|
658 |
|
|
659 | 1178 |
public void setNamespace(INamespace namespace) |
660 |
{ |
|
661 | 1178 |
_namespace = namespace; |
662 |
} |
|
663 |
|
|
664 |
/**
|
|
665 |
* Returns the body of the component, the element (which may be static HTML or components) that
|
|
666 |
* the component immediately wraps. May return null. Do not modify the returned array. The array
|
|
667 |
* may be padded with nulls.
|
|
668 |
*
|
|
669 |
* @since 2.3
|
|
670 |
* @see #getBodyCount()
|
|
671 |
*/
|
|
672 |
|
|
673 | 0 |
public IRender[] getBody()
|
674 |
{ |
|
675 | 0 |
return _body;
|
676 |
} |
|
677 |
|
|
678 |
/**
|
|
679 |
* Returns the active number of elements in the the body, which may be zero.
|
|
680 |
*
|
|
681 |
* @since 2.3
|
|
682 |
* @see #getBody()
|
|
683 |
*/
|
|
684 |
|
|
685 | 0 |
public int getBodyCount() |
686 |
{ |
|
687 | 0 |
return _bodyCount;
|
688 |
} |
|
689 |
|
|
690 |
/**
|
|
691 |
* Empty implementation of
|
|
692 |
* {@link org.apache.tapestry.event.PageRenderListener#pageEndRender(PageEvent)}. This allows
|
|
693 |
* classes to implement {@link org.apache.tapestry.event.PageRenderListener}and only implement
|
|
694 |
* the {@link org.apache.tapestry.event.PageRenderListener#pageBeginRender(PageEvent)}method.
|
|
695 |
*
|
|
696 |
* @since 3.0
|
|
697 |
*/
|
|
698 |
|
|
699 | 0 |
public void pageEndRender(PageEvent event) |
700 |
{ |
|
701 |
} |
|
702 |
|
|
703 |
/**
|
|
704 |
* Sets a property of a component.
|
|
705 |
*
|
|
706 |
* @see IComponent
|
|
707 |
* @since 3.0
|
|
708 |
*/
|
|
709 | 28 |
public void setProperty(String propertyName, Object value) |
710 |
{ |
|
711 | 28 |
PropertyUtils.write(this, propertyName, value);
|
712 |
} |
|
713 |
|
|
714 |
/**
|
|
715 |
* Gets a property of a component.
|
|
716 |
*
|
|
717 |
* @see IComponent
|
|
718 |
* @since 3.0
|
|
719 |
*/
|
|
720 | 2 |
public Object getProperty(String propertyName)
|
721 |
{ |
|
722 | 2 |
return PropertyUtils.read(this, propertyName); |
723 |
} |
|
724 |
|
|
725 |
/**
|
|
726 |
* @since 4.0
|
|
727 |
*/
|
|
728 |
|
|
729 | 4430 |
public boolean isRendering() |
730 |
{ |
|
731 | 4430 |
return _rendering;
|
732 |
} |
|
733 |
|
|
734 |
/**
|
|
735 |
* Returns true if the component has been transitioned into its active state by invoking
|
|
736 |
* {@link #enterActiveState()}
|
|
737 |
*
|
|
738 |
* @since 4.0
|
|
739 |
*/
|
|
740 |
|
|
741 | 1567 |
protected boolean isInActiveState() |
742 |
{ |
|
743 | 1567 |
return _active;
|
744 |
} |
|
745 |
|
|
746 |
/** @since 4.0 */
|
|
747 | 1151 |
public void enterActiveState() |
748 |
{ |
|
749 | 1151 |
_active = true;
|
750 |
} |
|
751 |
|
|
752 |
/** @since 4.0 */
|
|
753 |
|
|
754 | 2111 |
protected void checkActiveLock() |
755 |
{ |
|
756 | 2111 |
if (_active)
|
757 | 0 |
throw new UnsupportedOperationException(TapestryMessages.componentIsLocked(this)); |
758 |
} |
|
759 |
|
|
760 | 1 |
public Messages getMessages()
|
761 |
{ |
|
762 | 1 |
throw new IllegalStateException(TapestryMessages.providedByEnhancement("getMessages")); |
763 |
} |
|
764 |
|
|
765 | 1 |
public IComponentSpecification getSpecification()
|
766 |
{ |
|
767 | 1 |
throw new IllegalStateException(TapestryMessages.providedByEnhancement("getSpecification")); |
768 |
} |
|
769 |
} |
|