|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300 |
- /* *******************************************************************
- * Copyright (c) 2003 Contributors.
- * All rights reserved.
- * This program and the accompanying materials are made available
- * under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Wes Isberg initial implementation
- * ******************************************************************/
-
- package org.aspectj.testing.taskdefs;
-
- //import java.awt.Frame;
- import java.io.File;
- import java.io.IOException;
- //import java.lang.reflect.*;
- //import java.util.List;
- import java.util.ArrayList;
-
- import org.apache.tools.ant.BuildException;
- import org.apache.tools.ant.Project;
- import org.aspectj.bridge.ICommand;
- import org.aspectj.bridge.IMessage;
- import org.aspectj.bridge.IMessageHandler;
- import org.aspectj.bridge.IMessageHolder;
- import org.aspectj.bridge.MessageHandler;
- import org.aspectj.bridge.MessageUtil;
- import org.aspectj.tools.ant.taskdefs.AjcTask;
- import org.aspectj.util.FileUtil;
- import org.aspectj.util.LangUtil;
-
- /**
- * Drive tests using the Ant taskdef.
- * The non-incremental case is quite easy to implement,
- * but incremental compiles require running the compiler
- * in another thread using an incremental tag file.
- * This is imprecise because it assumes
- * incremental compiles are complete
- * when messages stop coming from the compiler.
- * Also, the client should call quit() when done compiling
- * to halt the process.
- * XXX build up ICommand with quit (and done-with-last-invocation?)
- * to avoid the kludge workarounds
- */
- public class AjcTaskCompileCommand implements ICommand {
- /**
- * 20 seconds of quiet in message holder
- * before we assume incremental compile is done
- */
- public static int COMPILE_SECONDS_WITHOUT_MESSAGES = 20;
-
- /** 5 minutes maximum time to wait for a compile to complete */
- public static int COMPILE_MAX_SECONDS = 300;
-
- /**
- * Wait until this holder has not changed the number of messages
- * in secs seconds, as a weak form of determining when the
- * compile has completed.
- * XXX implement "compile-complete" message instead.
- * @param holder the IMessageHolder to wait for
- * @param seconds the number of seconds that the messages should be the same
- * @param timeoutSeconds the int number of seconds after which to time out
- * @return true if the messages quiesced before the timeout
- * false if parameters are 0 or negative or if
- * seconds => timeoutSeconds
- */
- static boolean waitUntilMessagesQuiet(
- IMessageHolder holder,
- int seconds,
- int timeoutSeconds) {
- LangUtil.throwIaxIfNull(holder, "holder");
- if ((0 >= timeoutSeconds) || (0 >= seconds)
- || (timeoutSeconds <= seconds)) {
- return false;
- }
- long curTime = System.currentTimeMillis();
- final long timeout = curTime + (timeoutSeconds*1000);
- // final Thread thread = Thread.currentThread();
- final long targetQuietTime = 1000 * seconds;
- int numMessages = holder.numMessages(null, true);
- long numMessagesTime = curTime;
- // check for new messages every .5 to 3 seconds
- final long checkInterval;
- {
- long interval = seconds / 10;
- if (interval > 3000) {
- interval = 3000;
- } else if (interval < 200) {
- interval = 500;
- }
- checkInterval = interval;
- }
- while ((curTime < timeout)
- && (curTime < (numMessagesTime + targetQuietTime))) {
- // delay until next check
- long nextCheck = curTime + checkInterval;
- while (nextCheck > curTime) {
- try {
- Thread.sleep(nextCheck - curTime);
- } catch (InterruptedException e) {
- // ignore
- }
- curTime = System.currentTimeMillis();
- }
- int newNumMessages = holder.numMessages(null, true);
- if (newNumMessages != numMessages) {
- numMessages = newNumMessages;
- numMessagesTime = curTime;
- }
- }
- return (curTime >= (numMessagesTime + targetQuietTime));
- }
-
- // single-threaded driver
- MessageHandler messages = new MessageHandler();
- AjcTask ajcTask;
- File incrementalFile;
- Thread incrementalCompileThread;
-
- /**
- * Stop waiting for any further incremental compiles.
- * Safe to call in non-incremental modes.
- */
- public void quit() { // XXX requires downcast from ICommand, need validator,IMessageHandler interface
- AjcTask task = ajcTask;
- if (null != task) {
- task.quit(); // signal task to quit, thread to die
- ajcTask = null; // XXX need for cleanup?
- }
- updateIncrementalFile(false, true);
- Thread thread = incrementalCompileThread;
- if (null != thread) {
- if (thread.isAlive()) {
- try {
- thread.join(3000);
- } catch (InterruptedException e) {
- // ignore
- }
- if (thread.isAlive()) {
- String s = "WARNING: abandoning undying thread ";
- System.err.println(s + thread.getName());
- }
- }
- incrementalCompileThread = null;
- }
- }
-
- // --------- ICommand interface
- public boolean runCommand(String[] args, IMessageHandler handler) {
- return (makeAjcTask(args, handler)
- && doCommand(handler, false));
- }
-
- /**
- * Fails if called before runCommand or if
- * not in incremental mode or if the command
- * included an incremental file entry.
- * @return
- */
- public boolean repeatCommand(IMessageHandler handler) {
- return doCommand(handler, true);
- }
-
- protected boolean doCommand(IMessageHandler handler, boolean repeat) {
- messages.clearMessages();
- if (null == ajcTask) {
- MessageUtil.fail(messages, "ajcTask null - repeat without do");
- }
- try {
- // normal, non-incremental case
- if (!repeat && (null == incrementalFile)) {
- ajcTask.execute();
- // rest is for incremental mode
- } else if (null == incrementalFile) {
- MessageUtil.fail(messages, "incremental mode not specified");
- } else if (!updateIncrementalFile(false, false)) {
- MessageUtil.fail(messages, "can't update incremental file");
- } else if (!repeat) { // first incremental compile
- incrementalCompileThread = new Thread(
- new Runnable() {
- public void run() {
- ajcTask.execute();
- }
- }, "AjcTaskCompileCommand-incremental");
- incrementalCompileThread.start();
- waitUntilMessagesQuiet(messages, 10, 180);
- } else {
- Thread thread = incrementalCompileThread;
- if (null == thread) {
- MessageUtil.fail(messages, "incremental process stopped");
- } else if (!thread.isAlive()) {
- MessageUtil.fail(messages, "incremental process dead");
- } else {
- waitUntilMessagesQuiet(messages, 10, 180);
- }
- }
- } catch (BuildException e) {
- Throwable t = e.getCause();
- while (t instanceof BuildException) {
- t = ((BuildException) t).getCause();
- }
- if (null == t) {
- t = e;
- }
- MessageUtil.abort(messages, "BuildException " + e.getMessage(), t);
- } finally {
- MessageUtil.handleAll(handler, messages, false);
- }
- return (0 == messages.numMessages(IMessage.ERROR, true));
- }
-
-
- protected boolean makeAjcTask(String[] args, IMessageHandler handler) {
- ajcTask = null;
- incrementalFile = null;
- AjcTask result = null;
- try {
- result = new AjcTask();
- Project project = new Project();
- project.setName("AjcTaskCompileCommand");
- result.setProject(project);
- result.setMessageHolder(messages);
- // XXX argh - have to strip out "-incremental"
- // because tools.ajc.Main privileges it over tagfile
- ArrayList newArgs = new ArrayList();
- boolean incremental = false;
- for (int i = 0; i < args.length; i++) {
- if ("-incremental".equals(args[i])) {
- incremental = true;
- } else if ("-XincrementalFile".equals(args[i])) {
- // CommandController.TAG_FILE_OPTION = "-XincrementalFile";
- incremental = true;
- i++;
- } else {
- newArgs.add(args[i]);
- }
- }
- if (incremental) {
- args = (String[]) newArgs.toArray(new String[0]);
- }
-
- result.readArguments(args);
-
- if (incremental || result.isInIncrementalMode()) {
- // these should be impossible...
- if (result.isInIncrementalFileMode()) {
- String m = "incremental file set in command";
- MessageUtil.fail(handler, m);
- return false;
- } else if (null != incrementalFile) {
- String m = "incremental file set already";
- MessageUtil.fail(handler, m);
- return false;
- }
- String prefix = "AjcTaskCompileCommand_makeAjcTask";
- File tmpDir = FileUtil.getTempDir(prefix);
- incrementalFile = new File(tmpDir, "tagfile.tmp");
- boolean create = true;
- boolean delete = false;
- updateIncrementalFile(create, delete);
- result.setTagFile(incrementalFile);
- }
- // do not throw BuildException on error
- result.setFailonerror(false);
- ajcTask = result;
- } catch (BuildException e) {
- MessageUtil.abort(handler,"setting up AjcTask", e);
- }
- return (null != ajcTask);
- }
-
- protected boolean updateIncrementalFile(boolean create, boolean delete) {
- File file = incrementalFile;
- if (delete) {
- try {
- return (null == file)
- || !file.exists()
- || file.delete();
- } finally {
- incrementalFile = null;
- }
- }
- if (null == file) {
- return false;
- }
- if (file.exists()) {
- return file.setLastModified(System.currentTimeMillis());
- } else {
- try {
- return create && file.createNewFile();
- } catch (IOException e) { // XXX warn in verbose mode?
- return false;
- }
- }
- }
-
- }
-
|