/*
* Copyright (C) 2014 Divide.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.divide.client.data;
import com.google.gson.Gson;
import com.google.inject.Inject;
import io.divide.client.BackendObject;
import io.divide.client.Config;
import io.divide.client.auth.AuthManager;
import io.divide.client.web.AbstractWebManager;
import io.divide.shared.transitory.TransientObject;
import io.divide.shared.transitory.query.Query;
import io.divide.shared.util.IOUtils;
import io.divide.shared.util.ObjectUtils;
import retrofit.client.Response;
import rx.Observable;
import rx.Subscriber;
import java.io.IOException;
import java.lang.reflect.Array;
import java.util.Collection;
/*
* WebManager class used to handle all object transactions between client and server.
*/
public class DataManager extends AbstractWebManager<DataWebService> {
@Inject private AuthManager authManager;
@Inject
public DataManager(Config config) {
super(config);
}
@Override
protected Class<DataWebService> getType() {
return DataWebService.class;
}
/**
* Function used to save objects on remote server.
* @param objects Collection of objects to be saved.
* @param <B> Object type that extends BackendObject.
* @return Observable, no entity returned.
*/
public <B extends BackendObject> Observable<Void> send(final Collection<B> objects){
return getWebService().save(isLoggedIn(),objects)
.subscribeOn(config.subscribeOn()).observeOn(config.observeOn());
}
/**
* Function used to return specific objects corrosponding to the object keys provided.
* @param type Type of objects to be returned, if an object of a key provided does not match Type, it will not be returned.
* @param objects Collection of keys you wish to return from remote server.
* @param <B> Class type to be returned, extends BackendObject.
* @return Collection of objects corrosponding to keys provided.
*/
public <B extends BackendObject> Observable<Collection<B>> get(final Class<B> type, final Collection<String> objects){
return Observable.create(new Observable.OnSubscribe<Collection<B>>() {
@Override
public void call(Subscriber<? super Collection<B>> observer) {
try {
observer.onNext(convertRequest(getArrayType(type), getWebService().get(isLoggedIn(),Query.safeTable(type), objects)));
observer.onCompleted();
} catch (Exception e) {
observer.onError(e);
}
}
}).subscribeOn(config.subscribeOn()).observeOn(config.observeOn());
}
/**
* Function used to perform a remote query.
* @param type Type of objects to be returned, Type must match that which was provided to the Query.
* @param query Query to be executed.
* @param <B> Type of object extending BackendObject to be returned.
* @return Collection of objects matching query executed.
*/
public <B extends BackendObject> Observable<Collection<B>> query(final Class<B> type,final Query query){
return Observable.create(new Observable.OnSubscribe<Collection<B>>() {
@Override
public void call(Subscriber<? super Collection<B>> observer) {
try {
observer.onNext(convertRequest(getArrayType(type),getWebService().query(isLoggedIn(),query)));
observer.onCompleted();
} catch (Exception e) {
observer.onError(e);
}
}
}).subscribeOn(config.subscribeOn()).observeOn(config.observeOn());
}
/**
* Functin used to perform a count query against remote sever for specifed type.
* @param type Type to be counted.
* @param <B> Type extending BackendObject
* @return Count of objects on remote server matching specified type.
*/
public <B extends BackendObject> Observable<Integer> count(final Class<B> type){
return getWebService().count(isLoggedIn(),Query.safeTable(type))
.subscribeOn(config.subscribeOn()).observeOn(config.observeOn());
}
/**
* Used to determine if a user is logged in localy, if not remote operations can not be performed.
* @return authentication token for logged in user.
* @throws RuntimeException Execption thrown if if remote operaton is requested but no user is logged in.
*/
private String isLoggedIn() throws RuntimeException {
if(authManager != null && authManager.getUser() != null && authManager.getUser().getAuthToken() != null){
return "CUSTOM " + authManager.getUser().getAuthToken();
} else {
throw new RuntimeException("User state error.");
}
}
private static Gson gson = new Gson();
private <B extends TransientObject> Collection<B> convertRequest(Class<B[]> type, Response response){
String body = null;
try {
body = IOUtils.toString(response.getBody().in());
} catch (IOException e) {
e.printStackTrace();
}
B[] t = gson.fromJson(body,type);
return ObjectUtils.v2c(t);
}
/**
* Convience method to convert a specified type to an Array of that specified type.
* Example: Class<Integer[]> intArrayType = getArrayType(Integer.class);
* @param type class you wish to have concrete array type of.
* @return concrete array type of type specified.
*/
private <T extends TransientObject> Class<T[]> getArrayType(Class<T> type){
return (Class<T[]>) Array.newInstance(type, 0).getClass();
}
}