KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tapestry > spec > ComponentSpecification


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.spec;
16
17 import java.util.ArrayList JavaDoc;
18 import java.util.Collection JavaDoc;
19 import java.util.Collections JavaDoc;
20 import java.util.HashMap JavaDoc;
21 import java.util.HashSet JavaDoc;
22 import java.util.Iterator JavaDoc;
23 import java.util.List JavaDoc;
24 import java.util.Map JavaDoc;
25 import java.util.Set JavaDoc;
26
27 import org.apache.hivemind.ApplicationRuntimeException;
28 import org.apache.hivemind.HiveMind;
29 import org.apache.hivemind.Resource;
30 import org.apache.hivemind.util.ToStringBuilder;
31
32 /**
33  * A specification for a component, as read from an XML specification file.
34  * <p>
35  * A specification consists of
36  * <ul>
37  * <li>An implementing class
38  * <li>An optional description
39  * <li>A set of contained components
40  * <li>Bindings for the properties of each contained component
41  * <li>A set of named assets
42  * <li>Definitions for managed beans
43  * <li>Any reserved names (used for HTML attributes)
44  * <li>Declared properties
45  * <li>Property injections
46  * </ul>
47  * <p>
48  * From this information, an actual component may be instantiated and initialized. Instantiating a
49  * component is usually a recursive process, since to initialize a container component, it is
50  * necessary to instantiate and initialize its contained components as well.
51  *
52  * @see org.apache.tapestry.IComponent
53  * @see IContainedComponent
54  * @see org.apache.tapestry.engine.IPageLoader
55  * @author Howard Lewis Ship
56  */

57
58 public class ComponentSpecification extends LocatablePropertyHolder implements
59         IComponentSpecification
60 {
61     private String JavaDoc _componentClassName;
62
63     /** @since 1.0.9 * */
64
65     private String JavaDoc _description;
66
67     /**
68      * Keyed on component id, value is {@link IContainedComponent}.
69      */

70
71     protected Map JavaDoc _components;
72
73     /**
74      * Keyed on asset name, value is {@link IAssetSpecification}.
75      */

76
77     protected Map JavaDoc _assets;
78
79     /**
80      * Defines all formal parameters. Keyed on parameter name, value is
81      * {@link IParameterSpecification}.
82      */

83
84     protected Map JavaDoc _parameters;
85
86     /**
87      * Defines all helper beans. Keyed on name, value is {@link IBeanSpecification}.
88      *
89      * @since 1.0.4
90      */

91
92     protected Map JavaDoc _beans;
93
94     /**
95      * The names of all reserved informal parameter names (as lower-case). This allows the page
96      * loader to filter out any informal parameters during page load, rather than during render.
97      *
98      * @since 1.0.5
99      */

100
101     protected Set JavaDoc _reservedParameterNames;
102
103     /**
104      * Is the component allowed to have a body (that is, wrap other elements?).
105      */

106
107     private boolean _allowBody = true;
108
109     /**
110      * Is the component allow to have informal parameter specified.
111      */

112
113     private boolean _allowInformalParameters = true;
114
115     /**
116      * The XML Public Id used when the page or component specification was read (if applicable).
117      *
118      * @since 2.2
119      */

120
121     private String JavaDoc _publicId;
122
123     /**
124      * Indicates that the specification is for a page, not a component.
125      *
126      * @since 2.2
127      */

128
129     private boolean _pageSpecification;
130
131     /**
132      * The location from which the specification was obtained.
133      *
134      * @since 3.0
135      */

136
137     private Resource _specificationLocation;
138
139     /**
140      * A Map of {@link IPropertySpecification}keyed on the name of the property.
141      *
142      * @since 3.0
143      */

144
145     private Map JavaDoc _propertySpecifications;
146
147     /**
148      * List of {@link InjectSpecification}.
149      *
150      * @since 4.0
151      */

152
153     private List JavaDoc _injectSpecifications;
154
155     /**
156      * Keyed on property name, value is some other object (such as an IAssetSpecification) that has
157      * claimed a property of the page.
158      *
159      * @since 4.0
160      */

161
162     private Map JavaDoc _claimedProperties;
163
164     /**
165      * @since 4.0
166      */

167
168     private boolean _deprecated = false;
169
170     /**
171      * @throws ApplicationRuntimeException
172      * if the name already exists.
173      */

174
175     public void addAsset(String JavaDoc name, IAssetSpecification asset)
176     {
177         if (_assets == null)
178             _assets = new HashMap JavaDoc();
179
180         IAssetSpecification existing = (IAssetSpecification) _assets.get(name);
181
182         if (existing != null)
183             throw new ApplicationRuntimeException(SpecMessages.duplicateAsset(name, existing),
184                     asset.getLocation(), null);
185
186         claimProperty(asset.getPropertyName(), asset);
187
188         _assets.put(name, asset);
189
190     }
191
192     /**
193      * @throws ApplicationRuntimeException
194      * if the id is already defined.
195      */

196
197     public void addComponent(String JavaDoc id, IContainedComponent component)
198     {
199         if (_components == null)
200             _components = new HashMap JavaDoc();
201
202         IContainedComponent existing = (IContainedComponent) _components.get(id);
203
204         if (existing != null)
205             throw new ApplicationRuntimeException(SpecMessages.duplicateComponent(id, existing),
206                     component.getLocation(), null);
207
208         _components.put(id, component);
209
210         claimProperty(component.getPropertyName(), component);
211     }
212
213     /**
214      * Adds the parameter. The name is added as a reserved name.
215      *
216      * @throws ApplicationRuntimeException
217      * if the name already exists.
218      */

219
220     public void addParameter(IParameterSpecification spec)
221     {
222         if (_parameters == null)
223             _parameters = new HashMap JavaDoc();
224
225         String JavaDoc name = spec.getParameterName();
226
227         addParameterByName(name, spec);
228
229         Iterator JavaDoc i = spec.getAliasNames().iterator();
230         while (i.hasNext())
231         {
232             String JavaDoc alias = (String JavaDoc) i.next();
233
234             addParameterByName(alias, spec);
235         }
236
237         claimProperty(spec.getPropertyName(), spec);
238     }
239
240     private void addParameterByName(String JavaDoc name, IParameterSpecification spec)
241     {
242         IParameterSpecification existing = (IParameterSpecification) _parameters.get(name);
243
244         if (existing != null)
245             throw new ApplicationRuntimeException(SpecMessages.duplicateParameter(name, existing),
246                     spec.getLocation(), null);
247
248         _parameters.put(name, spec);
249
250         addReservedParameterName(name);
251     }
252
253     /**
254      * Returns true if the component is allowed to wrap other elements (static HTML or other
255      * components). The default is true.
256      *
257      * @see #setAllowBody(boolean)
258      */

259
260     public boolean getAllowBody()
261     {
262         return _allowBody;
263     }
264
265     /**
266      * Returns true if the component allows informal parameters (parameters not formally defined).
267      * Informal parameters are generally used to create additional HTML attributes for an HTML tag
268      * rendered by the component. This is often used to specify JavaScript event handlers or the
269      * class of the component (for Cascarding Style Sheets).
270      * <p>
271      * The default value is true.
272      *
273      * @see #setAllowInformalParameters(boolean)
274      */

275
276     public boolean getAllowInformalParameters()
277     {
278         return _allowInformalParameters;
279     }
280
281     /**
282      * Returns the {@link IAssetSpecification}with the given name, or null if no such specification
283      * exists.
284      *
285      * @see #addAsset(String,IAssetSpecification)
286      */

287
288     public IAssetSpecification getAsset(String JavaDoc name)
289     {
290
291         return (IAssetSpecification) get(_assets, name);
292     }
293
294     /**
295      * Returns a <code>List</code> of the String names of all assets, in alphabetical order
296      */

297
298     public List JavaDoc getAssetNames()
299     {
300         return sortedKeys(_assets);
301     }
302
303     /**
304      * Returns the specification of a contained component with the given id, or null if no such
305      * contained component exists.
306      *
307      * @see #addComponent(String, IContainedComponent)
308      */

309
310     public IContainedComponent getComponent(String JavaDoc id)
311     {
312         return (IContainedComponent) get(_components, id);
313     }
314
315     public String JavaDoc getComponentClassName()
316     {
317         return _componentClassName;
318     }
319
320     /**
321      * Returns an <code>List</code> of the String names of the {@link IContainedComponent}s for
322      * this component.
323      *
324      * @see #addComponent(String, IContainedComponent)
325      */

326
327     public List JavaDoc getComponentIds()
328     {
329         return sortedKeys(_components);
330     }
331
332     /**
333      * Returns the specification of a parameter with the given name, or null if no such parameter
334      * exists.
335      *
336      * @see #addParameter(String, IParameterSpecification)
337      */

338
339     public IParameterSpecification getParameter(String JavaDoc name)
340     {
341         return (IParameterSpecification) get(_parameters, name);
342     }
343
344     public Collection JavaDoc getRequiredParameters()
345     {
346         if (_parameters == null)
347             return Collections.EMPTY_LIST;
348
349         Collection JavaDoc result = new ArrayList JavaDoc();
350
351         Iterator JavaDoc i = _parameters.entrySet().iterator();
352         while (i.hasNext())
353         {
354             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) i.next();
355             String JavaDoc name = (String JavaDoc) entry.getKey();
356             IParameterSpecification spec = (IParameterSpecification) entry.getValue();
357
358             if (!spec.isRequired())
359                 continue;
360
361             if (!name.equals(spec.getParameterName()))
362                 continue;
363
364             result.add(spec);
365         }
366
367         return result;
368     }
369
370     /**
371      * Returns a List of of String names of all parameters. This list is in alphabetical order.
372      *
373      * @see #addParameter(String, IParameterSpecification)
374      */

375
376     public List JavaDoc getParameterNames()
377     {
378         return sortedKeys(_parameters);
379     }
380
381     public void setAllowBody(boolean value)
382     {
383         _allowBody = value;
384     }
385
386     public void setAllowInformalParameters(boolean value)
387     {
388         _allowInformalParameters = value;
389     }
390
391     public void setComponentClassName(String JavaDoc value)
392     {
393         _componentClassName = value;
394     }
395
396     /**
397      * @since 1.0.4
398      * @throws ApplicationRuntimeException
399      * if the bean already has a specification.
400      */

401
402     public void addBeanSpecification(String JavaDoc name, IBeanSpecification specification)
403     {
404         if (_beans == null)
405             _beans = new HashMap JavaDoc();
406
407         IBeanSpecification existing = (IBeanSpecification) _beans.get(name);
408
409         if (existing != null)
410             throw new ApplicationRuntimeException(SpecMessages.duplicateBean(name, existing),
411                     specification.getLocation(), null);
412
413         claimProperty(specification.getPropertyName(), specification);
414
415         _beans.put(name, specification);
416     }
417
418     /**
419      * Returns the {@link IBeanSpecification}for the given name, or null if not such specification
420      * exists.
421      *
422      * @since 1.0.4
423      */

424
425     public IBeanSpecification getBeanSpecification(String JavaDoc name)
426     {
427         return (IBeanSpecification) get(_beans, name);
428     }
429
430     /**
431      * Returns an unmodifiable collection of the names of all beans.
432      */

433
434     public Collection JavaDoc getBeanNames()
435     {
436         if (_beans == null)
437             return Collections.EMPTY_LIST;
438
439         return Collections.unmodifiableCollection(_beans.keySet());
440     }
441
442     /**
443      * Adds the value as a reserved name. Reserved names are not allowed as the names of informal
444      * parameters. Since the comparison is caseless, the value is converted to lowercase before
445      * being stored.
446      *
447      * @since 1.0.5
448      */

449
450     public void addReservedParameterName(String JavaDoc value)
451     {
452         if (_reservedParameterNames == null)
453             _reservedParameterNames = new HashSet JavaDoc();
454
455         _reservedParameterNames.add(value.toLowerCase());
456     }
457
458     /**
459      * Returns true if the value specified is in the reserved name list. The comparison is caseless.
460      * All formal parameters are automatically in the reserved name list, as well as any additional
461      * reserved names specified in the component specification. The latter refer to HTML attributes
462      * generated directly by the component.
463      *
464      * @since 1.0.5
465      */

466
467     public boolean isReservedParameterName(String JavaDoc value)
468     {
469         if (_reservedParameterNames == null)
470             return false;
471
472         return _reservedParameterNames.contains(value.toLowerCase());
473     }
474
475     public String JavaDoc toString()
476     {
477         ToStringBuilder builder = new ToStringBuilder(this);
478
479         builder.append("componentClassName", _componentClassName);
480         builder.append("pageSpecification", _pageSpecification);
481         builder.append("specificationLocation", _specificationLocation);
482         builder.append("allowBody", _allowBody);
483         builder.append("allowInformalParameter", _allowInformalParameters);
484
485         return builder.toString();
486     }
487
488     /**
489      * Returns the documentation for this component.
490      *
491      * @since 1.0.9
492      */

493
494     public String JavaDoc getDescription()
495     {
496         return _description;
497     }
498
499     /**
500      * Sets the documentation for this component.
501      *
502      * @since 1.0.9
503      */

504
505     public void setDescription(String JavaDoc description)
506     {
507         _description = description;
508     }
509
510     /**
511      * Returns the XML Public Id for the specification file, or null if not applicable.
512      * <p>
513      * This method exists as a convienience for the Spindle plugin. A previous method used an
514      * arbitrary version string, the public id is more useful and less ambiguous.
515      *
516      * @since 2.2
517      */

518
519     public String JavaDoc getPublicId()
520     {
521         return _publicId;
522     }
523
524     /** @since 2.2 * */
525
526     public void setPublicId(String JavaDoc publicId)
527     {
528         _publicId = publicId;
529     }
530
531     /**
532      * Returns true if the specification is known to be a page specification and not a component
533      * specification. Earlier versions of the framework did not distinguish between the two, but
534      * starting in 2.2, there are seperate XML entities for pages and components. Pages omit several
535      * attributes and entities related to parameters, as parameters only make sense for components.
536      *
537      * @since 2.2
538      */

539
540     public boolean isPageSpecification()
541     {
542         return _pageSpecification;
543     }
544
545     /** @since 2.2 * */
546
547     public void setPageSpecification(boolean pageSpecification)
548     {
549         _pageSpecification = pageSpecification;
550     }
551
552     /** @since 2.2 * */
553
554     private List JavaDoc sortedKeys(Map JavaDoc input)
555     {
556         if (input == null)
557             return Collections.EMPTY_LIST;
558
559         List JavaDoc result = new ArrayList JavaDoc(input.keySet());
560
561         Collections.sort(result);
562
563         return result;
564     }
565
566     /** @since 2.2 * */
567
568     private Object JavaDoc get(Map JavaDoc map, Object JavaDoc key)
569     {
570         if (map == null)
571             return null;
572
573         return map.get(key);
574     }
575
576     /** @since 3.0 * */
577
578     public Resource getSpecificationLocation()
579     {
580         return _specificationLocation;
581     }
582
583     /** @since 3.0 * */
584
585     public void setSpecificationLocation(Resource specificationLocation)
586     {
587         _specificationLocation = specificationLocation;
588     }
589
590     /**
591      * Adds a new property specification. The name of the property must not already be defined (and
592      * must not change after being added).
593      *
594      * @since 3.0
595      */

596
597     public void addPropertySpecification(IPropertySpecification spec)
598     {
599         if (_propertySpecifications == null)
600             _propertySpecifications = new HashMap JavaDoc();
601
602         String JavaDoc name = spec.getName();
603         IPropertySpecification existing = (IPropertySpecification) _propertySpecifications
604                 .get(name);
605
606         if (existing != null)
607             throw new ApplicationRuntimeException(SpecMessages.duplicateProperty(name, existing),
608                     spec.getLocation(), null);
609
610         claimProperty(name, spec);
611
612         _propertySpecifications.put(name, spec);
613     }
614
615     /**
616      * Returns a sorted, immutable list of the names of all
617      * {@link org.apache.tapestry.spec.IPropertySpecification}s.
618      *
619      * @since 3.0
620      */

621
622     public List JavaDoc getPropertySpecificationNames()
623     {
624         return sortedKeys(_propertySpecifications);
625     }
626
627     /**
628      * Returns the named {@link org.apache.tapestry.spec.IPropertySpecification}, or null if no
629      * such specification exist.
630      *
631      * @since 3.0
632      * @see #addPropertySpecification(IPropertySpecification)
633      */

634
635     public IPropertySpecification getPropertySpecification(String JavaDoc name)
636     {
637         return (IPropertySpecification) get(_propertySpecifications, name);
638     }
639
640     public void addInjectSpecification(InjectSpecification spec)
641     {
642         if (_injectSpecifications == null)
643             _injectSpecifications = new ArrayList JavaDoc();
644
645         claimProperty(spec.getProperty(), spec);
646
647         _injectSpecifications.add(spec);
648     }
649
650     public List JavaDoc getInjectSpecifications()
651     {
652         return safeList(_injectSpecifications);
653     }
654
655     private List JavaDoc safeList(List JavaDoc input)
656     {
657         if (input == null)
658             return Collections.EMPTY_LIST;
659
660         return Collections.unmodifiableList(input);
661     }
662
663     private void claimProperty(String JavaDoc propertyName, Object JavaDoc subSpecification)
664     {
665         if (propertyName == null)
666             return;
667
668         if (_claimedProperties == null)
669             _claimedProperties = new HashMap JavaDoc();
670
671         Object JavaDoc existing = _claimedProperties.get(propertyName);
672
673         if (existing != null)
674             throw new ApplicationRuntimeException(SpecMessages.claimedProperty(
675                     propertyName,
676                     existing), HiveMind.getLocation(subSpecification), null);
677
678         _claimedProperties.put(propertyName, subSpecification);
679     }
680
681     /** @since 4.0 */
682     public boolean isDeprecated()
683     {
684         return _deprecated;
685     }
686
687     /** @since 4.0 */
688     public void setDeprecated(boolean deprecated)
689     {
690         _deprecated = deprecated;
691     }
692 }
Popular Tags