/*
* Copyright (c) 2012. HappyDroids LLC, All rights reserved.
*/
package com.happydroids.server;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonFilter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.happydroids.HappyDroidConsts;
import com.happydroids.platform.Platform;
import org.apach3.http.Header;
import org.apach3.http.HttpResponse;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.PROTECTED_AND_PUBLIC)
@JsonFilter(value = "HappyDroidServiceObject")
public abstract class HappyDroidServiceObject {
public static final ApiRunnable NO_OP_API_RUNNABLE = new ApiRunnable();
private long id;
private String resourceUri;
private boolean fetchError;
@JsonIgnore
public abstract String getBaseResourceUri();
protected HappyDroidServiceObject() {
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getResourceUri() {
return resourceUri;
}
protected abstract boolean requireAuthentication();
public void setResourceUri(String resourceUri) {
if (resourceUri != null && !resourceUri.startsWith("http")) {
resourceUri = HappyDroidConsts.HAPPYDROIDS_URI + resourceUri;
}
this.resourceUri = resourceUri;
}
private void validateResourceUri() {
if (resourceUri != null && !resourceUri.startsWith("http")) {
resourceUri = HappyDroidConsts.HAPPYDROIDS_URI + resourceUri;
}
}
public void fetch(final ApiRunnable apiRunnable) {
if (resourceUri == null) {
throw new RuntimeException("resourceUri must not be null when using fetch()");
}
fetchError = true;
validateResourceUri();
HttpResponse response = HappyDroidService.instance()
.makeGetRequest(resourceUri, null, isCachingAllowed(), getCacheMaxAge());
if (response != null && response.getStatusLine().getStatusCode() == 200) {
fetchError = false;
copyValuesFromResponse(response);
}
apiRunnable.handleResponse(response, HappyDroidServiceObject.this);
}
protected int getCacheMaxAge() {
return -1;
}
protected boolean isCachingAllowed() {
return false;
}
public void save() {
save(NO_OP_API_RUNNABLE);
}
@SuppressWarnings("unchecked")
public void save(final ApiRunnable apiRunnable) {
try {
if (!Platform.getConnectionMonitor().isConnectedOrConnecting()) {
apiRunnable.onError(null, HttpStatusCode.ClientClosedRequest, this);
return;
} else if (!beforeSaveValidation(apiRunnable)) {
apiRunnable.onError(null, HttpStatusCode.ClientValidationFailed, this);
return;
}
validateResourceUri();
HttpResponse response;
if (resourceUri == null) {
response = HappyDroidService.instance().makePostRequest(getBaseResourceUri(), this);
if (response != null && response.getStatusLine().getStatusCode() == 201) {
Header location = Iterables.getFirst(Lists.newArrayList(response.getHeaders("Location")), null);
if (location != null) {
resourceUri = location.getValue();
}
copyValuesFromResponse(response);
}
} else {
response = HappyDroidService.instance().makePutRequest(resourceUri, this);
}
apiRunnable.handleResponse(response, HappyDroidServiceObject.this);
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
}
@SuppressWarnings("unchecked")
protected boolean beforeSaveValidation(ApiRunnable afterSave) {
if (!Platform.getConnectionMonitor().isConnectedOrConnecting()) {
afterSave.onError(null, HttpStatusCode.ClientClosedRequest, this);
return false;
}
return true;
}
private void copyValuesFromResponse(HttpResponse response) {
HappyDroidServiceObject serverInstance = HappyDroidService.materializeObject(response, getClass());
if (serverInstance != null) {
Class<?> currentClass = serverInstance.getClass();
do {
for (Field field : currentClass.getDeclaredFields()) {
copyValueFromField(serverInstance, field);
}
currentClass = currentClass.getSuperclass();
} while (!currentClass.equals(Object.class));
}
}
private void copyValueFromField(HappyDroidServiceObject 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);
}
}
@JsonIgnore
public boolean isSaved() {
return resourceUri != null;
}
protected ObjectMapper getObjectMapper() {
return HappyDroidService.instance().getObjectMapper();
}
public void fetch() {
fetch(NO_OP_API_RUNNABLE);
}
public boolean errorWhileFetching() {
return fetchError;
}
}