package com.pam.codenamehippie.modele.depot; import android.app.Activity; import android.app.Application; import android.app.Application.ActivityLifecycleCallbacks; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v4.util.ArrayMap; import com.pam.codenamehippie.modele.BaseModele; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; import okhttp3.OkHttpClient; /** * Classe servant à gérer les depots. Cette classe enregistre automatiquement les activitées qui * implémente l'interface {@link ObservateurDeDepot} au bon dépot. Cette classe est un singleton. */ public final class DepotManager implements ActivityLifecycleCallbacks { /** * Constante à utiliser pour les appels à * {@link android.content.Context#getSystemService(String)} */ public static final String DEPOT_SERVICE = "depot"; private static final AtomicReference<DepotManager> instanceRef = new AtomicReference<>(null); private final Application application; /** * Instance du client http pour l'application */ private final OkHttpClient httpClient; private final Map<Class, Class> registreActivite = new ArrayMap<>(); private final Map<Class, BaseModeleDepot> registreDeDepot = new ArrayMap<>(); /** * Instance de {@link UtilisateurModeleDepot} pour l'application */ private final UtilisateurModeleDepot utilisateurModeleDepot; /** * Instance d'{@link OrganismeModeleDepot} pour l'application */ private final OrganismeModeleDepot organismeModeleDepot; /** * Instance de {@link TransactionModeleDepot} pour l'application */ private final TransactionModeleDepot transactionModeleDepot; /** * Instance de {@link AlimentaireModeleDepot} pour l'application */ private final AlimentaireModeleDepot alimentaireModeleDepot; private DepotManager(Application application, OkHttpClient httpClient) { this.application = application; this.httpClient = httpClient; this.alimentaireModeleDepot = new AlimentaireModeleDepot(this.application, this.httpClient); this.registreDeDepot.put(this.alimentaireModeleDepot.classeDeT, this.alimentaireModeleDepot ); this.organismeModeleDepot = new OrganismeModeleDepot(this.application, this.httpClient); this.registreDeDepot.put(this.organismeModeleDepot.classeDeT, this.organismeModeleDepot ); this.transactionModeleDepot = new TransactionModeleDepot(this.application, this.httpClient); this.registreDeDepot.put(this.transactionModeleDepot.classeDeT, this.transactionModeleDepot ); this.utilisateurModeleDepot = new UtilisateurModeleDepot(this.application, this.httpClient); this.registreDeDepot.put(this.utilisateurModeleDepot.classeDeT, this.utilisateurModeleDepot ); } /** * Initialise le manager de dépot. Doit être appelée avant {@link DepotManager#getInstance()} * et au maximum une fois. * <p> * Cette méthode est en théorie thread-safe. * </p> * * @param application * Application courante * @param httpClient * Le client http a utiliser pour tout les depots * * @throws IllegalStateException * Si une instance existe déjà. */ public static void init(@NonNull Application application, @NonNull OkHttpClient httpClient) { DepotManager instance = new DepotManager(application, httpClient); if (!instanceRef.compareAndSet(null, instance)) { throw new IllegalStateException("Already initialzed"); } else { application.registerActivityLifecycleCallbacks(instance); } } /** * Retourne le manager de dépot. {@link DepotManager#init(Application, OkHttpClient)} doit * être appelée avant cette méthode. * <p> * Cette méthode est en théorie thread-safe. * </p> * * @throws IllegalStateException * Si une instance n'existe pas déjà. */ public static DepotManager getInstance() { DepotManager instance = instanceRef.get(); if (instance == null) { throw new IllegalStateException("Not initialzed"); } return instance; } /** * @return l'instance de {@link OkHttpClient} utilisé par les dépots */ public synchronized OkHttpClient getHttpClient() { return this.httpClient; } /** * Accesseur de depot * * @return Le depot correspondant au nom de la méthode */ public synchronized AlimentaireModeleDepot getAlimentaireModeleDepot() { return this.alimentaireModeleDepot; } /** * Accesseur de depot * * @return Le depot correspondant au nom de la méthode */ public synchronized OrganismeModeleDepot getOrganismeModeleDepot() { return this.organismeModeleDepot; } /** * Accesseur de depot * * @return Le depot correspondant au nom de la méthode */ public synchronized TransactionModeleDepot getTransactionModeleDepot() { return this.transactionModeleDepot; } /** * Accesseur de depot * * @return Le depot correspondant au nom de la méthode */ public synchronized UtilisateurModeleDepot getUtilisateurModeleDepot() { return this.utilisateurModeleDepot; } @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { Class clazz = activity.getClass(); if ((ObservateurDeDepot.class.isAssignableFrom(clazz)) && (!this.registreActivite.containsKey(clazz))) { Type[] interfaces = clazz.getGenericInterfaces(); for (Type iface : interfaces) { ParameterizedType gIface = ((iface instanceof ParameterizedType) ? ((ParameterizedType) iface) : null); if (gIface != null) { for (Type arg : gIface.getActualTypeArguments()) { if (BaseModele.class.isAssignableFrom((Class) arg)) { this.registreActivite.put(clazz, (Class) arg); } } } } } } @Override public void onActivityStarted(Activity activity) { } @Override public void onActivityResumed(Activity activity) { Class modelClass = this.registreActivite.get(activity.getClass()); if (modelClass != null) { BaseModeleDepot depot = this.registreDeDepot.get(modelClass); if (depot != null) { depot.ajouterUnObservateur((ObservateurDeDepot) activity); } } } @Override public void onActivityPaused(Activity activity) { Class modelClass = this.registreActivite.get(activity.getClass()); if (modelClass != null) { BaseModeleDepot depot = this.registreDeDepot.get(modelClass); if (depot != null) { depot.setFiltreDeListe(null); depot.supprimerTousLesObservateurs(); this.getHttpClient().dispatcher().cancelAll(); } } } @Override public void onActivityStopped(Activity activity) { } @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) { } @Override public void onActivityDestroyed(Activity activity) { } }