/* * Copyright (c) 2009. */ package ro.isdc.wro.model.resource.processor.impl.css; import java.io.IOException; import java.io.Reader; import java.io.Writer; import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ro.isdc.wro.model.resource.Resource; import ro.isdc.wro.model.resource.ResourceType; import ro.isdc.wro.model.resource.SupportedResourceType; import ro.isdc.wro.model.resource.processor.ResourcePostProcessor; import ro.isdc.wro.model.resource.processor.ResourcePreProcessor; import ro.isdc.wro.util.WroUtil; /** * Processor of css resources, responsible for replacing variables. (@see * http://disruptive-innovations.com/zoo/cssvariables/). This is a pre processor, because it makes sense to apply * variables only on the same css. <br/> * This processor is implemented as both: preprocessor & postprocessor. * * @author Alex Objelean * @created Created on Jul 05, 2009 */ @SupportedResourceType(ResourceType.CSS) public class CssVariablesProcessor implements ResourcePreProcessor, ResourcePostProcessor { private static final Logger LOG = LoggerFactory.getLogger(CssVariablesProcessor.class); public static final String ALIAS = "cssVariables"; /** * Compiled pattern for REGEX_VARIABLES_DEFINITION regex. */ private static final Pattern PATTERN_VARIABLES_DEFINITION = Pattern.compile(WroUtil.loadRegexpWithKey("cssVariables.definition")); /** * Compiled pattern for REGEX_VARIABLES_BODY pattern. */ private static final Pattern PATTERN_VARIABLES_BODY = Pattern.compile(WroUtil.loadRegexpWithKey("cssVariables.body")); /** * Compiled pattern for REGEX_VARIABLE_HOLDER pattern. */ private static final Pattern PATTERN_VARIABLE_HOLDER = Pattern.compile(WroUtil.loadRegexpWithKey("cssVariables.holder")); /** * Extract variables map from variables body. * * @param variablesBody * string containing variables mappings. * @return map with extracted variables. */ private Map<String, String> extractVariables(final String variablesBody) { final Map<String, String> map = new HashMap<String, String>(); final Matcher m = PATTERN_VARIABLES_BODY.matcher(variablesBody); LOG.debug("parsing variables body"); while (m.find()) { final String key = m.group(1); final String value = m.group(2); if (map.containsKey(key)) { LOG.warn("A duplicate variable name found with name: {} and value: {}.", key, value); } map.put(key, value); } return map; } /** * {@inheritDoc} */ public void process(final Reader reader, final Writer writer) throws IOException { process(null, reader, writer); } /** * {@inheritDoc} */ public void process(final Resource resource, final Reader reader, final Writer writer) throws IOException { try { final String css = IOUtils.toString(reader); final String result = parseCss(css); writer.write(result); } finally { reader.close(); writer.close(); } } /** * Parse css, find all defined variables & replace them. * * @param css * to parse. */ private String parseCss(final String css) { // map containing variables & their values final Map<String, String> map = new HashMap<String, String>(); final StringBuffer sb = new StringBuffer(); final Matcher m = PATTERN_VARIABLES_DEFINITION.matcher(css); while (m.find()) { final String variablesBody = m.group(1); // LOG.debug("variables body: " + variablesBody); // extract variables map.putAll(extractVariables(variablesBody)); // remove variables definition m.appendReplacement(sb, ""); } m.appendTail(sb); final String result = replaceVariables(sb.toString(), map); // LOG.debug("replaced variables: " + result); return result; } /** * Replace variables from css with provided variables map. * * @param cleanCss * used to replace variable placeholders. * @param variables * map of variables used for substitution. * @return css with all variables replaced. */ private String replaceVariables(final String css, final Map<String, String> variables) { final StringBuffer sb = new StringBuffer(); final Matcher m = PATTERN_VARIABLE_HOLDER.matcher(css); while (m.find()) { final String oldMatch = m.group(); final String variableName = m.group(1); final String variableValue = variables.get(variableName); if (variableValue != null) { final String newReplacement = oldMatch.replace(oldMatch, variableValue); m.appendReplacement(sb, newReplacement.trim()); } else { LOG.warn("No variable with name " + variableName + " was found!"); } } m.appendTail(sb); return sb.toString(); } }