content: package ro.isdc.wro.extensions.processor.css;
  
  import static org.apache.commons.lang3.Validate.notNull;
  
  import java.io.IOException;
  import java.io.Reader;
  import java.io.Writer;
  
  import org.apache.commons.io.IOUtils;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  import ro.isdc.wro.WroRuntimeException;
  import ro.isdc.wro.model.group.Inject;
  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.locator.factory.UriLocatorFactory;
  import ro.isdc.wro.model.resource.processor.ResourcePostProcessor;
  import ro.isdc.wro.model.resource.processor.ResourcePreProcessor;
  import ro.isdc.wro.util.WroUtil;
  
  import com.github.sommeri.less4j.Less4jException;
  import com.github.sommeri.less4j.LessCompiler;
  import com.github.sommeri.less4j.LessCompiler.CompilationResult;
  import com.github.sommeri.less4j.LessCompiler.Problem;
  import com.github.sommeri.less4j.LessSource;
  import com.github.sommeri.less4j.core.DefaultLessCompiler;
  
  
  /**
   * Yet another processor which compiles less to css. This implementation uses open source java library called less4j.
   *
   * @author Alex Objelean
   * @since 1.6.0
   * @created 5 Oct 2012
   */
  @SupportedResourceType(ResourceType.CSS)
  public class Less4jProcessor
      implements ResourcePreProcessor, ResourcePostProcessor {
    private static final Logger LOG = LoggerFactory.getLogger(Less4jProcessor.class);
    public static final String ALIAS = "less4j";
  
    /**
     * Required to use the less4j import mechanism.
     */
    private static class RelativeAwareLessSource
        extends LessSource.StringSource {
      private final Resource resource;
      private final UriLocatorFactory locatorFactory;
  
      public RelativeAwareLessSource(final Resource resource, final String content, final UriLocatorFactory locatorFactory) {
        super(content);
        this.resource = resource;
        notNull(locatorFactory);
        this.locatorFactory = locatorFactory;
      }
  
      @Override
      public LessSource relativeSource(final String relativePath)
          throws StringSourceException {
        return resource != null ? computeRelative(resource, relativePath) : super.relativeSource(relativePath);
      }
  
      private LessSource computeRelative(final Resource resource, final String relativePath) throws StringSourceException {
        try {
          final String relativeResourceUri = computeRelativeResourceUri(resource.getUri(), relativePath);
          final Resource relativeResource = Resource.create(relativeResourceUri, ResourceType.CSS);
          final String relativeResourceContent = IOUtils.toString(locatorFactory.locate(relativeResourceUri), "UTF-8");
          return new RelativeAwareLessSource(relativeResource, relativeResourceContent, locatorFactory);
        } catch (final IOException e) {
          LOG.error("Failed to compute relative resource: " + resource, e);
          throw new StringSourceException();
        }
      }
  
      public String computeRelativeResourceUri(final String originalResourceUri, final String relativePath) {
        final String fullPath = WroUtil.getFullPath(originalResourceUri) + relativePath;
        return WroUtil.normalize(fullPath);
      }
    }
    @Inject
    private UriLocatorFactory locatorFactory;
  
    private final LessCompiler compiler = new DefaultLessCompiler();
  
    @Override
    public void process(final Reader reader, final Writer writer)
        throws IOException {
      process(null, reader, writer);
    }
  
    @Override
    public void process(final Resource resource, final Reader reader, final Writer writer)
        throws IOException {
      try {
        final LessSource lessSource = new RelativeAwareLessSource(resource, IOUtils.toString(reader), locatorFactory);
        final CompilationResult result = compiler.compile(lessSource);
        logWarnings(result);
        writer.write(result.getCss());
      } catch (final Less4jException e) {
        LOG.error("Failed to compile less resource: {}.", resource);
        for (final Problem problem : e.getErrors()) {
          LOG.error(problemAsString(problem));
        }
        throw WroRuntimeException.wrap(e);
      }
    }
  
    private void logWarnings(final CompilationResult result) {
      if (!result.getWarnings().isEmpty()) {
        LOG.warn("Less warnings are:");
        for (final Problem problem : result.getWarnings()) {
          LOG.warn(problemAsString(problem));
        }
      }
    }
  
    private String problemAsString(final Problem problem) {
      return String.format("%s:%s %s.", problem.getLine(), problem.getCharacter(), problem.getMessage());
    }
  }
  