[ 
https://issues.apache.org/jira/browse/TRINIDAD-2406?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13790143#comment-13790143
 ] 

Anand V Nath commented on TRINIDAD-2406:
----------------------------------------

API and internal changes for implementing this are:

1.  Create an object to capture metadata about skin: 
org.apache.myfaces.trinidad.skin.SkinMetadata
        public final class SkinMetadata
        {
          SkinMetadata(id, family, renderKit, parentSkin, ... )
          public String getBaseSkinId()
          public String getId()
          public String getFamily()
          public String getRenderKit()
          public SkinVersion getVersion()
          public SkinFeatures getFeatures()
          public CustomMetadata getMetadata()
          public String getStyleSheetName()
          public String getResourceBundleName()
          public ValueExpression getTranslationSource()
        }

Include a static inner builder class for: 
org.apache.myfaces.trinidad.skin.SkinMetadata, 
org.apache.myfaces.trinidad.skin.SkinMetadata.Builder for easy instantiation of 
the SkinMetadata. Since we have too many parameters to be captured for 
SkinMetadata, we use a builder.

public final class SkinMetadata {
  private SkinMetadata(Builder b) 
  {
  }
...
  public static final class Builder
  {
    public Builder()

    // setters for optional items
    public Builder id(String id)
    public Builder family(String family)
    public Builder parent(String parent)
    public Builder version(SkinVersion version)
    public Builder styleSheetName(String styleSheetName)
    public Builder resourceBundleName(String resourceBundleName)
    public Builder translationSource(ValueExpression translationSource)
    public Builder baseSkinId(String baseSkinId)
    public Builder feature(SkinFeatures features)
    public Builder metadata(CustomMetadata metadata)

    // build method to create SkinMetadata object
    public SkinMetadata build()
  }

}

For example the client code would look like:

new 
SkinMetadata.Builder().id(skinId).family(family).renderKitId(renderKitId).version(version).build();

2. Create org.apache.myfaces.trinidad.skin.SkinProvider SPI

public abstract class SkinProvider
{
  /**
   * Returns the Skin for the given skin ID.
   *
   * The returned skin is not cached by the framework and thus it
   * is the responsibility of the provider to return the same instance
   * of the skin should it desire so.
   */
  public abstract Skin getSkin(FacesContext context, SkinMetadata metadata)

  /**
   * A provider can optionally return information about some or all of the 
skins it provides.
   * Typically this information is generated without loading the skins
   * as this is a quick way to find out about the Skins in the provider and 
also thereby
   * supporting lazy loading of Skins.
   * SkinMetadata for a Skin should contain only features and metadata that it
   * explicitly supports. It should not contain the features and metadata that
   * belongs only to its parent skins.
   * @param context
   * @return
   */
  public Collection<SkinMetadata> getSkinMetadata(FacesContext context)
  {
    return Collections.emptyList();
  }
}

3.  org.apache.myfaces.trinidadinternal.skin.provider.BaseSkinProvider extends 
org.apache.myfaces.trinidad.skin.SkinProvider to abstract all common 
functionality of trinidad internal providers.

public abstract class BaseSkinProvider extends SkinProvider
{
  public Skin getSkin(FacesContext context, SkinMetadata skinMetadata)
  {
    // common implementation shared between the internal trinidad skin 
providers.
  }

  public Collection<SkinMetadata> getSkinMetadata(FacesContext context)
  {
    // common implementation shared between the internal trinidad skin 
providers.
  }
}

4. Implement 
org.apache.myfaces.trinidadinternal.skin.provider.TrinidadBaseSkinProvider 
extends BaseSkinProvider to load all trinidad base skins and to be consistent 
with the SPI - This extracts logic from SkinUtils.registerBaseSkins

public final class TrinidadBaseSkinProvider extends BaseSkinProvider
{
  // Implement the methods for handling all base trinidad skins currently 
registered using SkinUtils.registerBaseSkins
}

5. Implement 
org.apache.myfaces.trinidadinternal.skin.provider.TrinidadSkinProvider extends 
BaseSkinProvider to read all the trinidad-skins.xml - This will consolidate 
code from SkinUtils.registerSkinExtensions

public final class TrinidadSkinProvider extends BaseSkinProvider
{
  // Implement the methods for handling all skins defined using 
trinidad-skins.xml
  // use this class as a wrapper on top on SkinFactory
  // remove any pre caching done in SkinFactory
  // load skins from SkinFactory only on need basis

  public Collection<SkinMetadata> getSkinMetadata()
  {
    // return the information inside trinidad-skins.xml
  }
}

6. Implement 
org.apache.myfaces.trinidadinternal.skin.provider.ExternalSkinProvider extends 
BaseSkinProvider to handle all externally registered skins using 
SkinFactory.addSkin and SkinFactory.reload routiens.

public final class ExternalSkinProviderextends BaseSkinProvider
{
  // this provider supports reload and addSkin as required by SkinFactory.
  // SkinFactoryImpl will now call this class for its operations.
  // and SkinFactoryImpl will serve only such externally registered skins.
  // all other skins like trinidad-skins.xml and base skins will be served by 
  // their respective providers.
}

7. Implement org.apache.myfaces.trinidad.skin.SkinProviderRegistry which is a 
one point API to load all kinds of SkinProviders - This API will query the SPIs 
to return the requested skin.

public final class SkinProviderRegistry implementes SkinProvider
{
  public static SkinProvider getInstance();

  // for any getSkin API, query the registered SPIs followed by 
TrinidadSkinProvider and TrinidadBaseSkinProvider
  // This gives a chance for the registered SPIs to return their skin in front 
of the default skins.
  // current implementation assumes that there will not be any collision for 
getSkin API based on skin-id, family, name, renderkit etc
  // solve this problem as an when it arises

  public Collection<SkinMetadata> getSkinMetadata()
  {
    // return the consolidated information from all registered SkinProvider 
SPIs 
  }
}

8. Expose SkinExtension creation via SkinFactory

/**
   * Creates a skin extension based on the supplied baseSkin and the 
information from supplied skinMetadata
   * The base skin supplied should be one that is queried out of SkinProvider.
   * @param context
   * @param baseSkinMetadata search criteria for the base skin
   * @param skinMetadata metadata to create new skin extension
   * @return a new SkinExtension object created using the skinMetadata supplied
   * @throws IllegalArgumentException if the baseSkinId contained in the 
supplied skinMetadata did not match the id of the supplied baseSkin
   * @throws ClassCastException if the base skin supplied is not one queried 
out of SkinProvider.
   */
  public Skin createSkin(FacesContext context, SkinMetadata baseSkinMetadata, 
SkinMetadata skinMetadata)

  /**
   * Creates a skin extension based on the information from supplied 
skinMetadata. Id of the base skin for the new
   * skin extension has to be set in the metadata.
   * @param context
   * @param skinMetadata metadata to create new skin extension
   * @return a new SkinExtension object createed using the skinMetadata supplied
   * @throws IllegalArgumentException if the baseSkinId contained in the 
supplied skinMetadata did not match the id of the supplied baseSkin
   */
  public Skin createSkin(FacesContext context, SkinMetadata skinMetadata)

9. Modify org.apache.myfaces.trinidadinternal.config.GlobalConfiguratorImpl not 
to init the skins using org.apache.myfaces.trinidad.skin.SkinFactory
10. Modify the callers which uses org.apache.myfaces.trinidad.skin.SkinFactory 
to query skins to use the new SkinProvider.
11.  Deprecate all methods in org.apache.myfaces.trinidad.skin.SkinFactory 
execpt for the new createSkin methods
12. Modify org.apache.myfaces.trinidad.skin.SkinFactory to fall back on 
SkinProvider and ExternalSkinProvide for all its operations.
13. Deprecate 
org.apache.myfaces.trinidadinternal.config.GlobalConfiguratorImpl.reloadSkins 
since reloading of a skin is SkinProvider internal implementation.
14. Remove org.apache.myfaces.trinidadinternal.skin.SkinUtils APIs like 
registerBaseSkins, registerSkinExtensions which are moved.
15. Add APIs to org.apache.myfaces.trinidadinternal.skin.SkinUtils to return 
the parsed information from trinidad-skins.xml. This will be used by internal 
trinidad SkinProvider.
16. Remove duplication in parsing code by using SkinMetadata, SkinAddition, 
SkinVersion etc which are already part of public API instead of 
SkinVersionNode, SkinAdditionNode, SkinNode etc.


> externalize skin repositories by using SkinProvider SPI
> -------------------------------------------------------
>
>                 Key: TRINIDAD-2406
>                 URL: https://issues.apache.org/jira/browse/TRINIDAD-2406
>             Project: MyFaces Trinidad
>          Issue Type: Improvement
>          Components: Skinning
>    Affects Versions: 2.1.0-core
>            Reporter: Anand V Nath
>
> Introduce SkinProvider SPI. Users can use this to create their own skip 
> repositories and expose their skins to the skinning framework.
> Provide an API to query skin using skin family, skin id, render kit - This 
> will make use of the existing SkinFactory APIs. Only change here is that it 
> should go over all the available SkinProvider SPIs to find a match.
> Create internal SkinProvider SPIs to handle the Trinidad and RCF skins (or 
> skins defined using trinidad-skins.xml).
> Provide an API to list all the available skins from all SkinProvider SPIs and 
> make the skin metadata thus available.
> Make SkinExtension part of public API so that users can use this class to 
> create the Skin objects which they expose through their SkinProvider SPIs



--
This message was sent by Atlassian JIRA
(v6.1#6144)

Reply via email to