blob: 9ffc7e95959282f6702520830c051cee174a0aa9 [file] [log] [blame]
// -------------------------------------------------------------------------------
// Copyright (c)2000 Apache Software Foundation
// -------------------------------------------------------------------------------
package org.apache.ant;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.zip.*;
/**
* Manager of tasks and all things related to tasks. Tasks can be found in a
* wide number of locations -- and most of these locations require class loading
* help. As well, new nodes on the task search path may be added at any time.
* When these are added, new tasks should be scanned for.
*
* @author James Duncan Davidson (duncan@apache.org)
*/
public class TaskManager {
// -----------------------------------------------------------------
// PRIVATE DATA MEMBERS
// -----------------------------------------------------------------
/**
* FrontEnd that this TaskManager can communicate through.
*/
private AntFrontEnd frontEnd;
/**
* Data structure where all the Class definition for all known tasks are
* held.
*/
private Hashtable taskClasses = new Hashtable();
/**
* Data structure that holds all the nodes where tasks are picked up from.
*/
private Vector taskPathNodes = new Vector();
// -----------------------------------------------------------------
// CONSTRUCTORS
// -----------------------------------------------------------------
/**
* Creates a new TaskManager.
*/
TaskManager(AntFrontEnd frontEnd) {
this.frontEnd = frontEnd;
}
// -----------------------------------------------------------------
// PUBLIC METHODS
// -----------------------------------------------------------------
/**
* Adds a node to the task path
*/
public void addTaskPathNode(File file) throws AntException {
taskPathNodes.addElement(file);
processTaskPathNode(file);
}
// -----------------------------------------------------------------
// PACKAGE METHODS
// -----------------------------------------------------------------
/**
*
*/
AbstractTask getTaskInstance(String taskName) throws AntException {
Class clazz = (Class)taskClasses.get(taskName);
try {
return (AbstractTask)clazz.newInstance();
} catch (Exception e) {
String msg = "Can't instantiate task: " + taskName;
AntException ae = new AntException(msg, e);
throw ae;
}
}
// -----------------------------------------------------------------
// PRIVATE METHODS
// -----------------------------------------------------------------
/**
* Returns an enum of the task names that are defined in a given
* properties file.
*/
private Enumeration getTaskNames(Properties props) {
Vector v = new Vector();
String s = props.getProperty("tasks");
StringTokenizer tok = new StringTokenizer(s, ",", false);
while (tok.hasMoreTokens()) {
String taskName = tok.nextToken().trim();
v.addElement(taskName);
}
return v.elements();
}
/**
* Processes a directory to get class defintions from it
*/
private void processDir(File dir) {
frontEnd.writeMessage("Scanning " + dir + " for tasks",
AntFrontEnd.MSG_LEVEL_LOW);
File file = new File(dir, "taskdef.properties");
if (file.exists()) {
try {
InputStream in = new FileInputStream(file);
Properties props = new Properties();
props.load(in);
in.close();
Enumeration enum = getTaskNames(props);
while (enum.hasMoreElements()) {
String taskName = (String)enum.nextElement();
String taskClass = props.getProperty("task." + taskName + ".class");
URLClassLoader loader = new URLClassLoader(new URL[] {dir.toURL()});
try {
Class clazz = loader.loadClass(taskClass);
frontEnd.writeMessage("Got Task: " + taskName +
clazz, AntFrontEnd.MSG_LEVEL_LOW);
taskClasses.put(taskName, clazz);
} catch (ClassNotFoundException cnfe) {
System.out.println("Couldn't load task: " + taskName);
System.out.println(cnfe);
// XXX error out and stop....
}
}
} catch (IOException ioe) {
System.out.println("Could not work with dir: " + dir);
System.out.println(ioe);
// XXX error out and stop the build
}
}
}
/**
* Processes a jar file to get class definitions from it
*/
private void processJar(File file) throws AntException {
frontEnd.writeMessage("Scanning " + file + " for tasks",
AntFrontEnd.MSG_LEVEL_LOW);
try {
ZipFile zipFile = new ZipFile(file);
ZipEntry zipEntry = zipFile.getEntry("taskdef.properties");
if (zipEntry != null) {
InputStream in = zipFile.getInputStream(zipEntry);
Properties props = new Properties();
props.load(in);
in.close();
Enumeration enum = getTaskNames(props);
while (enum.hasMoreElements()) {
String taskName = (String)enum.nextElement();
String taskClass = props.getProperty("task." + taskName + ".class");
if (taskClass == null) {
String msg = "No class definition for task " + taskName +
"in jar file " + file;
throw new AntException(msg);
}
URLClassLoader loader = new URLClassLoader(new URL[] {file.toURL()});
try {
Class clazz = loader.loadClass(taskClass);
frontEnd.writeMessage("Got Task: " + taskName +
clazz, AntFrontEnd.MSG_LEVEL_LOW);
taskClasses.put(taskName, clazz);
} catch (ClassNotFoundException cnfe) {
System.out.println("Couldn't load task: " + taskName);
System.out.println(cnfe);
// XXX error out and stop....
}
}
}
// make sure to not leave resources hanging
zipFile.close();
} catch (IOException ioe) {
System.out.println("Couldn't work with file: " + file);
System.out.println(ioe);
// XXX need to exception out of here properly to stop things
}
}
/**
* Processes a node of the task path searching for task definitions there
* and adding them to the list of known tasks
*/
private void processTaskPathNode(File file) throws AntException {
// task path nodes can be any of the following:
// * jar file
// * directory of jar files
// * directory holding class files
if(file.isDirectory()) {
// first look for all jar files here
// second look for a taskdefs.properties here to see if we should
// treat the directory as a classpath
String[] files = file.list();
for (int i = 0; i < files.length; i++) {
if (files[i].endsWith(".jar")) {
processJar(new File(file, files[i]));
} else if (files[i].equals("taskdef.properties")) {
processDir(file);
}
}
} else if (file.getName().endsWith(".jar")) {
processJar(file);
}
}
/**
* Sets up the taskpath based on the currently running operating
* system. In general, the ordering of the taskpath is: user directory,
* system directory, and then installation. This allows users or
* system admins to override or add tasks.
*/
private void setUpTaskPath() throws AntException {
// 1st, add user's home dir.
File f;
String userHome = System.getProperty("user.home");
// generic unix
f = new File(userHome + ".ant", "tasks");
if (f.exists() && f.isDirectory()) {
addTaskPathNode(f);
}
// macos x
f = new File(userHome + "/Library/Ant", "Tasks");
if (f.exists() && f.isDirectory()) {
addTaskPathNode(f);
}
// windows -- todo
// 2nd, add system local dir.
// generic unix
f = new File("/usr/local/ant/tasks");
if (f.exists() && f.isDirectory()) {
addTaskPathNode(f);
}
// macos x
f = new File("/Library/Ant/Tasks");
if (f.exists() && f.isDirectory()) {
addTaskPathNode(f);
}
// windows -- todo
// 3rd, add installation local dir.
//System.out.println("BASE: " + this.getClass().getResource("/"));
// XXX ---- not really sure how the best way of getting this info is...
// hafta think about it.
}
}