blob: 6bd9bdcb83572f72949b6190fa918d2b5ca57071 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.commons.jci2.listeners;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import org.apache.commons.jci2.compilers.CompilationResult;
import org.apache.commons.jci2.compilers.JavaCompiler;
import org.apache.commons.jci2.compilers.JavaCompilerFactory;
import org.apache.commons.jci2.monitor.FilesystemAlterationObserver;
import org.apache.commons.jci2.problems.CompilationProblem;
import org.apache.commons.jci2.readers.FileResourceReader;
import org.apache.commons.jci2.readers.ResourceReader;
import org.apache.commons.jci2.stores.MemoryResourceStore;
import org.apache.commons.jci2.stores.ResourceStore;
import org.apache.commons.jci2.stores.TransactionalResourceStore;
import org.apache.commons.jci2.utils.ConversionUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* A CompilingListener is an improved version of the ReloadingListener.
* It even compiles the classes from source before doing the reloading.
*
* @author tcurdt
*/
public class CompilingListener extends ReloadingListener {
private final Log log = LogFactory.getLog(CompilingListener.class);
private final JavaCompiler compiler;
private final TransactionalResourceStore transactionalStore;
private ResourceReader reader;
private CompilationResult lastResult;
public CompilingListener() {
this(new JavaCompilerFactory().createCompiler("eclipse"));
}
public CompilingListener( final JavaCompiler pCompiler ) {
this(pCompiler, new TransactionalResourceStore(new MemoryResourceStore()));
}
public CompilingListener( final JavaCompiler pCompiler, final TransactionalResourceStore pTransactionalStore ) {
super(pTransactionalStore);
compiler = pCompiler;
transactionalStore = pTransactionalStore;
lastResult = null;
}
public JavaCompiler getCompiler() {
return compiler;
}
public String getSourceFileExtension() {
return ".java";
}
public ResourceReader getReader( final FilesystemAlterationObserver pObserver ) {
return new FileResourceReader(pObserver.getRootDirectory());
}
public String getSourceNameFromFile( final FilesystemAlterationObserver pObserver, final File pFile ) {
return ConversionUtils.stripExtension(ConversionUtils.getResourceNameFromFileName(ConversionUtils.relative(pObserver.getRootDirectory(), pFile))) + getSourceFileExtension();
}
@Override
public ResourceStore getStore() {
return transactionalStore;
}
public synchronized CompilationResult getCompilationResult() {
return lastResult;
}
@Override
public void onStart( final FilesystemAlterationObserver pObserver ) {
super.onStart(pObserver);
reader = getReader(pObserver);
transactionalStore.onStart();
}
public String[] getResourcesToCompile( final FilesystemAlterationObserver pObserver ) {
final Collection<File> created = getCreatedFiles();
final Collection<File> changed = getChangedFiles();
final Collection<String> resourceNames = new ArrayList<String>();
for (final File createdFile : created) {
if (createdFile.getName().endsWith(getSourceFileExtension())) {
resourceNames.add(getSourceNameFromFile(pObserver, createdFile));
}
}
for (final File changedFile : changed) {
if (changedFile.getName().endsWith(getSourceFileExtension())) {
resourceNames.add(getSourceNameFromFile(pObserver, changedFile));
}
}
final String[] result = new String[resourceNames.size()];
resourceNames.toArray(result);
return result;
}
@Override
public boolean isReloadRequired( final FilesystemAlterationObserver pObserver ) {
boolean reload = false;
final Collection<File> created = getCreatedFiles();
final Collection<File> changed = getChangedFiles();
final Collection<File> deleted = getDeletedFiles();
log.debug("created:" + created.size() + " changed:" + changed.size() + " deleted:" + deleted.size() + " resources");
if (deleted.size() > 0) {
for (final File deletedFile : deleted) {
final String resourceName = ConversionUtils.getResourceNameFromFileName(ConversionUtils.relative(pObserver.getRootDirectory(), deletedFile));
if (resourceName.endsWith(getSourceFileExtension())) {
// if source resource got removed delete the corresponding class
transactionalStore.remove(ConversionUtils.stripExtension(resourceName) + ".class");
} else {
// ordinary resource to be removed
transactionalStore.remove(resourceName);
}
// FIXME: does not remove nested classes
}
reload = true;
}
final String[] resourcesToCompile = getResourcesToCompile(pObserver);
if (resourcesToCompile.length > 0) {
log.debug(resourcesToCompile.length + " classes to compile");
final CompilationResult result = compiler.compile(resourcesToCompile, reader, transactionalStore);
synchronized(this) {
lastResult = result;
}
final CompilationProblem[] errors = result.getErrors();
final CompilationProblem[] warnings = result.getWarnings();
log.debug(errors.length + " errors, " + warnings.length + " warnings");
if (errors.length > 0) {
// FIXME: they need to be marked for re-compilation
// and then added as compileables again
for (final String element : resourcesToCompile) {
transactionalStore.remove(element);
}
}
reload = true;
}
return reload;
}
}