Package net.andydvorak.intellij.lessc.fs

Source Code of net.andydvorak.intellij.lessc.fs.LessCompileJob

/*
* Copyright 2012 Andrew C. Dvorak.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package net.andydvorak.intellij.lessc.fs;

import com.asual.lesscss.LessEngine;
import com.asual.lesscss.LessException;
import com.intellij.openapi.diagnostic.Logger;
import net.andydvorak.intellij.lessc.observer.CompileEvent;
import net.andydvorak.intellij.lessc.observer.CompileObservable;
import net.andydvorak.intellij.lessc.observer.CompileObserver;
import net.andydvorak.intellij.lessc.state.LessProfile;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

public class LessCompileJob implements CompileObservable {

    private static final long WAIT_INTERVAL_MS = 250;
    private static final Logger LOG = Logger.getInstance("#" + LessCompileJob.class.getName());

    private final AtomicBoolean compiled = new AtomicBoolean();
    private final AtomicBoolean running = new AtomicBoolean();

    private final AtomicLong finished = new AtomicLong(0);

    private final LessFile sourceLessFile;
    private final LessProfile lessProfile;

    private final Set<LessFile> sourceAndDependents = new LinkedHashSet<LessFile>();
    private final AtomicInteger curLessFileIndex = new AtomicInteger(-1);

    private final Set<LessFile> updatedLessFiles = new LinkedHashSet<LessFile>();
    private final Set<CompileObserver> observers = new LinkedHashSet<CompileObserver>();

    /*
     * Constructors
     */

    public LessCompileJob(final LessFile sourceLessFile, final LessProfile lessProfile) {
        this.sourceLessFile = sourceLessFile;
        this.lessProfile = lessProfile;
    }

    /*
     * Public instance methods
     */

    public LessFile getSourceLessFile() {
        return sourceLessFile;
    }

    public Set<LessFile> getSourceAndDependents() {
        return sourceAndDependents;
    }

    public LessFile getCurLessFile() {
        final int index = curLessFileIndex.get();
        if (!sourceAndDependents.isEmpty() && index > -1) {
            final LessFile[] lessFiles = new LessFile[sourceAndDependents.size()];
            sourceAndDependents.toArray(lessFiles);
            return lessFiles[index];
        } else {
            return null;
        }
    }

    public void addUpdatedLessFile(final LessFile lessFile) {
        updatedLessFiles.add(lessFile);
    }

    /**
     * @return set of LESS {@code File}s that produced new or updated CSS files after being compiled
     */
    public Set<LessFile> getUpdatedLessFiles() {
        return new LinkedHashSet<LessFile>(updatedLessFiles);
    }

    public int getNumUpdated() {
        return getUpdatedLessFiles().size();
    }

    @Override
    public void addObserver(@NotNull final CompileObserver observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(@NotNull final CompileObserver observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers(@NotNull final CompileEvent event) {
        for (final CompileObserver observer : observers) {
            event.notify(observer);
        }
    }

    public void compile() throws IOException, LessException, IllegalStateException {
        preventConcurrency();
        try {
            start();
        } finally {
            finish();
        }
    }

    public void refreshVFS() {
        if (lessProfile != null)
            VirtualFileLocationChange.refresh(lessProfile.getCssDirectories());
    }

    public boolean isRunning() {
        return running.get();
    }

    public boolean isFinished() {
        return compiled.get();
    }

    public boolean needsToWait() {
        return isRunning() || (isFinished() && System.currentTimeMillis() - finished.get() <= WAIT_INTERVAL_MS);
    }

    /*
    * Private instance methods
    */

    /**
     * Throws an {@code IllegalStateException} if this job is run more than once.
     * @throws IllegalStateException
     */
    private void preventConcurrency() throws IllegalStateException {
        if (compiled.get() || running.get()) {
            final String message = "LessCompileJob for \"" + sourceLessFile.getName() + "\" can only be compiled once.";
            LOG.error(message);
            throw new IllegalStateException(message);
        }
    }

    private void findSourceAndDependents() throws IOException {
        if (sourceAndDependents.isEmpty()) {
            sourceAndDependents.add(sourceLessFile);
            if (lessProfile != null && lessProfile.hasCssDirectories()) {
                final Set<LessFile> dependents = sourceLessFile.getDependentsRecursive(lessProfile);
                sourceAndDependents.addAll(dependents);
            }
        }
    }

    private void start() throws IOException, LessException {
        running.set(true);

        findSourceAndDependents();

        notifyObservers(new CompileEvent() {
            @Override
            public void notify(@NotNull final CompileObserver observer) {
                observer.compileStarted(sourceAndDependents);
            }
        });

        for (final LessFile lessFile : sourceAndDependents) {
            compile(lessFile);
        }
    }

    private void compile(@NotNull final LessFile lessFile) throws IOException, LessException {
        final boolean cssChanged;

        curLessFileIndex.incrementAndGet();

        if (lessFile.shouldCompile(lessProfile)) {
            lessFile.compile(LessEngine.getInstance(), lessProfile);
            cssChanged = lessFile.hasCssChanged();
        } else {
            cssChanged = false;
        }

        final CompileEvent event;

        if (cssChanged) {
            addUpdatedLessFile(lessFile);
            event = new CompileEvent() {
                @Override
                public void notify(@NotNull final CompileObserver observer) {
                    observer.outputFileChanged(lessFile);
                }
            };
            refreshVFS();
        } else {
            event = new CompileEvent() {
                @Override
                public void notify(@NotNull final CompileObserver observer) {
                    observer.outputFileUnchanged(lessFile);
                }
            };
        }

        notifyObservers(event);
    }

    private void finish() {
        finished.set(System.currentTimeMillis());
        compiled.set(true);
        running.set(false);

        final int numCompiled = getNumUpdated();

        notifyObservers(new CompileEvent() {
            @Override
            public void notify(@NotNull final CompileObserver observer) {
                observer.compileFinished(numCompiled);
            }
        });
    }
}
TOP

Related Classes of net.andydvorak.intellij.lessc.fs.LessCompileJob

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.