GenericLoaderFactory.java revision 0ae32dc10d668a04f9f0484d587aefe5a7210e1c
10ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Juddpackage com.bumptech.glide.loader.bitmap.model;
20ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd
30ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Juddimport android.content.Context;
40ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd
50ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Juddimport java.util.HashMap;
60ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Juddimport java.util.Map;
70ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd
80ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd/**
90ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd * Maintain a map of model class to factory to retrieve a {@link ModelLoaderFactory} and/or a {@link ModelLoader}
100ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd * for a given model type.
110ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd */
120ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Juddpublic class GenericLoaderFactory {
130ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd    private Map<Class, Map<Class, ModelLoaderFactory>> modelClassToResourceFactories =
140ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd            new HashMap<Class, Map<Class, ModelLoaderFactory>>();
150ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd
160ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd    @SuppressWarnings("unchecked")
170ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd    public <T, Y> ModelLoaderFactory<T, Y> register(Class<T> modelClass, Class<Y> resourceClass,
180ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd            ModelLoaderFactory<T, Y> factory) {
190ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd        Map<Class, ModelLoaderFactory> resourceToFactories = modelClassToResourceFactories.get(modelClass);
200ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd        if (resourceToFactories == null) {
210ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd            resourceToFactories = new HashMap<Class, ModelLoaderFactory>();
220ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd            modelClassToResourceFactories.put(modelClass, resourceToFactories);
230ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd        }
240ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd
250ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd        ModelLoaderFactory<T, Y> previous = resourceToFactories.put(resourceClass, factory);
260ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd
270ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd        if (previous != null) {
280ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd            // This factory may be being used by another model. We don't want to say it has been removed unless we
290ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd            // know it has been removed for all models.
300ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd            for (Map<Class, ModelLoaderFactory> currentResourceToFactories : modelClassToResourceFactories.values()) {
310ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd                if (currentResourceToFactories.containsValue(previous)) {
320ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd                    previous = null;
330ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd                    break;
340ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd                }
350ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd            }
360ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd        }
370ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd        return previous;
380ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd    }
390ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd
400ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd    public <T, Y> ModelLoader<T, Y> buildModelLoader(Class<T> modelClass, Class<Y> resourceClass, Context context) {
410ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd        final ModelLoaderFactory<T, Y> factory = getFactory(modelClass, resourceClass);
420ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd        if (factory == null) {
430ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd            throw new IllegalArgumentException("No ModelLoaderFactory registered for class=" + modelClass);
440ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd        }
450ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd        return factory.build(context, this);
460ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd    }
470ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd
480ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd    @SuppressWarnings("unchecked")
490ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd    public <T, Y> ModelLoaderFactory<T, Y> getFactory(Class<T> modelClass, Class<Y> resourceClass) {
500ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd        Map<Class, ModelLoaderFactory> resourceToFactories = modelClassToResourceFactories.get(modelClass);
510ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd        ModelLoaderFactory result = null;
520ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd        if (resourceToFactories != null) {
530ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd            result = resourceToFactories.get(resourceClass);
540ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd        }
550ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd
560ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd
570ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd        if (result == null) {
580ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd            for (Class registeredModelClass : modelClassToResourceFactories.keySet()) {
590ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd                // This accounts for model subclasses, our map only works for exact matches. We should however still
600ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd                // match a subclass of a model with a factory for a super class of that model if if there isn't a
610ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd                // factory for that particular subclass. Uris are a great example of when this happens, most uris
620ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd                // are actually subclasses for Uri, but we'd generally rather load them all with the same factory rather
630ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd                // than trying to register for each subclass individually.
640ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd                if (registeredModelClass.isAssignableFrom(modelClass)) {
650ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd                    Map<Class, ModelLoaderFactory> currentResourceToFactories =
660ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd                            modelClassToResourceFactories.get(registeredModelClass);
670ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd                    if (currentResourceToFactories != null) {
680ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd                        result = currentResourceToFactories.get(resourceClass);
690ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd                        if (result != null) {
700ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd                            break;
710ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd                        }
720ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd                    }
730ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd                }
740ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd            }
750ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd        }
760ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd
770ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd        return result;
780ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd    }
790ae32dc10d668a04f9f0484d587aefe5a7210e1cSam Judd}
80