///////////////////////////////////////////////////////////////////////////// // // Project ProjectForge Community Edition // www.projectforge.org // // Copyright (C) 2001-2014 Kai Reinhard (k.reinhard@micromata.de) // // ProjectForge is dual-licensed. // // This community edition is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as published // by the Free Software Foundation; version 3 of the License. // // This community edition 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 General // Public License for more details. // // You should have received a copy of the GNU General Public License along // with this program; if not, see http://www.gnu.org/licenses/. // ///////////////////////////////////////////////////////////////////////////// package de.micromata.less; import java.io.File; import java.io.Serializable; import org.apache.wicket.markup.head.CssReferenceHeaderItem; import org.apache.wicket.markup.head.IHeaderResponse; import org.apache.wicket.util.listener.IChangeListener; import org.apache.wicket.util.watch.IModificationWatcher; import org.lesscss.LessCompiler; import org.lesscss.LessSource; import org.projectforge.core.Configuration; import org.projectforge.web.wicket.WicketApplication; import org.springframework.util.StringUtils; /** * Compiler utility class for less resource files * * @author Johannes Unterstein (j.unterstein@micromata.de) * */ public class LessWicketApplicationInstantiator implements Serializable { private static final long serialVersionUID = 243362344112860106L; private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LessWicketApplicationInstantiator.class); private static LessWicketApplicationInstantiator instance; private LessResourceReference reference; private final WicketApplication application; private final String folder; private final String lessPath; private final String cssPath; private final String relativeCssPath; private File referenceFile; private File lessTargetFile; private File cssTargetFile; /** * * @param application * @param folder * @param lessPath * @param cssPath */ public LessWicketApplicationInstantiator(final WicketApplication application, final String folder, final String lessPath, final String cssPath) { this.application = application; this.folder = folder; this.lessPath = lessPath; this.cssPath = cssPath; this.relativeCssPath = folder + "/" + cssPath; instance = this; } private void instantiateFiles() throws Exception { referenceFile = new File(application.getClass().getClassLoader().getResource("i18nKeys.properties").toURI()).getParentFile(); lessTargetFile = new File(referenceFile.getAbsolutePath() + "/" + folder + "/" + lessPath); cssTargetFile = new File(lessTargetFile.getAbsolutePath().replace(lessPath, "") + cssPath); } /** * compiles the saved .less to the wanted .css file * * @return * @throws Exception */ private LessSource compile() throws Exception { // compile file final LessCompiler lessCompiler = new LessCompiler(); // create new source final LessSource mainLessSource = new LessSource(lessTargetFile); log.info("compiling " + lessTargetFile.getAbsolutePath() + " to " + cssTargetFile.getAbsolutePath()); lessCompiler.compile(mainLessSource, cssTargetFile, false); return mainLessSource; } /** * instantiates the actual less compilement * * @throws Exception */ public void instantiate() throws Exception { instantiateFiles(); final LessSource mainLessSource = compile(); if (Configuration.isDevelopmentMode() == true) { // only add this fancy resource watcher in dev mode final IModificationWatcher resourceWatcher = application.getResourceSettings().getResourceWatcher(true); // add watchers addWatcher(resourceWatcher, mainLessSource); for (final LessSource importedSource : mainLessSource.getImports().values()) { addWatcher(resourceWatcher, importedSource); } } // mount compiled css file reference = new LessResourceReference(relativeCssPath, cssTargetFile); application.mountResource(encodePathWithCachingStrategy(relativeCssPath), reference); } public String encodePathWithCachingStrategy(final String path) { // wicket uses by default -ver-, so we need to use another prefix return StringUtils.replace(path, ".css", "-version-" + WicketApplication.getStartTime() + ".css"); } /** * adds a resource watcher entry to the given less source * * @param resourceWatcher * @param importedSource */ private void addWatcher(final IModificationWatcher resourceWatcher, final LessSource importedSource) { log.info("adding watcher to less file " + importedSource.getAbsolutePath()); resourceWatcher.add(new org.apache.wicket.util.file.File(new File(importedSource.getAbsolutePath())), new IChangeListener() { @Override public void onChange() { try { compile(); } catch (final Exception e) { log.error("unable to compile less source during watcher for file " + importedSource.getAbsolutePath(), e); } } }); } /** * Renders the compiled css reference to the given response * @param response */ public static void renderCompiledCssResource(final IHeaderResponse response) { if (instance != null && instance.reference != null) { response.render(CssReferenceHeaderItem.forReference(instance.reference)); } else { log.error("Unable to find compiled main projectforge.css less file"); } } }