/*******************************************************************************
*
* Copyright (c) 2004-2009, Oracle Corporation
*
* 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:
*
*
*
*
*******************************************************************************/
package hudson.init;
import org.jvnet.hudson.annotation_indexer.Index;
import org.jvnet.hudson.reactor.Milestone;
import org.jvnet.hudson.reactor.Task;
import org.jvnet.hudson.reactor.TaskBuilder;
import org.jvnet.hudson.reactor.MilestoneImpl;
import org.jvnet.hudson.reactor.Reactor;
import org.jvnet.localizer.ResourceBundleHolder;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;
import hudson.model.Hudson;
import static java.util.logging.Level.FINEST;
/**
* Discovers initialization tasks from {@link Initializer}.
*
* @author Kohsuke Kawaguchi
*/
public class InitializerFinder extends TaskBuilder {
private final ClassLoader cl;
private final Set<Method> discovered = new HashSet<Method>();
public InitializerFinder(ClassLoader cl) {
this.cl = cl;
}
public InitializerFinder() {
this(Thread.currentThread().getContextClassLoader());
}
public Collection<Task> discoverTasks(Reactor session) throws IOException {
List<Task> result = new ArrayList<Task>();
for (Method e : Index.list(Initializer.class, cl, Method.class)) {
if (!discovered.add(e)) {
continue; // already reported once
}
if (!Modifier.isStatic(e.getModifiers())) {
throw new IOException(e + " is not a static method");
}
Initializer i = e.getAnnotation(Initializer.class);
if (i == null) {
continue; // stale index
}
result.add(new TaskImpl(i, e));
}
return result;
}
/**
* Obtains the display name of the given initialization task
*/
protected String getDisplayNameOf(Method e, Initializer i) {
Class<?> c = e.getDeclaringClass();
try {
ResourceBundleHolder rb = ResourceBundleHolder.get(c.getClassLoader().loadClass(c.getPackage().getName() + ".Messages"));
String key = i.displayName();
if (key.length() == 0) {
return c.getSimpleName() + "." + e.getName();
}
return rb.format(key);
} catch (ClassNotFoundException x) {
LOGGER.log(FINEST, "Failed to load " + x.getMessage() + " for " + e.toString(), x);
return c.getSimpleName() + "." + e.getName();
}
}
/**
* Invokes the given initialization method.
*/
protected void invoke(Method e) {
try {
Class<?>[] pt = e.getParameterTypes();
Object[] args = new Object[pt.length];
for (int i = 0; i < args.length; i++) {
args[i] = lookUp(pt[i]);
}
e.invoke(null, args);
} catch (IllegalAccessException x) {
throw (Error) new IllegalAccessError().initCause(x);
} catch (InvocationTargetException x) {
throw new Error(x);
}
}
/**
* Determines the parameter injection of the initialization method.
*/
private Object lookUp(Class<?> type) {
if (type == Hudson.class) {
return Hudson.getInstance();
}
throw new IllegalArgumentException("Unable to inject " + type);
}
/**
* Task implementation.
*/
public class TaskImpl implements Task {
final Collection<Milestone> requires;
final Collection<Milestone> attains;
private final Initializer i;
private final Method e;
private TaskImpl(Initializer i, Method e) {
this.i = i;
this.e = e;
requires = toMilestones(i.requires(), i.after());
attains = toMilestones(i.attains(), i.before());
}
/**
* {@link Initializer} annotaion on the {@linkplain #getMethod() method}
*/
public Initializer getAnnotation() {
return i;
}
/**
* Static method that runs the initialization, that this task wraps.
*/
public Method getMethod() {
return e;
}
public Collection<Milestone> requires() {
return requires;
}
public Collection<Milestone> attains() {
return attains;
}
public String getDisplayName() {
return getDisplayNameOf(e, i);
}
public boolean failureIsFatal() {
return i.fatal();
}
public void run(Reactor session) {
invoke(e);
}
public String toString() {
return e.toString();
}
private Collection<Milestone> toMilestones(String[] tokens, InitMilestone m) {
List<Milestone> r = new ArrayList<Milestone>();
for (String s : tokens) {
try {
r.add(InitMilestone.valueOf(s));
} catch (IllegalArgumentException x) {
r.add(new MilestoneImpl(s));
}
}
r.add(m);
return r;
}
}
private static final Logger LOGGER = Logger.getLogger(InitializerFinder.class.getName());
}