/*******************************************************************************
* This file is part of OpenNMS(R).
*
* Copyright (C) 2008-2011 The OpenNMS Group, Inc.
* OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc.
*
* OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc.
*
* OpenNMS(R) is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* OpenNMS(R) is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenNMS(R). If not, see:
* http://www.gnu.org/licenses/
*
* For more information contact:
* OpenNMS(R) Licensing <license@opennms.org>
* http://www.opennms.org/
* http://www.opennms.com/
*******************************************************************************/
package org.opennms.netmgt.provision.service.lifecycle;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import org.opennms.core.tasks.BatchTask;
import org.opennms.core.tasks.ContainerTask;
import org.opennms.core.tasks.Task;
import org.opennms.core.utils.LogUtils;
import org.opennms.netmgt.provision.service.lifecycle.annotations.Activity;
import org.opennms.netmgt.provision.service.lifecycle.annotations.Attribute;
/**
* <p>Phase class.</p>
*
* @author ranger
* @version $Id: $
*/
public class Phase extends BatchTask {
private LifeCycleInstance m_lifecycle;
private String m_name;
private Object[] m_providers;
/**
* <p>Constructor for Phase.</p>
*
* @param parent a {@link org.opennms.core.tasks.ContainerTask} object.
* @param lifecycle a {@link org.opennms.netmgt.provision.service.lifecycle.LifeCycleInstance} object.
* @param name a {@link java.lang.String} object.
* @param providers an array of {@link java.lang.Object} objects.
*/
public Phase(ContainerTask<?> parent, LifeCycleInstance lifecycle, String name, Object[] providers) {
super(lifecycle.getCoordinator(), parent);
m_lifecycle = lifecycle;
m_name = name;
m_providers = providers;
addPhaseMethods();
}
/**
* <p>getName</p>
*
* @return a {@link java.lang.String} object.
*/
public String getName() {
return m_name;
}
/**
* <p>getLifeCycleInstance</p>
*
* @return a {@link org.opennms.netmgt.provision.service.lifecycle.LifeCycleInstance} object.
*/
public LifeCycleInstance getLifeCycleInstance() {
return m_lifecycle;
}
/**
* <p>createNestedLifeCycle</p>
*
* @param lifeCycleName a {@link java.lang.String} object.
* @return a {@link org.opennms.netmgt.provision.service.lifecycle.LifeCycleInstance} object.
*/
public LifeCycleInstance createNestedLifeCycle(String lifeCycleName) {
return m_lifecycle.createNestedLifeCycle(this, lifeCycleName);
}
/**
* <p>addPhaseMethods</p>
*/
public void addPhaseMethods() {
for(Object provider : m_providers) {
addPhaseMethods(provider);
}
}
/**
* <p>addPhaseMethods</p>
*
* @param provider a {@link java.lang.Object} object.
*/
public void addPhaseMethods(Object provider) {
for(Method method : provider.getClass().getMethods()) {
String schedulingHint = isPhaseMethod(method);
if (schedulingHint != null) {
//this.setPreferredExecutor(schedulingHint);
add(createPhaseMethod(provider, method, schedulingHint));
}
}
}
// public void run() {
// for(Object provider : m_providers) {
// PhaseMethod[] methods = findPhaseMethods(provider);
// for(PhaseMethod method : methods) {
// method.invoke();
// }
//
// }
//
// }
//
// private PhaseMethod[] findPhaseMethods(Object provider) {
// List<PhaseMethod> methods = new ArrayList<PhaseMethod>();
// for(Method method : provider.getClass().getMethods()) {
// if (isPhaseMethod(method)) {
// methods.add(new PhaseMethod(this, provider, method));
// }
// }
// return methods.toArray(new PhaseMethod[methods.size()]);
// }
private String isPhaseMethod(Method method) {
Activity activity = method.getAnnotation(Activity.class);
if (activity != null && activity.phase().equals(m_name) && activity.lifecycle().equals(m_lifecycle.getName())) {
return activity.schedulingHint();
}
return null;
}
PhaseMethod createPhaseMethod(Object provider, Method method, String schedulingHint) {
return new PhaseMethod(this, provider, method, schedulingHint);
}
public static class PhaseMethod extends BatchTask {
private Phase m_phase;
private Object m_target;
private Method m_method;
public PhaseMethod(Phase phase, Object target, Method method, String schedulingHint) {
super(phase.getCoordinator(), phase);
m_phase = phase;
m_target = target;
m_method = method;
add(phaseRunner(), schedulingHint);
}
private Runnable phaseRunner() {
return new Runnable() {
public void run() {
try {
doInvoke(m_phase.getLifeCycleInstance());
} catch (final Exception e) {
LogUtils.infof(this, e, "failed to invoke lifecycle instance");
}
}
public String toString() {
return "Runner for "+m_phase.toString();
}
};
}
private void doInvoke(LifeCycleInstance lifeCycle) throws IllegalAccessException, InvocationTargetException {
lifeCycle.setAttribute("currentPhase", m_phase);
Object[] args = findArguments(lifeCycle);
Object retVal = m_method.invoke(m_target, args);
Attribute retValAttr = m_method.getAnnotation(Attribute.class);
if (retValAttr != null) {
lifeCycle.setAttribute(retValAttr.value(), retVal);
}
else if (retVal instanceof Task) {
add((Task)retVal);
} else if (retVal != null) {
lifeCycle.setAttribute(retVal.getClass().getName(), retVal);
}
}
private Object[] findArguments(LifeCycleInstance lifeCycle) {
Type[] types = m_method.getGenericParameterTypes();
Object[] args = new Object[types.length];
for(int i = 0; i < types.length; i++) {
Attribute annot = getParameterAnnotation(m_method, i, Attribute.class);
if (annot != null) {
args[i] = lifeCycle.getAttribute(annot.value());
} else {
Type type = types[i];
if (type instanceof Class<?>) {
Class<?> clazz = (Class<?>)type;
args[i] = lifeCycle.findAttributeByType(clazz);
} else if (type instanceof ParameterizedType) {
ParameterizedType paramType = (ParameterizedType)type;
args[i] = lifeCycle.findAttributeByType((Class<?>) paramType.getRawType());
} else {
args[i] = null;
}
}
}
return args;
}
private <T extends Annotation> T getParameterAnnotation(Method method, int parmIndex, Class<T> annotationClass) {
Annotation[] annotations = method.getParameterAnnotations()[parmIndex];
for(Annotation a : annotations) {
if (annotationClass.isInstance(a)) {
return annotationClass.cast(a);
}
}
return null;
}
public String toString() {
return String.format("%s.%s(%s)", m_target.getClass().getSimpleName(), m_method.getName(), m_phase.getLifeCycleInstance());
}
}
/**
* <p>toString</p>
*
* @return a {@link java.lang.String} object.
*/
public String toString() {
return String.format("Phase %s of lifecycle %s", getName(), m_lifecycle.getName());
}
}