You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by jw...@apache.org on 2013/10/17 17:25:59 UTC

svn commit: r1533115 [3/3] - in /myfaces/trinidad/trunk: src/site/xdoc/devguide/ trinidad-api/src/main/java/org/apache/myfaces/trinidad/config/ trinidad-api/src/main/java/org/apache/myfaces/trinidad/skin/ trinidad-api/src/main/xrts/org/apache/myfaces/t...

Added: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/parse/CustomMetadataParser.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/parse/CustomMetadataParser.java?rev=1533115&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/parse/CustomMetadataParser.java (added)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/parse/CustomMetadataParser.java Thu Oct 17 15:25:57 2013
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.myfaces.trinidadinternal.skin.parse;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.myfaces.trinidad.logging.TrinidadLogger;
+import org.apache.myfaces.trinidad.skin.CustomMetadata;
+import org.apache.myfaces.trinidadinternal.share.xml.BaseNodeParser;
+import org.apache.myfaces.trinidadinternal.share.xml.NodeParser;
+import org.apache.myfaces.trinidadinternal.share.xml.ParseContext;
+
+import org.apache.myfaces.trinidadinternal.share.xml.StringParser;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXParseException;
+
+/**
+ * This class is used when we parse the trinidad-skins.xml file and there is a 'metadata' element
+ * as a child of the 'skin' element. This is a collection of simple 'metadata' nodes, represented as Strings
+ * @see CustomMetadata
+ *
+ * @version $Name:  $ ($Revision: $) $Date:  $
+ */
+public class CustomMetadataParser extends BaseNodeParser
+  implements XMLConstants
+{
+  @Override
+  public void startElement(
+    ParseContext context,
+    String       namespaceURI,
+    String       localName,
+    Attributes   attrs
+    ) throws SAXParseException
+  {
+    _skinMetadata = new HashMap<String, Object>();
+  }
+
+  @Override
+  public Object endElement(
+    ParseContext context,
+    String       namespaceURI,
+    String       localName
+    ) throws SAXParseException
+  {
+    return new CustomMetadata(_skinMetadata);
+  }
+
+  @Override
+  public NodeParser startChildElement(
+    ParseContext context,
+    String       namespaceURI,
+    String       localName,
+    Attributes   attrs
+    ) throws SAXParseException
+  {
+    return new StringParser();
+  }
+
+  @Override
+  public void addCompletedChild(
+    ParseContext context,
+    String       namespaceURI,
+    String       localName,
+    Object       child
+    ) throws SAXParseException
+  {
+    _skinMetadata.put(localName, child);
+  }
+
+  private Map<String, Object> _skinMetadata;
+}
\ No newline at end of file

Added: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/parse/SkinAdditionParser.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/parse/SkinAdditionParser.java?rev=1533115&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/parse/SkinAdditionParser.java (added)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/parse/SkinAdditionParser.java Thu Oct 17 15:25:57 2013
@@ -0,0 +1,192 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.trinidadinternal.skin.parse;
+
+import javax.el.ValueExpression;
+
+import org.apache.myfaces.trinidad.logging.TrinidadLogger;
+import org.apache.myfaces.trinidad.skin.CustomMetadata;
+import org.apache.myfaces.trinidad.skin.SkinAddition;
+import org.apache.myfaces.trinidad.skin.SkinFeatures;
+import org.apache.myfaces.trinidadinternal.config.LazyValueExpression;
+import org.apache.myfaces.trinidadinternal.share.xml.BaseNodeParser;
+import org.apache.myfaces.trinidadinternal.share.xml.NodeParser;
+import org.apache.myfaces.trinidadinternal.share.xml.ParseContext;
+import org.apache.myfaces.trinidadinternal.share.xml.StringParser;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXParseException;
+
+/**
+ * NodeParser for &lt;skin-addition&gt; node in trinidad-skins.xml
+ *
+ * @version $Name:  $ ($Revision: adfrt/faces/adf-faces-impl/src/main/java/oracle/adfinternal/view/faces/ui/laf/xml/parse/SkinExtensionParser.java#0 $) $Date: 10-nov-2005.18:50:44 $
+ * @todo ELIMINATE NAMESPACE
+ */
+public class SkinAdditionParser extends BaseNodeParser
+  implements XMLConstants
+{
+  @Override
+  public void startElement(
+    ParseContext context,
+    String       namespaceURI,
+    String       localName,
+    Attributes   attrs
+    ) throws SAXParseException
+  {
+  }
+
+  @Override
+  public Object endElement(
+    ParseContext context,
+    String       namespaceURI,
+    String       localName
+    ) throws SAXParseException
+  {
+
+    // id is required for a SkinAddition. log a severe error if it is null.
+    if (_skinId == null)
+      _LOG.severe("REQUIRED_ELEMENT_SKINID_NOT_FOUND");
+
+    if ((_resourceBundleName != null) && (_translationSourceExpression != null))
+    {
+      _LOG.severe("BOTH_BUNDLENAME_TRANSLATIONSOURCE_SET");
+      _translationSourceExpression = null;
+    }
+
+    if (_translationSourceExpression != null &&
+        !(_translationSourceExpression.startsWith("#{") &&
+        _translationSourceExpression.endsWith("}")))
+    {
+      _LOG.severe("TRANSLATION_SOURCE_NOT_EL");
+      _translationSourceExpression = null;
+    }
+
+    Object isMetaInf = context.getProperty(SKIN_NAMESPACE, META_INF);
+
+    if (isMetaInf != null && _styleSheetName != null
+      && Boolean.parseBoolean(isMetaInf.toString()) && !(_styleSheetName.startsWith("/")))
+      _styleSheetName = META_INF_DIR.concat(_styleSheetName);
+
+    SkinFeatures features = _skinFeatures;
+
+    SkinAddition addition = null;
+    if (_styleSheetName != null
+            || _resourceBundleName != null
+            || _translationSourceExpression != null)
+    {
+      if (_resourceBundleName != null)
+      {
+        // create SkinAddition with resourceBundleName
+        addition = new SkinAddition.Builder().skinId(_skinId).styleSheetName(_styleSheetName)
+          .resourceBundleName(_resourceBundleName).features(features).build();
+      }
+      else
+      {
+        ValueExpression translationSourceVE = null;
+
+        if (_translationSourceExpression != null)
+        {
+          translationSourceVE = LazyValueExpression.createValueExpression(_translationSourceExpression.trim(), Object.class);
+        }
+
+        if (translationSourceVE != null)
+        {
+          // Create a SkinAddition with translationSourceVE
+          addition = new SkinAddition.Builder().skinId(_skinId).styleSheetName(_styleSheetName)
+            .translationSource(translationSourceVE).features(features).build();
+        }
+        else
+        {
+          // Create a SkinAddition with stylesheetName only
+          addition = new SkinAddition.Builder().skinId(_skinId).styleSheetName(_styleSheetName).features(features).build();
+        }
+      }
+    }
+    else if (features != null)
+    {
+      addition = new SkinAddition.Builder().skinId(_skinId).features(features).build();
+    }
+
+    return addition;
+  }
+
+  @Override
+  public NodeParser startChildElement(
+    ParseContext context,
+    String       namespaceURI,
+    String       localName,
+    Attributes   attrs
+    ) throws SAXParseException
+  {
+
+    if ("skin-id".equals(localName) ||
+        "style-sheet-name".equals(localName) ||
+        "bundle-name".equals(localName) ||
+        "translation-source".equals(localName))
+
+    {
+      return new StringParser();
+    }
+    else if ("features".equals(localName))
+    {
+      return context.getParser(SkinFeatures.class, namespaceURI, localName);
+    }
+    else if ("metadata".equals(localName))
+    {
+      return context.getParser(CustomMetadata.class, namespaceURI, localName);
+    }
+
+    return null;
+  }
+
+  @Override
+  public void addCompletedChild(
+    ParseContext context,
+    String       namespaceURI,
+    String       localName,
+    Object       child
+    ) throws SAXParseException
+  {
+
+    if ("skin-id".equals(localName))
+      _skinId = (String) child;
+    else if ("style-sheet-name".equals(localName))
+      _styleSheetName = (String) child;
+    else if ("bundle-name".equals(localName))
+      _resourceBundleName = (String) child;
+    else if ("translation-source".equals(localName))
+      _translationSourceExpression = (String) child;
+    else if ("features".equals(localName))
+    {
+      _skinFeatures = (SkinFeatures) child;
+    }
+  }
+
+  private String _skinId;
+  private String _styleSheetName;
+  private String _resourceBundleName;
+  private String _translationSourceExpression;
+  private SkinFeatures _skinFeatures;
+
+
+  private static final TrinidadLogger _LOG = 
+    TrinidadLogger.createTrinidadLogger(SkinAdditionParser.class);
+
+}
\ No newline at end of file

Added: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/parse/SkinFeaturesParser.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/parse/SkinFeaturesParser.java?rev=1533115&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/parse/SkinFeaturesParser.java (added)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/parse/SkinFeaturesParser.java Thu Oct 17 15:25:57 2013
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.myfaces.trinidadinternal.skin.parse;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.myfaces.trinidad.logging.TrinidadLogger;
+
+import org.apache.myfaces.trinidad.skin.SkinFeatures;
+import org.apache.myfaces.trinidadinternal.share.xml.BaseNodeParser;
+import org.apache.myfaces.trinidadinternal.share.xml.NodeParser;
+import org.apache.myfaces.trinidadinternal.share.xml.ParseContext;
+
+import org.apache.myfaces.trinidadinternal.share.xml.StringParser;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXParseException;
+
+/**
+ * This class is used when we parse the trinidad-skins.xml file and there is a 'features' element
+ * as a child of the 'skin' element. This is a collection of simple 'feature' nodes, represented as Strings
+ * @see SkinFeatures
+ * 
+ * @version $Name:  $ ($Revision: $) $Date:  $
+ */
+public class SkinFeaturesParser extends BaseNodeParser
+  implements XMLConstants
+{
+  @Override
+  public void startElement(
+    ParseContext context,
+    String       namespaceURI,
+    String       localName,
+    Attributes   attrs
+    ) throws SAXParseException
+  {
+    _skinFeatures = new HashMap<String, String>();
+  }
+
+  @Override
+  public Object endElement(
+    ParseContext context,
+    String       namespaceURI,
+    String       localName
+    ) throws SAXParseException
+  {
+    
+    return new SkinFeatures(_skinFeatures);
+  }
+
+  @Override
+  public NodeParser startChildElement(
+    ParseContext context,
+    String       namespaceURI,
+    String       localName,
+    Attributes   attrs
+    ) throws SAXParseException
+  {
+    if("feature".equals(localName))
+    {
+      _currentAttributes = attrs;
+      return new StringParser();
+    }
+    else
+    { //Clear it out if we are not processing a feature currently
+      _currentAttributes = null;
+    }
+    return null;
+  }
+
+  @Override
+  public void addCompletedChild(
+    ParseContext context,
+    String       namespaceURI,
+    String       localName,
+    Object       child
+    ) throws SAXParseException
+  {
+
+    if ("feature".equals(localName) && _currentAttributes != null)
+    {
+      String name = _currentAttributes.getValue("name");
+      if(name != null && String.class.isInstance(child))
+      {
+        _skinFeatures.put(name, (String)child);
+      }
+    }
+  }
+
+  private Map<String, String> _skinFeatures;
+  private Attributes _currentAttributes;
+
+  private static final TrinidadLogger _LOG = 
+    TrinidadLogger.createTrinidadLogger(SkinFeaturesParser.class);
+}
\ No newline at end of file

Added: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/parse/SkinMetadataParser.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/parse/SkinMetadataParser.java?rev=1533115&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/parse/SkinMetadataParser.java (added)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/parse/SkinMetadataParser.java Thu Oct 17 15:25:57 2013
@@ -0,0 +1,199 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.trinidadinternal.skin.parse;
+
+import javax.el.ValueExpression;
+
+import org.apache.myfaces.trinidad.logging.TrinidadLogger;
+import org.apache.myfaces.trinidad.skin.CustomMetadata;
+import org.apache.myfaces.trinidad.skin.SkinFeatures;
+import org.apache.myfaces.trinidad.skin.SkinMetadata;
+import org.apache.myfaces.trinidad.skin.SkinVersion;
+import org.apache.myfaces.trinidadinternal.config.LazyValueExpression;
+import org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.XhtmlConstants;
+import org.apache.myfaces.trinidadinternal.share.xml.BaseNodeParser;
+import org.apache.myfaces.trinidadinternal.share.xml.NodeParser;
+import org.apache.myfaces.trinidadinternal.share.xml.ParseContext;
+import org.apache.myfaces.trinidadinternal.share.xml.StringParser;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXParseException;
+
+/**
+ * NodeParser for &lt;skin&gt; node in trinidad-skins.xml
+ *
+ * @version $Name:  $ ($Revision: adfrt/faces/adf-faces-impl/src/main/java/oracle/adfinternal/view/faces/ui/laf/xml/parse/SkinExtensionParser.java#0 $) $Date: 10-nov-2005.18:50:44 $
+ * @todo ELIMINATE NAMESPACE
+ */
+public class SkinMetadataParser extends BaseNodeParser
+  implements XMLConstants
+{
+  @Override
+  public void startElement(
+    ParseContext context,
+    String       namespaceURI,
+    String       localName,
+    Attributes   attrs
+    ) throws SAXParseException
+  {
+    _namespace = namespaceURI;
+  }
+
+  @Override
+  public Object endElement(
+    ParseContext context,
+    String       namespaceURI,
+    String       localName
+    ) throws SAXParseException
+  {
+
+    // id and family are required. log a severe error if they are null.
+    if (_id == null)
+    {
+      _LOG.severe("REQUIRED_ELEMENT_ID_NOT_FOUND");
+      throw new NullPointerException(_LOG.getMessage("NULL_ID"));
+    }
+
+    if (_family == null)
+    {
+      _LOG.severe("REQURIED_ELEMENT_FAMILY_NOT_FOUND");
+      throw new NullPointerException(_LOG.getMessage("NULL_FAMILY"));
+    }
+
+    if ((_bundleName != null) && (_translationSourceExpression != null))
+    {
+      _LOG.severe("BOTH_BUNDLENAME_TRANSLATIONSOURCE_SET");
+      _translationSourceExpression = null;
+    }
+
+    if (_translationSourceExpression != null &&
+        !(_translationSourceExpression.startsWith("#{") &&
+        _translationSourceExpression.endsWith("}")))
+    {
+      _LOG.severe("TRANSLATION_SOURCE_NOT_EL");
+      _translationSourceExpression = null;
+    }
+
+    Object isMetaInf = context.getProperty(SKIN_NAMESPACE, META_INF);
+
+    if (isMetaInf != null && _styleSheetName != null
+      && Boolean.parseBoolean(isMetaInf.toString()) && !(_styleSheetName.startsWith("/")))
+      _styleSheetName = META_INF_DIR.concat(_styleSheetName);
+
+    ValueExpression translationSource = null;
+    
+    if (_translationSourceExpression != null)
+      translationSource =  LazyValueExpression.createValueExpression(_translationSourceExpression, Object.class);
+
+    // here since we are reading from trinidad-skins.xml we have to assert that id and
+    // family is set.
+    // creation of SkinNode threw NullPointerException if Id or family was not provided
+    // at this point. Since we use SkinMetadata for querying skins we cannot assert that
+    // id and family should be set. So we do this check here in the parser.
+    return new SkinMetadata.Builder().id(_id).family(_family).renderKitId(SkinMetadata.RenderKitId.fromId(_renderKitId))
+    .baseSkinId(_extends).styleSheetName(_styleSheetName).resourceBundleName(_bundleName)
+    .translationSource(translationSource).version(_skinVersionNode)
+    .features(_skinFeaturesNode).metadata(_skinMetadataNode).build();
+  }
+
+  @Override
+  public NodeParser startChildElement(
+    ParseContext context,
+    String       namespaceURI,
+    String       localName,
+    Attributes   attrs
+    ) throws SAXParseException
+  {
+    if (!namespaceURI.equals(_namespace))
+      return null;
+
+    if ("id".equals(localName) ||
+        "family".equals(localName) ||
+        "render-kit-id".equals(localName) ||
+        "style-sheet-name".equals(localName) ||
+        "bundle-name".equals(localName) ||
+        "translation-source".equals(localName) ||
+        "extends".equals(localName))
+
+    {
+      return new StringParser();
+    }
+    else if ("version".equals(localName))
+    {
+      return context.getParser(SkinVersion.class, namespaceURI, localName);
+    }
+    else if ("features".equals(localName))
+    {
+      return context.getParser(SkinFeatures.class, namespaceURI, localName);
+    }
+    else if ("metadata".equals(localName))
+    {
+      return context.getParser(CustomMetadata.class, namespaceURI, localName);
+    }
+
+    return null;
+  }
+
+  @Override
+  public void addCompletedChild(
+    ParseContext context,
+    String       namespaceURI,
+    String       localName,
+    Object       child
+    ) throws SAXParseException
+  {
+
+    if ("id".equals(localName))
+      _id = (String) child;
+    else if ("family".equals(localName))
+      _family = (String) child;
+    else if ("render-kit-id".equals(localName))
+      _renderKitId = (String) child;
+    else if ("style-sheet-name".equals(localName))
+      _styleSheetName = (String) child;
+    else if ("bundle-name".equals(localName))
+      _bundleName = (String) child;
+    else if ("translation-source".equals(localName))
+      _translationSourceExpression = (String) child;
+    else if ("extends".equals(localName))
+      _extends = (String) child;
+    else if ((child instanceof SkinVersion))
+      _skinVersionNode = ((SkinVersion)child);
+    else if ((child instanceof SkinFeatures))
+      _skinFeaturesNode = ((SkinFeatures)child);
+    else if ((child instanceof CustomMetadata))
+      _skinMetadataNode = ((CustomMetadata)child);
+  }
+
+  private String      _namespace;
+  private String      _id;
+  private String      _family;
+  private String      _styleSheetName;
+  private String      _renderKitId;
+  private String      _bundleName;
+  private String      _translationSourceExpression;
+  private String      _extends;
+  private SkinVersion _skinVersionNode;
+  private SkinFeatures _skinFeaturesNode;
+  private CustomMetadata _skinMetadataNode;
+
+  private static final TrinidadLogger _LOG =
+    TrinidadLogger.createTrinidadLogger(SkinMetadataParser.class);
+
+}
\ No newline at end of file

Added: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/parse/SkinVersionParser.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/parse/SkinVersionParser.java?rev=1533115&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/parse/SkinVersionParser.java (added)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/parse/SkinVersionParser.java Thu Oct 17 15:25:57 2013
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.trinidadinternal.skin.parse;
+
+import org.apache.myfaces.trinidad.logging.TrinidadLogger;
+import org.apache.myfaces.trinidad.skin.SkinVersion;
+import org.apache.myfaces.trinidadinternal.share.xml.StringParser;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXParseException;
+
+import org.apache.myfaces.trinidadinternal.share.xml.BaseNodeParser;
+import org.apache.myfaces.trinidadinternal.share.xml.NodeParser;
+import org.apache.myfaces.trinidadinternal.share.xml.ParseContext;
+
+/**
+ * This class is used when we parse the trinidad-skins.xml file and there is a 'version' element
+ * as a child of the 'skin' element. A 'version' has both a 'name' (required) and 
+ * a 'default' (optional) element. After parsing, a SkinVersion object is created and attached
+ * to the Skin object.
+ * @see SkinVersion
+ * @see org.apache.myfaces.trinidadinternal.skin.SkinUtils
+ * @see org.apache.myfaces.trinidad.skin.SkinVersion
+ */
+public class SkinVersionParser extends BaseNodeParser
+  implements XMLConstants
+{
+  @Override
+  public void startElement(
+    ParseContext context,
+    String       namespaceURI,
+    String       localName,
+    Attributes   attrs
+    ) throws SAXParseException
+  {
+  }
+
+  @Override
+  public Object endElement(
+    ParseContext context,
+    String       namespaceURI,
+    String       localName
+    ) throws SAXParseException
+  {
+    // allow no name in version.
+    if (_name == null)
+      _name = "";
+
+    return new SkinVersion(_name, "true".equals(_default));
+  }
+
+  @Override
+  public NodeParser startChildElement(
+    ParseContext context,
+    String       namespaceURI,
+    String       localName,
+    Attributes   attrs
+    ) throws SAXParseException
+  {
+
+    if ("name".equals(localName) ||
+        "default".equals(localName))
+
+    {
+      return new StringParser();
+    }
+
+    return null;
+  }
+
+  @Override
+  public void addCompletedChild(
+    ParseContext context,
+    String       namespaceURI,
+    String       localName,
+    Object       child
+    ) throws SAXParseException
+  {
+
+    if ("name".equals(localName))
+      _name = (String) child;
+    else if ("default".equals(localName))
+    {
+      _default = (String) child;
+      // <default/> means true
+      if (_default == null || "".equals(_default))
+        _default = "true";
+    }
+  }
+
+  private String _name;
+  private String _default;
+
+  private static final TrinidadLogger _LOG = 
+    TrinidadLogger.createTrinidadLogger(SkinVersionParser.class);
+}
\ No newline at end of file

Modified: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/parse/SkinsNode.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/parse/SkinsNode.java?rev=1533115&r1=1533114&r2=1533115&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/parse/SkinsNode.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/parse/SkinsNode.java Thu Oct 17 15:25:57 2013
@@ -18,8 +18,13 @@
  */
 package org.apache.myfaces.trinidadinternal.skin.parse;
 
+import java.util.Collections;
+import java.util.Iterator;
 import java.util.List;
 
+import org.apache.myfaces.trinidad.skin.SkinAddition;
+import org.apache.myfaces.trinidad.skin.SkinMetadata;
+
 /**
  * Object which represents the skin and skin-addition nodes in trinidad-skins.xml.
  *
@@ -28,11 +33,11 @@ import java.util.List;
 public class SkinsNode
 {
   /**
-   * 
+   *
    */
   public SkinsNode(
-    List<SkinNode> skinNodes,
-    List<SkinAdditionNode> skinAdditionNodes)
+    List<SkinMetadata> skinNodes,
+    List<SkinAddition> skinAdditionNodes)
   {
     _skinAdditionNodes = skinAdditionNodes;
     _skinNodes = skinNodes;
@@ -40,19 +45,19 @@ public class SkinsNode
 
   /**
    */
-  public List<SkinAdditionNode> getSkinAdditionNodes()
+  public List<SkinAddition> getSkinAdditionNodes()
   {
     return _skinAdditionNodes;
   }
   /**
-   * 
+   *
    */
-  public List<SkinNode> getSkinNodes()
+  public List<SkinMetadata> getSkinNodes()
   {
     return _skinNodes;
   }
-  
-  private List<SkinAdditionNode> _skinAdditionNodes;
-  private List<SkinNode> _skinNodes;
+
+  private List<SkinAddition> _skinAdditionNodes;
+  private List<SkinMetadata> _skinNodes;
 
 }

Modified: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/parse/SkinsNodeParser.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/parse/SkinsNodeParser.java?rev=1533115&r1=1533114&r2=1533115&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/parse/SkinsNodeParser.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/parse/SkinsNodeParser.java Thu Oct 17 15:25:57 2013
@@ -22,6 +22,8 @@ import java.util.ArrayList;
 
 import java.util.List;
 
+import org.apache.myfaces.trinidad.skin.SkinAddition;
+import org.apache.myfaces.trinidad.skin.SkinMetadata;
 import org.xml.sax.Attributes;
 import org.xml.sax.SAXParseException;
 
@@ -46,9 +48,9 @@ public class SkinsNodeParser extends Bas
     ) throws SAXParseException
   {
     if ("skin-addition".equals(localName))
-      return context.getParser(SkinAdditionNode.class, namespaceURI, localName);
+      return context.getParser(SkinAddition.class, namespaceURI, localName);
     else
-      return context.getParser(SkinNode.class, namespaceURI, localName);
+      return context.getParser(SkinMetadata.class, namespaceURI, localName);
   }
 
   @Override
@@ -59,14 +61,16 @@ public class SkinsNodeParser extends Bas
     Object       child
     ) throws SAXParseException
   {
-    assert ((child == null) || 
-            (child instanceof SkinNode) ||
-            (child instanceof SkinAdditionNode));
-    
-    if ((child instanceof SkinAdditionNode))    
-      _skinAdditions.add((SkinAdditionNode)child);
-    else
-      _skins.add((SkinNode)child);
+    assert ((child == null) ||
+            (child instanceof SkinMetadata) ||
+            (child instanceof SkinAddition));
+
+    // we should not add a child which is null
+    // so use both instance checks
+    if (child instanceof SkinAddition)
+      _skinAdditions.add((SkinAddition)child);
+    else if (child instanceof SkinMetadata)
+      _skins.add((SkinMetadata)child);
   }
 
   @Override
@@ -80,7 +84,7 @@ public class SkinsNodeParser extends Bas
                          _skinAdditions);
   }
 
-  private List<SkinNode> _skins = new ArrayList<SkinNode>();
-  private List<SkinAdditionNode> _skinAdditions = new ArrayList<SkinAdditionNode>();
-  
+  private List<SkinMetadata> _skins = new ArrayList<SkinMetadata>();
+  private List<SkinAddition> _skinAdditions = new ArrayList<SkinAddition>();
+
 }

Modified: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/parse/XMLConstants.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/parse/XMLConstants.java?rev=1533115&r1=1533114&r2=1533115&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/parse/XMLConstants.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/parse/XMLConstants.java Thu Oct 17 15:25:57 2013
@@ -29,4 +29,7 @@ public interface XMLConstants
       "http://myfaces.apache.org/trinidad/skin";
 
   public static final String NULL_NAME             = "null";
+  public static final String META_INF              = "meta-inf";
+  public static final String META_INF_DIR          = "META-INF/";
+
 }

Modified: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/SkinPregenerationService.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/SkinPregenerationService.java?rev=1533115&r1=1533114&r2=1533115&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/SkinPregenerationService.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/SkinPregenerationService.java Thu Oct 17 15:25:57 2013
@@ -33,7 +33,8 @@ import javax.faces.context.ResponseWrite
 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
 import org.apache.myfaces.trinidad.render.InternalView;
 import org.apache.myfaces.trinidad.skin.Skin;
-import org.apache.myfaces.trinidad.skin.SkinFactory;
+import org.apache.myfaces.trinidad.skin.SkinMetadata;
+import org.apache.myfaces.trinidad.skin.SkinProvider;
 import org.apache.myfaces.trinidad.util.Enums;
 import org.apache.myfaces.trinidadinternal.skin.pregen.config.InvalidConfigException;
 import org.apache.myfaces.trinidadinternal.skin.pregen.config.PregenConfig;
@@ -137,11 +138,11 @@ public class SkinPregenerationService ex
     ExternalContext external = context.getExternalContext();
     return external.getRequestParameterMap().get(_SKIN_ID_REQUEST_PARAM);        
   }
-  
+
   private static Skin _getSkin(FacesContext context, String skinId)
   {
-    SkinFactory factory = SkinFactory.getFactory();
-    return factory.getSkin(context, skinId);
+    SkinProvider provider = SkinProvider.getCurrentInstance(context.getExternalContext());
+    return provider.getSkin(context, new SkinMetadata.Builder().id(skinId).build());
   }
 
   private static void _pregenFailed(FacesContext context, Exception e)

Added: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/provider/ExternalSkinProvider.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/provider/ExternalSkinProvider.java?rev=1533115&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/provider/ExternalSkinProvider.java (added)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/provider/ExternalSkinProvider.java Thu Oct 17 15:25:57 2013
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.trinidadinternal.skin.provider;
+
+import java.util.Map;
+
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+
+import org.apache.myfaces.trinidad.logging.TrinidadLogger;
+import org.apache.myfaces.trinidad.skin.Skin;
+import org.apache.myfaces.trinidad.skin.SkinFactory;
+import org.apache.myfaces.trinidad.skin.SkinMetadata;
+import org.apache.myfaces.trinidadinternal.config.GlobalConfiguratorImpl;
+
+/**
+ * ExternalSkinProvider serves to maintain backward compatibility with legacy SkinFactory users.
+ * Before we introduced SkinProvider SPI, users can register skins in the lifecycle of
+ * the Configurator using reloadSkins API.
+ * With SkinProvider SPI, this method of registering skins is deprecated. This provider is used to
+ * support the existing users who use SkinFactory to register / reload skins. This provider manages
+ * the skins added to the SkinFactory and provides methods to perform the SkinFactory operations.
+ *
+ * Essentially SkinFactory methods will call this provider for methods like addSkin, getSkinIds etc
+ * which interact with the skins added to the factory.
+ */
+public class ExternalSkinProvider extends BaseSkinProvider
+{
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected Skin loadAvailableSkin(FacesContext context, SkinMetadata skinMetadata)
+  {
+    // this case will never rise with this provider.
+    // any skin supported by this provider is added using
+    // addSkins API. So the parent class will have all the skins
+    // supported by this provider and there is no need to load it
+    return null;
+  }
+
+  /**
+   * called from SkinFactory to reload the skins that are registered with SkinFactory
+   * With this provider, the skins registered with SkinFactory are managed in this provider
+   */
+  public final void reload()
+  {
+    synchronized (this)
+    {
+      FacesContext fc = FacesContext.getCurrentInstance();
+
+      if (fc != null)
+      {
+        SkinFactory factory = SkinFactory.getFactory();
+        _LOG.fine("Reloading skins begin");
+
+        // backup the old skins to help in recovery if need be
+        Map<SkinMetadata, Skin> oldSkins = getSkins();
+        initSkins();
+
+        try
+        {
+          // give chance for configurator services to attach any skins that was not defined trinidad-skins.xml
+          GlobalConfiguratorImpl.getInstance().reloadSkins(fc.getExternalContext(), factory);
+        }
+        catch (Exception e)
+        {
+          _LOG.severe("SKIN_RELOAD_FAILURE", e);
+          setSkins(oldSkins);
+        }
+        finally
+        {
+          _LOG.fine("Reloading skins complete");
+        }
+      }
+    }
+  }
+
+  /**
+   * static factory method to get hold of a ExternalSkinProvider object
+   * This can be used for easy creation of Skin object without having to
+   * implement the abstract class
+   * @param ec
+   * @return
+   */
+  public static ExternalSkinProvider getCurrentInstance(ExternalContext ec)
+  {
+    if (ec == null)
+      throw new NullPointerException("ExternalContext is passed as null");
+
+    ExternalSkinProvider esp = (ExternalSkinProvider) ec.getApplicationMap().get(EXTERNAL_SKIN_PROVIDER_KEY);
+    return esp;
+  }
+
+  /**
+   * Key for the ExternalSkinProvider stored in ExternalContext
+   */
+  public static final String EXTERNAL_SKIN_PROVIDER_KEY =
+    "org.apache.myfaces.trinidad.skin.EXTERNAL_SKIN_PROVIDER_INSTANCE";
+
+  private static final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(ExternalSkinProvider.class);
+}
\ No newline at end of file

Added: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/provider/SkinProviderRegistry.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/provider/SkinProviderRegistry.java?rev=1533115&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/provider/SkinProviderRegistry.java (added)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/provider/SkinProviderRegistry.java Thu Oct 17 15:25:57 2013
@@ -0,0 +1,514 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.trinidadinternal.skin.provider;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import javax.faces.context.FacesContext;
+
+import org.apache.myfaces.trinidad.logging.TrinidadLogger;
+import org.apache.myfaces.trinidad.skin.Skin;
+import org.apache.myfaces.trinidad.skin.SkinMetadata;
+import org.apache.myfaces.trinidad.skin.SkinProvider;
+import org.apache.myfaces.trinidad.skin.SkinVersion;
+import org.apache.myfaces.trinidad.util.ClassLoaderUtils;
+import org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.TrinidadRenderingConstants;
+import org.apache.myfaces.trinidadinternal.skin.SkinUtils;
+
+/**
+ * Internal implementation of SkinProvider which is exposed using SkinProvider.getCurrentInstance()
+ * This class collates all SkinProvider SPIs, Trinidad SkinProviders
+ * and SkinFactory to return the best match for a Skin requested
+ * This class reads all registered SPIs using org.apache.myfaces.trinidad.skin.SkinProvider
+ *<p/>
+ * Instance of this class is created and put into the ExternalContext during
+ * bootstrap in GlobalConfiguratorImpl and retrieved in the static factory inside SkinProvider
+ * <p/>
+ */
+public class SkinProviderRegistry extends SkinProvider
+{
+
+  public SkinProviderRegistry()
+  {
+    List<SkinProvider> services = ClassLoaderUtils.getServices(SkinProvider.class.getName());
+
+    if (_LOG.isFine())
+      _LOG.fine("Adding providers from registered SPIs... " + services.size());
+
+    List<SkinProvider> providers = new ArrayList<SkinProvider>(services.size() + 2);
+    providers.addAll(services);
+
+    // add internal skin providers at the end
+    // this is to give the other SPIs a chance before the internal skin providers
+    if (_LOG.isFine())
+      _LOG.fine("Adding TrinidadSkinProvider... ");
+
+    providers.add(new TrinidadSkinProvider());
+
+    if (_LOG.isFine())
+      _LOG.fine("Adding TrinidadBaseSkinProvider... ");
+
+    providers.add(new TrinidadBaseSkinProvider());
+
+    if (_LOG.isFine())
+      _LOG.fine("Adding ExternalSkinProvider... ");
+
+    providers.add(SkinUtils.getExternalSkinProvider(null));
+
+    _providers = Collections.unmodifiableList(providers);
+  }
+
+  @Override
+  public Collection<SkinMetadata> getSkinMetadata(FacesContext context)
+  {
+    Collection<SkinMetadata> metadata = new ArrayList<SkinMetadata>();
+
+    for (SkinProvider provider : _providers)
+      metadata.addAll(provider.getSkinMetadata(context));
+
+    return Collections.unmodifiableCollection(metadata);
+  }
+
+  /**
+   * @param context
+   * @param skinMetadata   search criteria object containing the information of skin to be queried
+   *                       id, family, renderKit, version are the information used from skin metadata
+   *                       to perform search for the skin requested.
+   *                       Other fields do not participate in the search.
+   * @return matching skin for the search criteria passed,
+   *         if none found, return the simple skin for the renderKit in search criteria
+   *         if renderKit not specified in search criteria, skinMetadata automatically assumes it as
+   *         SkinMetadata.RenderKitId.DESKTOP
+   */
+  @Override
+  public Skin getSkin(FacesContext context, SkinMetadata skinMetadata)
+  {
+    _handleCircularDependency(context, skinMetadata);
+
+    List<Skin> matchingSkins = new ArrayList<Skin>();
+    Skin matchingSkin = null;
+
+    if (_LOG.isFine())
+      _LOG.fine("Skin request for metadata: " + skinMetadata);
+
+    for (SkinProvider provider : _providers)
+    {
+      matchingSkin = provider.getSkin(context, skinMetadata);
+
+      if (matchingSkin != null)
+      {
+        // log which provider got skin etc
+        if (_LOG.isFine())
+          _LOG.fine("Skin obtained for metadata: " + skinMetadata + " from provider: " + provider);
+
+        matchingSkins.add(matchingSkin);
+      }
+    }
+
+    if (matchingSkin != null)
+    {
+      if (_LOG.isFine())
+        _LOG.fine("Skin obtained for metadata: " + skinMetadata + " from Skinfactory");
+
+      matchingSkins.add(matchingSkin);
+    }
+
+    if (_LOG.isFine())
+      _LOG.fine("Matches obtained for " + skinMetadata + ": " + matchingSkins.size());
+
+    // now we are done with asking all skin providers
+    // ensure that the matching skins returned are indeed matching the search criteria
+    // onus is on SkinProviderRegistry to serve the skin requested, even if a SkinProvider
+    // returns a wrong skin.
+
+    // filter the results obtained from skin providers based on id, family and renderKit
+    // filtering on version is more complicated and taken up subsequently
+    matchingSkins = _filterSkins(matchingSkins, skinMetadata);
+
+    if (matchingSkins.isEmpty())
+    {
+      if (_LOG.isFine())
+        _LOG.fine("NO MATCH. Will return a simple skin or null for skin metadata: " + skinMetadata);
+
+      assert  (skinMetadata.getRenderKitId() != null);
+      // if renderKit is available return the simple skin for that renderKit
+      // skinMetadata.getRenderKitId() can never be null, default renderKit will always be DESKTOP
+      return _returnSkin(context, skinMetadata, _getSimpleSkinForRenderKit(context, skinMetadata.getRenderKitId()));
+    }
+
+
+    // we have at least one match now
+    // if we have only one match
+    // return that skin
+    if (matchingSkins.size() == 1)
+    {
+      if (_LOG.isFine())
+        _LOG.fine("returning ONLY match for skin metadata: " + skinMetadata);
+
+      return _returnSkin(context, skinMetadata, matchingSkins.get(0));
+    }
+
+    // at this point we have more than one matches for the search criteria passed
+    // so, extract the best match based on version
+    return _versionFilter(context, skinMetadata, matchingSkins);
+  }
+
+  /**
+   * ensure sanity in the list of matches received by filtering the skins based on id, family and renderKit
+   * @param skins
+   * @param metadata
+   * @return
+   */
+  private List<Skin> _filterSkins(List<Skin> skins, SkinMetadata metadata)
+  {
+    if (skins == null || skins.isEmpty() || metadata == null)
+      return Collections.emptyList();
+
+    List<Skin> filterList = _idFilter(skins, metadata.getId());
+
+    // if the id based filtering resulted in only match then return that
+    // provided id was mentioned in search criteria
+    if (filterList.size() == 1 && metadata.getId() != null)
+    {
+      return filterList;
+    }
+
+    // if more than one match for id or if id is not specified, then filter by family
+    filterList = _familyFilter(filterList, metadata.getFamily());
+
+    // if the family based filtering resulted in only match then return that
+    // provided family was mentioned in search criteria
+    if (filterList.size() == 1 && metadata.getFamily() != null)
+    {
+      return filterList;
+    }
+
+    // if family based filtering resulted in multiple matches, or if family and id are not specified,
+    // proceed with renderKit based filtering.
+    filterList = _renderKitFilter(filterList, metadata.getRenderKitId());
+
+    return filterList;
+  }
+
+  /**
+   * filter based on skin id, if mentioned. Otherwise return the list as is
+   * @param skins
+   * @param id
+   * @return
+   */
+  private List<Skin> _idFilter(List<Skin> skins, String id)
+  {
+    if (id == null || id.isEmpty())
+      return skins;
+
+    List<Skin> filterList = new ArrayList<Skin>(skins.size());
+
+    for (Skin skin : skins)
+      if (id.equals(skin.getId()))
+        filterList.add(skin);
+
+    return filterList;
+  }
+
+  /**
+   * filter based on skin family, if mentioned. Otherwise return the list as is
+   * @param skins
+   * @param family
+   * @return
+   */
+  private List<Skin> _familyFilter(List<Skin> skins, String family)
+  {
+    if (family == null || family.isEmpty())
+      return skins;
+
+    List<Skin> filterList = new ArrayList<Skin>(skins.size());
+
+    for (Skin skin : skins)
+      if (family.equals(skin.getFamily()))
+        filterList.add(skin);
+
+    return filterList;
+  }
+
+  /**
+   * filter based on skin renderkit id, if mentioned. Otherwise return the list as is
+   * @param skins
+   * @param renderKitId
+   * @return
+   */
+  private List<Skin> _renderKitFilter(List<Skin> skins, String renderKitId)
+  {
+    if (renderKitId == null || renderKitId.isEmpty())
+      return skins;
+
+    List<Skin> filterList = new ArrayList<Skin>(skins.size());
+
+    for (Skin skin : skins)
+      if (renderKitId.equals(skin.getRenderKitId()))
+        filterList.add(skin);
+
+    return filterList;
+  }
+
+  /**
+   * filter based on version
+   * if version is mentioned try to return exact match
+   * else if version is not mentioned or version is default try to return default skin
+   * else try to return leaf skin
+   * else return first match
+   * @param context
+   * @param searchCriteria
+   * @param matchingSkins
+   * @return
+   */
+  private Skin _versionFilter(FacesContext context, SkinMetadata searchCriteria, List<Skin> matchingSkins)
+  {
+    SkinVersion version = searchCriteria.getVersion();
+    Skin matchingSkin;
+    // we can now find the best match based on version
+    // now that there is a version mentioned and skins matching is > 1
+    // look for exact name match
+    matchingSkin = _findSkinForVersionName(matchingSkins, version);
+
+    // if we found exact match in version, return it.
+    if (matchingSkin != null)
+    {
+      if (_LOG.isFine())
+        _LOG.fine("returning exact version match.");
+
+      return _returnSkin(context, searchCriteria, matchingSkin);
+    }
+
+    // either user is looking for default version or did not find the version requested
+    // try to find a default skin
+    matchingSkin = _findSkinWithDefaultVersion(matchingSkins);
+
+    // if we found the default version skin, return it.
+    if (matchingSkin != null)
+    {
+      if (_LOG.isFine())
+        _LOG.fine("returning DEFAULT version match.");
+      return _returnSkin(context, searchCriteria, matchingSkin);
+    }
+
+    // the version that user asked for is not available
+    // so find leaf skin
+    matchingSkin = _findLeafSkin(matchingSkins);
+
+    // if we found a leaf skin return that
+    if (matchingSkin != null)
+    {
+      if (_LOG.isFine())
+        _LOG.fine("return LEAF skin or one of the matches.");
+
+      return _returnSkin(context, searchCriteria, matchingSkin);
+    }
+
+    // we failed to find any better result for the given version, so return first match
+    if (_LOG.isFine())
+      _LOG.fine("nothing worked so return first match.");
+
+    return _returnSkin(context, searchCriteria, matchingSkins.get(0));
+  }
+
+  private Skin _returnSkin(FacesContext context, SkinMetadata skinMetadata, Skin skin)
+  {
+    // nothing to do if context is not available
+    if (context == null)
+      return skin;
+
+    Object o = context.getAttributes().get(_SKIN_PROVIDER_CONTEXT);
+    List<SkinMetadata> requesters = null;
+
+    if (o == null)
+    {
+      requesters = new ArrayList<SkinMetadata>();
+      context.getAttributes().put(_SKIN_PROVIDER_CONTEXT, requesters);
+    }
+    else
+      requesters = (List) o;
+
+    // remove the skinMetadata
+    requesters.remove(skinMetadata);
+
+    if (_LOG.isFiner())
+    {
+      _LOG.finer("Removing " + skinMetadata + " from context");
+      _LOG.finer("Context now is " + requesters);
+    }
+
+    return skin;
+  }
+
+  /**
+   * find a skin with version passed
+   * @param skins
+   * @param version
+   * @return
+   */
+  private Skin _findSkinForVersionName(Collection<Skin> skins, SkinVersion version)
+  {
+    if (version == null)
+      throw new IllegalArgumentException("skin version cannot be null");
+
+    if (version.getName() == null || version.getName().isEmpty())
+      return null;
+
+    for (Skin skin : skins)
+    {
+      // metadata cannot be null and also version inside it cannot be null
+      if (version.getName().equals(skin.getVersion().getName()))
+      {
+        if (_LOG.isFine())
+          _LOG.fine("Found version match skin: " + skin);
+
+        return skin;
+      }
+    }
+
+    return null;
+  }
+
+  /**
+   * Latest skin is the one which is last in the family hierarchy
+   * eg: fusion-v1 -> fusion-v2 -> fusion-v3
+   * Among this fusion-v3 is the latest. So we look for a skin that is
+   * not extended by any other skin in the family.
+   * @param skins
+   * @return
+   */
+  private Skin _findLeafSkin(Collection<Skin> skins)
+  {
+    List<Skin> leafSkins = new ArrayList<Skin>();
+    List<String> parentIds = new ArrayList<String>();
+
+    // collect parents skins among the list
+    for (Skin metadata : skins)
+    {
+      Skin baseSkin = metadata.getBaseSkin();
+      if (baseSkin != null)
+      {
+        String parentId = baseSkin.getId();
+        if (parentId != null)
+          parentIds.add(parentId);
+      }
+    }
+
+    // find leaf skins, which is not in parent list
+    for (Skin skin : skins)
+    {
+      String skinId = skin.getId();
+      if (skinId != null && !parentIds.contains(skinId))
+      {
+        leafSkins.add(skin);
+      }
+    }
+
+    // if there are no leaves, return null
+    // this is a rare case, almost impossible since there will be
+    // at least one skin which is not parent of another
+    // but let us cover the corner case if any
+    if (leafSkins.isEmpty())
+      return null;
+
+    // if there is one leaf skin return that
+    // if there are many, return the last one among the leaves
+    return leafSkins.get(leafSkins.size() - 1);
+  }
+
+  /**
+   * find a skin that has its SkinVersion set to 'default', if it exists.
+   * @param matchingSkinList A list of Skins that we will look through to find the 'default'.
+   * @return Skin with SkinVersion isDefault true, otherwise, null.
+   */
+  private Skin _findSkinWithDefaultVersion(Collection<Skin> matchingSkinList)
+  {
+    for (Skin skin : matchingSkinList)
+    {
+      SkinVersion skinVersion = skin.getVersion();
+
+      if (skinVersion != null && skinVersion.isDefault())
+      {
+        if (_LOG.isFine())
+          _LOG.fine("Found default skin: " + skin);
+
+        return skin;
+      }
+    }
+
+    return null;
+  }
+
+  private void _handleCircularDependency(FacesContext context, SkinMetadata skinMetadata)
+  {
+    // nothing to do if context is not available
+    if (context == null)
+      return;
+
+    Object o = context.getAttributes().get(_SKIN_PROVIDER_CONTEXT);
+    List<SkinMetadata> requesters = null;
+
+    if (o == null)
+    {
+      requesters = new ArrayList<SkinMetadata>();
+      context.getAttributes().put(_SKIN_PROVIDER_CONTEXT, requesters);
+    }
+    else
+      requesters = (List) o;
+
+    if (requesters.contains(skinMetadata))
+    {
+      String message = "Circlular dependency detected whille loading skin: " + skinMetadata
+                       + ". Requesters are: " + requesters;
+      if (_LOG.isSevere())
+        _LOG.severe(message);
+
+      throw new IllegalStateException(message);
+    }
+
+    // add the currently requested metadata into list
+    requesters.add(skinMetadata);
+
+    if (_LOG.isFiner())
+    {
+      _LOG.finer("Adding " + skinMetadata + " to context");
+      _LOG.finer("Context now is " + requesters);
+    }
+  }
+
+  private Skin _getSimpleSkinForRenderKit(FacesContext context, String renderKitId)
+  {
+    if (renderKitId != null && renderKitId.equals(TrinidadRenderingConstants.APACHE_TRINIDAD_PORTLET))
+      return getSkin(context, new SkinMetadata.Builder().id(TrinidadRenderingConstants.SIMPLE_PORTLET_ID).build());
+
+    if (renderKitId != null && renderKitId.equals(TrinidadRenderingConstants.APACHE_TRINIDAD_PDA))
+      return getSkin(context, new SkinMetadata.Builder().id(TrinidadRenderingConstants.SIMPLE_PDA_ID).build());
+
+    return getSkin(context, new SkinMetadata.Builder().id(TrinidadRenderingConstants.SIMPLE_DESKTOP_ID).build());
+  }
+
+  private final List<SkinProvider> _providers;
+
+  private static final String _SKIN_PROVIDER_CONTEXT =
+    "org.apache.myfaces.trinidadinternal.skin.provider.SkinProviderRegistry.Context";
+  private static final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(SkinProviderRegistry.class);
+}
\ No newline at end of file

Added: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/provider/TrinidadBaseSkinProvider.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/provider/TrinidadBaseSkinProvider.java?rev=1533115&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/provider/TrinidadBaseSkinProvider.java (added)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/provider/TrinidadBaseSkinProvider.java Thu Oct 17 15:25:57 2013
@@ -0,0 +1,199 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.trinidadinternal.skin.provider;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+
+import javax.faces.context.FacesContext;
+
+import org.apache.myfaces.trinidad.skin.Skin;
+import org.apache.myfaces.trinidad.skin.SkinMetadata;
+import org.apache.myfaces.trinidadinternal.renderkit.core.skin.CasablancaDesktopSkin;
+import org.apache.myfaces.trinidadinternal.renderkit.core.skin.CasablancaPdaSkin;
+import org.apache.myfaces.trinidadinternal.renderkit.core.skin.CasablancaPortletSkin;
+import org.apache.myfaces.trinidadinternal.renderkit.core.skin.MinimalDesktopSkinExtension;
+import org.apache.myfaces.trinidadinternal.renderkit.core.skin.MinimalPdaSkinExtension;
+import org.apache.myfaces.trinidadinternal.renderkit.core.skin.MinimalPortletSkinExtension;
+import org.apache.myfaces.trinidadinternal.renderkit.core.skin.SimpleDesktopSkin;
+import org.apache.myfaces.trinidadinternal.renderkit.core.skin.SimplePdaSkin;
+import org.apache.myfaces.trinidadinternal.renderkit.core.skin.SimplePortletSkin;
+import static org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.TrinidadRenderingConstants.CASABLANCA_DESKTOP_ID;
+import static org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.TrinidadRenderingConstants.CASABLANCA_PDA_ID;
+import static org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.TrinidadRenderingConstants.CASABLANCA_PORTLET_ID;
+import static org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.TrinidadRenderingConstants.CASABLANCA_SKIN_FAMILY;
+import static org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.TrinidadRenderingConstants.CASABLANCA_STYLE_SHEET_NAME;
+import static org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.TrinidadRenderingConstants.MINIMAL_DESKTOP_ID;
+import static org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.TrinidadRenderingConstants.MINIMAL_DESKTOP_STYLE_SHEET_NAME;
+import static org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.TrinidadRenderingConstants.MINIMAL_PDA_ID;
+import static org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.TrinidadRenderingConstants.MINIMAL_PDA_STYLE_SHEET_NAME;
+import static org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.TrinidadRenderingConstants.MINIMAL_PORTLET_ID;
+import static org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.TrinidadRenderingConstants.MINIMAL_PORTLET_STYLE_SHEET_NAME;
+import static org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.TrinidadRenderingConstants.MINIMAL_SKIN_FAMILY;
+import static org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.TrinidadRenderingConstants.SIMPLE_DESKTOP_ID;
+import static org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.TrinidadRenderingConstants.SIMPLE_DESKTOP_LOCATION;
+import static org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.TrinidadRenderingConstants.SIMPLE_PDA_ID;
+import static org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.TrinidadRenderingConstants.SIMPLE_PDA_LOCATION;
+import static org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.TrinidadRenderingConstants.SIMPLE_PORTLET_ID;
+import static org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.TrinidadRenderingConstants.SIMPLE_PORTLET_LOCATION;
+import static org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.TrinidadRenderingConstants.SIMPLE_SKIN_FAMILY;
+
+/**
+ * This SkinProvider creates the very base skins such as simple, minimal and casablanca
+ */
+public class TrinidadBaseSkinProvider extends BaseSkinProvider
+{
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Collection<SkinMetadata> getSkinMetadata(FacesContext context)
+  {
+    return Collections.unmodifiableCollection(_METADATA);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected Skin loadAvailableSkin(FacesContext context, SkinMetadata search)
+  {
+    // avoid round trips to SkinProviderRegistry for trinidad base skins
+    // any base skin used in this provider is also a static skin and can be loaded locally
+    // there fore load the base skins locally
+
+    Skin skin = getSkins().get(search);
+
+    if (skin != null)
+    {
+      return skin;
+    }
+
+    Skin loadedSkin = null;
+    Skin parentSkin = null;
+
+    if (search == _CASABLANCA_DESKTOP_METADATA)
+    {
+      parentSkin = _loadBaseSkinAndRegisterIfRequired(context, _SIMPLE_DESKTOP_METADATA);
+      loadedSkin =  new CasablancaDesktopSkin(parentSkin);
+    }
+    else if (search == _CASABLANCA_PDA_METADATA)
+    {
+      parentSkin = _loadBaseSkinAndRegisterIfRequired(context, _SIMPLE_PDA_METADATA);
+      loadedSkin = new CasablancaPdaSkin(parentSkin);
+    }
+    else if (search == _CASABLANCA_PORTLET_METADATA)
+    {
+      parentSkin = _loadBaseSkinAndRegisterIfRequired(context, _SIMPLE_PORTLET_METADATA);
+      loadedSkin = new CasablancaPortletSkin(parentSkin);
+    }
+    else if (search == _MINIMAL_DESKTOP_METADATA)
+    {
+      parentSkin = _loadBaseSkinAndRegisterIfRequired(context, _SIMPLE_DESKTOP_METADATA);
+      loadedSkin =  new MinimalDesktopSkinExtension(parentSkin);
+    }
+    else if (search == _MINIMAL_PDA_METADATA)
+    {
+      parentSkin = _loadBaseSkinAndRegisterIfRequired(context, _SIMPLE_PDA_METADATA);
+      loadedSkin = new MinimalPdaSkinExtension(parentSkin);
+    }
+    else if (search == _MINIMAL_PORTLET_METADATA)
+    {
+      parentSkin = _loadBaseSkinAndRegisterIfRequired(context, _SIMPLE_PORTLET_METADATA);
+      loadedSkin = new MinimalPortletSkinExtension(parentSkin);
+    }
+    else if (search == _SIMPLE_DESKTOP_METADATA)
+    {
+      loadedSkin = new SimpleDesktopSkin();
+    }
+    else if (search == _SIMPLE_PDA_METADATA)
+    {
+      loadedSkin = new SimplePdaSkin();
+    }
+    else if (search == _SIMPLE_PORTLET_METADATA)
+    {
+      loadedSkin = new SimplePortletSkin();
+    }
+
+    return loadedSkin;
+  }
+
+  private Skin _loadBaseSkinAndRegisterIfRequired(FacesContext context, SkinMetadata metadata)
+  {
+    Skin skin = getSkins().get(metadata);
+
+    if (skin == null)
+    {
+      skin = loadAvailableSkin(context, metadata);
+      addSkin(metadata, skin);
+    }
+
+    return skin;
+  }
+
+
+  private final static Collection<SkinMetadata> _METADATA;
+  private final static SkinMetadata _SIMPLE_DESKTOP_METADATA;
+  private final static SkinMetadata _SIMPLE_PDA_METADATA;
+  private final static SkinMetadata _SIMPLE_PORTLET_METADATA;
+  private final static SkinMetadata _MINIMAL_DESKTOP_METADATA;
+  private final static SkinMetadata _MINIMAL_PORTLET_METADATA;
+  private final static SkinMetadata _MINIMAL_PDA_METADATA;
+  private final static SkinMetadata _CASABLANCA_DESKTOP_METADATA;
+  private final static SkinMetadata _CASABLANCA_PDA_METADATA;
+  private final static SkinMetadata _CASABLANCA_PORTLET_METADATA;
+
+  static {
+    _SIMPLE_DESKTOP_METADATA = new SkinMetadata.Builder().id(SIMPLE_DESKTOP_ID).family(SIMPLE_SKIN_FAMILY)
+      .renderKitId(SkinMetadata.RenderKitId.DESKTOP).styleSheetName(SIMPLE_DESKTOP_LOCATION).build();
+    _SIMPLE_PDA_METADATA = new SkinMetadata.Builder().id(SIMPLE_PDA_ID).family(SIMPLE_SKIN_FAMILY)
+      .renderKitId(SkinMetadata.RenderKitId.PDA).styleSheetName(SIMPLE_PDA_LOCATION).build();
+    _SIMPLE_PORTLET_METADATA = new SkinMetadata.Builder().id(SIMPLE_PORTLET_ID).family(SIMPLE_SKIN_FAMILY)
+      .renderKitId(SkinMetadata.RenderKitId.PORTLET).styleSheetName(SIMPLE_PORTLET_LOCATION).build();
+    _MINIMAL_DESKTOP_METADATA= new SkinMetadata.Builder().id(MINIMAL_DESKTOP_ID).family(MINIMAL_SKIN_FAMILY)
+      .renderKitId(SkinMetadata.RenderKitId.DESKTOP).baseSkinId(SIMPLE_DESKTOP_ID)
+      .styleSheetName(MINIMAL_DESKTOP_STYLE_SHEET_NAME).build();
+    _MINIMAL_PDA_METADATA = new SkinMetadata.Builder().id(MINIMAL_PDA_ID).family(MINIMAL_SKIN_FAMILY)
+      .renderKitId(SkinMetadata.RenderKitId.PDA).baseSkinId(SIMPLE_PDA_ID)
+      .styleSheetName(MINIMAL_PDA_STYLE_SHEET_NAME).build();
+    _MINIMAL_PORTLET_METADATA = new SkinMetadata.Builder().id(MINIMAL_PORTLET_ID).family(MINIMAL_SKIN_FAMILY)
+      .renderKitId(SkinMetadata.RenderKitId.PORTLET).baseSkinId(SIMPLE_PORTLET_ID)
+      .styleSheetName(MINIMAL_PORTLET_STYLE_SHEET_NAME).build();
+    _CASABLANCA_DESKTOP_METADATA = new SkinMetadata.Builder().id(CASABLANCA_DESKTOP_ID).family(CASABLANCA_SKIN_FAMILY)
+      .renderKitId(SkinMetadata.RenderKitId.DESKTOP).baseSkinId(SIMPLE_DESKTOP_ID)
+      .styleSheetName(CASABLANCA_STYLE_SHEET_NAME).build();
+    _CASABLANCA_PDA_METADATA = new SkinMetadata.Builder().id(CASABLANCA_PDA_ID).family(CASABLANCA_SKIN_FAMILY)
+      .renderKitId(SkinMetadata.RenderKitId.PDA).baseSkinId(SIMPLE_PDA_ID)
+      .styleSheetName(CASABLANCA_STYLE_SHEET_NAME).build();
+    _CASABLANCA_PORTLET_METADATA = new SkinMetadata.Builder().id(CASABLANCA_PORTLET_ID).family(CASABLANCA_SKIN_FAMILY)
+      .renderKitId(SkinMetadata.RenderKitId.PORTLET).baseSkinId(SIMPLE_PORTLET_ID).build();
+
+    _METADATA = new ArrayList<SkinMetadata>(9);
+    _METADATA.add(_SIMPLE_DESKTOP_METADATA);
+    _METADATA.add(_SIMPLE_PDA_METADATA);
+    _METADATA.add(_SIMPLE_PORTLET_METADATA);
+    _METADATA.add(_MINIMAL_DESKTOP_METADATA);
+    _METADATA.add(_MINIMAL_PDA_METADATA);
+    _METADATA.add(_MINIMAL_PORTLET_METADATA);
+    _METADATA.add(_CASABLANCA_DESKTOP_METADATA);
+    _METADATA.add(_CASABLANCA_PDA_METADATA);
+    _METADATA.add(_CASABLANCA_PORTLET_METADATA);
+  }
+}
\ No newline at end of file

Added: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/provider/TrinidadSkinProvider.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/provider/TrinidadSkinProvider.java?rev=1533115&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/provider/TrinidadSkinProvider.java (added)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/provider/TrinidadSkinProvider.java Thu Oct 17 15:25:57 2013
@@ -0,0 +1,223 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.trinidadinternal.skin.provider;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import javax.el.ValueExpression;
+
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+
+import org.apache.myfaces.trinidad.logging.TrinidadLogger;
+import org.apache.myfaces.trinidad.skin.Skin;
+import org.apache.myfaces.trinidad.skin.SkinAddition;
+import org.apache.myfaces.trinidad.skin.SkinMetadata;
+import org.apache.myfaces.trinidad.skin.SkinProvider;
+import org.apache.myfaces.trinidad.skin.SkinVersion;
+import org.apache.myfaces.trinidadinternal.config.LazyValueExpression;
+import org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.TrinidadRenderingConstants;
+import org.apache.myfaces.trinidadinternal.skin.SkinExtension;
+import org.apache.myfaces.trinidadinternal.skin.SkinUtils;
+import org.apache.myfaces.trinidadinternal.skin.parse.SkinsNode;
+
+/**
+ * This is the Trinidad's SkinProvider for loading skins from trinidad-skins.xml. This provider reads and caches
+ * trinidad-skins.xml from various sources like META-INF, WEB-INF and SkinResourceLoader API during its initialization.
+ * Subsequently the Skin objects are created lazily using the cached metadata, only when it is first requested for.
+ */
+public final class TrinidadSkinProvider extends BaseSkinProvider
+{
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Collection<SkinMetadata> getSkinMetadata(FacesContext context)
+  {
+    // already initialized to unmodifiableCollection
+    return _skinMetadata;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected Skin loadAvailableSkin(FacesContext context, SkinMetadata skinMetadata)
+  {
+    SkinMetadata matchingNode = null;
+
+    for (SkinMetadata node : _skinMetadata)
+    {
+      if (skinMetadata.getId().equals(node.getId()))
+      {
+        matchingNode = node;
+        break;
+      }
+    }
+
+    if (matchingNode == null)
+    {
+      // This cannot happen because base class checks for availability before it calls for the skin to be loaded
+      if (_LOG.isSevere())
+        _LOG.severe("SP_LOADING_UNKNOWN_SKIN", new Object[] {skinMetadata.getId()});
+
+      throw new NullPointerException(_LOG.getMessage("SP_LOADING_UNKNOWN_SKIN", new Object[] {skinMetadata.getId()}));
+    }
+
+    String id =  matchingNode.getId();
+    String family =  matchingNode.getFamily();
+    String renderKitId =  matchingNode.getRenderKitId();
+    Skin baseSkin = null;
+    String baseSkinId = matchingNode.getBaseSkinId();
+    SkinProvider provider = SkinUtils.getSkinProvider(context);
+
+    if (provider != null && baseSkinId != null)
+      baseSkin = provider.getSkin(context, new SkinMetadata.Builder().id(baseSkinId).build());
+
+    // if there is no base skin then use the default base skin for the renderKit
+    if (baseSkin == null)
+      baseSkin = _getDefaultBaseSkin(provider, renderKitId);
+
+    if (id == null)
+      throw new NullPointerException(_LOG.getMessage("NULL_SKIN_ID"));
+
+    if (family == null)
+      throw new NullPointerException("Null family");
+
+    if (_LOG.isFine())
+      _LOG.fine("Creating skin extension for : " + skinMetadata);
+
+    // features object itself cannot be null
+    Skin loadedSkin = new SkinExtension(baseSkin, matchingNode);
+
+    if (_skinAdditionNodes != null)
+      for (SkinAddition addition : _skinAdditionNodes)
+      {
+        String additionSkinId = addition.getSkinId();
+
+        if (id.equals(additionSkinId))
+        {
+          if (_LOG.isFine())
+            _LOG.fine("Adding skin addition : " + addition);
+
+          loadedSkin.addSkinAddition(addition);
+        }
+
+        if (baseSkinId.equals(additionSkinId)
+          && !_hasSkinAddition(baseSkin.getSkinAdditions(), addition))
+        {
+            if (_LOG.isFine())
+              _LOG.fine("Adding parent skin addition : " + addition);
+
+            baseSkin.addSkinAddition(addition);
+        }
+      }
+
+    return loadedSkin;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  protected void initialize(FacesContext context)
+  {
+    if (context == null || context.getExternalContext() == null)
+    {
+      return;
+    }
+
+    if (_skinMetadata == null)
+    {
+      if (_LOG.isFine())
+        _LOG.fine("init provider.");
+
+      // only now do initialization
+      ExternalContext extCtxt = context.getExternalContext();
+      List<SkinsNode> skinsNodes = SkinUtils.buildSkinsNodes(extCtxt);
+      List<SkinMetadata> skinNodes = new ArrayList<SkinMetadata>();
+      List<SkinAddition> skinAdditionNodes = new ArrayList<SkinAddition>();
+
+      for (SkinsNode node : skinsNodes)
+      {
+        if  (node != null)
+        {
+          skinNodes.addAll(node.getSkinNodes());
+          skinAdditionNodes.addAll(node.getSkinAdditionNodes());
+        }
+      }
+
+      if (skinNodes.isEmpty())
+        _skinMetadata = Collections.emptyList();
+      else
+        _skinMetadata = Collections.unmodifiableList(skinNodes);
+
+      if (skinAdditionNodes.isEmpty())
+        _skinAdditionNodes = Collections.emptyList();
+      else
+        _skinAdditionNodes = Collections.unmodifiableList(skinAdditionNodes);
+
+      if (_LOG.isFine())
+      {
+        _LOG.fine("trindiad-skins loaded: " + _skinMetadata.size());
+        _LOG.fine("trindiad-skins additions loaded: " + _skinAdditionNodes.size());
+      }
+    }
+  }
+
+  private boolean _hasSkinAddition(List<SkinAddition> additions, SkinAddition search)
+  {
+    if (search == null)
+      return false;
+
+    // here we check only stylesheet name as an addition with a stylesheet name needs to added only once
+    for (SkinAddition addn : additions)
+      if (addn != null && search.getStyleSheetName().equals(addn.getStyleSheetName()))
+        return true;
+
+    return false;
+  }
+
+  private static Skin _getDefaultBaseSkin(SkinProvider provider, String renderKitId)
+  {
+    String baseSkinId;
+
+    if (TrinidadRenderingConstants.APACHE_TRINIDAD_PDA.equals(renderKitId))
+      baseSkinId =  TrinidadRenderingConstants.SIMPLE_PDA_ID;
+    else if (TrinidadRenderingConstants.APACHE_TRINIDAD_PORTLET.equals(renderKitId))
+      baseSkinId =  TrinidadRenderingConstants.SIMPLE_PORTLET_ID;
+    else
+      baseSkinId = TrinidadRenderingConstants.SIMPLE_DESKTOP_ID;
+
+    Skin baseSkin = provider.getSkin(null, new SkinMetadata.Builder().id(baseSkinId).build());
+
+    // this will never be null because we are asking for the default simple skin
+    assert (baseSkin != null);
+    return baseSkin;
+  }
+
+  private List<SkinMetadata> _skinMetadata;
+  private List<SkinAddition> _skinAdditionNodes;
+
+  private final static TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(TrinidadSkinProvider.class);
+}
\ No newline at end of file

Modified: myfaces/trinidad/trunk/trinidad-impl/src/main/xrts/org/apache/myfaces/trinidadinternal/resource/LoggerBundle.xrts
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/xrts/org/apache/myfaces/trinidadinternal/resource/LoggerBundle.xrts?rev=1533115&r1=1533114&r2=1533115&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/xrts/org/apache/myfaces/trinidadinternal/resource/LoggerBundle.xrts (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/xrts/org/apache/myfaces/trinidadinternal/resource/LoggerBundle.xrts Thu Oct 17 15:25:57 2013
@@ -247,8 +247,8 @@
 <!-- RENDERER_NOT_FOUND -->
 <resource key="RENDERER_NOT_FOUND">Renderer ''{0}'' not found for component family ''{1}''</resource>
 
-<!-- NO_SKIN_FACTORY -->
-<resource key="NO_SKIN_FACTORY">There is no SkinFactory</resource>
+<!-- NO_SKIN_PROVIDER -->
+<resource key="NO_SKIN_PROVIDER">There is no SkinProvider</resource>
 
 <!-- STYLESHEETDOCUMENT_ID_NOT_MATCH_LOCAL_SKIN -->
 <resource key="STYLESHEETDOCUMENT_ID_NOT_MATCH_LOCAL_SKIN">
@@ -262,8 +262,8 @@ The skin {0} specified on the requestMap
 <!-- REQUESTMAP_SKIN_NOT_USED_BECAUSE_NOT_EXIST -->
 <resource key="REQUESTMAP_SKIN_NOT_USED_BECAUSE_NOT_EXIST">The skin {0} specified on the requestMap will not be used because it does not exist.</resource>
 
-<!-- CANNOT_GET_SKIN_FROM_SKINFACTORY -->
-<resource key="CANNOT_GET_SKIN_FROM_SKINFACTORY">Could not get skin {0} from the SkinFactory</resource>
+<!-- CANNOT_GET_SKIN_FROM_SKINPROVIDER -->
+<resource key="CANNOT_GET_SKIN_FROM_SKINPROVIDER">Could not get skin {0} from the SkinProvider</resource>
 
 <!-- SKIN_CIRCULAR_INCLUDE_ERROR -->
 <resource key="SKIN_CIRCULAR_INCLUDE_ERROR">Circular dependency detected in skin reference icon {0}</resource>
@@ -468,7 +468,22 @@ The skin {0} specified on the requestMap
 <resource key="ERR_PARSING_SKIN_SELECTOR">Error reading from the skin css file. There is an extra comma in selector: {0}</resource>
 
 <!-- CANNOT_ADD_SKIN -->
-<resource key="CANNOT_ADD_SKIN">Can't add Skin with null skinId or null skin</resource>
+<resource key="CANNOT_ADD_SKIN">Can't add Skin with null skin metadata or null skin</resource>
+
+<!-- NULL_FC_SKIN_METADATA -->
+<resource key="NULL_FC_SKIN_METADATA">Cannot create skin extension with null context or null skin metadata.</resource>
+
+<!-- NULL_FC_SKIN_BASE_SKIN_METADATA -->
+<resource key="NULL_FC_SKIN_BASE_SKIN_METADATA">Cannot create skin extension with null context or null skin metadata or null base skin metadata.</resource>
+
+<!-- NULL_SKIN_METADATA_TO_CREATE_SKIN -->
+<resource key="NULL_BASE_SKIN_ID">Make sure that base skin id is mentioned in the skin metadata. Base skin is mandatory for creating a skin extension.</resource>
+
+  <!-- INVALID_BASE_SKIN_ID -->
+<resource key="INVALID_BASE_SKIN_ID">Skin id in base skin metadata does not match with the base skin id in skin metadata.</resource>
+
+<!-- INVALID_BASE_SKIN -->
+<resource key="INVALID_BASE_SKIN">Base skin provided cannot be obtained using SkinProvider. Make sure that the base skin information provided is valid and supported by at least one SkinProvider.</resource>
 
 <!-- DUPLICATE_ADD_SKIN_TO_SKIN_FACTORY -->
 <resource key="DUPLICATE_ADD_SKIN_TO_SKIN_FACTORY">The previously added {0} skin has been added again. If you cached this skin in your application, you might get inconsistent results. Check for duplicate trinidad-skins.xml files on the classpath.</resource>
@@ -1209,4 +1224,14 @@ The skin {0} specified on the requestMap
 
 <resource key="INVALID_SURROGATE_CHAR">During encoding, a high surrogate character was found, but the codePoint was invalid. ch is {0}, codePoint is {1} and index is {2}.</resource>
 
+<resource key="SP_CANNOT_FIND_SKIN_WITHOUT_FAMILY_OR_ID">Cannot search for skin without skinId or skin family.</resource>
+
+<resource key="SP_FINDING_SKIN_FOR">Searching for skin {0}.</resource>
+
+<resource key="SP_CANNOT_FIND_MATCHING_SKIN_ID">Can''t find a skin that matches skinId {0}.</resource>
+
+<resource key="SP_CANNOT_FIND_MATCHING_SKIN">Can''t find a skin that matches family {0} and renderkit {1}.</resource>
+
+<resource key="SP_LOADING_UNKNOWN_SKIN">Cannot load skin with id {0}. This skin is unknown to the current TrinidadSkinProvider.</resource>
+
 </resources>

Modified: myfaces/trinidad/trunk/trinidad-impl/src/test/java/org/apache/myfaces/trinidadinternal/renderkit/RenderKitBootstrap.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/test/java/org/apache/myfaces/trinidadinternal/renderkit/RenderKitBootstrap.java?rev=1533115&r1=1533114&r2=1533115&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/test/java/org/apache/myfaces/trinidadinternal/renderkit/RenderKitBootstrap.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/test/java/org/apache/myfaces/trinidadinternal/renderkit/RenderKitBootstrap.java Thu Oct 17 15:25:57 2013
@@ -38,7 +38,6 @@ import org.apache.myfaces.trinidadintern
 import org.apache.myfaces.trinidadinternal.agent.AgentImpl;
 
 import org.apache.myfaces.trinidadinternal.skin.SkinFactoryImpl;
-import org.apache.myfaces.trinidadinternal.skin.SkinUtils;
 
 public class RenderKitBootstrap
 {
@@ -151,11 +150,6 @@ public class RenderKitBootstrap
     if (SkinFactory.getFactory() == null)
     {
       SkinFactory.setFactory(new SkinFactoryImpl());
-
-      // register the base skins
-      // =-=AEW Because we don't have a "ServletContext", we can't
-      // find any custom skins
-      SkinUtils.registerBaseSkins();
     }
   }
 

Modified: myfaces/trinidad/trunk/trinidad-impl/src/test/java/org/apache/myfaces/trinidadinternal/renderkit/RenderKitTestCase.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/test/java/org/apache/myfaces/trinidadinternal/renderkit/RenderKitTestCase.java?rev=1533115&r1=1533114&r2=1533115&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/test/java/org/apache/myfaces/trinidadinternal/renderkit/RenderKitTestCase.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/test/java/org/apache/myfaces/trinidadinternal/renderkit/RenderKitTestCase.java Thu Oct 17 15:25:57 2013
@@ -48,14 +48,16 @@ import org.apache.commons.lang.StringUti
 import org.apache.myfaces.trinidad.context.Agent;
 import org.apache.myfaces.trinidad.context.RequestContext;
 import org.apache.myfaces.trinidad.render.ExtendedRenderKitService;
+import org.apache.myfaces.trinidad.skin.SkinProvider;
 import org.apache.myfaces.trinidad.util.Service;
 
 import org.apache.myfaces.trinidadbuild.test.FacesTestCase;
 
 import org.apache.myfaces.trinidadinternal.io.XhtmlResponseWriter;
+import org.apache.myfaces.trinidadinternal.skin.provider.ExternalSkinProvider;
+import org.apache.myfaces.trinidadinternal.skin.provider.SkinProviderRegistry;
 
 import junit.framework.AssertionFailedError;
-import junit.framework.TestCase;
 import junit.framework.TestResult;
 import junit.framework.TestSuite;
 
@@ -185,7 +187,10 @@ abstract public class RenderKitTestCase 
       Application mockApplication,
       boolean testMode)
     {
-      return new MFacesContext(mockApplication, testMode);
+      MFacesContext ctx = new MFacesContext(mockApplication, testMode);
+      ctx.getExternalContext().getApplicationMap().put(ExternalSkinProvider.EXTERNAL_SKIN_PROVIDER_KEY, new ExternalSkinProvider());
+      ctx.getExternalContext().getApplicationMap().put(SkinProvider.SKIN_PROVIDER_INSTANCE_KEY, new SkinProviderRegistry());
+      return ctx;
     }
 
     protected MRequestContext createRequestContext()

Modified: myfaces/trinidad/trunk/trinidad-impl/src/test/java/org/apache/myfaces/trinidadinternal/ui/laf/base/xhtml/XhtmlLafUtilsTest.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/test/java/org/apache/myfaces/trinidadinternal/ui/laf/base/xhtml/XhtmlLafUtilsTest.java?rev=1533115&r1=1533114&r2=1533115&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/test/java/org/apache/myfaces/trinidadinternal/ui/laf/base/xhtml/XhtmlLafUtilsTest.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/test/java/org/apache/myfaces/trinidadinternal/ui/laf/base/xhtml/XhtmlLafUtilsTest.java Thu Oct 17 15:25:57 2013
@@ -21,18 +21,16 @@ package org.apache.myfaces.trinidadinter
 import java.util.Locale;
 
 import javax.faces.component.UIViewRoot;
-import javax.faces.context.ResponseWriter;
 
 import junit.framework.TestCase;
 
-import org.apache.myfaces.trinidad.context.RenderingContext;
 import org.apache.myfaces.trinidad.context.RequestContext;
-import org.apache.myfaces.trinidadinternal.io.XhtmlResponseWriter;
-import org.apache.myfaces.trinidadinternal.renderkit.FacesConfigInfo;
+import org.apache.myfaces.trinidad.skin.SkinProvider;
+import org.apache.myfaces.trinidadinternal.skin.provider.ExternalSkinProvider;
+import org.apache.myfaces.trinidadinternal.skin.provider.SkinProviderRegistry;
 import org.apache.myfaces.trinidadinternal.renderkit.MApplication;
 import org.apache.myfaces.trinidadinternal.renderkit.MFacesContext;
 import org.apache.myfaces.trinidadinternal.renderkit.MRequestContext;
-import org.apache.myfaces.trinidadinternal.renderkit.NullWriter;
 import org.apache.myfaces.trinidadinternal.renderkit.RenderKitBootstrap;
 import org.apache.myfaces.trinidadinternal.renderkit.core.CoreRenderingContext;
 
@@ -69,6 +67,8 @@ public class XhtmlLafUtilsTest extends T
     _requestContext.setAgent(RenderKitBootstrap.getGeckoAgent());
     _requestContext.setRightToLeft(false);
     _requestContext.setAccessibilityMode(null);
+    _facesContext.getExternalContext().getApplicationMap().put(ExternalSkinProvider.EXTERNAL_SKIN_PROVIDER_KEY, new ExternalSkinProvider());
+    _facesContext.getExternalContext().getApplicationMap().put(SkinProvider.SKIN_PROVIDER_INSTANCE_KEY, new SkinProviderRegistry());
 
     UIViewRoot root = RenderKitBootstrap.createUIViewRoot(_facesContext);
     root.setRenderKitId("org.apache.myfaces.trinidad.core");