org.apache.myfaces.trinidadinternal.skin.SkinUtils Maven / Gradle / Ivy
Show all versions of trinidad-impl Show documentation
/*
* 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;
import java.beans.Beans;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.Stack;
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.resource.SkinResourceLoader;
import org.apache.myfaces.trinidad.share.io.NameResolver;
import org.apache.myfaces.trinidad.skin.Icon;
import org.apache.myfaces.trinidad.skin.Skin;
import org.apache.myfaces.trinidad.skin.SkinAddition;
import org.apache.myfaces.trinidad.skin.SkinFactory;
import org.apache.myfaces.trinidad.skin.SkinVersion;
import org.apache.myfaces.trinidad.util.ClassLoaderUtils;
import org.apache.myfaces.trinidadinternal.config.LazyValueExpression;
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 org.apache.myfaces.trinidadinternal.share.xml.ClassParserFactory;
import org.apache.myfaces.trinidadinternal.share.xml.ParseContextImpl;
import org.apache.myfaces.trinidadinternal.share.xml.ParserFactory;
import org.apache.myfaces.trinidadinternal.share.xml.ParserManager;
import org.apache.myfaces.trinidadinternal.share.xml.TreeBuilder;
import org.apache.myfaces.trinidadinternal.share.xml.XMLProvider;
import org.apache.myfaces.trinidadinternal.share.xml.XMLUtils;
import org.apache.myfaces.trinidadinternal.skin.icon.ReferenceIcon;
import org.apache.myfaces.trinidadinternal.skin.parse.SkinAdditionNode;
import org.apache.myfaces.trinidadinternal.skin.parse.SkinNode;
import org.apache.myfaces.trinidadinternal.skin.parse.SkinVersionNode;
import org.apache.myfaces.trinidadinternal.skin.parse.SkinsNode;
import org.apache.myfaces.trinidadinternal.skin.parse.XMLConstants;
import org.xml.sax.InputSource;
/**
* Utility functions for creating Skin objects and SkinExtension objects
* from the trinidad-skins.xml file and
* adding them to the SkinFactory. It also adds SkinAdditions to the Skin objects.
* @version $Name: $ ($Revision: adfrt/faces/adf-faces-impl/src/main/java/oracle/adfinternal/view/faces/skin/SkinUtils.java#0 $) $Date: 10-nov-2005.18:59:00 $
*/
public class SkinUtils
{
/**
* Register the base skins with the SkinFactory. (simple/minimal)
* Make sure the SkinFactory.getFactory() does not return null before
* calling this method.
*/
static public void registerBaseSkins()
{
SkinFactory skinFactory = SkinFactory.getFactory();
// skinFactory should be non-null when this is called since it is
// initiated in the TrinidadFilterImpl, but in case it isn't do this
if (skinFactory == null)
{
SkinFactory.setFactory(new SkinFactoryImpl());
skinFactory = SkinFactory.getFactory();
}
_registerTrinidadSkins(skinFactory);
}
/**
* Register any custom skin extensions (and skin-additions) found in the
* trinidad-skins.xml file with the SkinFactory.
*
* Make sure the SkinFactory.getFactory() does not return null before
* calling this method.
* You should call registerBaseSkins() before calling this method.
* @param context ServletContext, used to get the trinidad-skins.xml file.
*/
static public void registerSkinExtensions(
ExternalContext context)
{
SkinFactory skinFactory = SkinFactory.getFactory();
// skinFactory should be non-null when this is called since it is
// initiated in the TrinidadFilterImpl, but in case it isn't do this
if (skinFactory == null)
{
SkinFactory.setFactory(new SkinFactoryImpl());
skinFactory = SkinFactory.getFactory();
}
boolean fine = _LOG.isFine();
if (fine) _LOG.fine("Begin registerSkinExtensions");
_registerSkinExtensionsAndAdditions(context, skinFactory);
if (fine) _LOG.fine("End registerSkinExtensions");
}
/**
* Returns the actual Icon referenced by the ReferenceIcon.
* @param skin the Skin to use when resolving the ReferenceIcon
* @param refIcon a ReferenceIcon instance
* @return icon which is resolved. i.e., it is not a ReferenceIcon.
*/
static public Icon resolveReferenceIcon(
Skin skin,
ReferenceIcon refIcon)
{
return _resolveReferenceIcon(skin, refIcon, null);
}
/**
* Helper for resolveReferenceIcon which uses a Stack of icon names
* to detect circular dependencies.
*
* @param skin the Skin to use when resolving the ReferenceIcon
* @param refIcon a ReferenceIcon instance
* @param referencedIconStack The stack of reference icon names which have
* already been visited. Used to detect circular dependencies.
* @return icon which is resolved. i.e., it is not a ReferenceIcon.
*/
static private Icon _resolveReferenceIcon(
Skin skin,
ReferenceIcon refIcon,
Stack referencedIconStack)
{
String refName = refIcon.getName();
// make sure we don't have a circular dependency
if ((referencedIconStack != null) && referencedIconStack.contains(refName))
{
if (_LOG.isWarning())
_LOG.warning("SKIN_CIRCULAR_INCLUDE_ERROR", refName);
return null;
}
if (referencedIconStack == null)
{
referencedIconStack = new Stack();
}
referencedIconStack.push(refName);
Icon icon = skin.getIcon(refName, false);
if ((icon instanceof ReferenceIcon) && (icon != null))
{
return _resolveReferenceIcon(skin,
(ReferenceIcon)icon,
referencedIconStack);
}
return icon;
}
/**
* Create a SkinExtension off a generic SAX input source, using
* a custom parsing manager.
*
* @param provider
* @param resolver A NameResolver that can be used to locate
* resources, such as source images for colorized
* icons.
* @param parserManager the ParserManager to use for parsing
* Must be non-null.
* @throws NullPointerException when inputStream or parserManager
* is null.
*/
/**
*
* @param provider an XMLProvider implementation.
* @param resolver A NameResolver that can be used to locate
* resources, such as source images for colorized
* icons.
* @param inputStream the inputStream. Must be non-null
* @param parserManager the ParserManager to use for parsing
* Must be non-null.
* @param configFile The name of the config file we are parsing.
* @return A SkinsNode object (contains a List of SkinNode and a List of SkinAdditionNode)
*/
static private SkinsNode _getSkinsNodeFromInputStream(
XMLProvider provider,
NameResolver resolver,
InputStream inputStream,
ParserManager parserManager,
String configFile
)
{
if (inputStream == null)
throw new NullPointerException(_LOG.getMessage(
"NO_INPUTSTREAM"));
if (parserManager == null)
throw new NullPointerException(_LOG.getMessage(
"NULL_PARSEMANAGER"));
SkinsNode skinsNode = null;
try
{
InputSource input = new InputSource();
input.setByteStream(inputStream);
input.setPublicId(configFile);
ParseContextImpl context = new ParseContextImpl();
// Set up the NameResolver if we have one
if (resolver != null)
XMLUtils.setResolver(context, resolver);
// Create the TreeBuilder
TreeBuilder builder = new TreeBuilder(parserManager,
SkinsNode.class);
skinsNode = ((SkinsNode)builder.parse(provider, input, context));
}
catch (Exception e)
{
_LOG.warning("SKIN_CONFIG_PROCESS_FAILURE", configFile);
_LOG.warning(e);
}
finally
{
try
{
inputStream.close();
}
catch (IOException ioe)
{
// Ignore
;
}
}
return skinsNode;
}
/**
* Creates a ParserManager pre-registered witih all
* the default ParserFactories needed to create SkinExtensions.
*/
static public ParserManager createDefaultManager()
{
ParserManager manager = new ParserManager();
// Register top-level factory
_registerFactory(manager, SkinsNode.class, "SkinsNode");
// Register skin node factory and skin addition node factory
_registerFactory(manager, SkinNode.class, "SkinNode");
_registerFactory(manager, SkinAdditionNode.class, "SkinAdditionNode");
_registerFactory(manager, SkinVersionNode.class, "SkinVersionNode");
return manager;
}
// Returns a singleton instance of the default ParserManager
static private ParserManager _getDefaultManager()
{
if (_sManager == null)
_sManager = createDefaultManager();
return _sManager;
}
// Registers a ParserFactory for the LAF namespace
static private void _registerFactory(
ParserManager manager,
Class> expectedType,
String baseName
)
{
String className = _LAF_PARSE_PACKAGE + baseName + "Parser";
ParserFactory factory = new ClassParserFactory(className);
manager.registerFactory(expectedType,
XMLConstants.SKIN_NAMESPACE,
factory);
}
/**
* register the Trinidad skins: simpleDesktopSkin, simplePdaSkin,
* and minimalDesktopSkin, minimalPdaSkin, casablancaSkin and portlet skins.
* @param skinFactory
*/
private static void _registerTrinidadSkins(
SkinFactory skinFactory)
{
// SimpleDesktopSkin is the BASE skin for org.apache.myfaces.trinidad.desktop renderKit
// SimplePdaSkin is the BASE skin for org.apache.myfaces.trinidad.pda renderKit. By
// BASE skin, I mean, this is the skin that all SkinExtensions extend
// from.
SimpleDesktopSkin simpleDesktopSkin = new SimpleDesktopSkin();
skinFactory.addSkin(simpleDesktopSkin.getId(), simpleDesktopSkin);
SimplePdaSkin simplePdaSkin = new SimplePdaSkin();
skinFactory.addSkin(simplePdaSkin.getId(), simplePdaSkin);
//portlet skin maps most of our style classes to portlet style classes,
// so we output portlet style classes.
// It also clears out the portlet style class definitions.
SimplePortletSkin simplePortletSkin = new SimplePortletSkin();
skinFactory.addSkin(simplePortletSkin.getId(), simplePortletSkin);
MinimalDesktopSkinExtension minimalDesktopSkin =
new MinimalDesktopSkinExtension(simpleDesktopSkin);
skinFactory.addSkin(minimalDesktopSkin.getId(), minimalDesktopSkin);
MinimalPdaSkinExtension minimalPdaSkin =
new MinimalPdaSkinExtension(simplePdaSkin);
skinFactory.addSkin(minimalPdaSkin.getId(), minimalPdaSkin);
MinimalPortletSkinExtension minimalPortletSkin =
new MinimalPortletSkinExtension(simplePortletSkin);
skinFactory.addSkin(minimalPortletSkin.getId(), minimalPortletSkin);
CasablancaDesktopSkin casablancaDesktopSkin = new CasablancaDesktopSkin(simpleDesktopSkin);
skinFactory.addSkin(casablancaDesktopSkin.getId(), casablancaDesktopSkin);
CasablancaPdaSkin casablancaPdaSkin = new CasablancaPdaSkin(simplePdaSkin);
skinFactory.addSkin(casablancaPdaSkin.getId(), casablancaPdaSkin);
CasablancaPortletSkin casablancaPortletSkin = new CasablancaPortletSkin(simplePortletSkin);
skinFactory.addSkin(casablancaPortletSkin.getId(), casablancaPortletSkin);
}
/**
* Parse the trinidad-skins.xml file for SkinExtensions and SkinAdditionNodes and add each
* SkinExtension to the skinFactory and each SkinAddition to its skin.
* First find all the trinidad-skins.xml files that are in META-INF directory, and
* add those skins and skin additions.
* Then find the WEB-INF/trinidad-skins.xml file and add those skins and skin additions.
* The skins are ordered so that the 'extended' skins are registered before the skins that extend
* them.
* @param context
* @param skinFactory
*/
private static void _registerSkinExtensionsAndAdditions(
ExternalContext context,
SkinFactory skinFactory)
{
if (context == null)
return;
// Add META-INF/trinidad-skins.xml skins to skin factory. (sorted first to make sure
// we register the most 'base' skins first)
if (_LOG.isFine()) _LOG.fine("Parse META-INF/trinidad-skins.xml files");
List metaInfSkinsNodeList = _getMetaInfSkinsNodeList();
// Go through each SkinsNode object
// (contains List of SkinNodes and List of SkinAdditionNodes)
// and return a List of the SkinNodes.
List metaInfSkinNodes = new ArrayList();
for (SkinsNode skinsNode : metaInfSkinsNodeList)
{
List skinNodes = skinsNode.getSkinNodes();
if (skinNodes != null)
metaInfSkinNodes.addAll(skinNodes);
}
List sortedMetaInfSkinNodes = _sortSkinNodes(skinFactory, metaInfSkinNodes);
for (SkinNode skinNode : sortedMetaInfSkinNodes)
{
_addSkinToFactory(skinFactory, skinNode, true);
}
// Add WEB-INF/trinidad-skins.xml skins to skin factory. (sorted first)
if (_LOG.isFine()) _LOG.fine("Parse WEB-INF/trinidad-skins.xml files");
SkinsNode webInfSkinsNode = _getWebInfSkinsNode(context);
if (webInfSkinsNode != null)
{
List webInfSkinNodes = webInfSkinsNode.getSkinNodes();
List sortedWebInfSkinNodes = _sortSkinNodes(skinFactory, webInfSkinNodes);
// register skins found in webInfSkinNodes
for (SkinNode skinNode : sortedWebInfSkinNodes)
{
_addSkinToFactory(skinFactory, skinNode, false);
}
}
// register all the skin additions from META-INF trinidad-skins.xml and WEB-INF
// trinidad-skins.xml that we have stored in the metaInfSkinsNodeList object and the
// webInfSkinsNode object
// skin-additions are additions to a skin, not extensions. They are used by
// custom component developers that want to add a stylesheet for their components
// to a particular skin, like the simple skin.
FacesContext fContext = FacesContext.getCurrentInstance();
// register skin-additions from META-INF/trinidad-skins.xml files
_registerMetaInfSkinAdditions(fContext, skinFactory, metaInfSkinsNodeList);
// register skin-additions from WEB-INF/trinidad-skins.xml file
if (webInfSkinsNode != null)
{
List skinAdditionNodeList = webInfSkinsNode.getSkinAdditionNodes();
_registerSkinAdditions(fContext, skinFactory, skinAdditionNodeList, false);
}
_registerTrinidadSkinsFromSkinResourceLoaderServices(context, skinFactory);
}
// this finds the trinidad-skins.xml files by calling findResource on any SkinResourceLoader
// services. This is used by the DT to find trinidad-skins.xml files that are not in META-INF
// or WEB-INF. See TRINIDAD-1914
private static void _registerTrinidadSkinsFromSkinResourceLoaderServices(
ExternalContext context,
SkinFactory skinFactory)
{
if (_LOG.isFine()) _LOG.fine("Parse SkinResourceLoader trinidad-skins.xml");
// register skins found in DT using the META-INF/services
List urlProviders = ClassLoaderUtils.getServices(
"org.apache.myfaces.trinidad.resource.SkinResourceLoader");
if (urlProviders != null && !urlProviders.isEmpty())
{
List additionalSkins = _getAdditionalTrinidadSkins(context, urlProviders);
// Go through each SkinsNode object
// (contains List of SkinNodes and List of SkinAdditionNodes)
// and return a List of the SkinNodes.
List additionalSkinNodeList = new ArrayList();
for (SkinsNode skinsNode : additionalSkins)
{
additionalSkinNodeList.addAll(skinsNode.getSkinNodes());
}
List sortedAdditionalSkinNodes = _sortSkinNodes(skinFactory, additionalSkinNodeList);
for (SkinNode skinNode : sortedAdditionalSkinNodes)
{
if (_LOG.isFine()) _LOG.fine("Skin {0} with stylesheet {1}",
new Object[]{skinNode.getId(), skinNode.getStyleSheetName()});
_addSkinToFactory(skinFactory, skinNode, false);
}
}
}
/**
* Given the a List of SkinNodes, sort them so that the SkinNodes in such a way so that
* when we register the skins we make sure that the 'base' skins are registered before
* skins that extend them.
* @param skinFactory
* @param skinNodes
* @return sorted List of SkinNodes
*/
private static List _sortSkinNodes(
SkinFactory skinFactory,
List skinNodes)
{
List sortedSkinNodes = new ArrayList();
List skinNodesAdded = new ArrayList();
List baseSkinIds = new ArrayList();
for (Iterator i = skinFactory.getSkinIds(); i.hasNext();)
{
baseSkinIds.add(i.next());
}
// first, the skins that don't extend anything
for (SkinNode skinNode : skinNodes)
{
String skinExtends = skinNode.getSkinExtends();
if (skinExtends == null)
{
sortedSkinNodes.add(skinNode);
skinNodesAdded.add(skinNode.getId());
}
}
// second, the skins that extend another skin
_sortSkinNodesWithExtensions(skinNodes, sortedSkinNodes, skinNodesAdded, baseSkinIds, 0);
return sortedSkinNodes;
}
/**
* This sorts SkinNodes that have their 'extends' value set, which means the skin
* extends another skin. The order of our skin nodes matters in this case. We want the
* base skin to be registered first.
* @param skinNodes
* @param sortedSkinNodes
* @param skinNodesAdded
* @param baseSkinIds
*/
private static void _sortSkinNodesWithExtensions(
List skinNodes,
List sortedSkinNodes,
List skinNodesAdded,
List baseSkinIds,
int originalLeftOverListSize)
{
List leftOverList = new ArrayList();
for (SkinNode skinNode : skinNodes)
{
String skinExtends = skinNode.getSkinExtends();
if (skinExtends != null)
{
if (skinNodesAdded.contains(skinExtends) ||
baseSkinIds.contains(skinExtends))
{
sortedSkinNodes.add(skinNode);
skinNodesAdded.add(skinNode.getId());
}
else
{
// left over, put in a left-over list
leftOverList.add(skinNode);
}
}
}
if ((originalLeftOverListSize > 0) &&
(leftOverList.size() == originalLeftOverListSize))
{
// Ok, we are left with skinNodes that cannot be registered because the skin they extend is
// not in the skinNodesAdded List. The skin they extend might not exist at all, or
// there is a circular dependency.
// So..., just add these to the list. When we register these, they will cause a severe error
// and the default base skin will be used.
StringBuffer buffer = new StringBuffer();
for (SkinNode leftOverNode : leftOverList)
{
buffer.append("Skin with id: " + leftOverNode.getId() +
" extends skin with id: " + leftOverNode.getSkinExtends() + "\n");
sortedSkinNodes.add(leftOverNode);
skinNodesAdded.add(leftOverNode.getId());
}
_LOG.warning("The following skins extend each other in a circular " +
"fashion or the skin they extend does not exist.\n" + buffer.toString());
}
else if (leftOverList.size() > 0)
{
_sortSkinNodesWithExtensions(leftOverList, sortedSkinNodes,
skinNodesAdded, baseSkinIds, leftOverList.size());
}
}
/**
* Given a skinNode, create a Skin object and
* register the SkinExtension object with the skinFactory
* @param skinFactory
* @param skinNode
*/
private static void _addSkinToFactory(
SkinFactory skinFactory,
SkinNode skinNode,
boolean isMetaInfFile)
{
// if the renderKitId is not specified,
// set it to _RENDER_KIT_ID_CORE.
String renderKitId = skinNode.getRenderKitId();
String id = skinNode.getId();
String family = skinNode.getFamily();
String styleSheetName = skinNode.getStyleSheetName();
String bundleName = skinNode.getBundleName();
String translationSourceExpression =
skinNode.getTranslationSourceExpression();
SkinVersionNode skinVersionNode = skinNode.getSkinVersionNode();
SkinVersion skinVersion = _createSkinVersion(skinVersionNode);
if (renderKitId == null)
renderKitId = _RENDER_KIT_ID_DESKTOP;
// figure out the base skin.
Skin baseSkin = null;
String skinExtends = skinNode.getSkinExtends();
if (skinExtends != null)
baseSkin = skinFactory.getSkin(null, skinExtends);
if (baseSkin == null)
{
baseSkin = _getDefaultBaseSkin(skinFactory, renderKitId);
if (skinExtends != null)
{
_LOG.severe("UNABLE_LOCATE_BASE_SKIN",
new String[]{skinExtends, id, family, renderKitId, baseSkin.getId()});
}
}
// Set the style sheet
if (styleSheetName != null)
{
// If the styleSheetName is in the META-INF/trinidad-skins.xml file, then
// we prepend META-INF to the styleSheetName if it doesn't begin with '/'.
// This way we can find the file when we go to parse it later.
if (isMetaInfFile)
styleSheetName = _prependMetaInf(styleSheetName);
}
// If bundleName and translationSourceExpression are both set, then we
// only use the bundleName. An error was already logged during trinidad-skins
// parsing.
Skin skin = null;
// bundle-name takes precedence over translation-source
if (bundleName != null)
{
skin = new SkinExtension(baseSkin,
id,
family,
renderKitId,
styleSheetName,
bundleName,
skinVersion);
}
else
{
ValueExpression translationSourceVE = null;
if (translationSourceExpression != null)
{
translationSourceVE =
_createTranslationSourceValueExpression(translationSourceExpression);
}
if (translationSourceVE != null)
{
skin = new SkinExtension(baseSkin,
id,
family,
renderKitId,
styleSheetName,
translationSourceVE,
skinVersion);
}
else
{
skin = new SkinExtension(baseSkin,
id,
family,
renderKitId,
styleSheetName,
skinVersion);
}
}
// Create a SkinExtension object and register skin with factory
skinFactory.addSkin(id, skin);
}
private static ValueExpression
_createTranslationSourceValueExpression(
String translationSourceExpression)
{
if (translationSourceExpression != null)
{
translationSourceExpression = translationSourceExpression.trim();
return LazyValueExpression.createValueExpression(translationSourceExpression,
Object.class);
}
else
return null;
}
// Create a SkinVersion object from the SkinVersionNode object.
private static SkinVersion _createSkinVersion(SkinVersionNode skinVersionNode)
{
if (skinVersionNode != null)
{
String name = skinVersionNode.getName();
boolean isDefault = skinVersionNode.isDefault();
if ("".equals(name) && !isDefault)
return SkinVersion.EMPTY_SKIN_VERSION;
else
return new SkinVersion(name, isDefault);
}
else
return SkinVersion.EMPTY_SKIN_VERSION;
}
/**
* Get the WEB-INF/trinidad-skins.xml file, parse it, and return a List of SkinsNode objects.
* @param context ServletContext used to getResourceAsStream
* @return List of SkinNodes (skin elements) found in trinidad-skins.xml
*/
private static SkinsNode _getWebInfSkinsNode(
ExternalContext context)
{
InputStream in = context.getResourceAsStream(_CONFIG_FILE);
if (in != null)
{
SkinsNode webInfSkinsNode =
_getSkinsNodeFromInputStream(null, null, in, _getDefaultManager(), _CONFIG_FILE);
if (_LOG.isFine())
{
for (SkinNode node : webInfSkinsNode.getSkinNodes())
{
_LOG.fine("Skin {0} with stylesheet {1}",
new Object[]{node.getId(), node.getStyleSheetName()});
}
for (SkinAdditionNode node: webInfSkinsNode.getSkinAdditionNodes())
{
_LOG.fine("SkinAddition {0} with stylesheet {1}",
new Object[]{node.getSkinId(), node.getStyleSheetName()});
}
}
return webInfSkinsNode;
}
else
{
return null;
}
}
/**
* Get all the META-INF/trinidad-skins.xml files, parse them, and from each file we get
* a SkinsNode object -- the information inside the <skins> element -- each skin
* and each skin-addition.
* @return Each SkinsNode object we get from each META-INF/trinidad-skins.xml file,
* in a List.
*/
private static List _getMetaInfSkinsNodeList()
{
List allSkinsNodes = new ArrayList();
ClassLoader loader = Thread.currentThread().getContextClassLoader();
try
{
Enumeration urls = loader.getResources(_META_INF_CONFIG_FILE);
Set urlPaths = new HashSet(16);
while (urls.hasMoreElements())
{
URL url = urls.nextElement();
// if url matches one we've already processed, skip it
boolean successfullyAdded = urlPaths.add(url.getPath());
// _processTrinidadSkinsURL logs the url we are processing
_processTrinidadSkinsURL(allSkinsNodes, url, successfullyAdded);
}
}
catch (IOException e)
{
_LOG.severe("ERR_LOADING_FILE", _META_INF_CONFIG_FILE);
_LOG.severe(e);
}
return allSkinsNodes;
}
private static Skin _getDefaultBaseSkin(
SkinFactory factory,
String renderKitId)
{
String baseSkinId = (_RENDER_KIT_ID_PDA.equals(renderKitId)) ?
_SIMPLE_PDA_SKIN_ID :
_SIMPLE_DESKTOP_SKIN_ID;
Skin baseSkin = factory.getSkin(null, baseSkinId);
// It is an error if we were unable to find the base skin
if (baseSkin == null)
_LOG.severe(_UNKNOWN_BASE_SKIN_ERROR + baseSkinId);
return baseSkin;
}
// register the META-INF skin additions.
// It should not matter what order we process skin-additions since they should not
// depend upon one another.
// We sort them by style-sheet-name so the StyleSheetDocumentId will be the same regardless
// of order. Portals are using the styleSheetDocumentId to determine if the producer's skin
// matches the consumer's skin, and the order of the skin-additions should not change this.
private static void _registerMetaInfSkinAdditions(
FacesContext fContext,
SkinFactory skinFactory,
List metaInfSkinsNodeList)
{
List skinAdditionNodeList = new ArrayList();
for (SkinsNode skinsNode : metaInfSkinsNodeList)
{
skinAdditionNodeList.addAll(skinsNode.getSkinAdditionNodes());
}
Collections.sort(skinAdditionNodeList);
_registerSkinAdditions(fContext, skinFactory, skinAdditionNodeList, true);
}
/**
* Get the skin id and other information from each SkinAdditionNode and
* get the skin and register the SkinAddition with the skin
* @param fContext
* @param skinFactory
* @param skinAdditionNodeList
* @param isMetaInfFile true if the trinidad-skins.xml file is in the META-INF
* directory.
*/
private static void _registerSkinAdditions(
FacesContext fContext,
SkinFactory skinFactory,
List skinAdditionNodeList,
boolean isMetaInfFile
)
{
for (SkinAdditionNode skinAdditionNode : skinAdditionNodeList)
{
String skinId = skinAdditionNode.getSkinId();
String styleSheetName = skinAdditionNode.getStyleSheetName();
String resourceBundleName = skinAdditionNode.getResourceBundleName();
String translationSourceExpression =
skinAdditionNode.getTranslationSourceExpression();
Skin skin = skinFactory.getSkin(fContext, skinId);
if (skin != null
&& ((styleSheetName != null)
|| (resourceBundleName != null)
|| (translationSourceExpression != null)))
{
// If the styleSheetName is in the META-INF/trinidad-skins.xml file, then
// we prepend META-INF to the styleSheetName if it doesn't begin with '/'.
// This way we can find the file when we go to parse it later.
if (isMetaInfFile && (styleSheetName != null))
styleSheetName = _prependMetaInf(styleSheetName);
SkinAddition addition = null;
if (resourceBundleName != null)
{
// create SkinAddition with resourceBundleName
addition = new SkinAddition(styleSheetName, resourceBundleName);
}
else
{
ValueExpression translationSourceVE = null;
if (translationSourceExpression != null)
{
translationSourceVE =
_createTranslationSourceValueExpression(translationSourceExpression);
}
if (translationSourceVE != null)
{
// Create a SkinAddition with translationSourceVE
addition = new SkinAddition(styleSheetName, translationSourceVE);
}
else
{
// Create a SkinAddition with stylesheetName only
addition = new SkinAddition(styleSheetName);
}
}
skin.addSkinAddition(addition);
}
}
}
/**
* Prepend META-INF to the styleSheetName if it doesn't begin with '/'.
* @param styleSheetName
* @return String styleSheetName or the styleSheetName prepended with META-INF/
*/
private static String _prependMetaInf(String styleSheetName)
{
if (!(styleSheetName.startsWith("/")))
return _META_INF_DIR.concat(styleSheetName);
else
return styleSheetName;
}
// register skins found in DT using the META-INF/services
private static List _getAdditionalTrinidadSkins(
ExternalContext context,
List providers)
{
Set urlPaths = new HashSet(16);
List allSkinsNodes = new ArrayList();
for (SkinResourceLoader urlProvider : providers )
{
Iterator urlIterator = urlProvider.findResources(context, _TRINIDAD_SKINS_XML);
if (urlIterator != null)
{
try
{
while (urlIterator.hasNext())
{
URL url = urlIterator.next();
// if url matches one we've already processed, skip it
boolean successfullyAdded = urlPaths.add(url.getPath());
// _processTrinidadSkinsURL logs the url we are processing
_processTrinidadSkinsURL(allSkinsNodes, url, successfullyAdded);
}
}
catch (IOException e)
{
_LOG.severe("ERR_LOADING_FILE", _META_INF_CONFIG_FILE);
_LOG.severe(e);
}
}
}
return allSkinsNodes;
}
private static void _processTrinidadSkinsURL(
List allSkinsNodes,
URL url,
boolean successfullyAdded)
throws IOException
{
if (!successfullyAdded)
{
if (_LOG.isFine())
{
_LOG.fine("Skipping skin URL:{0} because it was already processed. " +
"It was on the classpath more than once.",
url);
}
// continue to the next url
}
else
{
if (_LOG.isFine()) _LOG.fine("Processing skin URL:{0}", url);
URLConnection urlConnection = url.openConnection();
// prevent caching during DT where the source may change...
if (Beans.isDesignTime())
{
urlConnection.setUseCaches(false);
}
InputStream in = urlConnection.getInputStream();
try
{
// parse the config file and register the skin's additional stylesheets.
if (in != null)
{
SkinsNode metaInfSkinsNode =
_getSkinsNodeFromInputStream(null, null, in,
_getDefaultManager(),
url.toString());
if (metaInfSkinsNode != null)
{
// for debug only.
if (_LOG.isFine())
{
for (SkinNode node : metaInfSkinsNode.getSkinNodes())
_LOG.fine("Skin {0} with stylesheet {1}",
new Object[]{node.getId(), node.getStyleSheetName()});
for (SkinAdditionNode node: metaInfSkinsNode.getSkinAdditionNodes())
_LOG.fine("SkinAddition {0} with stylesheet {1}",
new Object[]{node.getSkinId(), node.getStyleSheetName()});
}
allSkinsNodes.add(metaInfSkinsNode);
}
else
{
if(_LOG.isFine()) _LOG.fine("No skins found in the URL.");
}
}
}
catch (Exception e)
{
_LOG.warning("ERR_PARSING", url);
_LOG.warning(e);
}
finally
{
in.close();
}
}
}
private SkinUtils() {}
// The default ParserManager
static private ParserManager _sManager;
// Constants
// Prefix of LAf parsing package
static private final String _LAF_PARSE_PACKAGE =
"org.apache.myfaces.trinidadinternal.skin.parse.";
static private final String _CONFIG_FILE = "/WEB-INF/trinidad-skins.xml";
static private final String _META_INF_CONFIG_FILE = "META-INF/trinidad-skins.xml";
static private final String _TRINIDAD_SKINS_XML = "trinidad-skins.xml";
static private final String _META_INF_DIR = "META-INF/";
static private final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(SkinUtils.class);
// Error messages
private static final String _UNKNOWN_BASE_SKIN_ERROR =
"Unable to locate base skin: ";
static private final String _RENDER_KIT_ID_DESKTOP = "org.apache.myfaces.trinidad.desktop";
static private final String _RENDER_KIT_ID_PDA = "org.apache.myfaces.trinidad.pda";
static private final String _SIMPLE_PDA_SKIN_ID = "simple.pda";
static private final String _SIMPLE_DESKTOP_SKIN_ID = "simple.desktop";
}