/* * Copyright (c) 2012. HappyDroids LLC, All rights reserved. */ package com.happydroids.server; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.eventbus.EventBus; import com.happydroids.droidtowers.events.SafeEventBus; import com.happydroids.events.CollectionChangeEvent; import org.apach3.http.HttpResponse; import org.apach3.http.entity.BufferedHttpEntity; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.HashMap; import java.util.List; @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) public abstract class HappyDroidServiceCollection<CollectionType extends HappyDroidServiceObject> { private static final ApiCollectionRunnable NO_OP_API_RUNNABLE = new ApiCollectionRunnable(); private Metadata meta; private List<CollectionType> objects; private HashMap<String, String> currentFilters; private EventBus eventBus; private boolean fetching; public HappyDroidServiceCollection() { objects = Lists.newArrayList(); currentFilters = Maps.newHashMap(); } public void fetch(final ApiCollectionRunnable<HappyDroidServiceCollection<CollectionType>> apiRunnable) { fetchBlocking(apiRunnable); } private void copyValuesFromResponse(HttpResponse response) throws IOException { HappyDroidServiceCollection collection = HappyDroidService.instance() .getObjectMapper() .readValue(new BufferedHttpEntity(response.getEntity()).getContent(), getClass()); if (collection != null) { Class<?> currentClass = collection.getClass(); do { for (Field field : currentClass.getDeclaredFields()) { copyValueFromField(collection, field); } currentClass = currentClass.getSuperclass(); } while (!currentClass.equals(Object.class)); } } private void copyValueFromField(Object serverInstance, Field field) { try { if (!Modifier.isFinal(field.getModifiers())) { field.setAccessible(true); field.set(this, field.get(serverInstance)); } } catch (IllegalAccessException e) { throw new RuntimeException(e); } } protected abstract boolean requireAuthentication(); public abstract String getBaseResourceUri(); public List<CollectionType> getObjects() { return objects; } public boolean isEmpty() { return objects == null || objects.isEmpty(); } public void fetchBlocking(ApiCollectionRunnable<HappyDroidServiceCollection<CollectionType>> apiRunnable) { fetching = true; HttpResponse response = HappyDroidService.instance() .makeGetRequest(getBaseResourceUri(), currentFilters, isCachingAllowed(), getCacheMaxAge()); fetching = false; if (response != null && response.getStatusLine() != null && response.getStatusLine().getStatusCode() == 200) { ObjectMapper objectMapper = HappyDroidService.instance().getObjectMapper(); try { copyValuesFromResponse(response); } catch (IOException e) { throw new RuntimeException(e); } } apiRunnable.handleResponse(response, this); } protected int getCacheMaxAge() { return -1; } protected boolean isCachingAllowed() { return false; } public HappyDroidServiceCollection<CollectionType> filterBy(final String fieldName, final String filterValue) { if (currentFilters == null) { currentFilters = new HashMap<String, String>(); } currentFilters.put(fieldName, filterValue); return this; } public HappyDroidServiceCollection<CollectionType> filterBy(final String fieldName, long filterValue) { return filterBy(fieldName, "" + filterValue); } public void fetch() { fetch(NO_OP_API_RUNNABLE); } public void add(CollectionType object) { for (CollectionType collectionType : objects) { if (collectionType.getResourceUri() != null && collectionType.getResourceUri().equals(object.getResourceUri())) { return; } } objects.add(object); if (eventBus != null) { eventBus.post(new CollectionChangeEvent(object)); } } public EventBus events() { if (eventBus == null) { eventBus = new SafeEventBus(); } return eventBus; } public boolean isFetching() { return fetching; } public int size() { return objects.size(); } public void clear() { objects.clear(); } @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) public static class Metadata { public int limit; public int offset; public int totalCount; public String next; public String previous; public Metadata() { } } }