content: /**
   * Copyright wro4j@2011
   */
  package ro.isdc.wro.model.resource.processor.impl;
  
  import java.io.IOException;
  import java.io.Reader;
  import java.io.Writer;
  import java.util.Properties;
  import java.util.regex.Matcher;
  import java.util.regex.Pattern;
  
  import org.apache.commons.io.IOUtils;
  import org.apache.commons.lang3.StringUtils;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  import ro.isdc.wro.WroRuntimeException;
  import ro.isdc.wro.model.resource.Resource;
  import ro.isdc.wro.model.resource.processor.ResourcePostProcessor;
  import ro.isdc.wro.model.resource.processor.ResourcePreProcessor;
  import ro.isdc.wro.util.ObjectFactory;
  import ro.isdc.wro.util.WroUtil;
  
  
  /**
   * A processor which parse a resource and search for placeholders of this type: <code>${}</code> and replace them with
   * the values found in a map provided the by client.
   *
   * @author Alex Objelean
   * @since 1.3.8
   * @created 15 Jun 2011
   */
  public class PlaceholderProcessor
    implements ResourcePreProcessor, ResourcePostProcessor {
    private static final Logger LOG = LoggerFactory.getLogger(PlaceholderProcessor.class);
    private static final Pattern PATTERN_PLACEHOLDER = Pattern.compile(WroUtil.loadRegexpWithKey("placeholder"));
    private static final Properties EMPTY_PROPERTIES = new Properties();
  
    /**
     * Factory used to build Properties object containing values of the variables to substitute.
     */
    private ObjectFactory<Properties> propertiesFactory;
  
    /**
     * If false, when a variable is not defined, a runtime exception will be thrown. Default value is true - meaning that
     * missing variables will be replaced with empty value.
     */
    private boolean ignoreMissingVariables = true;
  
    /**
     * {@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 {
      final String content = IOUtils.toString(reader);
      final Matcher matcher = PATTERN_PLACEHOLDER.matcher(content);
      final StringBuffer sb = new StringBuffer();
  
      Properties properties = null;
      if (propertiesFactory != null) {
        properties = propertiesFactory.create();
      }
      //be sure that properties will never be null;
      if (properties == null) {
        properties = EMPTY_PROPERTIES;
      }
      while (matcher.find()) {
        final String variableName = matcher.group(1);
        LOG.debug("found placeholder: {}", variableName);
        matcher.appendReplacement(sb, replaceVariable(properties, variableName));
      }
      matcher.appendTail(sb);
      writer.write(sb.toString());
    }
  
  
    /**
     * @param variableName
     * @return
     */
    private String replaceVariable(final Properties properties, final String variableName) {
      final String variableValue = properties.getProperty(variableName);
      if (!ignoreMissingVariables && variableValue == null) {
        throw new WroRuntimeException("No value defind for variable called: [" + variableName + "]");
      }
  
      final String result = variableValue == null ? StringUtils.EMPTY : variableValue;
      LOG.debug("replacing: [{}] with [{}]", variableName, result);
      return result;
    }
  
  
    /**
     * @param ignoreMissingVariables the ignoreMissingVariables to set
     */
    public PlaceholderProcessor setIgnoreMissingVariables(final boolean ignoreMissingVariables) {
      this.ignoreMissingVariables = ignoreMissingVariables;
      return this;
    }
  
  
    /**
     * @param propertiesFactory the propertiesFactory to set
     */
    public PlaceholderProcessor setPropertiesFactory(final ObjectFactory<Properties> propertiesFactory) {
      this.propertiesFactory = propertiesFactory;
      return this;
    }
  }
  