You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by an...@apache.org on 2012/03/21 20:33:47 UTC
svn commit: r1303525 [2/3] - in /myfaces/trinidad/trunk:
src/site/xdoc/devguide/
trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/
trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/
trinidad-api/src/main/xrts/org/apache/myfaces/...
Added: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/share/nls/NullLocaleContext.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/share/nls/NullLocaleContext.java?rev=1303525&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/share/nls/NullLocaleContext.java (added)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/share/nls/NullLocaleContext.java Wed Mar 21 19:33:45 2012
@@ -0,0 +1,112 @@
+/*
+ * 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.share.nls;
+
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.util.TimeZone;
+
+import org.apache.myfaces.trinidad.context.LocaleContext;
+
+/**
+ * LocaleContext implementation for cases where the Locale is
+ * null/unknown.
+ */
+public final class NullLocaleContext extends LocaleContext
+{
+ public static LocaleContext getLeftToRightContext()
+ {
+ return _LTR_INSTANCE;
+ }
+
+ public static LocaleContext getRightToLeftContext()
+ {
+ return _RTL_INSTANCE;
+ }
+
+ @Override
+ public Locale getFormattingLocale()
+ {
+ return null;
+ }
+
+ @Override
+ public String getFormattingIANALocaleString()
+ {
+ return null;
+ }
+
+ @Override
+ public Locale getTranslationLocale()
+ {
+ return null;
+ }
+
+ @Override
+ public String getTranslationIANALocaleString()
+ {
+ return null;
+ }
+
+ @Override
+ public boolean isRightToLeft()
+ {
+ return _rightToLeft;
+ }
+
+ @Override
+ public TimeZone getTimeZone()
+ {
+ return null;
+ }
+
+ @Override
+ public ResourceBundle getBundle(String baseBundleName)
+ {
+ return null;
+ }
+
+ @Override
+ public int getTwoDigitYearStart()
+ {
+ return 0;
+ }
+
+ @Override
+ public char getGroupingSeparator()
+ {
+ return 0;
+ }
+
+ @Override
+ public char getDecimalSeparator()
+ {
+ return 0;
+ }
+
+ private NullLocaleContext(boolean rightToLeft)
+ {
+ _rightToLeft = rightToLeft;
+ }
+
+ private final boolean _rightToLeft;
+
+ private static final LocaleContext _RTL_INSTANCE = new NullLocaleContext(true);
+ private static final LocaleContext _LTR_INSTANCE = new NullLocaleContext(false);
+}
Modified: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/AgentAtRuleMatcher.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/AgentAtRuleMatcher.java?rev=1303525&r1=1303524&r2=1303525&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/AgentAtRuleMatcher.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/AgentAtRuleMatcher.java Wed Mar 21 19:33:45 2012
@@ -20,6 +20,7 @@ package org.apache.myfaces.trinidadinter
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -31,10 +32,13 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.myfaces.trinidad.context.Version;
+import org.apache.myfaces.trinidad.util.Range;
+
import org.apache.myfaces.trinidad.logging.TrinidadLogger;
import org.apache.myfaces.trinidadinternal.agent.TrinidadAgent;
import org.apache.myfaces.trinidadinternal.style.util.NameUtils;
+
/**
* Threadsafe immutable class that stores the @agent rule for a particular @agent query string
* from the skinning css file (e.g., @agent ie and (version:5), ie and (version:6), gecko {}).
@@ -44,7 +48,6 @@ import org.apache.myfaces.trinidadintern
*/
public final class AgentAtRuleMatcher
{
-
/**
* Enumeration representing the result of a call to <code>match</code>.
* @see #match
@@ -219,6 +222,69 @@ public final class AgentAtRuleMatcher
}
/**
+ * Returns a non-null Collection of agent applications that are matched by
+ * this matcher.
+ */
+ public Collection<TrinidadAgent.Application> getAllApplications()
+ {
+ return new ArrayList<TrinidadAgent.Application>(_selectorAgents.keySet());
+ }
+
+ /**
+ * Returns a non-null collection of agent version ranges that are matched by
+ * this matcher.
+ *
+ * @param application the agent application for which matching version ranges
+ * should be returned.
+ */
+ public Collection<Range<Version>> getAllVersionsForApplication(TrinidadAgent.Application application)
+ {
+ Collection<Range<Version>> versionRanges = new HashSet<Range<Version>>();
+ Collection<AgentMatcher> agentMatchers = _selectorAgents.get(application);
+
+ for (AgentMatcher agentMatcher : agentMatchers)
+ {
+ Range<Version> versionRange = agentMatcher.getMatchedVersions();
+ assert(versionRange != null);
+
+ versionRanges.add(versionRange);
+ }
+
+ return versionRanges;
+ }
+
+ /**
+ * Returns a non-null range of versions that represent that intersection
+ * of all verions that:
+ *
+ * a) are matched by this matcher, and...
+ * b) contain the specified agent version.
+ *
+ * @param application the agent application for which matching version ranges
+ * should be returned.
+ * @param agentVersion only ranges that contain this version will be matched.
+ */
+ public Range<Version> getMatchedVersionsForApplication(
+ TrinidadAgent.Application application,
+ Version agentVersion
+ )
+ {
+ Collection<Range<Version>> allVersions = getAllVersionsForApplication(application);
+
+ Range<Version> matchedVersions = Version.ALL_VERSIONS;
+
+ for (Range<Version> range : allVersions)
+ {
+ if (range.contains(agentVersion))
+ {
+ matchedVersions = matchedVersions.intersect(range);
+ }
+ }
+
+ return matchedVersions;
+ }
+
+ /**
* Parses touchScreen rule and creates appropriate AgentMatcher
* @param currSelector
*/
@@ -490,6 +556,17 @@ public final class AgentAtRuleMatcher
* @return <code>true</code> if the match succeeds
*/
public abstract boolean match(TrinidadAgent agent);
+
+ /**
+ * Returns the versions matched by this AgentMatcher.
+ *
+ * By default, all versions are matched. Subclasses should
+ * override to constrain to the versions that they match.
+ */
+ public Range<Version> getMatchedVersions()
+ {
+ return Version.ALL_VERSIONS;
+ }
@Override
public abstract int hashCode();
@@ -556,6 +633,29 @@ public final class AgentAtRuleMatcher
}
@Override
+ public Range<Version> getMatchedVersions()
+ {
+ Version start = Version.MIN_VERSION;
+ Version end = Version.MAX_VERSION;
+
+ switch (_comparison)
+ {
+ case MIN:
+ start = _version.toMinimumVersion();
+ break;
+ case MAX:
+ end = _version.toMaximumVersion();
+ break;
+ case EQUALS:
+ start = _version.toMinimumVersion();;
+ end = _version.toMaximumVersion();;
+ break;
+ }
+
+ return Range.of(start, end);
+ }
+
+ @Override
public final int hashCode()
{
return _hashCode;
@@ -613,23 +713,28 @@ public final class AgentAtRuleMatcher
// their hash codes each time our hash code is called
_hashCode = matchers.hashCode();
+ boolean hasVersionMatcher = false;
+ boolean hasTouchMatcher = false;
for (AgentMatcher matcher : matchers)
{
if (matcher instanceof VersionMatcher)
hasVersionMatcher = true;
if (matcher instanceof TouchScreenCapabilityMatcher)
- hasTouchScreenCapabilityMatcher = true;
+ hasTouchMatcher = true;
}
+
+ _hasVersionMatcher = hasVersionMatcher;
+ _hasTouchScreenCapabilityMatcher = hasTouchMatcher;
}
protected boolean hasTouchScreenCapabilityMatcher()
{
- return hasTouchScreenCapabilityMatcher;
+ return _hasTouchScreenCapabilityMatcher;
}
protected boolean hasVersionMatcher()
{
- return hasVersionMatcher;
+ return _hasVersionMatcher;
}
/**
@@ -654,6 +759,19 @@ public final class AgentAtRuleMatcher
}
@Override
+ public Range<Version> getMatchedVersions()
+ {
+ Range<Version> versionRange = Version.ALL_VERSIONS;
+
+ for (AgentMatcher matcher : _matchers)
+ {
+ versionRange = versionRange.intersect(matcher.getMatchedVersions());
+ }
+
+ return versionRange;
+ }
+
+ @Override
public int hashCode()
{
return _hashCode;
@@ -683,11 +801,12 @@ public final class AgentAtRuleMatcher
return super.toString() + ", matchers=" + _matchers;
}
+
+
private final List<AgentMatcher> _matchers;
private final int _hashCode;
- private boolean hasVersionMatcher;
- private boolean hasTouchScreenCapabilityMatcher;
-
+ private final boolean _hasVersionMatcher;
+ private final boolean _hasTouchScreenCapabilityMatcher;
}
/**
Added: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/AllVariantsSkinPregenerator.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/AllVariantsSkinPregenerator.java?rev=1303525&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/AllVariantsSkinPregenerator.java (added)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/AllVariantsSkinPregenerator.java Wed Mar 21 19:33:45 2012
@@ -0,0 +1,278 @@
+/*
+ * 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.pregen;
+
+import java.util.HashSet;
+import java.util.List;
+
+import java.util.Set;
+
+import javax.faces.context.FacesContext;
+
+import org.apache.myfaces.trinidad.logging.TrinidadLogger;
+import org.apache.myfaces.trinidad.skin.Skin;
+
+import org.apache.myfaces.trinidadinternal.agent.TrinidadAgent.Application;
+import org.apache.myfaces.trinidadinternal.skin.DocumentProviderSkin;
+import org.apache.myfaces.trinidadinternal.skin.pregen.config.PregenConfig;
+import org.apache.myfaces.trinidadinternal.skin.pregen.context.PregenStyleContext;
+import org.apache.myfaces.trinidadinternal.skin.pregen.variant.SkinVariant;
+import org.apache.myfaces.trinidadinternal.skin.pregen.variant.SkinVariants;
+import org.apache.myfaces.trinidadinternal.style.StyleContext;
+import org.apache.myfaces.trinidadinternal.style.StyleProvider;
+import org.apache.myfaces.trinidadinternal.style.util.NameUtils;
+import org.apache.myfaces.trinidadinternal.style.xml.parse.StyleSheetDocument;
+import org.apache.myfaces.trinidadinternal.style.xml.parse.StyleSheetNode;
+
+/**
+ * SkinPregenerator implementation that generates all possible style
+ * sheet variants for the skin.
+ *
+ * This class is not thread safe.
+ */
+class AllVariantsSkinPregenerator implements SkinPregenerator
+{
+ @Override
+ public void pregenerate(
+ FacesContext context,
+ Skin skin,
+ PregenConfig config,
+ StyleProvider provider
+ )
+ {
+ _pregenerateWithStats(context, skin, config, provider);
+ }
+
+ private void _pregenerateWithStats(
+ FacesContext context,
+ Skin skin,
+ PregenConfig config,
+ StyleProvider provider
+ )
+ {
+ Stats stats = new Stats(skin, config);
+ stats.start();
+
+ try
+ {
+ _pregenerate(context, skin, config, provider, stats);
+ }
+ finally
+ {
+ stats.end();
+ }
+ }
+
+ private void _pregenerate(
+ FacesContext context,
+ Skin skin,
+ PregenConfig config,
+ StyleProvider provider,
+ Stats stats
+ )
+ {
+ StyleSheetDocument document = _getDocumentForSkin(context, skin, config, provider);
+ _pregenerateAllVariants(context, config, provider, document, stats);
+ }
+
+ private StyleSheetDocument _getDocumentForSkin(
+ FacesContext context,
+ Skin skin,
+ PregenConfig config,
+ StyleProvider provider
+ )
+ {
+ StyleSheetDocument document = null;
+
+ if (skin instanceof DocumentProviderSkin)
+ {
+ StyleContext styleContext =
+ PregenStyleContext.documentContext(context, provider, config.getTargetDirectoryPath());
+ document = ((DocumentProviderSkin) skin).getStyleSheetDocument(styleContext);
+ }
+
+ if (document == null)
+ {
+ _LOG.warning("SKIN_PREGEN_NO_DOCUMENT", skin.getId());
+ document = _EMPTY_DOCUMENT;
+ }
+
+ return document;
+ }
+
+ private void _pregenerateAllVariants(
+ FacesContext context,
+ PregenConfig config,
+ StyleProvider provider,
+ StyleSheetDocument document,
+ Stats stats
+ )
+ {
+ SkinVariants variants = new SkinVariants(document, config);
+
+ for (SkinVariant variant : variants)
+ {
+ _pregenerateVariant(context, config, provider, variant, stats);
+ }
+ }
+
+ private void _pregenerateVariant(
+ FacesContext context,
+ PregenConfig config,
+ StyleProvider provider,
+ SkinVariant variant,
+ Stats stats
+ )
+ {
+ StyleContext styleContext = _createStyleContext(context,
+ config,
+ provider,
+ variant);
+
+ // This, finally, triggers pregeneration for the current variant.
+ List<String> uris = provider.getStyleSheetURIs(styleContext);
+
+ stats.variant(variant, uris);
+ _variant = variant;
+ }
+
+ private StyleContext _createStyleContext(
+ FacesContext context,
+ PregenConfig config,
+ StyleProvider provider,
+ SkinVariant variant
+ )
+ {
+ assert(variant != null);
+
+ return new PregenStyleContext(context,
+ provider,
+ config.getTargetDirectoryPath(),
+ variant,
+ _isDirty(variant));
+ }
+
+ // Tests whether we should dirty the style provider when pregenerating
+ // the specified variant. FileSystemStyleCache currently does not prune
+ // memory used by its entry caches. During pregeneration, these caches
+ // become fully populated, which can put significant pressure on the heap.
+ // We keep memory usage in check by allowing the style provider to free
+ // up its caches from time to time.
+ private boolean _isDirty(SkinVariant variant)
+ {
+ // Switching between platforms seems like as good a time as any to let
+ // the style provider reset its caches. This promotes cache reuse within
+ // each platform variant while not letting cache size get too out of control.
+ return ((_variant != null) && (_variant.getPlatform() != variant.getPlatform()));
+ }
+
+ // Little utility class for tracking statistics (eg.
+ // # of generated style sheets, duration, etc...)
+ private class Stats
+ {
+ public Stats(Skin skin, PregenConfig config)
+ {
+ _skin = skin;
+ _targetDirectoryPath = config.getTargetDirectoryPath();
+ }
+
+ public void start()
+ {
+ _logStartMessage();
+ _startTime = System.currentTimeMillis();
+ }
+
+ public void variant(SkinVariant variant, List<String> uris)
+ {
+ _visitedVariantsCount++;
+
+ if (_isNewURI(uris))
+ {
+ _generatingVariantsCount++;
+ _uris.addAll(uris);
+ }
+
+ _logVariant(variant);
+ }
+
+ public void end()
+ {
+ long endTime = System.currentTimeMillis();
+ _logEndMessage(endTime);
+ }
+
+ private boolean _isNewURI(List<String> uris)
+ {
+ return ((uris != null) && !uris.isEmpty() && !_uris.contains(uris.get(0)));
+ }
+
+ private void _logStartMessage()
+ {
+ _LOG.info("SKIN_PREGEN_STARTING", _skin.getId());
+ }
+
+ private void _logEndMessage(long endTime)
+ {
+ long duration = (endTime - _startTime);
+
+ _LOG.info("SKIN_PREGEN_COMPLETED",
+ new Object[] {
+ _skin.getId(),
+ _uris.size(),
+ _generatingVariantsCount,
+ _visitedVariantsCount,
+ duration,
+ _targetDirectoryPath});
+ }
+
+ private void _logVariant(SkinVariant variant)
+ {
+ assert(variant != null);
+ int platform = variant.getPlatform();
+ Application agentApplication = variant.getApplicationAndVersion().application;
+
+ if ((_variant == null) ||
+ (platform != _variant.getPlatform()) ||
+ (agentApplication != _variant.getApplicationAndVersion().application))
+ {
+ _LOG.info("SKIN_PREGEN_VARIANT",
+ new Object[] {
+ NameUtils.getPlatformName(platform),
+ agentApplication.getAgentName(),
+ _skin.getId() });
+ }
+ }
+
+ private final Skin _skin;
+ private final String _targetDirectoryPath;
+ private final Set<String> _uris = new HashSet<String>(101);
+ private int _visitedVariantsCount = 0;
+ private int _generatingVariantsCount = 0;
+ private long _startTime = -1;
+ }
+
+ // The variant that we are currently processing
+ private SkinVariant _variant;
+
+ private static final StyleSheetDocument _EMPTY_DOCUMENT =
+ new StyleSheetDocument(new StyleSheetNode[0], null, StyleSheetDocument.UNKNOWN_TIMESTAMP);
+
+ private static final TrinidadLogger _LOG =
+ TrinidadLogger.createTrinidadLogger(AllVariantsSkinPregenerator.class);
+}
Added: 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=1303525&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/SkinPregenerationService.java (added)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/SkinPregenerationService.java Wed Mar 21 19:33:45 2012
@@ -0,0 +1,315 @@
+/*
+ * 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.pregen;
+
+import java.io.IOException;
+
+import java.util.Map;
+
+import javax.faces.FacesException;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+
+import javax.faces.context.ResponseWriter;
+
+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.util.Enums;
+import org.apache.myfaces.trinidadinternal.skin.pregen.config.InvalidConfigException;
+import org.apache.myfaces.trinidadinternal.skin.pregen.config.PregenConfig;
+
+/**
+ * InternalView implementation that provides skin pregeneration service.
+ *
+ * See the "Pre-generating Skin Style Sheets" section in the Skinning chapter
+ * of the Trinidad Developer's Guide for the specification of this service.
+ */
+public class SkinPregenerationService extends InternalView
+{
+ /**
+ * Tests whether the pregeneration service is enabled.
+ */
+ public static boolean isEnabled()
+ {
+ return (_getServiceStatus() == ServiceStatus.ON);
+ }
+
+ /**
+ * Tests whether the view id corresponds to a skin pregeneration request.
+ */
+ public static boolean isPregenerationRequest(String viewId)
+ {
+ return _VIEW_ID.equals(viewId);
+ }
+
+ @Override
+ public UIViewRoot createView(FacesContext context, String viewId)
+ {
+ return null;
+ }
+
+ @Override
+ public UIViewRoot restoreView(FacesContext context, String viewId)
+ {
+ return null;
+ }
+
+ @Override
+ public void renderView(FacesContext context, UIViewRoot viewToRender)
+ throws IOException, FacesException
+ {
+ if (!isEnabled())
+ {
+ _sendPregenerationDisabledError(context);
+ return;
+ }
+
+ long duration = _pregenerateSkin(context);
+
+ if (!context.getResponseComplete())
+ {
+ _renderResponse(context, duration);
+ }
+ }
+
+ // Pregenerates the skin based on the config specified via
+ // request parameters and returns the duration.
+ private static long _pregenerateSkin(FacesContext context)
+ {
+ long startTime = System.currentTimeMillis();
+
+ try
+ {
+ PregenConfig config = PregenConfig.parse(context);
+ Skin skin = _parseSkin(context);
+ SkinPregenerationUtils.pregenerate(context, skin, config);
+ }
+ catch (Exception e)
+ {
+ _pregenFailed(context, e);
+ }
+
+ return (System.currentTimeMillis() - startTime);
+ }
+
+ // Returns a non-null Skin corresponding based on the "id"
+ // request parameter. Throws InvalidConfigException if no
+ // skin is found.
+ private static Skin _parseSkin(FacesContext context)
+ throws InvalidConfigException
+ {
+ String skinId = _getSkinId(context);
+ if (skinId != null)
+ {
+ Skin skin = _getSkin(context, skinId);
+ if (skin != null)
+ {
+ return skin;
+ }
+ }
+
+ String message = _LOG.getMessage("SKIN_PREGEN_REQUESTED_SKIN_INVALID", skinId);
+ throw new InvalidConfigException(message);
+ }
+
+ private static String _getSkinId(FacesContext context)
+ {
+ 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);
+ }
+
+ private static void _pregenFailed(FacesContext context, Exception e)
+ {
+ String message = _LOG.getMessage("SKIN_PREGEN_FAILED", e.getMessage());
+ _LOG.severe(message, e);
+ _sendError(context, message);
+ }
+
+ private static void _sendPregenerationDisabledError(FacesContext context)
+ {
+ String message = _LOG.getMessage("SKIN_PREGEN_DISABLED",
+ new Object[] {_SERVICE_PROPERTY,
+ _getServicePropertyValues()});
+
+ _sendError(context, message);
+ }
+
+ private static String _getServicePropertyValues()
+ {
+ return Enums.patternOf(ServiceStatus.class,
+ Enums.displayNameStringProducer(ServiceStatus.class));
+ }
+
+
+ private static void _sendError(FacesContext context, String message)
+ {
+ if (context.getResponseComplete())
+ {
+ return;
+ }
+
+ ExternalContext external = context.getExternalContext();
+
+ try
+ {
+ external.responseSendError(500, message);
+ }
+ catch (IOException e)
+ {
+ _LOG.warning(e);
+ }
+ finally
+ {
+ context.responseComplete();
+ }
+ }
+
+ // Render the content to send back in the event that skin
+ // generation is successful.
+ private static void _renderResponse(
+ FacesContext context,
+ long duration
+ ) throws IOException
+ {
+ ResponseWriter rw = _getResponseWriter(context);
+
+ rw.startDocument();
+ rw.write(_RESPONSE_DOCTYPE);
+ rw.startElement("html", null);
+ rw.startElement("head", null);
+ rw.startElement("title", null);
+ rw.writeText(_LOG.getMessage("SKIN_PREGEN_RESPONSE_TITLE"), null);
+ rw.endElement("title");
+ rw.endElement("head");
+ rw.startElement("body", null);
+ rw.startElement("p", null);
+
+ String message = _LOG.getMessage("SKIN_PREGEN_RESPONSE", duration);
+ rw.writeText(message, null);
+
+ rw.endElement("p");
+ rw.endElement("body");
+ rw.endElement("html");
+ rw.endDocument();
+ }
+
+ private static ResponseWriter _getResponseWriter(FacesContext context)
+ throws IOException
+ {
+ ExternalContext external = context.getExternalContext();
+ String contentType = "text/html";
+ String encoding = "UTF-8";
+
+ external.setResponseContentType(contentType);
+ external.setResponseCharacterEncoding(encoding);
+
+ ResponseWriter rw = context.getRenderKit().createResponseWriter(
+ external.getResponseOutputWriter(),
+ contentType,
+ encoding);
+
+ context.setResponseWriter(rw);
+
+ return rw;
+ }
+
+ private static ServiceStatus _getServiceStatus()
+ {
+ if (_sServiceStatus == null)
+ {
+ String serviceProperty = System.getProperty(_SERVICE_PROPERTY);
+ if ((serviceProperty != null) && (serviceProperty.length() > 0))
+ {
+ try
+ {
+ _sServiceStatus = ServiceStatus.valueOfDisplayName(serviceProperty);
+ }
+ catch (IllegalArgumentException e)
+ {
+ _sServiceStatus = ServiceStatus.OFF;
+
+ _LOG.severe("ILLEGAL_SYSTEM_PROPERTY_VALUE",
+ new Object[] {
+ serviceProperty,
+ _SERVICE_PROPERTY,
+ _getServicePropertyValues()});
+ }
+ }
+ }
+
+ return _sServiceStatus;
+ }
+
+ // Little utility enum that we use to track the
+ // enabled/disabed status of the pregeneration service.
+ public static enum ServiceStatus
+ {
+ ON("on"),
+ OFF("off");
+
+ ServiceStatus(String displayName)
+ {
+ _displayName = displayName;
+ }
+
+ public String displayName()
+ {
+ return _displayName;
+ }
+
+ public static ServiceStatus valueOfDisplayName(String displayName)
+ {
+ return Enums.stringToEnum(_displayNameMap, displayName, ServiceStatus.class);
+ }
+
+ private final String _displayName;
+ private static final Map<String, ServiceStatus> _displayNameMap;
+
+ static
+ {
+ _displayNameMap = Enums.createDisplayNameMap(ServiceStatus.class);
+ }
+ }
+
+ private static volatile ServiceStatus _sServiceStatus;
+
+ private static final String _SKIN_ID_REQUEST_PARAM = "id";
+
+ private static final String _SERVICE_PROPERTY =
+ "org.apache.myfaces.trinidad.SKIN_PREGENERATION_SERVICE";
+
+ private static final String _RESPONSE_DOCTYPE =
+ "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">";
+
+ // The view id for the pregeneration service.
+ private static final String _VIEW_ID = "/-tr-pregenerate-skins";
+
+ private static final TrinidadLogger _LOG =
+ TrinidadLogger.createTrinidadLogger(SkinPregenerationService.class);
+}
Added: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/SkinPregenerationUtils.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/SkinPregenerationUtils.java?rev=1303525&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/SkinPregenerationUtils.java (added)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/SkinPregenerationUtils.java Wed Mar 21 19:33:45 2012
@@ -0,0 +1,107 @@
+/*
+ * 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.pregen;
+
+import java.beans.Beans;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+import javax.faces.context.FacesContext;
+
+import org.apache.myfaces.trinidad.skin.Skin;
+import org.apache.myfaces.trinidad.util.FileUtils;
+import org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.TrinidadRenderingConstants;
+import org.apache.myfaces.trinidadinternal.skin.pregen.config.PregenConfig;
+import org.apache.myfaces.trinidadinternal.skin.pregen.context.PregenStyleProvider;
+import org.apache.myfaces.trinidadinternal.style.StyleProvider;
+
+/**
+ * Skin pregeneration utilities.
+ */
+public final class SkinPregenerationUtils
+{
+ /**
+ * Pregenerates style sheets for the specified skin.
+ *
+ * @param context the FacesContext for the current request
+ * @param skin the non-null Skin to pregenerate
+ * @param config configuration info that determines how pregeneration
+ * is performed.
+ */
+ public static void pregenerate(
+ FacesContext context,
+ Skin skin,
+ PregenConfig config
+ ) throws IOException
+ {
+ assert(skin != null);
+ assert(config != null);
+
+ SkinPregenerator pregenerator = _getSkinPregenerator();
+ String stylesCacheDirectoryPath = _getStylesCacheDirectoryPath(config);
+ StyleProvider provider = new PregenStyleProvider(skin, stylesCacheDirectoryPath);
+
+ pregenerator.pregenerate(context, skin, config, provider);
+ }
+
+ private static SkinPregenerator _getSkinPregenerator()
+ {
+ if (Beans.isDesignTime())
+ {
+ return _NOOP_PREGENERATOR;
+ }
+
+ return new AllVariantsSkinPregenerator();
+ }
+
+ // Returns the subdirectory for skin-specific generated files.
+ // Throws an IOException if the directory does not exist/cannot be
+ // created or is not writable.
+ private static String _getStylesCacheDirectoryPath(PregenConfig config)
+ throws IOException
+ {
+ String targetDirPath = config.getTargetDirectoryPath();
+ String subDirPath = TrinidadRenderingConstants.STYLES_CACHE_DIRECTORY;
+ String stylesCacheDirPath = targetDirPath + subDirPath;
+
+ // Verify that the directory exists and is writable.
+ FileUtils.toWritableDirectory(stylesCacheDirPath);
+
+ return stylesCacheDirPath;
+ }
+
+ private SkinPregenerationUtils()
+ {
+ }
+
+ private static final SkinPregenerator _NOOP_PREGENERATOR =
+ new SkinPregenerator()
+ {
+ @Override
+ public void pregenerate(
+ FacesContext context,
+ Skin skin,
+ PregenConfig config,
+ StyleProvider provider)
+ {
+ }
+ };
+}
Added: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/SkinPregenerator.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/SkinPregenerator.java?rev=1303525&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/SkinPregenerator.java (added)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/SkinPregenerator.java Wed Mar 21 19:33:45 2012
@@ -0,0 +1,45 @@
+/*
+ * 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.pregen;
+
+import javax.faces.context.FacesContext;
+
+import org.apache.myfaces.trinidad.skin.Skin;
+import org.apache.myfaces.trinidadinternal.skin.pregen.config.PregenConfig;
+import org.apache.myfaces.trinidadinternal.style.StyleProvider;
+
+/**
+ * Interface for objects that perform skin pregeneration.
+ */
+interface SkinPregenerator
+{
+
+ /**
+ * Pregenerate style sheets for the specified skin
+ * @param context the FacesContext for the current request
+ * @param skin the Skin to pregenerate
+ * @param config configuration info that influences pregeneration
+ */
+ public void pregenerate(
+ FacesContext context,
+ Skin skin,
+ PregenConfig config,
+ StyleProvider provider
+ );
+}
Added: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/config/InvalidConfigException.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/config/InvalidConfigException.java?rev=1303525&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/config/InvalidConfigException.java (added)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/config/InvalidConfigException.java Wed Mar 21 19:33:45 2012
@@ -0,0 +1,37 @@
+/*
+ * 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.pregen.config;
+
+/**
+ * Exception thrown from PregenConfig.parse() if a failure occurs during
+ * parsing.
+ */
+public final class InvalidConfigException extends RuntimeException
+{
+ /**
+ * Creates an InvalidConfigException with a message that is
+ * suitable for publication to the end user.
+ */
+ public InvalidConfigException(String message)
+ {
+ super(message);
+ }
+
+ private static final long serialVersionUID = 1L;
+}
Added: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/config/PregenConfig.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/config/PregenConfig.java?rev=1303525&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/config/PregenConfig.java (added)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/config/PregenConfig.java Wed Mar 21 19:33:45 2012
@@ -0,0 +1,623 @@
+/*
+ * 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.pregen.config;
+
+import java.io.File;
+import java.io.IOException;
+
+import java.util.AbstractCollection;
+import java.util.Arrays;
+import java.util.Collection;
+
+import java.util.Collections;
+import java.util.Iterator;
+
+import java.util.Map;
+
+import javax.faces.context.ExternalContext;
+
+import javax.faces.context.FacesContext;
+
+import org.apache.myfaces.trinidad.context.AccessibilityProfile;
+import org.apache.myfaces.trinidad.context.LocaleContext;
+import org.apache.myfaces.trinidad.logging.TrinidadLogger;
+import org.apache.myfaces.trinidad.util.EnumParseException;
+import org.apache.myfaces.trinidad.util.Enums;
+import org.apache.myfaces.trinidad.util.FileUtils;
+import org.apache.myfaces.trinidadinternal.agent.TrinidadAgent;
+import org.apache.myfaces.trinidadinternal.agent.TrinidadAgent.Application;
+import org.apache.myfaces.trinidadinternal.renderkit.core.CoreRenderingContext;
+import org.apache.myfaces.trinidadinternal.share.nls.NullLocaleContext;
+import org.apache.myfaces.trinidadinternal.util.nls.LocaleUtils;
+
+/**
+ * Specifies configuration constraints for skin pregeneration.
+ *
+ * For the moment, only two types of configurations are supported:
+ *
+ * - all: All possible variants are pregenerated
+ * - common: Only the most common variants are pregenerated
+ *
+ * The "variants" request parameter specifies which of these two
+ * configurations to use.
+ *
+ * In the future, we can consider supporting finer-grained configuration
+ * specification - eg. we could allow specific platforms/agents/locales
+ * to be specified via an XML configuration file.
+ */
+abstract public class PregenConfig
+{
+ /**
+ * Constant returned from variants accessors to indicate that
+ * all possible values of the variant should be included during
+ * pregeneration.
+ */
+ public static final Collection<?> ALL_VARIANTS =
+ new AbstractCollection() {
+
+ @Override
+ public boolean isEmpty()
+ {
+ return false;
+ }
+
+ @Override
+ public Iterator iterator()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int size()
+ {
+ throw new UnsupportedOperationException();
+ }
+ };
+
+ /**
+ * Returns a null/empty PregenConfig instance.
+ */
+ public static PregenConfig nullInstance()
+ {
+ return _NULL_CONFIG;
+ }
+
+ /**
+ * Creates a PregenConfig instance that is configured based on request
+ * parmeter values.
+ *
+ * Request parameters are documented in SkinPregenerationService class doc.
+ *
+ * @param context the FacesContext to use for retreving request parameter
+ * values.
+ * @return
+ */
+ public static PregenConfig parse(FacesContext context)
+ throws InvalidConfigException
+ {
+ ExternalContext external = context.getExternalContext();
+
+ return _isAllVariantsRequest(external) ?
+ new AllPregenConfig(context) :
+ new CommonPregenConfig(context);
+ }
+
+ private static boolean _isAllVariantsRequest(ExternalContext external)
+ throws InvalidConfigException
+ {
+ Collection<Variants> variants = _parseDisplayNameParam(external,
+ "variants",
+ Variants.class,
+ Variants.COMMON);
+
+ return variants.contains(Variants.ALL);
+ }
+
+ private static <E extends Enum> Collection<E> _parseDisplayNameParam(
+ ExternalContext external,
+ String paramName,
+ Class<E> enumClass,
+ E defaultValue
+ ) throws InvalidConfigException
+ {
+ try
+ {
+ return Enums.parseDisplayNameEnumRequestParameter(external,
+ paramName,
+ enumClass,
+ defaultValue);
+ }
+ catch (EnumParseException e)
+ {
+ throw new InvalidConfigException(e.getMessage());
+ }
+ }
+
+ /**
+ * Returns the (non-null) platform variants to pregenerate.
+ *
+ * The collection values correspond to TrinidadAgent.OS_* constants.
+ *
+ * A return value of PregenConfig.ALL indicates that all platform
+ * variants should be pregenerated.
+ */
+ abstract public Collection<Integer> getPlatformVariants();
+
+ /**
+ * Returns the (non-null) locale variants to pregenerate.
+ *
+ * A return value of PregenConfig.ALL indicates that all locale
+ * variants should be pregenerated.
+ */
+ abstract public Collection<LocaleContext> getLocaleVariants();
+
+ /**
+ * Returns the (non-null) reading direction variants to pregenerate.
+ *
+ * A return value of PregenConfig.ALL indicates that both ltr and
+ * rtl variants should be pregenerated.
+ */
+ abstract public Collection<Integer> getReadingDirectionVariants();
+
+ /**
+ * Returns the (non-null) agent application variants to pregenerate.
+ *
+ * A return value of PregenConfig.ALL indicates that all agent application
+ * variants should be pregenerated.
+ */
+ abstract public Collection<Application> getAgentApplicationVariants();
+
+ /**
+ * Returns the (non-null) accessibility variants to pregenerate.
+ *
+ * A return value of PregenConfig.ALL indicates that all accessibility
+ * variants should be pregenerated.
+ */
+ abstract public Collection<AccessibilityProfile> getAccessibilityVariants();
+
+ /**
+ * Returns the conatiner types to pregenerate.
+ */
+ abstract public Collection<ContainerType> getContainerTypes();
+
+ /**
+ * Returns the request types to pregenerate.
+ */
+ abstract public Collection<RequestType> getRequestTypes();
+
+ /**
+ * Returns the style class types to pregenerate.
+ */
+ abstract public Collection<StyleClassType> getStyleClassTypes();
+
+ /**
+ * Returns the path of the target output directory.
+ *
+ * This returns a non-null path to an existing, writable directory.
+ *
+ * The returned path is guaranteed to not have a trailing file
+ * separator.
+ */
+ abstract public String getTargetDirectoryPath();
+
+ // Utility enum class used to identify whether PregenConfig.parse() should
+ // return a PregenConfig instance that is configured for generating
+ // "common" or "all" variants.
+ public enum Variants
+ {
+ COMMON("common"),
+ ALL("all");
+
+ Variants(String displayName)
+ {
+ _displayName = displayName;
+ }
+
+ public String displayName()
+ {
+ return _displayName;
+ }
+
+ public static Variants valueOfDisplayName(String displayName)
+ {
+ return Enums.stringToEnum(_displayNameMap, displayName, Variants.class);
+ }
+
+ private final String _displayName;
+ private static final Map<String, Variants> _displayNameMap;
+
+ static
+ {
+ _displayNameMap = Enums.createDisplayNameMap(Variants.class);
+ }
+ }
+
+ // Enum that is used to indicate whether pregeneration should target
+ // servlet or portlet containers (or both).
+ public enum ContainerType
+ {
+ SERVLET("servlet"),
+ PORTLET("portlet");
+
+ ContainerType(String displayName)
+ {
+ _displayName = displayName;
+ }
+
+ public String displayName()
+ {
+ return _displayName;
+ }
+
+ public static ContainerType valueOfDisplayName(String displayName)
+ {
+ return Enums.stringToEnum(_displayNameMap, displayName, ContainerType.class);
+ }
+
+ private final String _displayName;
+ private static final Map<String, ContainerType> _displayNameMap;
+
+ static
+ {
+ _displayNameMap = Enums.createDisplayNameMap(ContainerType.class);
+ }
+ }
+
+ // Enum that is used to indicate whether pregeneration should target
+ // secure or nonsecure request types (or both).
+ public enum RequestType
+ {
+ NONSECURE("nonsecure"),
+ SECURE("secure");
+
+ RequestType(String displayName)
+ {
+ _displayName = displayName;
+ }
+
+ public String displayName()
+ {
+ return _displayName;
+ }
+
+ public static RequestType valueOfDisplayName(String displayName)
+ {
+ return Enums.stringToEnum(_displayNameMap, displayName, RequestType.class);
+ }
+
+ private final String _displayName;
+ private static final Map<String, RequestType> _displayNameMap;
+
+ static
+ {
+ _displayNameMap = Enums.createDisplayNameMap(RequestType.class);
+ }
+ }
+
+ // Enum that is used to indicate whether pregeneration should target
+ // compressed or uncompressed style classes (or both).
+ public enum StyleClassType
+ {
+ COMPRESSED("compressed"),
+ UNCOMPRESSED("uncompressed");
+
+ StyleClassType(String displayName)
+ {
+ _displayName = displayName;
+ }
+
+ public String displayName()
+ {
+ return _displayName;
+ }
+
+ public static StyleClassType valueOfDisplayName(String displayName)
+ {
+ return Enums.stringToEnum(_displayNameMap, displayName, StyleClassType.class);
+ }
+
+ private final String _displayName;
+ private static final Map<String, StyleClassType> _displayNameMap;
+
+ static
+ {
+ _displayNameMap = Enums.createDisplayNameMap(StyleClassType.class);
+ }
+ }
+
+ protected PregenConfig()
+ {
+ }
+
+ // A PregenConfig implementation that derives its contextual configuration
+ // from request parameters.
+ private static abstract class ParamPregenConfig extends PregenConfig
+ {
+ public ParamPregenConfig(FacesContext context)
+ throws InvalidConfigException
+ {
+ ExternalContext external = context.getExternalContext();
+
+ _containerTypes = _parseDisplayNameParam(external,
+ "containerType",
+ ContainerType.class,
+ ContainerType.SERVLET);
+
+ _requestTypes = _parseDisplayNameParam(external,
+ "requestType",
+ RequestType.class,
+ RequestType.NONSECURE);
+
+ _styleClassTypes = _parseDisplayNameParam(external,
+ "styleClassType",
+ StyleClassType.class,
+ StyleClassType.COMPRESSED);
+
+ _targetDirectoryPath = _getTargetDirectoryPath(context);
+ }
+
+ @Override
+ public Collection<ContainerType> getContainerTypes()
+ {
+ return _containerTypes;
+ }
+
+ @Override
+ public Collection<RequestType> getRequestTypes()
+ {
+ return _requestTypes;
+ }
+
+ @Override
+ public Collection<StyleClassType> getStyleClassTypes()
+ {
+ return _styleClassTypes;
+ }
+
+ @Override
+ public String getTargetDirectoryPath()
+ {
+ return _targetDirectoryPath;
+ }
+
+ // Returns the target directory path. Throws an InvalidConfigException
+ // if the target directory does not exist/cannot be created or is not
+ // writable.
+ private static String _getTargetDirectoryPath(FacesContext context)
+ throws InvalidConfigException
+ {
+ String targetDirectoryPath = _getNormalizedTargetDirectoryPath(context);
+
+ try
+ {
+ FileUtils.toWritableDirectory(targetDirectoryPath);
+ }
+ catch (IOException e)
+ {
+ // The directory either does not exist/cannot be created or
+ // exists but is not writable. Propagate this failure out.
+ throw new InvalidConfigException(e.getMessage());
+ }
+
+ return targetDirectoryPath;
+ }
+
+ // Returns the target directory path in its normalized form.
+ private static String _getNormalizedTargetDirectoryPath(FacesContext context)
+ {
+ String targetDirectoryPath = System.getProperty(_TARGET_DIRECTORY_PROPERTY);
+
+ if ((targetDirectoryPath == null) || targetDirectoryPath.isEmpty())
+ {
+ // Refactor to avoid dependency on core renderkit-specific API?
+ targetDirectoryPath = CoreRenderingContext.getTemporaryDirectory(context, false);
+ }
+
+ return _normalizeDirectoryPath(targetDirectoryPath);
+ }
+
+ // Normalizes the specified directory path by stripping off the trailing
+ // file separator, if present.
+ private static String _normalizeDirectoryPath(String path)
+ throws InvalidConfigException
+ {
+ if ((path == null) || path.isEmpty())
+ {
+ String message = _LOG.getMessage("SKIN_PREGEN_NO_TARGET_DIRECTORY",
+ _TARGET_DIRECTORY_PROPERTY);
+ throw new InvalidConfigException(message);
+ }
+
+ return _hasTrailingSeparator(path) ?
+ path.substring(0, path.length() - 1) :
+ path;
+ }
+
+ private static boolean _hasTrailingSeparator(String path)
+ {
+ char lastChar = path.charAt(path.length() - 1);
+
+ // Explicitly check '/' just in case someone happens to be using
+ // this as a separator in their sys property value (and we're on
+ // a platform that uses a different separator, eg. Windows).
+ return ((lastChar == File.separatorChar) || (lastChar == '/'));
+ }
+
+ private final Collection<ContainerType> _containerTypes;
+ private final Collection<RequestType> _requestTypes;
+ private final Collection<StyleClassType> _styleClassTypes;
+ private final String _targetDirectoryPath;
+ }
+
+ // PregenConfig implementation that is used for pregeneration of
+ // all possible variant values.
+ private static class AllPregenConfig extends ParamPregenConfig
+ {
+ public AllPregenConfig(FacesContext context)
+ {
+ super(context);
+ }
+
+ @Override
+ public Collection<Integer> getPlatformVariants()
+ {
+ return (Collection<Integer>)ALL_VARIANTS;
+ }
+
+ @Override
+ public Collection<LocaleContext> getLocaleVariants()
+ {
+ return (Collection<LocaleContext>)ALL_VARIANTS;
+ }
+
+ @Override
+ public Collection<Integer> getReadingDirectionVariants()
+ {
+ return (Collection<Integer>)ALL_VARIANTS;
+ }
+
+ @Override
+ public Collection<Application> getAgentApplicationVariants()
+ {
+ return (Collection<Application>)ALL_VARIANTS;
+ }
+
+ @Override
+ public Collection<AccessibilityProfile> getAccessibilityVariants()
+ {
+ return (Collection<AccessibilityProfile>)ALL_VARIANTS;
+ }
+ }
+
+ // PregenConfig implementation that is used for pregeneration of
+ // only the most common variant values.
+ private static class CommonPregenConfig extends ParamPregenConfig
+ {
+ public CommonPregenConfig(FacesContext context)
+ {
+ super(context);
+ }
+
+ @Override
+ public Collection<Integer> getPlatformVariants()
+ {
+ return Arrays.asList(
+ TrinidadAgent.OS_ANDROID,
+ TrinidadAgent.OS_IPHONE,
+ TrinidadAgent.OS_LINUX,
+ TrinidadAgent.OS_MACOS,
+ TrinidadAgent.OS_WINDOWS);
+ }
+
+ @Override
+ public Collection<LocaleContext> getLocaleVariants()
+ {
+ return Arrays.asList(
+ NullLocaleContext.getLeftToRightContext(),
+ NullLocaleContext.getRightToLeftContext());
+ }
+
+ @Override
+ public Collection<Integer> getReadingDirectionVariants()
+ {
+ return Arrays.asList(LocaleUtils.DIRECTION_LEFTTORIGHT);
+ }
+
+ @Override
+ public Collection<Application> getAgentApplicationVariants()
+ {
+ return Arrays.asList(Application.GECKO,
+ Application.IEXPLORER,
+ Application.SAFARI);
+ }
+
+ @Override
+ public Collection<AccessibilityProfile> getAccessibilityVariants()
+ {
+ return Arrays.asList(AccessibilityProfile.getDefaultInstance());
+ }
+ }
+
+ // Null PregenConfig implementation. Only used for error cases, to
+ // avoid null comparisons.
+ private static final class NullPregenConfig extends PregenConfig
+ {
+ @Override
+ public Collection<Integer> getPlatformVariants()
+ {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public Collection<LocaleContext> getLocaleVariants()
+ {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public Collection<Integer> getReadingDirectionVariants()
+ {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public Collection<Application> getAgentApplicationVariants()
+ {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public Collection<AccessibilityProfile> getAccessibilityVariants()
+ {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public Collection<PregenConfig.ContainerType> getContainerTypes()
+ {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public Collection<PregenConfig.RequestType> getRequestTypes()
+ {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public Collection<PregenConfig.StyleClassType> getStyleClassTypes()
+ {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public String getTargetDirectoryPath()
+ {
+ return null;
+ }
+ }
+
+ private static final PregenConfig _NULL_CONFIG = new NullPregenConfig();
+
+ private static final String _TARGET_DIRECTORY_PROPERTY =
+ "org.apache.myfaces.trinidad.SKIN_PREGENERATION_SERVICE_TARGET_DIRECTORY";
+
+ private static final TrinidadLogger _LOG =
+ TrinidadLogger.createTrinidadLogger(PregenConfig.class);
+}
Added: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/context/PregenStyleContext.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/context/PregenStyleContext.java?rev=1303525&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/context/PregenStyleContext.java (added)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/context/PregenStyleContext.java Wed Mar 21 19:33:45 2012
@@ -0,0 +1,244 @@
+/*
+ * 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.pregen.context;
+
+import javax.faces.context.FacesContext;
+
+import org.apache.myfaces.trinidad.context.AccessibilityProfile;
+import org.apache.myfaces.trinidad.context.Agent;
+import org.apache.myfaces.trinidad.context.LocaleContext;
+import org.apache.myfaces.trinidad.style.Styles;
+import org.apache.myfaces.trinidadinternal.agent.AgentNameUtil;
+import org.apache.myfaces.trinidadinternal.agent.DefaultAgent;
+import org.apache.myfaces.trinidadinternal.agent.TrinidadAgent;
+import org.apache.myfaces.trinidadinternal.agent.TrinidadAgentImpl;
+import org.apache.myfaces.trinidadinternal.skin.pregen.config.PregenConfig.ContainerType;
+import org.apache.myfaces.trinidadinternal.skin.pregen.config.PregenConfig.RequestType;
+import org.apache.myfaces.trinidadinternal.skin.pregen.config.PregenConfig.StyleClassType;
+import org.apache.myfaces.trinidadinternal.skin.pregen.variant.ApplicationAndVersion;
+import org.apache.myfaces.trinidadinternal.skin.pregen.variant.SkinVariant;
+import org.apache.myfaces.trinidadinternal.style.StyleContext;
+import org.apache.myfaces.trinidadinternal.style.StyleProvider;
+import org.apache.myfaces.trinidadinternal.style.StyleSheetNamingStrategy;
+
+/**
+ * StyleContext implementation used during skin pregeneration.
+ */
+public final class PregenStyleContext implements StyleContext
+{
+ /**
+ * Returns a StyleContext instance that can be used to retrieve the
+ * StyleSheetDocument for the specified StyleProvider.
+ *
+ * @param provider the StyleProvider for which we'll retrieve the StyleSheetDocument
+ * @param path the generated files path
+ * @return
+ */
+ public static StyleContext documentContext(
+ FacesContext context,
+ StyleProvider provider,
+ String path
+ )
+ {
+ // Note: DocumentProviderSkin.getStyleSheetDocument() minimally requires
+ // the StyleContet's StyleProvider and the generated files path, so that is
+ // all that we bother with here.
+ return new PregenStyleContext(context,
+ provider,
+ path,
+ null,
+ false);
+ }
+
+ /**
+ * Creates a StyleContext that can be used for pregeneration
+ * of a single skin variant.
+ *
+ * @param context the FacesContext
+ * @param provider the StyleProvider
+ * @param generatedFilesPath the root generated files path
+ * @param variant the variant of the skin to generate
+ */
+ public PregenStyleContext(
+ FacesContext context,
+ StyleProvider provider,
+ String generatedFilesPath,
+ SkinVariant variant,
+ boolean dirty
+ )
+ {
+ _styleProvider = provider;
+ _generatedFilesPath = generatedFilesPath;
+ _variant = variant;
+ _agent = _createTrinidadAgent(context, variant);
+ _dirty = dirty;
+ }
+
+ @Override
+ public LocaleContext getLocaleContext()
+ {
+ return _variant.getLocaleContext();
+ }
+
+ @Override
+ public TrinidadAgent getAgent()
+ {
+ return _agent;
+ }
+
+ @Override
+ public String getGeneratedFilesPath()
+ {
+ return _generatedFilesPath;
+ }
+
+ @Override
+ public StyleSheetNamingStrategy getNamingStrategy()
+ {
+ // Stable names are required for pregeneration in order
+ // for runtime names to match pregenerated names.
+ return StyleSheetNamingStrategy.STABLE;
+ }
+
+ @Override
+ public boolean checkStylesModified()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean disableStandardsMode()
+ {
+ return false;
+ }
+
+ @Override
+ public StyleProvider getStyleProvider()
+ {
+ return getStyleProvider(false);
+ }
+
+ @Override
+ public StyleProvider getStyleProvider(boolean recompute)
+ {
+ return _styleProvider;
+ }
+
+ @Override
+ public Styles getStyles()
+ {
+ return null;
+ }
+
+ @Override
+ public AccessibilityProfile getAccessibilityProfile()
+ {
+ return _variant.getAccessibilityProfile();
+ }
+
+ @Override
+ public boolean isPortletMode()
+ {
+ return (_variant.getContainerType() == ContainerType.PORTLET);
+ }
+
+ @Override
+ public boolean isDisableStyleCompression()
+ {
+ return (_variant.getStyleClassType() == StyleClassType.UNCOMPRESSED);
+ }
+
+ @Override
+ public boolean isDirty()
+ {
+ return _dirty;
+ }
+
+ @Override
+ public boolean isRequestSecure()
+ {
+ return (_variant.getRequestType() == RequestType.SECURE);
+ }
+
+ private static TrinidadAgent _createTrinidadAgent(
+ FacesContext context,
+ SkinVariant variant
+ )
+ {
+ if (variant == null)
+ {
+ // Null variant == bootstrapping case. No need for agent access.
+ return null;
+ }
+
+ // In theory we should be able to create/use our own trivial TrinidadAgent
+ // implementation. However, TrinidadAgentImpl contains all of the magic
+ // for figuring out agent capabilities. Turns out to be easier if we
+ // just use this implementation rather than create our own. Unfortunately,
+ // this means that we first need to jump through the hoop of translating
+ // the agent information into org.apache.myfaces.trinidad.context.Agent
+ // land.
+ Agent agent = new PregenAgent(variant.getPlatform(), variant.getApplicationAndVersion());
+
+ return new TrinidadAgentImpl(context, agent);
+ }
+
+ private static class PregenAgent extends DefaultAgent
+ {
+ public PregenAgent(
+ int platform,
+ ApplicationAndVersion appAndVersion
+ )
+ {
+ assert(appAndVersion != null);
+
+ _platformName = AgentNameUtil.getPlatformName(platform);
+ _agentName = appAndVersion.application.getAgentName();
+ _agentVersion = appAndVersion.version.toString();
+ }
+
+ @Override
+ public String getAgentName()
+ {
+ return _agentName;
+ }
+
+ @Override
+ public String getAgentVersion()
+ {
+ return _agentVersion;
+ }
+
+ @Override
+ public String getPlatformName()
+ {
+ return _platformName;
+ }
+
+ private final String _agentName;
+ private final String _agentVersion;
+ private final String _platformName;
+ }
+
+ private final StyleProvider _styleProvider;
+ private final String _generatedFilesPath;
+ private final SkinVariant _variant;
+ private final TrinidadAgent _agent;
+ private final boolean _dirty;
+}
Added: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/context/PregenStyleProvider.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/context/PregenStyleProvider.java?rev=1303525&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/context/PregenStyleProvider.java (added)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/context/PregenStyleProvider.java Wed Mar 21 19:33:45 2012
@@ -0,0 +1,47 @@
+/*
+ * 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.pregen.context;
+
+import org.apache.myfaces.trinidad.skin.Skin;
+import org.apache.myfaces.trinidadinternal.skin.SkinStyleProvider;
+
+/**
+ * StyleProvider implementation used during skin pregeneration.
+ *
+ * During skin pregeneration we periodically clear out the
+ * StyleProvider in order to free up memory. However, when
+ * we do this, we don't want to force a re-parse of the skin
+ * definitions. We override getClearOnDirty() to avoid this.
+ */
+public class PregenStyleProvider extends SkinStyleProvider
+{
+ public PregenStyleProvider(Skin skin, String targetDirectoryPath)
+ throws IllegalArgumentException
+ {
+ super(skin, targetDirectoryPath);
+ }
+
+ @Override
+ protected ClearOnDirty getClearOnDirty()
+ {
+ // Only clear out cache entries - don't blow away the
+ // StyleSheetDocument and associated data.
+ return ClearOnDirty.ENTRIES;
+ }
+}
Added: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/variant/AccessibilityVariantExtractor.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/variant/AccessibilityVariantExtractor.java?rev=1303525&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/variant/AccessibilityVariantExtractor.java (added)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/variant/AccessibilityVariantExtractor.java Wed Mar 21 19:33:45 2012
@@ -0,0 +1,160 @@
+/*
+ * 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.pregen.variant;
+
+import java.util.ArrayList;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+
+import org.apache.myfaces.trinidad.context.AccessibilityProfile;
+import org.apache.myfaces.trinidadinternal.style.xml.XMLConstants;
+import org.apache.myfaces.trinidadinternal.style.xml.parse.StyleSheetNode;
+
+/**
+ * Helper class for extracting @accessibility-profile rule metadata.
+ */
+final class AccessibilityVariantExtractor implements SkinVariantExtractor<AccessibilityProfile>
+{
+ public AccessibilityVariantExtractor()
+ {
+ _accProfiles = new HashSet<AccessibilityProfile>();
+
+ // Seed with default accessibility profile. This won't show
+ // up as at @accessibility rule, but needs to be covered during
+ // pregeneration.
+ _accProfiles.add(AccessibilityProfile.getDefaultInstance());
+ }
+
+ @Override
+ public void visit(StyleSheetNode node)
+ {
+ Collection<String> accProps = node.getAccessibilityProperties();
+
+ for (String accProp : accProps)
+ {
+ _addAccessibilityProfile(accProp);
+ }
+ }
+
+ /**
+ * Returns un unmodifiable list containing AccessibilityProfiles corresponding
+ * to all @accesibility-profile rules in the specified document.
+ */
+ public List<AccessibilityProfile> getVariants()
+ {
+ _addCompoundAccessibilityProfile();
+
+ List<AccessibilityProfile> accProfilesList =
+ new ArrayList<AccessibilityProfile>(_accProfiles);
+
+ return accProfilesList;
+ }
+
+ // Adds the compound high contrast + large fonts profile
+ // if necessary.
+ private void _addCompoundAccessibilityProfile()
+ {
+ // In cases where the skin contains both:
+ //
+ // - @accessibility-profile high-contrast, and...
+ // - @accessibility-profile large-fonts
+ //
+ // Then we need to generate a style sheet for end users
+ // that happen to run with both high contrast and large fonts
+ // enabled. Thus, we add in a compound high contrast + large
+ // fonts profile if we've seen each property individually.
+ if (_accProfiles.contains(_HIGH_CONTRAST_ONLY) &&
+ _accProfiles.contains(_LARGE_FONTS_ONLY) &&
+ !_accProfiles.contains(_HIGH_CONTRAST_LARGE_FONTS))
+ {
+ _accProfiles.add(_HIGH_CONTRAST_LARGE_FONTS);
+ }
+ }
+
+ private void _addAccessibilityProfile(String accProp)
+ {
+ AccessibilityProfile accProfile = _toAccessibilityProfile(accProp);
+
+ _accProfiles.add(accProfile);
+ }
+
+ private static AccessibilityProfile _toAccessibilityProfile(String accProp)
+ {
+ boolean highContrast = false;
+ boolean largeFonts = false;
+
+ if (_isHighContrast(accProp))
+ {
+ highContrast = true;
+ }
+ else if (_isLargeFonts(accProp))
+ {
+ largeFonts = true;
+ }
+ else if (_isHighContrastLargeFonts(accProp))
+ {
+ highContrast = true;
+ largeFonts = true;
+ }
+
+ return _getAccessibilityProfile(highContrast, largeFonts);
+ }
+
+ private static boolean _isHighContrast(String accProp)
+ {
+ return XMLConstants.ACC_HIGH_CONTRAST.equals(accProp);
+ }
+
+ private static boolean _isLargeFonts(String accProp)
+ {
+ return XMLConstants.ACC_LARGE_FONTS.equals(accProp);
+ }
+
+ private static boolean _isHighContrastLargeFonts(String accProp)
+ {
+ return ((accProp.indexOf(XMLConstants.ACC_HIGH_CONTRAST) > -1) &&
+ (accProp.indexOf(XMLConstants.ACC_LARGE_FONTS) > -1));
+ }
+
+ private static AccessibilityProfile _getAccessibilityProfile(
+ boolean highContrast,
+ boolean largeFonts
+ )
+ {
+ return AccessibilityProfile.getInstance(
+ highContrast ?
+ AccessibilityProfile.ColorContrast.HIGH :
+ AccessibilityProfile.ColorContrast.STANDARD,
+ largeFonts ?
+ AccessibilityProfile.FontSize.LARGE :
+ AccessibilityProfile.FontSize.MEDIUM);
+ }
+
+ private final Collection<AccessibilityProfile> _accProfiles;
+
+ private static final AccessibilityProfile _HIGH_CONTRAST_ONLY =
+ _getAccessibilityProfile(true, false);
+ private static final AccessibilityProfile _LARGE_FONTS_ONLY =
+ _getAccessibilityProfile(false, true);
+ private static final AccessibilityProfile _HIGH_CONTRAST_LARGE_FONTS =
+ _getAccessibilityProfile(true, true);
+}
Added: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/variant/AgentVariantExtractor.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/variant/AgentVariantExtractor.java?rev=1303525&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/variant/AgentVariantExtractor.java (added)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/variant/AgentVariantExtractor.java Wed Mar 21 19:33:45 2012
@@ -0,0 +1,222 @@
+/*
+ * 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.pregen.variant;
+
+import java.util.AbstractCollection;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import java.util.Collections;
+import java.util.HashMap;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.myfaces.trinidad.context.Version;
+import org.apache.myfaces.trinidad.util.Range;
+
+import org.apache.myfaces.trinidadinternal.agent.TrinidadAgent.Application;
+import org.apache.myfaces.trinidadinternal.skin.AgentAtRuleMatcher;
+import org.apache.myfaces.trinidadinternal.style.xml.parse.StyleSheetNode;
+
+/**
+ * An @-rule processor for extracting @agent rule metadata.
+ */
+final class AgentVariantExtractor implements SkinVariantExtractor<ApplicationAndVersion>
+{
+ /**
+ * Creates an AgentVariantExtractor for a specified set of supported
+ * agent applications. AgentVariantExtractor.getVariants() will only
+ * ApplicationAndVersion instances corresponding to these agent
+ * applications. If no supported agent applications are specified,
+ * all agent applications found in the style sheet nodes will be
+ * treated as supported.
+ */
+ public AgentVariantExtractor(
+ Collection<Application> supportedApplications
+ )
+ {
+ _appVersionsMap =
+ new HashMap<Application, Set<Version>>();
+
+ _supportedApplications = _initSupportedApplications(supportedApplications);
+
+ // Seed the map with unknown agent. This won't appear
+ // in the skin definition, but we need to cover this case
+ // during pregeneration.
+ _addApplicationIfSupported(Application.UNKNOWN);
+ }
+
+ private Collection<Application> _initSupportedApplications(
+ Collection<Application> supportedApplications
+ )
+ {
+ if ((supportedApplications == null) || supportedApplications.isEmpty())
+ {
+ return new AbstractCollection<Application>() {
+
+ @Override
+ public boolean contains(Object o)
+ {
+ return true;
+ }
+
+ @Override
+ public Iterator<Application> iterator()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int size()
+ {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ return new HashSet<Application>(supportedApplications);
+ }
+
+ @Override
+ public void visit(StyleSheetNode node)
+ {
+ AgentAtRuleMatcher agentMatcher = node.getAgentMatcher();
+
+ if (agentMatcher != null)
+ {
+ _addApplicationVersions(agentMatcher);
+ }
+ }
+
+ /**
+ * Returns alist containing ApplicationAndVersions
+ * corresponding to all processed @agent rules.
+ */
+ public List<ApplicationAndVersion> getVariants()
+ {
+ List<ApplicationAndVersion> appAndVersionsList =
+ _toAppAndVersionsList(_appVersionsMap);
+
+ return appAndVersionsList;
+ }
+
+ private void _addApplicationVersions(AgentAtRuleMatcher agentMatcher)
+ {
+ assert(agentMatcher != null);
+
+ Collection<Application> nodeApplications =
+ agentMatcher.getAllApplications();
+
+ for (Application application : nodeApplications)
+ {
+
+ boolean supported = _addApplicationIfSupported(application);
+
+ if (supported)
+ {
+ Collection<Range<Version>> versionRanges = agentMatcher.getAllVersionsForApplication(application);
+ _addVersions(application, versionRanges);
+ }
+
+ }
+ }
+
+ private boolean _addApplicationIfSupported(Application application)
+ {
+ if (!_supportedApplications.contains(application))
+ {
+ return false;
+ }
+
+ if (!_appVersionsMap.containsKey(application))
+ {
+ Set<Version> versions = new TreeSet<Version>();
+
+ // Minimally, every application needs to be able
+ // to pregenerate for the unknown version case.
+ versions.add(_UNKNOWN_VERSION);
+
+ _appVersionsMap.put(application, versions);
+ }
+
+ return true;
+ }
+
+ private void _addVersions(
+ Application application,
+ Collection<Range<Version>> versionRanges
+ )
+ {
+ Collection<Version> versions = _appVersionsMap.get(application);
+ assert(versions != null);
+
+ for (Range<Version> versionRange : versionRanges)
+ {
+ // We add the start/end points of the range to our
+ // set of versions to pregenerate.
+
+ // Also note that from here on out we only want to
+ // deal with "concrete" versions. If we leave version
+ // wildcards in place, we can lose information due to
+ // Version's wildcard-sensitive natural ordering (ie.
+ // a Set.add() might fail because a matching/wildcarded
+ // version is already present.)
+ versions.add(versionRange.getStart().toMinimumVersion());
+ versions.add(versionRange.getEnd().toMaximumVersion());
+ }
+ }
+
+ private static List<ApplicationAndVersion> _toAppAndVersionsList(
+ Map<Application, Set<Version>> appVersionsMap
+ )
+ {
+ List<ApplicationAndVersion> appAndVersions =
+ new ArrayList<ApplicationAndVersion>();
+
+ for (Map.Entry<Application, Set<Version>> entry : appVersionsMap.entrySet())
+ {
+ for (Version version : entry.getValue())
+ {
+ appAndVersions.add(new ApplicationAndVersion(entry.getKey(), version));
+ }
+ }
+
+ // Sort to make logger output/progress easier to monitor
+ Collections.sort(appAndVersions);
+
+ return appAndVersions;
+ }
+
+ // Map of application to versions that have been encountered
+ // during processing
+ private final Map<Application, Set<Version>> _appVersionsMap;
+
+ // Only extract version information for these applications.
+ private final Collection<Application> _supportedApplications;
+
+ // A Version that we use to ensure that we pregenerate style sheets
+ // for the case where the agent version does not match any version
+ // specified in the skin.
+ private static final Version _UNKNOWN_VERSION = new Version("unknown");
+}
Added: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/variant/ApplicationAndVersion.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/variant/ApplicationAndVersion.java?rev=1303525&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/variant/ApplicationAndVersion.java (added)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/pregen/variant/ApplicationAndVersion.java Wed Mar 21 19:33:45 2012
@@ -0,0 +1,126 @@
+/*
+ * 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.pregen.variant;
+
+import org.apache.myfaces.trinidad.context.Version;
+import org.apache.myfaces.trinidad.util.Args;
+import org.apache.myfaces.trinidadinternal.agent.TrinidadAgent.Application;
+
+/**
+ * A convenience duple class that holds onto a TrinidadAgent.Application and
+ * Version value.
+ *
+ * Only note of interest: the AppicationAndVersion.version is guaranteed to
+ * be concrete (ie. no wildcards). As a result, although Version.equals()
+ * and Version.compareTo() are typically inconsistent, ApplicationAndVersion's
+ * equals() and compareTo() implementations are consistent - ie. if
+ * ApplicationAndVersion.compareTo() returns zero, equals() returns true
+ * (and vice versa).
+ */
+public final class ApplicationAndVersion implements Comparable<ApplicationAndVersion>
+{
+ public final Application application;
+ public final Version version;
+
+ /**
+ * An instance that can be used as a placeholder for cases
+ * where the application and version are not known.
+ */
+ public static final ApplicationAndVersion UNKNOWN =
+ new ApplicationAndVersion(
+ Application.UNKNOWN,
+ Version.MIN_VERSION);
+
+ /**
+ * Creates an AppplicationAndVersion instance for the
+ * specified application and version.
+ *
+ * If the Version contains wildcards, this will be replaced by a new,
+ * matching, concrete (wildcard-free) Version instance.
+ *
+ * @param application a non-null TrinidadAgent.Application instance.
+ * @param version a non-null Version instance.
+ *
+ * @throws IllegalArgumentException if either application or version are null.
+ */
+ public ApplicationAndVersion(
+ Application application,
+ Version version
+ ) throws IllegalArgumentException
+ {
+ Args.notNull(application, "application");
+ Args.notNull(version, "version");
+
+ this.application = application;
+
+ // Any concrete version will do, we'll go with the min.
+ this.version = version.toMinimumVersion();
+ }
+
+ @Override
+ public String toString()
+ {
+ return this.application + "v" + this.version;
+ }
+
+ @Override
+ public int compareTo(ApplicationAndVersion otherAppAndVersion)
+ {
+ String agentName = this.application.getAgentName();
+ String otherAgentName = otherAppAndVersion.application.getAgentName();
+
+ int nameResult = agentName.compareTo(otherAgentName);
+ if (nameResult != 0)
+ {
+ return nameResult;
+ }
+
+ return this.version.compareTo(otherAppAndVersion.version);
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (this == o)
+ {
+ return true;
+ }
+
+ if (!(o instanceof ApplicationAndVersion))
+ {
+ return false;
+ }
+
+ ApplicationAndVersion appAndVersion = (ApplicationAndVersion)o;
+
+ return (this.application.equals(appAndVersion.application) &&
+ this.version.equals(appAndVersion.version));
+ }
+
+ @Override
+ public int hashCode()
+ {
+ int result = 17;
+
+ result = 31 * result + this.application.hashCode();
+ result = 31 * result + this.version.hashCode();
+
+ return result;
+ }
+}