Coverage Report - org.apache.tapestry.spec.LibrarySpecification
 
Classes in this File Line Coverage Branch Coverage Complexity
LibrarySpecification
0%
0/110
0%
0/44
1.972
 
 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 org.apache.hivemind.ApplicationRuntimeException;
 18  
 import org.apache.hivemind.Location;
 19  
 import org.apache.hivemind.Resource;
 20  
 import org.apache.hivemind.util.ToStringBuilder;
 21  
 import org.apache.tapestry.Tapestry;
 22  
 
 23  
 import java.util.*;
 24  
 
 25  
 /**
 26  
  * Specification for a library.
 27  
  * {@link org.apache.tapestry.spec.ApplicationSpecification}is a specialized
 28  
  * kind of library.
 29  
  *
 30  
  * @author Howard Lewis Ship
 31  
  * @since 2.2bv
 32  
  */
 33  
 
 34  0
 public class LibrarySpecification extends LocatablePropertyHolder implements ILibrarySpecification
 35  
 {
 36  
 
 37  
     /**
 38  
      * Map of page name to page specification path.
 39  
      */
 40  
 
 41  
     private Map _pages;
 42  
 
 43  
     /**
 44  
      * Map of component alias to component specification path.
 45  
      */
 46  
     private Map _components;
 47  
 
 48  
     /**
 49  
      * Map of library id to library specification path.
 50  
      */
 51  
 
 52  
     private Map _libraries;
 53  
 
 54  
     private String _description;
 55  
 
 56  
     /**
 57  
      * Map of extension name to {@link IExtensionSpecification}.
 58  
      */
 59  
 
 60  
     private Map _extensions;
 61  
 
 62  
     /**
 63  
      * Map of extension name to Object for instantiated extensions.
 64  
      */
 65  
 
 66  
     private Map _instantiatedExtensions;
 67  
 
 68  
     /**
 69  
      * The XML Public Id used when the library specification was read (if
 70  
      * applicable).
 71  
      *
 72  
      * @since 2.2
 73  
      */
 74  
 
 75  
     private String _publicId;
 76  
 
 77  
     /**
 78  
      * The location of the specification.
 79  
      */
 80  
 
 81  
     private Resource _specificationLocation;
 82  
 
 83  
     public String getLibrarySpecificationPath(String id)
 84  
     {
 85  0
         return (String) get(_libraries, id);
 86  
     }
 87  
 
 88  
     /**
 89  
      * Sets the specification path for an embedded library.
 90  
      *
 91  
      * @throws IllegalArgumentException
 92  
      *             if a library with the given id already exists
 93  
      */
 94  
 
 95  
     public void setLibrarySpecificationPath(String id, String path)
 96  
     {
 97  0
         if (_libraries == null) _libraries = new HashMap();
 98  
 
 99  0
         if (_libraries.containsKey(id))
 100  0
             throw new IllegalArgumentException(Tapestry.format("LibrarySpecification.duplicate-child-namespace-id", id));
 101  
 
 102  0
         _libraries.put(id, path);
 103  0
     }
 104  
 
 105  
     public List getLibraryIds()
 106  
     {
 107  0
         return sortedKeys(_libraries);
 108  
     }
 109  
 
 110  
     public String getPageSpecificationPath(String name)
 111  
     {
 112  0
         return (String) get(_pages, name);
 113  
     }
 114  
 
 115  
     public void setPageSpecificationPath(String name, String path)
 116  
     {
 117  0
         if (_pages == null)
 118  0
             _pages = new HashMap();
 119  
 
 120  0
         if (_pages.containsKey(name))
 121  0
             throw new IllegalArgumentException(Tapestry.format("LibrarySpecification.duplicate-page-name", name));
 122  
 
 123  0
         _pages.put(name, path);
 124  0
     }
 125  
 
 126  
     public List getPageNames()
 127  
     {
 128  0
         return sortedKeys(_pages);
 129  
     }
 130  
 
 131  
     public void setComponentSpecificationPath(String alias, String path)
 132  
     {
 133  0
         if (_components == null)
 134  0
             _components = new HashMap();
 135  
 
 136  0
         if (_components.containsKey(alias))
 137  0
             throw new IllegalArgumentException(Tapestry.format("LibrarySpecification.duplicate-component-alias", alias));
 138  
 
 139  0
         _components.put(alias, path);
 140  0
     }
 141  
 
 142  
     public String getComponentSpecificationPath(String alias)
 143  
     {
 144  0
         return (String) get(_components, alias);
 145  
     }
 146  
 
 147  
     /**
 148  
      * @since 3.0
 149  
      */
 150  
 
 151  
     public List getComponentTypes()
 152  
     {
 153  0
         return sortedKeys(_components);
 154  
     }
 155  
 
 156  
     private List sortedKeys(Map map)
 157  
     {
 158  0
         if (map == null)
 159  0
             return Collections.EMPTY_LIST;
 160  
 
 161  0
         List result = new ArrayList(map.keySet());
 162  
 
 163  0
         Collections.sort(result);
 164  
 
 165  0
         return result;
 166  
     }
 167  
 
 168  
     private Object get(Map map, Object key)
 169  
     {
 170  0
         if (map == null)
 171  0
             return null;
 172  
 
 173  0
         return map.get(key);
 174  
     }
 175  
 
 176  
     /**
 177  
      * Returns the documentation for this library..
 178  
      */
 179  
 
 180  
     public String getDescription()
 181  
     {
 182  0
         return _description;
 183  
     }
 184  
 
 185  
     /**
 186  
      * Sets the documentation for this library.
 187  
      */
 188  
 
 189  
     public void setDescription(String description)
 190  
     {
 191  0
         _description = description;
 192  0
     }
 193  
 
 194  
     /**
 195  
      * Returns a Map of extensions; key is extension name, value is
 196  
      * {@link org.apache.tapestry.spec.IExtensionSpecification}. May return
 197  
      * null. The returned Map is immutable.
 198  
      */
 199  
 
 200  
     public Map getExtensionSpecifications()
 201  
     {
 202  0
         if (_extensions == null)
 203  0
             return null;
 204  
 
 205  0
         return Collections.unmodifiableMap(_extensions);
 206  
     }
 207  
 
 208  
     /**
 209  
      * Adds another extension specification.
 210  
      *
 211  
      * @throws IllegalArgumentException
 212  
      *             if an extension with the given name already exists.
 213  
      */
 214  
     public void addExtensionSpecification(String name, IExtensionSpecification extension)
 215  
     {
 216  0
         if (_extensions == null)
 217  0
             _extensions = new HashMap();
 218  
 
 219  0
         if (_extensions.containsKey(name))
 220  0
             throw new IllegalArgumentException(Tapestry.format("LibrarySpecification.duplicate-extension-name",
 221  
                                                                this, name));
 222  
 
 223  0
         _extensions.put(name, extension);
 224  0
     }
 225  
 
 226  
     /**
 227  
      * Returns a sorted List of the names of all extensions. May return the
 228  
      * empty list, but won't return null.
 229  
      */
 230  
 
 231  
     public synchronized List getExtensionNames()
 232  
     {
 233  0
         return sortedKeys(_instantiatedExtensions);
 234  
     }
 235  
 
 236  
     /**
 237  
      * Returns the named IExtensionSpecification, or null if it doesn't exist.
 238  
      */
 239  
 
 240  
     public IExtensionSpecification getExtensionSpecification(String name)
 241  
     {
 242  0
         if (_extensions == null)
 243  0
             return null;
 244  
 
 245  0
         return (IExtensionSpecification) _extensions.get(name);
 246  
     }
 247  
 
 248  
     /**
 249  
      * Returns true if this library specification has a specification for the
 250  
      * named extension.
 251  
      */
 252  
 
 253  
     public boolean checkExtension(String name)
 254  
     {
 255  0
         if (_extensions == null)
 256  0
             return false;
 257  
 
 258  0
         return _extensions.containsKey(name);
 259  
     }
 260  
 
 261  
     /**
 262  
      * Returns an instantiated extension. Extensions are created as needed and
 263  
      * cached for later use.
 264  
      *
 265  
      * @throws IllegalArgumentException
 266  
      *             if no extension specification exists for the given name.
 267  
      */
 268  
 
 269  
     public synchronized Object getExtension(String name)
 270  
     {
 271  0
         return getExtension(name, null);
 272  
     }
 273  
 
 274  
     /** @since 3.0 * */
 275  
 
 276  
     public synchronized Object getExtension(String name, Class typeConstraint)
 277  
     {
 278  0
         if (_instantiatedExtensions == null)
 279  0
             _instantiatedExtensions = new HashMap();
 280  
 
 281  0
         Object result = _instantiatedExtensions.get(name);
 282  0
         IExtensionSpecification spec = getExtensionSpecification(name);
 283  
 
 284  0
         if (spec == null)
 285  0
             throw new IllegalArgumentException(Tapestry.format("LibrarySpecification.no-such-extension", name));
 286  
 
 287  0
         if (result == null)
 288  
         {
 289  
 
 290  0
             result = spec.instantiateExtension();
 291  
 
 292  0
             _instantiatedExtensions.put(name, result);
 293  
         }
 294  
 
 295  0
         if (typeConstraint != null)
 296  0
             applyTypeConstraint(name, result, typeConstraint, spec.getLocation());
 297  
 
 298  0
         return result;
 299  
     }
 300  
 
 301  
     /**
 302  
      * Checks that an extension conforms to the supplied type constraint.
 303  
      *
 304  
      * @param name
 305  
      *          Name of the extension to apply constraint check to.
 306  
      * @param extension
 307  
      *          Object extension.
 308  
      * @param typeConstraint
 309  
      *          Constraint to check.
 310  
      * @param location
 311  
      *          Location of specified extension.
 312  
      * 
 313  
      * @throws IllegalArgumentException
 314  
      *             if the extension fails the check.
 315  
      * @since 3.0
 316  
      */
 317  
 
 318  
     protected void applyTypeConstraint(String name, Object extension,
 319  
                                        Class typeConstraint, Location location)
 320  
     {
 321  0
         Class extensionClass = extension.getClass();
 322  
 
 323  
         // Can you assign an instance of the extension to a variable
 324  
         // of type typeContraint legally?
 325  
 
 326  0
         if (typeConstraint.isAssignableFrom(extensionClass))
 327  0
             return;
 328  
 
 329  0
         String key = typeConstraint.isInterface()
 330  
                      ? "LibrarySpecification.extension-does-not-implement-interface"
 331  
                      : "LibrarySpecification.extension-not-a-subclass";
 332  
 
 333  0
         throw new ApplicationRuntimeException(
 334  
           Tapestry.format(key, name, extensionClass.getName(), typeConstraint.getName()), location, null);
 335  
     }
 336  
 
 337  
     /**
 338  
      * Invoked after the entire specification has been constructed to
 339  
      * instantiate any extensions marked immediate.
 340  
      */
 341  
 
 342  
     public synchronized void instantiateImmediateExtensions()
 343  
     {
 344  0
         if (_extensions == null)
 345  0
             return;
 346  
 
 347  0
         Iterator i = _extensions.entrySet().iterator();
 348  
 
 349  0
         while(i.hasNext())
 350  
         {
 351  0
             Map.Entry entry = (Map.Entry) i.next();
 352  
 
 353  0
             IExtensionSpecification spec = (IExtensionSpecification) entry.getValue();
 354  
 
 355  0
             if (!spec.isImmediate())
 356  0
                 continue;
 357  
 
 358  0
             String name = (String) entry.getKey();
 359  
 
 360  0
             getExtension(name);
 361  0
         }
 362  
 
 363  0
     }
 364  
 
 365  
     /**
 366  
      * Returns the extensions map.
 367  
      *
 368  
      * @return Map of objects.
 369  
      */
 370  
 
 371  
     protected Map getExtensions()
 372  
     {
 373  0
         return _extensions;
 374  
     }
 375  
 
 376  
     /**
 377  
      * Updates the extension map.
 378  
      *
 379  
      * @param extension
 380  
      *            A Map of extension specification paths keyed on extension id.
 381  
      *            <p>
 382  
      *            The map is retained, not copied.
 383  
      */
 384  
 
 385  
     protected void setExtensions(Map extension)
 386  
     {
 387  0
         _extensions = extension;
 388  0
     }
 389  
 
 390  
     /**
 391  
      * Returns the libraries map.
 392  
      *
 393  
      * @return Map of {@link LibrarySpecification}.
 394  
      */
 395  
 
 396  
     protected Map getLibraries()
 397  
     {
 398  0
         return _libraries;
 399  
     }
 400  
 
 401  
     /**
 402  
      * Updates the library map.
 403  
      *
 404  
      * @param libraries
 405  
      *            A Map of library specification paths keyed on library id.
 406  
      *            <p>
 407  
      *            The map is retained, not copied.
 408  
      */
 409  
 
 410  
     protected void setLibraries(Map libraries)
 411  
     {
 412  0
         _libraries = libraries;
 413  0
     }
 414  
 
 415  
     /**
 416  
      * Returns the pages map.
 417  
      *
 418  
      * @return Map of {@link IComponentSpecification}.
 419  
      */
 420  
 
 421  
     protected Map getPages()
 422  
     {
 423  0
         return _pages;
 424  
     }
 425  
 
 426  
     /**
 427  
      * Updates the page map.
 428  
      *
 429  
      * @param pages
 430  
      *            A Map of page specification paths keyed on page id.
 431  
      *            <p>
 432  
      *            The map is retained, not copied.
 433  
      */
 434  
 
 435  
     protected void setPages(Map pages)
 436  
     {
 437  0
         _pages = pages;
 438  0
     }
 439  
 
 440  
     /**
 441  
      * Returns the components map.
 442  
      *
 443  
      * @return Map of {@link IContainedComponent}.
 444  
      */
 445  
 
 446  
     protected Map getComponents()
 447  
     {
 448  0
         return _components;
 449  
     }
 450  
 
 451  
     /**
 452  
      * Updates the components map.
 453  
      *
 454  
      * @param components
 455  
      *            A Map of {@link IContainedComponent}keyed on component id.
 456  
      *            The map is retained, not copied.
 457  
      */
 458  
 
 459  
     protected void setComponents(Map components)
 460  
     {
 461  0
         _components = components;
 462  0
     }
 463  
 
 464  
     /**
 465  
      * Returns the XML Public Id for the library file, or null if not
 466  
      * applicable.
 467  
      * <p>
 468  
      * This method exists as a convienience for the Spindle plugin. A previous
 469  
      * method used an arbitrary version string, the public id is more useful and
 470  
      * less ambiguous.
 471  
      */
 472  
 
 473  
     public String getPublicId()
 474  
     {
 475  0
         return _publicId;
 476  
     }
 477  
 
 478  
     public void setPublicId(String publicId)
 479  
     {
 480  0
         _publicId = publicId;
 481  0
     }
 482  
 
 483  
     /** @since 3.0 * */
 484  
 
 485  
     public Resource getSpecificationLocation()
 486  
     {
 487  0
         return _specificationLocation;
 488  
     }
 489  
 
 490  
     /** @since 3.0 * */
 491  
 
 492  
     public void setSpecificationLocation(Resource specificationLocation)
 493  
     {
 494  0
         _specificationLocation = specificationLocation;
 495  0
     }
 496  
 
 497  
     /** @since 3.0 * */
 498  
 
 499  
     public synchronized String toString()
 500  
     {
 501  0
         ToStringBuilder builder = new ToStringBuilder(this);
 502  
 
 503  0
         builder.append("components", _components);
 504  0
         builder.append("description", _description);
 505  0
         builder.append("instantiatedExtensions", _instantiatedExtensions);
 506  0
         builder.append("libraries", _libraries);
 507  0
         builder.append("pages", _pages);
 508  0
         builder.append("publicId", _publicId);
 509  0
         builder.append("specificationLocation", _specificationLocation);
 510  
 
 511  0
         extendDescription(builder);
 512  
 
 513  0
         return builder.toString();
 514  
     }
 515  
 
 516  
     /**
 517  
      * Does nothing, subclasses may override to add additional description.
 518  
      *
 519  
      * @see #toString()
 520  
      * @since 3.0
 521  
      */
 522  
 
 523  
     protected void extendDescription(ToStringBuilder builder)
 524  
     {
 525  0
     }
 526  
 
 527  
 }