/*******************************************************************************
* Copyright (c) 2008 Dennis Schenk, Peter Siska.
* 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:
* Dennis Schenk - initial implementation
* Peter Siska - initial implementation
*******************************************************************************/
package ch.unibe.iam.scg.archie.utils;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.Map;
import ch.elexis.core.ui.util.Log;
import ch.unibe.iam.scg.archie.ArchieActivator;
import ch.unibe.iam.scg.archie.annotations.GetProperty;
import ch.unibe.iam.scg.archie.annotations.SetProperty;
import ch.unibe.iam.scg.archie.model.AbstractDataProvider;
/**
* <p>
* Utility class providing helper functions for data providers. This class
* provides convenience methods for annotation retrieval and sorting. This class
* also handles the retrieval and setting of annotation methods and values for a
* given provider.
* </p>
*
* $Id: ProviderHelper.java 705 2009-01-03 17:48:46Z peschehimself $
*
* @author Peter Siska
* @author Dennis Schenk
* @version $Rev: 705 $
*/
public class ProviderHelper {
/** magic constant for getter methods */
private static final int GETTER = 0;
/** magic constant for setter methods */
private static final int SETTER = 1;
/**
* Returns a map of getter methods for providers mapped from the method's
* name to it's value.
*
* @param provider
* AbstractDataProvider to retrieve the methods from.
* @param sorted
* If true, the methods will be sorted according to their index.
* @return Map with getter method names and values.
*/
public static Map<String, Object> getGetterMap(final AbstractDataProvider provider, final boolean sorted) {
LinkedHashMap<String, Object> getterMap = new LinkedHashMap<String, Object>();
for (Method method : ProviderHelper.getGetterMethods(provider, sorted)) {
GetProperty getter = method.getAnnotation(GetProperty.class);
getterMap.put(getter.name(), ProviderHelper.getValue(method, provider));
}
return getterMap;
}
/**
* Convenient method to retrieve all getters from a given provider.
*
* @param provider
* AbstractDataProvider to retrieve the methods from.
* @param sorted
* If true, the methods will be sorted according to their index.
* @return List of getter methods for a given provider.
*/
public static ArrayList<Method> getGetterMethods(final AbstractDataProvider provider, final boolean sorted) {
return ProviderHelper.getMethods(provider, sorted, ProviderHelper.GETTER);
}
/**
* Convenient method to retrieve all setters from a given provider.
*
* @param provider
* AbstractDataProvider to retrieve the methods from.
* @param sorted
* If true, the methods will be sorted according to their index.
* @return List of setter methods for a given provider.
*/
public static ArrayList<Method> getSetterMethods(final AbstractDataProvider provider, final boolean sorted) {
return ProviderHelper.getMethods(provider, sorted, ProviderHelper.SETTER);
}
/**
* Retrieves the value of a given method for a given provider by invoking
* the method on the given provider.
*
* @param method
* Method to invoke.
* @param provider
* Provider where the method will be invoked.
* @return Value of the method invoked.
*/
public static Object getValue(final Method method, final AbstractDataProvider provider) {
try {
return method.invoke(provider);
} catch (Exception e) {
ArchieActivator.LOG.log("Could not invoke a method for a provider." + "\n" + "Method: " + method.getName()
+ "\n" + provider.getClass().getName() + "\n" + e.getLocalizedMessage(), Log.ERRORS);
}
return null;
}
/**
* Sets the value of a given method for a given provider by invoking the
* method on the given provider.
*
* @param method
* Method to invoke.
* @param provider
* Provider where the method will be invoked.
* @param value
* Value to use for the method invocation.
* @throws Exception
* Exception when the value count not be set invoking the method
* on the given provider.
*/
public static void setValue(final AbstractDataProvider provider, final Method method, final Object value)
throws Exception {
try {
method.invoke(provider, value);
} catch (Exception e) {
throw (Exception) e.getCause();
}
}
/**
* Internal method for retrieving a list of methods for a given provider.
*
* @param provider
* AbstractDataProvider to retrieve the methods from.
* @param sorted
* If true, the methods will be sorted according to their index.
* @param which
* What method type, either getter or setter, to retrieve.
* @return List of either getter or setter methods for a given provider.
*/
private static ArrayList<Method> getMethods(final AbstractDataProvider provider, final boolean sorted,
final int which) {
ArrayList<Method> methods = new ArrayList<Method>();
// get all provider methods and only keep the getter annotations
for (Method method : provider.getClass().getMethods()) {
if (which == ProviderHelper.GETTER && method.isAnnotationPresent(GetProperty.class)) {
methods.add(method);
} else if (which == ProviderHelper.SETTER && method.isAnnotationPresent(SetProperty.class)) {
methods.add(method);
}
}
// sort if applicable
if (sorted) {
ProviderHelper.sortMethodList(methods);
}
return methods;
}
/**
* Sorts the methods according to the index of the property annotation.
*
* @param methodList
* a list containing only methods having a Set/GetProperty
* annotation.
*/
private static void sortMethodList(ArrayList<Method> methodList) {
Collections.sort(methodList, new Comparator<Method>() {
public int compare(Method o1, Method o2) {
int index1 = 0;
int index2 = 0;
if (o1.isAnnotationPresent(GetProperty.class)) {
GetProperty anno1 = o1.getAnnotation(GetProperty.class);
GetProperty anno2 = o2.getAnnotation(GetProperty.class);
index1 = anno1.index();
index2 = anno2.index();
} else { // has to have a SetProperty annotation
SetProperty anno1 = o1.getAnnotation(SetProperty.class);
SetProperty anno2 = o2.getAnnotation(SetProperty.class);
index1 = anno1.index();
index2 = anno2.index();
}
return index1 - index2;
}
});
}
}