+package org.argeo.slc.ant;\r
+\r
+import java.net.InetAddress;\r
+import java.net.UnknownHostException;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.UUID;\r
+import java.util.Vector;\r
+\r
+import org.apache.log4j.AppenderSkeleton;\r
+import org.apache.log4j.LogManager;\r
+import org.apache.log4j.spi.LoggingEvent;\r
+import org.apache.tools.ant.BuildEvent;\r
+import org.apache.tools.ant.BuildListener;\r
+import org.apache.tools.ant.Project;\r
+\r
+import org.argeo.slc.core.process.SlcExecution;\r
+import org.argeo.slc.core.process.SlcExecutionNotifier;\r
+import org.argeo.slc.core.process.SlcExecutionStep;\r
+\r
+public class SlcExecutionBuildListener extends AppenderSkeleton implements\r
+ BuildListener {\r
+ public static final String ANT_TYPE = "org.apache.tools.ant";\r
+ public static final String SLC_ANT_TYPE = "org.argeo.slc.ant";\r
+\r
+ public static final String REF_SLC_EXECUTION = "slcExecution";\r
+\r
+ private Project project;\r
+ \r
+ // to avoid stack overflow when logging for log4j\r
+ private boolean isLogging = false;\r
+\r
+ private List<SlcExecutionNotifier> notifiers = new Vector<SlcExecutionNotifier>();\r
+\r
+ private Map<SlcExecution, SlcExecutionStep> currentStep = new HashMap<SlcExecution, SlcExecutionStep>();\r
+\r
+ public void buildStarted(BuildEvent event) {\r
+ // SlcExecution slcExecution = getSlcExecution(event);\r
+\r
+ }\r
+\r
+ public void buildFinished(BuildEvent event) {\r
+ SlcExecution slcExecution = getSlcExecution(event);\r
+ slcExecution.setStatus(SlcExecution.STATUS_FINISHED);\r
+\r
+ for (SlcExecutionNotifier notifier : notifiers) {\r
+ notifier.updateExecution(slcExecution);\r
+ }\r
+ }\r
+\r
+ public void messageLogged(BuildEvent event) {\r
+ SlcExecution slcExecution = getSlcExecution(event);\r
+ if (slcExecution != null) {\r
+ SlcExecutionStep step = currentStep.get(slcExecution);\r
+ if (step == null) {\r
+ step = new SlcExecutionStep("LOG", event.getMessage());\r
+ notifyStep(slcExecution, step);\r
+ } else {\r
+ step.addLog(event.getMessage());\r
+ }\r
+ } else {\r
+ // TODO: log before initialization?\r
+ }\r
+ }\r
+\r
+ public void targetStarted(BuildEvent event) {\r
+ addLogStep(event, "Target " + event.getTarget().getName() + " started");\r
+ }\r
+\r
+ public void targetFinished(BuildEvent event) {\r
+ addLogStep(event, "Target " + event.getTarget().getName() + " finished");\r
+ }\r
+\r
+ public void taskStarted(BuildEvent event) {\r
+ SlcExecution slcExecution = getSlcExecution(event);\r
+ SlcExecutionStep currStep = currentStep.get(slcExecution);\r
+ if (currStep != null) {\r
+ notifyStep(slcExecution, currStep);\r
+ currentStep.remove(currStep);\r
+ }\r
+\r
+ SlcExecutionStep step = new SlcExecutionStep("LOG", "Task "\r
+ + event.getTask().getTaskName() + " started");\r
+ currentStep.put(slcExecution, step);\r
+ }\r
+\r
+ public void taskFinished(BuildEvent event) {\r
+ SlcExecution slcExecution = getSlcExecution(event);\r
+ SlcExecutionStep step = currentStep.get(slcExecution);\r
+ if (step != null) {\r
+ step.addLog("Task " + event.getTask().getTaskName() + " finished");\r
+\r
+ slcExecution.getSteps().add(step);\r
+ notifyStep(slcExecution, step);\r
+\r
+ currentStep.remove(slcExecution);\r
+ }\r
+ }\r
+\r
+ public void setNotifiers(List<SlcExecutionNotifier> notifiers) {\r
+ this.notifiers = notifiers;\r
+ }\r
+\r
+ protected SlcExecution getSlcExecution(BuildEvent event) {\r
+ Project project = event.getProject();\r
+ SlcExecution slcExecution = (SlcExecution) project\r
+ .getReference(REF_SLC_EXECUTION);\r
+ if (slcExecution == null) {\r
+ // for log4j\r
+ this.project = project;// FIXME\r
+ if (!LogManager.getRootLogger().isAttached(this)) {\r
+ LogManager.getRootLogger().addAppender(this);\r
+ }\r
+ \r
+ slcExecution = new SlcExecution();\r
+ slcExecution.setUuid(UUID.randomUUID().toString());\r
+ try {\r
+ slcExecution.setHost(InetAddress.getLocalHost().getHostName());\r
+ } catch (UnknownHostException e) {\r
+ slcExecution.setHost(SlcExecution.UNKOWN_HOST);\r
+ }\r
+\r
+ if (project.getReference(SlcProjectHelper.REF_ROOT_CONTEXT) != null) {\r
+ slcExecution.setType(SLC_ANT_TYPE);\r
+ } else {\r
+ slcExecution.setType(ANT_TYPE);\r
+ }\r
+\r
+ slcExecution.setPath(project.getProperty("ant.file"));\r
+ slcExecution.setStatus(SlcExecution.STATUS_RUNNING);\r
+\r
+ project.addReference(REF_SLC_EXECUTION, slcExecution);\r
+\r
+ for (SlcExecutionNotifier notifier : notifiers) {\r
+ notifier.newExecution(slcExecution);\r
+ }\r
+\r
+ }\r
+ return slcExecution;\r
+ }\r
+\r
+ protected void addLogStep(BuildEvent event, String msg) {\r
+ SlcExecutionStep step = new SlcExecutionStep("LOG", msg);\r
+ SlcExecution slcExecution = getSlcExecution(event);\r
+ slcExecution.getSteps().add(step);\r
+\r
+ notifyStep(slcExecution, step);\r
+ }\r
+\r
+ protected void notifyStep(SlcExecution slcExecution, SlcExecutionStep step) {\r
+ Vector<SlcExecutionStep> additionalSteps = new Vector<SlcExecutionStep>();\r
+ additionalSteps.add(step);\r
+ notifySteps(slcExecution, additionalSteps);\r
+ }\r
+\r
+ protected void notifySteps(SlcExecution slcExecution,\r
+ List<SlcExecutionStep> additionalSteps) {\r
+ for (SlcExecutionNotifier notifier : notifiers) {\r
+ notifier.addSteps(slcExecution, additionalSteps);\r
+ }\r
+ }\r
+\r
+ /* Log4j methods */\r
+\r
+ @Override\r
+ protected void append(LoggingEvent event) {\r
+ if(isLogging){\r
+ // avoid StackOverflow if notification calls Log4j itself.\r
+ return;\r
+ }\r
+ isLogging = true;\r
+ \r
+ try {\r
+ SlcExecution slcExecution = (SlcExecution) project\r
+ .getReference(REF_SLC_EXECUTION);\r
+ if (slcExecution != null) {\r
+ SlcExecutionStep step = currentStep.get(slcExecution);\r
+ if (step == null) {\r
+ step = new SlcExecutionStep("LOG", event.getMessage()\r
+ .toString());\r
+ notifyStep(slcExecution, step);\r
+ } else {\r
+ step.addLog(event.getMessage().toString());\r
+ }\r
+ } else {\r
+ // TODO: log before initialization?\r
+ }\r
+ } finally{\r
+ isLogging = false;\r
+ }\r
+ \r
+ \r
+ }\r
+\r
+ @Override\r
+ public void close() {\r
+ // TODO Auto-generated method stub\r
+\r
+ }\r
+\r
+ @Override\r
+ public boolean requiresLayout() {\r
+ // TODO Auto-generated method stub\r
+ return false;\r
+ }\r
+\r
+}\r