Author: nbelaevski
Date: 2010-04-22 20:12:50 -0400 (Thu, 22 Apr 2010)
New Revision: 16797
Added:
root/framework/trunk/impl/src/main/java/org/richfaces/resource/css/
root/framework/trunk/impl/src/main/java/org/richfaces/resource/css/AbstractCSSVisitor.java
root/framework/trunk/impl/src/main/java/org/richfaces/resource/css/CSSVisitorImpl.java
Removed:
root/framework/trunk/impl/src/main/java/org/richfaces/resource/CSSCompiler.java
Modified:
root/framework/trunk/impl/src/main/java/org/richfaces/resource/AbstractBaseResource.java
root/framework/trunk/impl/src/main/java/org/richfaces/resource/CompiledCSSResource.java
root/framework/trunk/impl/src/main/java/org/richfaces/resource/ResourceHandlerImpl.java
root/framework/trunk/impl/src/main/java/org/richfaces/resource/Xcss2EcssConverter.java
Log:
Dynamic CSS refactoring & fixes
Modified:
root/framework/trunk/impl/src/main/java/org/richfaces/resource/AbstractBaseResource.java
===================================================================
---
root/framework/trunk/impl/src/main/java/org/richfaces/resource/AbstractBaseResource.java 2010-04-22
15:59:04 UTC (rev 16796)
+++
root/framework/trunk/impl/src/main/java/org/richfaces/resource/AbstractBaseResource.java 2010-04-23
00:12:50 UTC (rev 16797)
@@ -21,17 +21,9 @@
package org.richfaces.resource;
-import org.ajax4jsf.resource.InternetResource;
-import org.richfaces.context.SingletonsContext;
-import org.richfaces.log.RichfacesLogger;
import static org.richfaces.resource.ResourceUtils.millisToSecond;
import static org.richfaces.resource.ResourceUtils.secondToMillis;
-import org.richfaces.util.Util;
-import org.slf4j.Logger;
-import javax.faces.FacesException;
-import javax.faces.component.StateHolder;
-import javax.faces.context.FacesContext;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
@@ -44,6 +36,16 @@
import java.util.Map;
import java.util.Map.Entry;
+import javax.faces.FacesException;
+import javax.faces.component.StateHolder;
+import javax.faces.context.FacesContext;
+
+import org.ajax4jsf.resource.InternetResource;
+import org.richfaces.context.SingletonsContext;
+import org.richfaces.log.RichfacesLogger;
+import org.richfaces.util.Util;
+import org.slf4j.Logger;
+
/**
* @author Nick Belaevski
* @since 4.0
@@ -184,9 +186,6 @@
}
@Override
- public abstract InputStream getInputStream();
-
- @Override
public String getRequestPath() {
// TODO - cache resource request path in request scope
Deleted: root/framework/trunk/impl/src/main/java/org/richfaces/resource/CSSCompiler.java
===================================================================
---
root/framework/trunk/impl/src/main/java/org/richfaces/resource/CSSCompiler.java 2010-04-22
15:59:04 UTC (rev 16796)
+++
root/framework/trunk/impl/src/main/java/org/richfaces/resource/CSSCompiler.java 2010-04-23
00:12:50 UTC (rev 16797)
@@ -1,280 +0,0 @@
-package org.richfaces.resource;
-
-import com.steadystate.css.parser.CSSOMParser;
-import org.richfaces.log.RichfacesLogger;
-import org.slf4j.Logger;
-import org.w3c.css.sac.InputSource;
-import org.w3c.dom.css.CSSImportRule;
-import org.w3c.dom.css.CSSRule;
-import org.w3c.dom.css.CSSRuleList;
-import org.w3c.dom.css.CSSStyleDeclaration;
-import org.w3c.dom.css.CSSStyleRule;
-import org.w3c.dom.css.CSSStyleSheet;
-
-import javax.el.ELContext;
-import javax.el.ELException;
-import javax.el.ValueExpression;
-import javax.faces.application.Resource;
-import javax.faces.context.FacesContext;
-import java.io.BufferedInputStream;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Pattern;
-
-public final class CSSCompiler {
-
- private static final Logger LOGGER = RichfacesLogger.RESOURCE.getLogger();
- private static final String INVALID_RESOURCE_FORMAT_COLON_ERROR =
- "Invalid resource format. Property ''{0}'' contains
more than one colon (:).";
- private static final String INVALID_RESOURCE_FORMAT_NO_LIBRARY_NAME_ERROR =
- "Invalid resource format. Property ''{0}'' cannot be
parsed to extract resource name and library name.";
- private static final String INVALID_RESOURCE_FORMAT_ERROR =
- "Invalid resource format. Property ''{0}'' cannot be
parsed.";
-
- private CSSCompiler() {
- }
-
- public static InputStream parse(Resource resource) throws IOException {
- FacesContext ctx = FacesContext.getCurrentInstance();
- InputStream stream = new BufferedInputStream(
- new ELEvaluatingInputStream(ctx,
- resource,
- resource.getInputStream()));
- StringBuilder main = new StringBuilder();
- try {
- InputSource source = new InputSource(new InputStreamReader(stream));
- CSSOMParser parser = new CSSOMParser();
- // parse and create a stylesheet composition
- CSSStyleSheet stylesheet = parser.parseStyleSheet(source, null, null);
-
- // now iterate through the dom and inspect.
-
- CSSRuleList ruleList = stylesheet.getCssRules();
- for (int i = 0; i < ruleList.getLength(); i++) {
- CSSRule rule = ruleList.item(i);
- if (rule instanceof CSSImportRule) {
- main.append(rule.getCssText());
- main.append("\r\n");
- } else if (rule instanceof CSSStyleRule) {
- CSSStyleRule styleRule = (CSSStyleRule) rule;
- boolean needAppendSelector = false;
- StringBuilder selector = new StringBuilder();
- selector.append(styleRule.getSelectorText());
- CSSStyleDeclaration styleDeclaration = styleRule.getStyle();
- selector.append("{" + "\r\n");
- for (int j = 0; j < styleDeclaration.getLength(); j++) {
- String property = styleDeclaration.item(j);
- String value =
styleDeclaration.getPropertyCSSValue(property).getCssText();
- if (value.startsWith("\"")) {
- //Remove quotas
- value = value.substring(1, value.length() - 1);
- }
- if (value != null && value.trim().length() > 0
&& !value.equals("\"\"")) {
- //One of properties of selector is not empty
- needAppendSelector = true;
- selector.append("\t" + property + ":");
- selector.append(value + ";" + "\r\n");
- }
- }
- selector.append("}" + "\r\n");
- if (needAppendSelector) {
- main.append(selector);
- }
- }// end of StyleRule instance test
- } // end of ruleList loop
-
- if (stream != null) {
- stream.close();
- }
- new ByteArrayInputStream(main.toString().getBytes());
- return new
ByteArrayInputStream(main.toString().getBytes("US-ASCII"));
- } catch (IOException ioe) {
- LOGGER.warn("IO Error: " + ioe + "while evaluating dynamic
CSS");
- } catch (Exception e) {
- LOGGER.warn("Error: " + e + "while evaluating dynamic
CSS");
- }
- return null;
- }
-
- private static final class ELEvaluatingInputStream extends InputStream {
-
- // Premature optimization is the root of all evil. Blah blah.
- private List<Integer> buf = new ArrayList<Integer>(1024);
- private boolean failedExpressionTest = false;
- private boolean writingExpression = false;
- private InputStream inner;
- private FacesContext ctx;
- private Resource info;
-
- private int nextRead = -1;
- // ---------------------------------------------------- Constructors
-
-
- public ELEvaluatingInputStream(FacesContext ctx,
- Resource info,
- InputStream inner) {
-
- this.inner = inner;
- this.info = info;
- this.ctx = ctx;
-
- }
-
-
- // ------------------------------------------------ Methods from InputStream
-
-
- @Override
- public int read() throws IOException {
- int i;
- char c;
-
- if (failedExpressionTest) {
- i = nextRead;
- nextRead = -1;
- failedExpressionTest = false;
- } else if (writingExpression) {
- if (0 < buf.size()) {
- i = buf.remove(0);
- } else {
- writingExpression = false;
- i = inner.read();
- }
- } else {
- // Read a character.
- i = inner.read();
- c = (char) i;
- // If it *might* be an expression...
- if (c == '#') {
- // read another character.
- i = inner.read();
- c = (char) i;
- // If it's '{', assume we have an expression.
- if (c == '{') {
- // read it into the buffer, and evaluate it into the
- // same buffer.
- readExpressionIntoBufferAndEvaluateIntoBuffer();
- // set the flag so that we need to return content
- // from the buffer.
- writingExpression = true;
- // Make sure to swallow the '{'.
- i = this.read();
- } else {
- // It's not an expression, we need to return '#',
- i = (int) '#';
- // then return whatever we just read, on the
- // *next* read;
- nextRead = (int) c;
- failedExpressionTest = true;
- }
- }
- }
-
- return i;
- }
-
- private void readExpressionIntoBufferAndEvaluateIntoBuffer()
- throws IOException {
-
- int i;
- char c;
- do {
- i = inner.read();
- c = (char) i;
- if (c == '}') {
- evaluateExpressionIntoBuffer();
- } else {
- buf.add(i);
- }
- } while (c != '}' && i != -1);
- }
-
- /*
- * At this point, we know that getBuf() returns a List<Integer>
- * that contains the bytes of the expression.
- * Turn it into a String, turn the String into a ValueExpression,
- * evaluate it, store the toString() of it in
- * expressionResult;
- */
- private void evaluateExpressionIntoBuffer() {
- char [] chars = new char[buf.size()];
- int len = buf.size();
- for (int i = 0; i < len; i++) {
- chars[i] = (char) (int) buf.get(i);
- }
- String expressionBody = new String(chars);
-
- // If this expression contains a ":"
- int colon = expressionBody.indexOf(":");
- if (-1 != colon) {
- // Make sure it contains only one ":"
- if (!isPropertyValid(expressionBody)) {
- String message =
MessageFormat.format(INVALID_RESOURCE_FORMAT_COLON_ERROR,
- expressionBody);
- throw new ELException(message);
- }
- String[] parts = split(expressionBody, ":");
- if (null == parts[0] || null == parts[1]) {
- String message =
MessageFormat.format(INVALID_RESOURCE_FORMAT_NO_LIBRARY_NAME_ERROR,
- expressionBody);
- throw new ELException(message);
-
- }
- try {
- int mark = parts[0].indexOf("[") + 2;
- char quoteMark = parts[0].charAt(mark - 1);
- parts[0] = parts[0].substring(mark, colon);
- if (parts[0].equals("this")) {
- parts[0] = info.getLibraryName();
- mark = parts[1].indexOf("]") - 1;
- parts[1] = parts[1].substring(0, mark);
- expressionBody = "resource[" + quoteMark + parts[0] +
- ":" + parts[1] + quoteMark + "]";
- }
- } catch (Exception e) {
- String message = MessageFormat.format(INVALID_RESOURCE_FORMAT_ERROR,
- expressionBody);
- throw new ELException(message);
-
- }
- }
- ELContext elContext = ctx.getELContext();
- ValueExpression ve =
- ctx.getApplication().getExpressionFactory().
- createValueExpression(elContext, "#{" +
expressionBody +
- "}", String.class);
- Object value = ve.getValue(elContext);
- String expressionResult = ((value != null) ? value.toString() :
"");
- buf.clear();
- int expressionResultLen = expressionResult.length();
- for (int i = 0; i < expressionResultLen; i++) {
- buf.add((int) expressionResult.charAt(i));
- }
- }
-
-
- private String[] split(String expressionBody, String toSplit) {
- return Pattern.compile(expressionBody).split(toSplit, 0);
- }
-
-
- @Override
- public void close() throws IOException {
- inner.close();
- super.close();
-
- }
-
-
- private boolean isPropertyValid(String property) {
- int idx = property.indexOf(':');
- return (property.indexOf(':', idx + 1) == -1);
- }
-
- }
-}
Modified:
root/framework/trunk/impl/src/main/java/org/richfaces/resource/CompiledCSSResource.java
===================================================================
---
root/framework/trunk/impl/src/main/java/org/richfaces/resource/CompiledCSSResource.java 2010-04-22
15:59:04 UTC (rev 16796)
+++
root/framework/trunk/impl/src/main/java/org/richfaces/resource/CompiledCSSResource.java 2010-04-23
00:12:50 UTC (rev 16797)
@@ -21,18 +21,36 @@
*/
package org.richfaces.resource;
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+import javax.el.ELContext;
+import javax.el.ELException;
+import javax.el.ValueExpression;
import javax.faces.application.ProjectStage;
import javax.faces.application.Resource;
import javax.faces.context.FacesContext;
-import org.richfaces.application.ServiceTracker;
import org.richfaces.log.RichfacesLogger;
+import org.richfaces.resource.css.CSSVisitorImpl;
+import org.richfaces.skin.Skin;
import org.richfaces.skin.SkinFactory;
import org.slf4j.Logger;
+import org.w3c.css.sac.CSSException;
+import org.w3c.css.sac.CSSParseException;
+import org.w3c.css.sac.ErrorHandler;
+import org.w3c.css.sac.InputSource;
+import org.w3c.dom.css.CSSStyleSheet;
+import com.steadystate.css.parser.CSSOMParser;
+
/**
* @author amarkhel
* Class, that represented dynamic CSS resource.
@@ -40,9 +58,18 @@
public class CompiledCSSResource extends AbstractBaseResource {
private static final String SKIN = "?skin=";
- private static final String TEXT_CSS = "text/css";
+
private static final Logger LOGGER = RichfacesLogger.RESOURCE.getLogger();
+ private static final String INVALID_RESOURCE_FORMAT_COLON_ERROR =
+ "Invalid resource format. Property ''{0}'' contains
more than one colon (:).";
+ private static final String INVALID_RESOURCE_FORMAT_NO_LIBRARY_NAME_ERROR =
+ "Invalid resource format. Property ''{0}'' cannot be
parsed to extract resource name and library name.";
+ private static final String INVALID_RESOURCE_FORMAT_ERROR =
+ "Invalid resource format. Property ''{0}'' cannot be
parsed.";
+ private static final String NULL_STYLESHEET =
+ "Parsed stylesheet for ''{0}'':''{1}''
resource is null.";
+
private Resource resourceDelegate;
public CompiledCSSResource(Resource resource) {
@@ -50,19 +77,55 @@
}
@Override
- public InputStream getInputStream() {
+ public InputStream getInputStream() throws IOException {
+ FacesContext ctx = FacesContext.getCurrentInstance();
InputStream stream = null;
+ CSSStyleSheet styleSheet = null;
try {
- stream = CSSCompiler.parse(resourceDelegate);
- } catch (IOException ioe) {
- LOGGER.warn("IO Error: " + ioe + "while loading dynamic
CSS");
+ stream = new BufferedInputStream(
+ new ELEvaluatingInputStream(ctx,
+ resourceDelegate,
+ resourceDelegate.getInputStream()));
+
+ InputSource source = new InputSource(new InputStreamReader(stream));
+ CSSOMParser parser = new CSSOMParser();
+ ErrorHandlerImpl errorHandler = new ErrorHandlerImpl(resourceDelegate,
+ ctx.isProjectStage(ProjectStage.Production));
+
+ parser.setErrorHandler(errorHandler);
+
+ // parse and create a stylesheet composition
+ styleSheet = parser.parseStyleSheet(source, null, null);
+ } finally {
+ if (stream != null) {
+ try {
+ stream.close();
+ } catch (IOException e) {
+ LOGGER.warn(e.getMessage(), e);
+ }
+ }
}
- return stream;
+
+ if (styleSheet != null) {
+ //TODO nick - handle encoding
+ CSSVisitorImpl cssVisitor = new CSSVisitorImpl();
+ cssVisitor.visitStyleSheet(styleSheet);
+
+ String cssText = cssVisitor.getCSSText();
+
+ return new ByteArrayInputStream(cssText.getBytes("US-ASCII"));
+ } else {
+ if (!ctx.isProjectStage(ProjectStage.Production)) {
+ LOGGER.info(MessageFormat.format(NULL_STYLESHEET,
resourceDelegate.getLibraryName(),
+ resourceDelegate.getResourceName()));
+ }
+ return null;
+ }
}
@Override
public String getContentType() {
- return TEXT_CSS;
+ return "text/css";
}
public Resource getResourceDelegate() {
@@ -80,23 +143,264 @@
@Override
public String getRequestPath() {
- StringBuilder b = new StringBuilder();
+ //TODO nick - review
String path = resourceDelegate.getRequestPath();
+
+ StringBuilder b = new StringBuilder(path.length() + SKIN.length() + 8 /* hash
code max length */);
b.append(path);
b.append(SKIN);
- b.append(getSkinHashCode());
+ b.append(Integer.toHexString(getSkinHashCode()));
+
return b.toString();
}
private int getSkinHashCode() {
- return ((SkinFactory)
ServiceTracker.getService(FacesContext.getCurrentInstance(),
SkinFactory.class)).getSkin(FacesContext.getCurrentInstance()).hashCode();
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ Skin skin = SkinFactory.getInstance().getSkin(facesContext);
+ return skin.hashCode(facesContext);
}
@Override
public boolean userAgentNeedsUpdate(FacesContext context) {
+ //TODO nick - review
+ //return resourceDelegate.userAgentNeedsUpdate(context);
+
if (context.isProjectStage(ProjectStage.Development)) {
return true;
}
return super.userAgentNeedsUpdate(context);
}
+
+ private static final class ErrorHandlerImpl implements ErrorHandler {
+
+ //TODO nick - sort out logging between stages
+ private boolean productionStage;
+
+ private Resource resource;
+
+ private String resourceLocator;
+
+ public ErrorHandlerImpl(Resource resource, boolean productionStage) {
+ super();
+ this.resource = resource;
+ this.productionStage = productionStage;
+ }
+
+ private String getResourceLocator() {
+ if (resourceLocator == null) {
+ String libraryName = resource.getLibraryName();
+ String resourceName = resource.getResourceName();
+
+ if (libraryName != null && libraryName.length() != 0) {
+ resourceLocator = libraryName + '/' + resourceName;
+ } else {
+ resourceLocator = resourceName;
+ }
+ }
+
+ return resourceLocator;
+ }
+
+ private void logException(CSSParseException e) {
+ String formattedMessage = MessageFormat.format("Problem parsing
''{0}'' resource: {1}",
+ getResourceLocator(),
+ e.getMessage());
+
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug(formattedMessage, e);
+ } else {
+ LOGGER.warn(formattedMessage);
+ }
+ }
+
+ public void error(CSSParseException e) throws CSSException {
+ logException(e);
+ }
+
+ public void fatalError(CSSParseException e) throws CSSException {
+ logException(e);
+ }
+
+ public void warning(CSSParseException e) throws CSSException {
+ logException(e);
+ }
+
+ }
+
+ private static final class ELEvaluatingInputStream extends InputStream {
+
+ // Premature optimization is the root of all evil. Blah blah.
+ private List<Integer> buf = new ArrayList<Integer>(1024);
+ private boolean failedExpressionTest = false;
+ private boolean writingExpression = false;
+ private InputStream inner;
+ private FacesContext ctx;
+ private Resource info;
+
+ private int nextRead = -1;
+ // ---------------------------------------------------- Constructors
+
+
+ public ELEvaluatingInputStream(FacesContext ctx,
+ Resource info,
+ InputStream inner) {
+
+ this.inner = inner;
+ this.info = info;
+ this.ctx = ctx;
+
+ }
+
+
+ // ------------------------------------------------ Methods from InputStream
+
+
+ @Override
+ public int read() throws IOException {
+ int i;
+ char c;
+
+ if (failedExpressionTest) {
+ i = nextRead;
+ nextRead = -1;
+ failedExpressionTest = false;
+ } else if (writingExpression) {
+ if (0 < buf.size()) {
+ i = buf.remove(0);
+ } else {
+ writingExpression = false;
+ i = inner.read();
+ }
+ } else {
+ // Read a character.
+ i = inner.read();
+ c = (char) i;
+ // If it *might* be an expression...
+ if (c == '#') {
+ // read another character.
+ i = inner.read();
+ c = (char) i;
+ // If it's '{', assume we have an expression.
+ if (c == '{') {
+ // read it into the buffer, and evaluate it into the
+ // same buffer.
+ readExpressionIntoBufferAndEvaluateIntoBuffer();
+ // set the flag so that we need to return content
+ // from the buffer.
+ writingExpression = true;
+ // Make sure to swallow the '{'.
+ i = this.read();
+ } else {
+ // It's not an expression, we need to return '#',
+ i = (int) '#';
+ // then return whatever we just read, on the
+ // *next* read;
+ nextRead = (int) c;
+ failedExpressionTest = true;
+ }
+ }
+ }
+
+ return i;
+ }
+
+ private void readExpressionIntoBufferAndEvaluateIntoBuffer()
+ throws IOException {
+
+ int i;
+ char c;
+ do {
+ i = inner.read();
+ c = (char) i;
+ if (c == '}') {
+ evaluateExpressionIntoBuffer();
+ } else {
+ buf.add(i);
+ }
+ } while (c != '}' && i != -1);
+ }
+
+ /*
+ * At this point, we know that getBuf() returns a List<Integer>
+ * that contains the bytes of the expression.
+ * Turn it into a String, turn the String into a ValueExpression,
+ * evaluate it, store the toString() of it in
+ * expressionResult;
+ */
+ private void evaluateExpressionIntoBuffer() {
+ char [] chars = new char[buf.size()];
+ int len = buf.size();
+ for (int i = 0; i < len; i++) {
+ chars[i] = (char) (int) buf.get(i);
+ }
+ String expressionBody = new String(chars);
+
+ // If this expression contains a ":"
+ int colon = expressionBody.indexOf(":");
+ if (-1 != colon) {
+ // Make sure it contains only one ":"
+ if (!isPropertyValid(expressionBody)) {
+ String message =
MessageFormat.format(INVALID_RESOURCE_FORMAT_COLON_ERROR,
+ expressionBody);
+ throw new ELException(message);
+ }
+ String[] parts = split(expressionBody, ":");
+ if (null == parts[0] || null == parts[1]) {
+ String message =
MessageFormat.format(INVALID_RESOURCE_FORMAT_NO_LIBRARY_NAME_ERROR,
+ expressionBody);
+ throw new ELException(message);
+
+ }
+ try {
+ int mark = parts[0].indexOf("[") + 2;
+ char quoteMark = parts[0].charAt(mark - 1);
+ parts[0] = parts[0].substring(mark, colon);
+ if (parts[0].equals("this")) {
+ parts[0] = info.getLibraryName();
+ mark = parts[1].indexOf("]") - 1;
+ parts[1] = parts[1].substring(0, mark);
+ expressionBody = "resource[" + quoteMark + parts[0] +
+ ":" + parts[1] + quoteMark + "]";
+ }
+ } catch (Exception e) {
+ String message = MessageFormat.format(INVALID_RESOURCE_FORMAT_ERROR,
+ expressionBody);
+ throw new ELException(message);
+
+ }
+ }
+ ELContext elContext = ctx.getELContext();
+ ValueExpression ve =
+ ctx.getApplication().getExpressionFactory().
+ createValueExpression(elContext, "#{" +
expressionBody +
+ "}", String.class);
+ Object value = ve.getValue(elContext);
+ String expressionResult = ((value != null) ? value.toString() :
"");
+ buf.clear();
+ int expressionResultLen = expressionResult.length();
+ for (int i = 0; i < expressionResultLen; i++) {
+ buf.add((int) expressionResult.charAt(i));
+ }
+ }
+
+
+ private String[] split(String expressionBody, String toSplit) {
+ return Pattern.compile(expressionBody).split(toSplit, 0);
+ }
+
+
+ @Override
+ public void close() throws IOException {
+ inner.close();
+ super.close();
+
+ }
+
+
+ private boolean isPropertyValid(String property) {
+ int idx = property.indexOf(':');
+ return (property.indexOf(':', idx + 1) == -1);
+ }
+
+ }
}
Modified:
root/framework/trunk/impl/src/main/java/org/richfaces/resource/ResourceHandlerImpl.java
===================================================================
---
root/framework/trunk/impl/src/main/java/org/richfaces/resource/ResourceHandlerImpl.java 2010-04-22
15:59:04 UTC (rev 16796)
+++
root/framework/trunk/impl/src/main/java/org/richfaces/resource/ResourceHandlerImpl.java 2010-04-23
00:12:50 UTC (rev 16797)
@@ -21,15 +21,15 @@
package org.richfaces.resource;
-import org.ajax4jsf.cache.Cache;
-import org.ajax4jsf.cache.CacheManager;
-import org.ajax4jsf.resource.Java2Dresource;
-import org.richfaces.context.AttributesContext;
-import org.richfaces.context.SingletonsContext;
-import org.richfaces.log.RichfacesLogger;
-import org.richfaces.util.RequestStateManager.BooleanRequestStateVariable;
-import org.richfaces.util.Util;
-import org.slf4j.Logger;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URL;
+import java.text.MessageFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Map.Entry;
import javax.faces.application.ProjectStage;
import javax.faces.application.Resource;
@@ -40,16 +40,17 @@
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.URL;
-import java.text.MessageFormat;
-import java.util.Date;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Map.Entry;
+import org.ajax4jsf.cache.Cache;
+import org.ajax4jsf.cache.CacheManager;
+import org.ajax4jsf.resource.Java2Dresource;
+import org.richfaces.context.AttributesContext;
+import org.richfaces.context.SingletonsContext;
+import org.richfaces.log.RichfacesLogger;
+import org.richfaces.util.Util;
+import org.richfaces.util.RequestStateManager.BooleanRequestStateVariable;
+import org.slf4j.Logger;
+
/**
* @author Nick Belaevski
* @since 4.0
@@ -469,7 +470,7 @@
result = createHandlerDependentResource(resourceName, params);
} else {
result = defaultHandler.createResource(resourceName, libraryName,
contentType);
- if (resourceName.indexOf(".ecss") != -1) {
+ if (result != null && resourceName.endsWith(".ecss")) {
result = new CompiledCSSResource(result);
}
}
@@ -497,9 +498,10 @@
@Override
public String getRendererTypeForResourceName(String resourceName) {
- if (resourceName.indexOf(".ecss") != -1) {
+ if (resourceName.endsWith(".ecss")) {
return "javax.faces.resource.Stylesheet";
}
+
return defaultHandler.getRendererTypeForResourceName(resourceName);
}
Modified:
root/framework/trunk/impl/src/main/java/org/richfaces/resource/Xcss2EcssConverter.java
===================================================================
---
root/framework/trunk/impl/src/main/java/org/richfaces/resource/Xcss2EcssConverter.java 2010-04-22
15:59:04 UTC (rev 16796)
+++
root/framework/trunk/impl/src/main/java/org/richfaces/resource/Xcss2EcssConverter.java 2010-04-23
00:12:50 UTC (rev 16797)
@@ -1,21 +1,20 @@
package org.richfaces.resource;
import java.io.File;
+import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
-import java.io.IOException;
-import java.net.URLDecoder;
+import java.net.URLEncoder;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
+import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
-import org.xml.sax.Attributes;
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.ParserConfigurationException;
-
public final class Xcss2EcssConverter {
private Xcss2EcssConverter() {
@@ -132,7 +131,7 @@
ecssContent.append(name);
ecssContent.append("=");
try {
- ecssContent.append(URLDecoder.decode(value, "UTF-8"));
+ ecssContent.append(URLEncoder.encode(value, "UTF-8"));
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Added:
root/framework/trunk/impl/src/main/java/org/richfaces/resource/css/AbstractCSSVisitor.java
===================================================================
---
root/framework/trunk/impl/src/main/java/org/richfaces/resource/css/AbstractCSSVisitor.java
(rev 0)
+++
root/framework/trunk/impl/src/main/java/org/richfaces/resource/css/AbstractCSSVisitor.java 2010-04-23
00:12:50 UTC (rev 16797)
@@ -0,0 +1,153 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.resource.css;
+
+import org.w3c.dom.css.CSSCharsetRule;
+import org.w3c.dom.css.CSSFontFaceRule;
+import org.w3c.dom.css.CSSImportRule;
+import org.w3c.dom.css.CSSMediaRule;
+import org.w3c.dom.css.CSSPageRule;
+import org.w3c.dom.css.CSSRule;
+import org.w3c.dom.css.CSSRuleList;
+import org.w3c.dom.css.CSSStyleDeclaration;
+import org.w3c.dom.css.CSSStyleRule;
+import org.w3c.dom.css.CSSStyleSheet;
+import org.w3c.dom.css.CSSUnknownRule;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public abstract class AbstractCSSVisitor {
+
+ public void visitStyleSheet(CSSStyleSheet styleSheet) {
+ startStyleSheet(styleSheet);
+
+ CSSRuleList rules = styleSheet.getCssRules();
+ int length = rules.getLength();
+ for (int i = 0; i < length; i++) {
+ CSSRule rule = rules.item(i);
+ visitRule(rule);
+ }
+
+ endStyleSheet(styleSheet);
+ }
+
+ public void visitRule(CSSRule rule) {
+ switch (rule.getType()) {
+ case CSSRule.UNKNOWN_RULE:
+ visitUnknownRule((CSSUnknownRule) rule);
+ break;
+
+ case CSSRule.STYLE_RULE:
+ visitStyleRule((CSSStyleRule) rule);
+ break;
+
+ case CSSRule.CHARSET_RULE:
+ visitCharsetRule((CSSCharsetRule) rule);
+ break;
+
+ case CSSRule.IMPORT_RULE:
+ visitImportRule((CSSImportRule) rule);
+ break;
+
+ case CSSRule.MEDIA_RULE:
+ visitMediaRule((CSSMediaRule) rule);
+ break;
+
+ case CSSRule.FONT_FACE_RULE:
+ visitFontFaceRule((CSSFontFaceRule) rule);
+ break;
+
+ case CSSRule.PAGE_RULE:
+ visitPageRule((CSSPageRule) rule);
+ break;
+
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
+ protected abstract void startStyleSheet(CSSStyleSheet styleSheet);
+
+ protected abstract void endStyleSheet(CSSStyleSheet styleSheet);
+
+ public abstract void visitUnknownRule(CSSUnknownRule rule);
+
+ public void visitStyleRule(CSSStyleRule rule) {
+ startStyleRule(rule);
+ CSSStyleDeclaration style = rule.getStyle();
+ visitStyleDeclaration(style);
+ endStyleRule(rule);
+ }
+
+ protected abstract void startStyleRule(CSSStyleRule rule);
+
+ protected abstract void endStyleRule(CSSStyleRule rule);
+
+ public abstract void visitCharsetRule(CSSCharsetRule rule);
+
+ public abstract void visitImportRule(CSSImportRule rule);
+
+ public void visitMediaRule(CSSMediaRule rule) {
+ startMediaRule(rule);
+
+ CSSRuleList rules = rule.getCssRules();
+ int length = rules.getLength();
+ for (int i = 0; i < length; i++) {
+ CSSRule childRule = rules.item(i);
+ visitRule(childRule);
+ }
+
+
+ endMediaRule(rule);
+ }
+
+ protected abstract void startMediaRule(CSSMediaRule rule);
+
+ protected abstract void endMediaRule(CSSMediaRule rule);
+
+ public void visitFontFaceRule(CSSFontFaceRule rule) {
+ startFontRule(rule);
+ CSSStyleDeclaration style = rule.getStyle();
+ visitStyleDeclaration(style);
+ endFontRule(rule);
+ }
+
+ protected abstract void startFontRule(CSSFontFaceRule rule);
+
+ protected abstract void endFontRule(CSSFontFaceRule rule);
+
+ public void visitPageRule(CSSPageRule rule) {
+ startPageRule(rule);
+ CSSStyleDeclaration style = rule.getStyle();
+ visitStyleDeclaration(style);
+ endPageRule(rule);
+ }
+
+ protected abstract void startPageRule(CSSPageRule rule);
+
+ protected abstract void endPageRule(CSSPageRule rule);
+
+ public abstract void visitStyleDeclaration(CSSStyleDeclaration styleDeclaration);
+
+}
Added:
root/framework/trunk/impl/src/main/java/org/richfaces/resource/css/CSSVisitorImpl.java
===================================================================
---
root/framework/trunk/impl/src/main/java/org/richfaces/resource/css/CSSVisitorImpl.java
(rev 0)
+++
root/framework/trunk/impl/src/main/java/org/richfaces/resource/css/CSSVisitorImpl.java 2010-04-23
00:12:50 UTC (rev 16797)
@@ -0,0 +1,190 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.resource.css;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.w3c.dom.css.CSSCharsetRule;
+import org.w3c.dom.css.CSSFontFaceRule;
+import org.w3c.dom.css.CSSImportRule;
+import org.w3c.dom.css.CSSMediaRule;
+import org.w3c.dom.css.CSSPageRule;
+import org.w3c.dom.css.CSSRule;
+import org.w3c.dom.css.CSSStyleDeclaration;
+import org.w3c.dom.css.CSSStyleRule;
+import org.w3c.dom.css.CSSStyleSheet;
+import org.w3c.dom.css.CSSUnknownRule;
+import org.w3c.dom.stylesheets.MediaList;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public final class CSSVisitorImpl extends AbstractCSSVisitor {
+
+ private static final String NEW_LINE = "\r\n";
+
+ private String encoding;
+
+ private StringBuilder buffer = new StringBuilder();
+
+ private List<String> prefixes = new ArrayList<String>(2);
+
+ private void appendCSSText(CSSRule rule) {
+ String cssText = rule.getCssText().trim();
+
+ //TODO nick - escape values
+ if (cssText.length() != 0) {
+ buffer.append(cssText);
+ buffer.append(NEW_LINE);
+ }
+ }
+
+ private void flushPrefixes() {
+ if (!prefixes.isEmpty()) {
+ for (String prefix : prefixes) {
+ buffer.append(prefix);
+ buffer.append(" {");
+ buffer.append(NEW_LINE);
+ }
+
+ prefixes.clear();
+ }
+ }
+
+ private void flushSuffix() {
+ if (prefixes.isEmpty()) {
+ buffer.append('}');
+ buffer.append(NEW_LINE);
+ }
+ }
+
+ @Override
+ public void visitUnknownRule(CSSUnknownRule rule) {
+ appendCSSText(rule);
+ }
+
+ @Override
+ public void visitCharsetRule(CSSCharsetRule rule) {
+ encoding = rule.getEncoding();
+
+ appendCSSText(rule);
+ }
+
+ @Override
+ public void visitImportRule(CSSImportRule rule) {
+ //TODO nick - process imported stylesheet?
+ appendCSSText(rule);
+ }
+
+ @Override
+ protected void startFontRule(CSSFontFaceRule rule) {
+ prefixes.add("@font-face");
+ }
+
+ @Override
+ protected void endFontRule(CSSFontFaceRule rule) {
+ flushSuffix();
+ }
+
+ @Override
+ protected void startMediaRule(CSSMediaRule rule) {
+ MediaList mediaList = rule.getMedia();
+ String mediaText = mediaList.getMediaText();
+ prefixes.add("@media " + mediaText);
+ }
+
+ @Override
+ protected void endMediaRule(CSSMediaRule rule) {
+ flushSuffix();
+ }
+
+ @Override
+ protected void startPageRule(CSSPageRule rule) {
+ String selectorText = rule.getSelectorText();
+
+ //TODO nick - multiple selectors?
+ prefixes.add("@page " + selectorText);
+ }
+
+ @Override
+ protected void endPageRule(CSSPageRule rule) {
+ flushSuffix();
+ }
+
+ @Override
+ protected void startStyleRule(CSSStyleRule rule) {
+ String selectorText = rule.getSelectorText();
+ prefixes.add(selectorText);
+ }
+
+ @Override
+ protected void endStyleRule(CSSStyleRule rule) {
+ flushSuffix();
+ }
+
+ @Override
+ protected void startStyleSheet(CSSStyleSheet styleSheet) {
+ }
+
+ @Override
+ protected void endStyleSheet(CSSStyleSheet styleSheet) {
+ }
+
+ @Override
+ public void visitStyleDeclaration(CSSStyleDeclaration styleDeclaration) {
+ for (int j = 0; j < styleDeclaration.getLength(); j++) {
+ String propertyName = styleDeclaration.item(j);
+
+ String value = styleDeclaration.getPropertyValue(propertyName).trim();
+ String priority = styleDeclaration.getPropertyPriority(propertyName);
+
+ if (value.length() != 0 && !value.equals("\"\"")
&& !value.equals("''")) {
+ flushPrefixes();
+
+ //One of properties of selector is not empty
+ buffer.append('\t');
+ buffer.append(propertyName);
+ buffer.append(": ");
+
+ buffer.append(value);
+
+ if (priority != null && priority.length() != 0) {
+ buffer.append(" !");
+ buffer.append(priority);
+ }
+
+ buffer.append(";");
+ buffer.append(NEW_LINE);
+ }
+ }
+ }
+
+ public String getEncoding() {
+ return encoding;
+ }
+
+ public String getCSSText() {
+ return buffer.toString();
+ }
+}