001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.commons.jci.listeners;
019:
020: import java.io.File;
021: import java.util.ArrayList;
022: import java.util.Collection;
023: import java.util.Iterator;
024:
025: import org.apache.commons.jci.compilers.CompilationResult;
026: import org.apache.commons.jci.compilers.JavaCompiler;
027: import org.apache.commons.jci.compilers.JavaCompilerFactory;
028: import org.apache.commons.jci.monitor.FilesystemAlterationObserver;
029: import org.apache.commons.jci.problems.CompilationProblem;
030: import org.apache.commons.jci.readers.FileResourceReader;
031: import org.apache.commons.jci.readers.ResourceReader;
032: import org.apache.commons.jci.stores.MemoryResourceStore;
033: import org.apache.commons.jci.stores.ResourceStore;
034: import org.apache.commons.jci.stores.TransactionalResourceStore;
035: import org.apache.commons.jci.utils.ConversionUtils;
036: import org.apache.commons.logging.Log;
037: import org.apache.commons.logging.LogFactory;
038:
039: /**
040: * A CompilingListener is an improved version of the ReloadingListener.
041: * It even compiles the classes from source before doing the reloading.
042: *
043: * @author tcurdt
044: */
045: public class CompilingListener extends ReloadingListener {
046:
047: private final Log log = LogFactory.getLog(CompilingListener.class);
048:
049: private final JavaCompiler compiler;
050: private final TransactionalResourceStore transactionalStore;
051: private ResourceReader reader;
052: private CompilationResult lastResult;
053:
054: public CompilingListener() {
055: this (new JavaCompilerFactory().createCompiler("eclipse"));
056: }
057:
058: public CompilingListener(final JavaCompiler pCompiler) {
059: this (pCompiler, new TransactionalResourceStore(
060: new MemoryResourceStore()));
061: }
062:
063: public CompilingListener(final JavaCompiler pCompiler,
064: final TransactionalResourceStore pTransactionalStore) {
065: super (pTransactionalStore);
066: compiler = pCompiler;
067: transactionalStore = pTransactionalStore;
068: lastResult = null;
069: }
070:
071: public JavaCompiler getCompiler() {
072: return compiler;
073: }
074:
075: public String getSourceFileExtension() {
076: return ".java";
077: }
078:
079: public ResourceReader getReader(
080: final FilesystemAlterationObserver pObserver) {
081: return new FileResourceReader(pObserver.getRootDirectory());
082: }
083:
084: public String getSourceNameFromFile(
085: final FilesystemAlterationObserver pObserver,
086: final File pFile) {
087: return ConversionUtils.stripExtension(ConversionUtils
088: .getResourceNameFromFileName(ConversionUtils.relative(
089: pObserver.getRootDirectory(), pFile)))
090: + getSourceFileExtension();
091: }
092:
093: public ResourceStore getStore() {
094: return transactionalStore;
095: }
096:
097: public synchronized CompilationResult getCompilationResult() {
098: return lastResult;
099: }
100:
101: public void onStart(final FilesystemAlterationObserver pObserver) {
102: super .onStart(pObserver);
103:
104: reader = getReader(pObserver);
105:
106: transactionalStore.onStart();
107: }
108:
109: public String[] getResourcesToCompile(
110: final FilesystemAlterationObserver pObserver) {
111: final Collection created = getCreatedFiles();
112: final Collection changed = getChangedFiles();
113:
114: final Collection resourceNames = new ArrayList();
115:
116: for (final Iterator it = created.iterator(); it.hasNext();) {
117: final File createdFile = (File) it.next();
118: if (createdFile.getName()
119: .endsWith(getSourceFileExtension())) {
120: resourceNames.add(getSourceNameFromFile(pObserver,
121: createdFile));
122: }
123: }
124:
125: for (final Iterator it = changed.iterator(); it.hasNext();) {
126: final File changedFile = (File) it.next();
127: if (changedFile.getName()
128: .endsWith(getSourceFileExtension())) {
129: resourceNames.add(getSourceNameFromFile(pObserver,
130: changedFile));
131: }
132: }
133:
134: final String[] result = new String[resourceNames.size()];
135: resourceNames.toArray(result);
136: return result;
137: }
138:
139: public boolean isReloadRequired(
140: final FilesystemAlterationObserver pObserver) {
141: boolean reload = false;
142:
143: final Collection created = getCreatedFiles();
144: final Collection changed = getChangedFiles();
145: final Collection deleted = getDeletedFiles();
146:
147: log.debug("created:" + created.size() + " changed:"
148: + changed.size() + " deleted:" + deleted.size()
149: + " resources");
150:
151: if (deleted.size() > 0) {
152: for (Iterator it = deleted.iterator(); it.hasNext();) {
153: final File deletedFile = (File) it.next();
154:
155: final String resourceName = ConversionUtils
156: .getResourceNameFromFileName(ConversionUtils
157: .relative(pObserver.getRootDirectory(),
158: deletedFile));
159:
160: if (resourceName.endsWith(getSourceFileExtension())) {
161: // if source resource got removed delete the corresponding class
162: transactionalStore.remove(ConversionUtils
163: .stripExtension(resourceName)
164: + ".class");
165: } else {
166: // ordinary resource to be removed
167: transactionalStore.remove(resourceName);
168: }
169:
170: // FIXME: does not remove nested classes
171:
172: }
173: reload = true;
174: }
175:
176: final String[] resourcesToCompile = getResourcesToCompile(pObserver);
177:
178: if (resourcesToCompile.length > 0) {
179:
180: log
181: .debug(resourcesToCompile.length
182: + " classes to compile");
183:
184: final CompilationResult result = compiler.compile(
185: resourcesToCompile, reader, transactionalStore);
186:
187: synchronized (this ) {
188: lastResult = result;
189: }
190:
191: final CompilationProblem[] errors = result.getErrors();
192: final CompilationProblem[] warnings = result.getWarnings();
193:
194: log.debug(errors.length + " errors, " + warnings.length
195: + " warnings");
196:
197: if (errors.length > 0) {
198: // FIXME: they need to be marked for re-compilation
199: // and then added as compileables again
200: for (int j = 0; j < resourcesToCompile.length; j++) {
201: transactionalStore.remove(resourcesToCompile[j]);
202: }
203: }
204:
205: reload = true;
206: }
207:
208: return reload;
209: }
210: }
|