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