All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.agilecoders.wicket.less.LessPackageResource Maven / Gradle / Ivy

package de.agilecoders.wicket.less;

import de.agilecoders.wicket.Bootstrap;
import de.agilecoders.wicket.settings.IBootstrapLessCompilerSettings;
import org.apache.wicket.Application;
import org.apache.wicket.WicketRuntimeException;
import org.apache.wicket.request.resource.CssPackageResource;
import org.apache.wicket.util.lang.Bytes;
import org.apache.wicket.util.resource.IResourceStream;
import org.apache.wicket.util.resource.ResourceStreamNotFoundException;
import org.apache.wicket.util.time.Duration;
import org.apache.wicket.util.time.Time;

import java.io.IOException;
import java.io.InputStream;
import java.util.Locale;

/**
 * Package resource for css files. It strips comments and whitespace from css.
 *
 * @author miha
 * @version 1.0
 */
public class LessPackageResource extends CssPackageResource {
    private static final long serialVersionUID = 1L;

    private final LessCompilable lessCompilable;
    private boolean compile;
    private Time lastModifiedTime;

    /**
     * Construct.
     *
     * @param scope     This argument will be used to get the class loader for loading the package
     *                  resource, and to determine what package it is in
     * @param name      The relative path to the resource
     * @param locale    The locale of the resource
     * @param style     The style of the resource
     * @param variation The component's variation (of the style)
     */
    public LessPackageResource(Class scope, String name, Locale locale, String style,
                               String variation, LessCompilable lessCompilable) {
        super(scope, name, locale, style, variation);

        this.lessCompilable = lessCompilable;
        this.compile = settings().useLessCompiler();
    }

    public boolean getCompile() {
        return compile && settings().useLessCompiler();
    }

    public LessPackageResource setCompile(final boolean compile) {
        this.compile = compile;
        return this;
    }

    @Override
    protected byte[] processResponse(final Attributes attributes, final byte[] bytes) {
        IBootstrapLessCompiler compiler = getCompiler();

        if (compiler != null && getCompile()) {
            final byte[] content = super.processResponse(attributes, compiler.generate(lessCompilable));

            if (settings().storeChanges() && wasModified()) {
                storeChanges(content);
            }

            return content;
        } else {
            return super.processResponse(attributes, bytes);
        }
    }

    protected boolean wasModified() {
        return lastModifiedTime != null &&
               lastModifiedTime.after(Time.now().subtract(Duration.seconds(10)));
    }

    protected void storeChanges(byte[] content) {
        try {
            lessCompilable.storeCompiledLess(content);
        } catch (IOException e) {
            throw new WicketRuntimeException(e);
        }
    }

    /**
     * Gets the {@link BootstrapLessCompiler} to be used. By default returns the configured compiler on
     * application level, but can be overriden by the user application to provide compiler
     * specific to the resource.
     *
     * @return the configured application level less compiler. May be {@code null}.
     */
    protected IBootstrapLessCompiler getCompiler() {
        IBootstrapLessCompiler compiler = null;
        if (Application.exists()) {
            compiler = settings().getLessCompiler();
        }
        return compiler;
    }

    /**
     * @return the bootstrap less compiler settings.
     */
    private IBootstrapLessCompilerSettings settings() {
        return Bootstrap.getSettings(Application.get()).getBootstrapLessCompilerSettings();
    }

    @Override
    public IResourceStream getResourceStream() {
        IResourceStream delegate = super.getResourceStream();

        if (delegate != null) {
            ResourceStreamDecorator stream = new ResourceStreamDecorator(delegate);

            lastModifiedTime = detectLastModifiedTime();
            stream.setLastModifiedTime(lastModifiedTime);

            return stream;
        }

        return delegate;
    }

    /**
     * detects the last modified timestamp of all less files and their imports.
     *
     * @return last modified time
     */
    private Time detectLastModifiedTime() {
        switch (settings().getCacheStrategy()) {
            case Never: return Time.now().add(Duration.days(365));
            case Forever: return Time.START_OF_UNIX_TIME;
        }
        return getCompiler().lastModifiedRecursive(lessCompilable);
    }

    private static final class ResourceStreamDecorator implements IResourceStream {

        private final IResourceStream resourceStream;
        private Time lastModifiedTime;

        private ResourceStreamDecorator(IResourceStream resourceStream) {
            this.resourceStream = resourceStream;
        }

        @Override
        public String getContentType() {
            return resourceStream.getContentType();
        }

        @Override
        public Bytes length() {
            return resourceStream.length();
        }

        @Override
        public InputStream getInputStream() throws ResourceStreamNotFoundException {
            return resourceStream.getInputStream();
        }

        @Override
        public void close() throws IOException {
            resourceStream.close();
        }

        @Override
        public Locale getLocale() {
            return resourceStream.getLocale();
        }

        @Override
        public void setLocale(Locale locale) {
            resourceStream.setLocale(locale);
        }

        @Override
        public String getStyle() {
            return resourceStream.getStyle();
        }

        @Override
        public void setStyle(String style) {
            resourceStream.setStyle(style);
        }

        @Override
        public String getVariation() {
            return resourceStream.getVariation();
        }

        @Override
        public void setVariation(String variation) {
            resourceStream.setVariation(variation);
        }

        @Override
        public Time lastModifiedTime() {
            return lastModifiedTime;
        }

        private void setLastModifiedTime(Time time) {
            lastModifiedTime = time;
        }
    }
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy