You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@geronimo.apache.org by db...@apache.org on 2005/11/16 08:46:52 UTC
svn commit: r344942 - in
/geronimo/gbuild/trunk/gbuild-agent/src/main/java/org/apache/geronimo/gbuild/agent:
DirectoryMonitor.java PropertiesBuildTaskProducer.java
Author: dblevins
Date: Tue Nov 15 23:46:49 2005
New Revision: 344942
URL: http://svn.apache.org/viewcvs?rev=344942&view=rev
Log:
DirectoryMonitor based on Aaron's DirectoryMonitor. The properties build task producer now watches a dir for properties files containing build definitions
Added:
geronimo/gbuild/trunk/gbuild-agent/src/main/java/org/apache/geronimo/gbuild/agent/DirectoryMonitor.java
Modified:
geronimo/gbuild/trunk/gbuild-agent/src/main/java/org/apache/geronimo/gbuild/agent/PropertiesBuildTaskProducer.java
Added: geronimo/gbuild/trunk/gbuild-agent/src/main/java/org/apache/geronimo/gbuild/agent/DirectoryMonitor.java
URL: http://svn.apache.org/viewcvs/geronimo/gbuild/trunk/gbuild-agent/src/main/java/org/apache/geronimo/gbuild/agent/DirectoryMonitor.java?rev=344942&view=auto
==============================================================================
--- geronimo/gbuild/trunk/gbuild-agent/src/main/java/org/apache/geronimo/gbuild/agent/DirectoryMonitor.java (added)
+++ geronimo/gbuild/trunk/gbuild-agent/src/main/java/org/apache/geronimo/gbuild/agent/DirectoryMonitor.java Tue Nov 15 23:46:49 2005
@@ -0,0 +1,318 @@
+/**
+ *
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 org.apache.geronimo.gbuild.agent;
+
+import org.codehaus.plexus.logging.AbstractLogEnabled;
+
+import java.io.File;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class DirectoryMonitor extends AbstractLogEnabled implements Runnable {
+
+ public interface Listener {
+ /**
+ * @return true if the addition was processed successfully. If not
+ * the file will be added again next time it changes.
+ */
+ boolean fileAdded(File file);
+
+ /**
+ * @return true if the removal was processed successfully. If not
+ * the file will be removed again on the next pass.
+ */
+ boolean fileRemoved(File file);
+
+ void fileUpdated(File file);
+ }
+
+ private boolean run = false;
+ private int pollIntervalMillis;
+ private File directory;
+ private Listener listener;
+ private Map files = new HashMap();
+
+ public DirectoryMonitor(File directory, Listener listener, int pollIntervalMillis) {
+ assert listener != null: "No point in scanning without a listener.";
+ assert directory.isDirectory(): "File specified is not a directory. " + directory.getAbsolutePath();
+ assert !directory.canRead(): "Directory specified cannot be read. " + directory.getAbsolutePath();
+ assert pollIntervalMillis > 0: "Poll Interval must be above zero.";
+
+ this.directory = directory;
+ this.listener = listener;
+ this.pollIntervalMillis = pollIntervalMillis;
+ }
+
+ public int getPollIntervalMillis() {
+ return pollIntervalMillis;
+ }
+
+ public File getDirectory() {
+ return directory;
+ }
+
+ public Listener getListener() {
+ return listener;
+ }
+
+ public synchronized boolean isRunning() {
+ return run;
+ }
+
+ public synchronized void stop() {
+ this.run = false;
+ }
+
+ public void run() {
+ run = true;
+ initialize();
+ while (run) {
+ try {
+ scanDirectory();
+ } catch (Exception e) {
+ getLogger().error("Scan failed.", e);
+ }
+
+ try {
+ Thread.sleep(pollIntervalMillis);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ public void initialize() {
+ File parent = directory;
+ File[] children = parent.listFiles();
+ for (int i = 0; i < children.length; i++) {
+ File child = children[i];
+
+ if (!child.canRead()) {
+ continue;
+ }
+
+ FileInfo now = newInfo(child);
+ now.setChanging(false);
+ updateInfo(now);
+ }
+ }
+
+ private FileInfo newInfo(File child) {
+ return child.isDirectory() ? new DirectoryInfo(child) : new FileInfo(child);
+ }
+
+ /**
+ * Looks for changes to the immediate contents of the directory we're watching.
+ */
+ private void scanDirectory() {
+ File parent = directory;
+ File[] children = parent.listFiles();
+
+ HashSet oldList = new HashSet(files.keySet());
+
+ for (int i = 0; i < children.length; i++) {
+
+ File child = children[i];
+
+ if (!child.canRead()) {
+ continue;
+ }
+
+ FileInfo newStatus = newInfo(child);
+ FileInfo oldStatus = oldInfo(child);
+
+ if ( oldStatus == null ) {
+
+ getLogger().debug("File Discovered: " + newStatus);
+
+ // Brand new, but assume it's changing and
+ // wait a bit to make sure it's not still changing
+ newStatus.setNewFile(true);
+ newStatus.setChanging(true);
+ updateInfo(newStatus);
+
+ } else if ( !newStatus.isSame(oldStatus) ) {
+
+ getLogger().debug("File Changing: " + newStatus);
+
+ // The two records are different -- record the latest as a file that's changing
+ // and later when it stops changing we'll do the add or update as appropriate.
+ newStatus.setChanging(true);
+ newStatus.setNewFile(oldStatus.isNewFile());
+ updateInfo(newStatus);
+
+ oldList.remove(oldStatus.getPath());
+
+ } else if ( oldStatus.isChanging() ){
+
+ // Used to be changing, now in (hopefully) its final state
+ oldStatus.setChanging(false);
+
+ if (oldStatus.isNewFile()) {
+
+ getLogger().debug("New File: " + newStatus);
+ oldStatus.setNewFile(!listener.fileAdded(child));
+
+ } else {
+
+ getLogger().debug("Updated File: " + newStatus);
+ listener.fileUpdated(child);
+
+ }
+
+ oldList.remove(oldStatus.getPath());
+
+ }// else it's just totally unchanged and we ignore it this pass
+ }
+
+ // Look for any files we used to know about but didn't find in this pass
+ for (Iterator it = oldList.iterator(); it.hasNext();) {
+ String path = (String) it.next();
+
+ getLogger().debug("File removed: " + path);
+
+ FileInfo info = oldInfo(path);
+
+ if (info.isNewFile() || listener.fileRemoved(new File(path))) {
+ removeInfo(path);
+ }
+ }
+ }
+
+ private void removeInfo(String path) {
+ files.remove(path);
+ }
+
+ private void updateInfo(FileInfo newStatus) {
+ files.put(newStatus.getPath(), newStatus);
+ }
+
+ private FileInfo oldInfo(File file) {
+ return oldInfo(file.getAbsolutePath());
+ }
+
+ private FileInfo oldInfo(String path) {
+ return (FileInfo) files.get(path);
+ }
+
+ private static class DirectoryInfo extends FileInfo {
+
+ /**
+ * We don't pay attention to the size of the directory or files in the
+ * directory, only the highest last modified time of anything in the
+ * directory. Hopefully this is good enough.
+ */
+ public DirectoryInfo(File dir) {
+ super(dir.getAbsolutePath(), 0, getLastModifiedInDir(dir));
+ }
+
+ private static long getLastModifiedInDir(File dir) {
+ long value = dir.lastModified();
+ File[] children = dir.listFiles();
+ long test;
+ for (int i = 0; i < children.length; i++) {
+ File child = children[i];
+ if (!child.canRead()) {
+ continue;
+ }
+ if (child.isDirectory()) {
+ test = getLastModifiedInDir(child);
+ } else {
+ test = child.lastModified();
+ }
+ if (test > value) {
+ value = test;
+ }
+ }
+ return value;
+ }
+ }
+
+ private static class FileInfo implements Serializable {
+ private String path;
+ private long size;
+ private long modified;
+ private boolean newFile;
+ private boolean changing;
+
+ public FileInfo(File file) {
+ this(file.getAbsolutePath(), file.length(), file.lastModified());
+ }
+
+ public FileInfo(String path, long size, long modified) {
+ this.path = path;
+ this.size = size;
+ this.modified = modified;
+ this.newFile = false;
+ this.changing = true;
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public long getSize() {
+ return size;
+ }
+
+ public void setSize(long size) {
+ this.size = size;
+ }
+
+ public long getModified() {
+ return modified;
+ }
+
+ public void setModified(long modified) {
+ this.modified = modified;
+ }
+
+ public boolean isNewFile() {
+ return newFile;
+ }
+
+
+ public void setNewFile(boolean newFile) {
+ this.newFile = newFile;
+ }
+
+ public boolean isChanging() {
+ return changing;
+ }
+
+ public void setChanging(boolean changing) {
+ this.changing = changing;
+ }
+
+ public boolean isSame(FileInfo info) {
+ if (!path.equals(info.path)) {
+ throw new IllegalArgumentException("Should only be used to compare two files representing the same path!");
+ }
+ return size == info.size && modified == info.modified;
+ }
+
+ public String toString() {
+ return path;
+ }
+ }
+
+}
Modified: geronimo/gbuild/trunk/gbuild-agent/src/main/java/org/apache/geronimo/gbuild/agent/PropertiesBuildTaskProducer.java
URL: http://svn.apache.org/viewcvs/geronimo/gbuild/trunk/gbuild-agent/src/main/java/org/apache/geronimo/gbuild/agent/PropertiesBuildTaskProducer.java?rev=344942&r1=344941&r2=344942&view=diff
==============================================================================
--- geronimo/gbuild/trunk/gbuild-agent/src/main/java/org/apache/geronimo/gbuild/agent/PropertiesBuildTaskProducer.java (original)
+++ geronimo/gbuild/trunk/gbuild-agent/src/main/java/org/apache/geronimo/gbuild/agent/PropertiesBuildTaskProducer.java Tue Nov 15 23:46:49 2005
@@ -21,6 +21,10 @@
import org.apache.maven.continuum.model.project.BuildDefinition;
import org.apache.maven.continuum.model.project.Project;
import org.apache.maven.continuum.project.ContinuumProjectState;
+import org.codehaus.plexus.logging.AbstractLogEnabled;
+import org.codehaus.plexus.personality.plexus.lifecycle.phase.Startable;
+import org.codehaus.plexus.personality.plexus.lifecycle.phase.StartingException;
+import org.codehaus.plexus.personality.plexus.lifecycle.phase.StoppingException;
import javax.jms.Connection;
import javax.jms.DeliveryMode;
@@ -28,14 +32,17 @@
import javax.jms.Queue;
import javax.jms.Session;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
-import java.util.Iterator;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
/**
* @version $Rev$ $Date$
*/
-public class PropertiesBuildTaskProducer implements BuildTaskProducer {
+public class PropertiesBuildTaskProducer extends AbstractLogEnabled implements Startable, DirectoryMonitor.Listener {
/**
* @plexus.configuration
@@ -62,15 +69,56 @@
*/
private String headerPrefix = "header.";
+ /**
+ * @plexus.configuration
+ */
+ private String watchDirectory;
+
+ /**
+ * @plexus.configuration
+ */
+ private int pollInterval;
+
+ private DirectoryMonitor scanner;
+
+ public synchronized void start() throws StartingException {
+ File dir = new File(watchDirectory);
+ scanner = new DirectoryMonitor(dir, this, pollInterval);
+ Thread thread = new Thread(scanner);
+ thread.setDaemon(false);
+ thread.start();
+ }
+
+ public synchronized void stop() throws StoppingException {
+ scanner.stop();
+ }
- public void run() {
+ public boolean fileAdded(File file) {
+ Properties properties = null;
try {
- queueBuildTasks(new Properties());
+ FileInputStream in = new FileInputStream(file);
+ properties = new Properties();
+ properties.load(in);
+ } catch (IOException e) {
+ getLogger().error("Unable to load properties file: "+file.getAbsolutePath(), e);
+ }
+ try {
+ queueBuildTasks(properties);
} catch (Exception e) {
- e.printStackTrace();
+ getLogger().error("Unable to process file: "+file.getAbsolutePath(), e);
}
+ return true;
}
+ public boolean fileRemoved(File file) {
+ return true;
+ }
+
+ public void fileUpdated(File file) {
+ }
+
+
+ // TODO: Improve this so you can have ${my-property} parts to property values
private void queueBuildTasks(Properties def) throws Exception {
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(coordinatorUrl);
@@ -94,6 +142,7 @@
String buildFile = getString(def, "project.buildFile");
+ getLogger().info("Project - " + id + " - " + name + " " + version);
String executor = ShellBuildExecutor.ID;
@@ -119,6 +168,8 @@
if (!key.startsWith(buildPrefix)) {
continue;
}
+
+ getLogger().info("Build - " + buildIds + " - " + key + " " + value);
BuildDefinition bd = new BuildDefinition();
bd.setId(buildIds++);