Forked from HYCAR-Hydro / airGR
Source project has a limited visibility.
ObservablesHandler.java 11.67 KiB
package fr.cemagref.observation.kernel;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
// TODO troduce in english
public class ObservablesHandler {
    private java.util.ArrayList<ObserverListener> observers;
    private transient ObservableFetcher[] fetchers;
    /**
     * Constructeur.
     * @param cl La classe à laquelle on associe le présent ClassObservable
    public ObservablesHandler(Class cl) {
        // observable attributes initialisation
        List<Field> v = new ArrayList<Field>();
        List<Method> v2 = new ArrayList<Method>();
        // observable methods initialisation
        Class inheritanceNavigator = cl;
        while (inheritanceNavigator != null) {
            for (Field f : inheritanceNavigator.getDeclaredFields()) {
                if (f.isAnnotationPresent(Observable.class)) {
                    v.add(f);
            for (Method m : inheritanceNavigator.getDeclaredMethods()) {
                if (m.isAnnotationPresent(Observable.class)) {
                    v2.add(m);
            inheritanceNavigator = inheritanceNavigator.getSuperclass();
        fetchers = new ObservableFetcher[v.size() + v2.size()];
        for (int i = 0; i < v.size(); i++) {
            fetchers[i] = new FieldFetcher(v.get(i));
        for (int i = 0; i < v2.size(); i++) {
            fetchers[v.size() + i] = new MethodFetcher(v2.get(i));
        // observers intialisation
        observers = new ArrayList<ObserverListener>();
    public Object getValue(int i, Object instance) throws IllegalArgumentException, IllegalAccessException,
            InvocationTargetException {
        return fetchers[i].fetchValue(instance);
    /** 
     * Equivalent à getAttributes()[n], sauf s'il n'y a aucun attribut annoté comme observable (dans
     * quel cas null est renvoyé).
     * @param n Un indice
     * @return Le java.lang.reflect.Field correspondant au n-ième attribut, ou null si aucun attribut 
     * n'est annoté comme observable.
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
public ObservableFetcher getObservableFetcher(int n) { return fetchers[n]; } public ObservableFetcher[] getObservableFetchers() { return fetchers; } /** Renvoie l'attribut dont la description est passée en argument. * * PERFS : Très mauvaises. A n'utiliser que pour un stockage initial de l'attribut * afin de l'utiliser intensivement ensuite. * * @param desc Une description * @return L'attribut qui correspond à cette description. */ public ObservableFetcher getObservableFetcher(String desc) { if ((fetchers.length == 0) || (desc == null)) { return null; } desc = desc.trim(); for (int i = 0; i < fetchers.length; i++) { if (desc.equals(fetchers[i].getDescription().trim())) { return fetchers[i]; } } return null; } public ObservableFetcher getObservableFetcherByName(String name) { if ((fetchers.length == 0) || (name == null)) { return null; } name = name.trim(); for (int i = 0; i < fetchers.length; i++) { if (name.equals(fetchers[i].getDeclaredName().trim())) { return fetchers[i]; } } return null; } /** * @return Le nombre d'attributes observables. */ public int numberOfAttributes() { return fetchers.length; } /** * Accesseur vers les descriptions des attributes observables, dans le même ordre * que getAttributes, c'est à dire que getAttributes()[n] ou getAttribute(n) ont la description * getDescriptions()[n]. * * Si aucun attribut n'est annoté comme étant observable, renvoie null. * * PERFS : Comme les description ne sont pas destinées à être utilisées de façon intensive, * le tableau est reconstruit à chaque appel de la méthode. * * @return Un tableau de descriptions des attributes annotés comme observables. * null si aucun attribut n'est annoté comme observable. */ public String[] getDescriptions() { String[] t = new String[fetchers.length]; for (int i = 0; i < fetchers.length; i++) { t[i] = fetchers[i].getDescription(); } return t; }
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
/** Equivalent à getAttribute(n).getAnnotation(Observable.class).description() sauf si * aucun attribut n'est annoté comme étant observabel, dans quel cas on renvoie null. * @param n * @return La description du n-ième attribut. */ public String getDescription(int n) { return fetchers[n].getDescription(); } public String getDeclaredName(int n) { return fetchers[n].getDeclaredName(); } /** Ajoute un ObserverListener à la liste. * * @param ob L'ObserverListener à ajouter. */ public ObserverListener addObserverListener(ObserverListener ob) { observers.add(ob); ob.addObservable(this); return ob; } /** Retire un seul observerListener de la liste. Renvoie true s'il a effectivement été trouvé * et retiré. * @param ob L'ObserverListener à retirer. * @return */ public boolean removeObserverListener(ObserverListener ob) { boolean response = observers.remove(ob); ObservableManager.getObservableManager().fireObservableManagerStructureChanged(); return response; } /** * <code>size</code> * * @see java.util.ArrayList#size() */ public int getObserversCount() { return observers.size(); } /** * Notifie les changement aux observers déclarés. Pour le moment les appelle l'un après l'autre. * * @param instanceEnCours * @param t */ public void fireChanges(Object instanceEnCours, long t) { for (ObserverListener listener : observers) { listener.valueChanged(this, instanceEnCours, t); } } public Collection<ObserverListener> getObservers() { return observers; } /** * @see java.util.ArrayList#clear() */ void clearObservers() { this.observers.clear(); } /** * @see java.util.ArrayList#get(int) */ public ObserverListener getObserver(int i) {
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
return observers.get(i); } public abstract class ObservableFetcher { public ObservableFetcher(AccessibleObject accessibleObject) { accessibleObject.setAccessible(true); } public abstract Object fetchValue(Object instance) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException; public Object fetchValueOrNull(Object instance) { try { return fetchValue(instance); } catch (IllegalArgumentException ex) { Logger.getLogger(ObservablesHandler.class.getName()).log(Level.SEVERE, null, ex); return null; } catch (IllegalAccessException ex) { Logger.getLogger(ObservablesHandler.class.getName()).log(Level.SEVERE, null, ex); return null; } catch (InvocationTargetException ex) { Logger.getLogger(ObservablesHandler.class.getName()).log(Level.SEVERE, null, ex); return null; } } /** * Return the size of each dimension. If a "labelsMethod" is declared, it will be used, otherwise, the given sizes will be returned. See the @Observable documentation. * @param instance * @return * @throws NoSuchMethodException * @throws IllegalAccessException * @throws IllegalArgumentException * @throws InvocationTargetException */ public int[] getSizes(Object instance) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { int[] sizes; if (getLabelsMethod().length() > 0) { sizes = new int[getSize().length]; for (int i = 0; i < sizes.length; i++) { String[] localLabels = (String[]) instance.getClass().getDeclaredMethod(getLabelsMethod(), Integer.class).invoke(instance, i); sizes[i] = (localLabels).length; } } else { sizes = getSize(); } return sizes; } public List<String>[] getLabels(Object instance) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { List<String>[] labels = new List[getSize().length]; if (getLabelsMethod().length() > 0) { for (int i = 0; i < getSize().length; i++) { String[] localLabels = (String[]) instance.getClass().getDeclaredMethod(getLabelsMethod(), Integer.class).invoke(instance, i); labels[i] = Arrays.asList(localLabels); } } else { for (int i = 0; i < getSize().length; i++) { labels[i] = new ArrayList<String>(getSize()[i]); labels[i].add(getDeclaredName() + "[0]"); for (int j = 1; j < getSize()[i]; j++) { labels[i].add("[" + j + "]"); } } } return labels; } public abstract Observable getAnnotation();
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
public abstract String getDeclaredName(); public String getDescription() { return getAnnotation().description(); } protected final int[] getSize() { return getAnnotation().size(); } public String getLabelsMethod() { return getAnnotation().labelsMethod(); } public abstract Class getDeclaredType(); } public class MethodFetcher extends ObservableFetcher { private Method method; public MethodFetcher(Method method) { super(method); this.method = method; } @Override public Object fetchValue(Object instance) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { // TODO add the ability to use arguments return method.invoke(instance, new Object[]{}); } @Override public Observable getAnnotation() { return method.getAnnotation(Observable.class); } @Override public String getDeclaredName() { return method.getName(); } @Override public Class getDeclaredType() { return method.getReturnType(); } } public class FieldFetcher extends ObservableFetcher { private Field field; public FieldFetcher(Field field) { super(field); this.field = field; } @Override public Object fetchValue(Object instance) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { return field.get(instance); } @Override public Observable getAnnotation() { return field.getAnnotation(Observable.class); }
351352353354355356357358359360361362
@Override public String getDeclaredName() { return field.getName(); } @Override public Class getDeclaredType() { return field.getType(); } } }