/*
* Copyright 2015 Victor Albertos
*
* 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.rx_cache2.internal;
import io.reactivex.Flowable;
import io.reactivex.Maybe;
import io.reactivex.Observable;
import io.reactivex.Single;
import io.rx_cache2.ConfigProvider;
import io.rx_cache2.DynamicKey;
import io.rx_cache2.DynamicKeyGroup;
import io.rx_cache2.Encrypt;
import io.rx_cache2.EvictProvider;
import io.rx_cache2.Expirable;
import io.rx_cache2.LifeCache;
import io.rx_cache2.Reply;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import javax.inject.Inject;
public final class ProxyTranslator {
private final Map<Method, ConfigProvider> configProviderMethodCache;
@Inject ProxyTranslator() {
configProviderMethodCache = new HashMap<>();
}
ConfigProvider processMethod(Method method, Object[] objectsMethod) {
ConfigProvider prev = loadConfigProviderMethod(method);
ConfigProvider configProvider = new ConfigProvider(prev.getProviderKey(),
null, prev.getLifeTimeMillis(), prev.requiredDetailedResponse(), prev.isExpirable(),
prev.isEncrypted(), getDynamicKey(method, objectsMethod),
getDynamicKeyGroup(method, objectsMethod),
getLoaderObservable(method, objectsMethod),
evictProvider(method, objectsMethod));
return configProvider;
}
private String getProviderKey(Method method) {
return method.getName();
}
private String getDynamicKey(Method method, Object[] objectsMethod) {
DynamicKey dynamicKey = getObjectFromMethodParam(method, DynamicKey.class, objectsMethod);
if (dynamicKey != null) return dynamicKey.getDynamicKey().toString();
DynamicKeyGroup dynamicKeyGroup =
getObjectFromMethodParam(method, DynamicKeyGroup.class, objectsMethod);
if (dynamicKeyGroup != null) return dynamicKeyGroup.getDynamicKey().toString();
return "";
}
private String getDynamicKeyGroup(Method method, Object[] objectsMethod) {
DynamicKeyGroup dynamicKeyGroup =
getObjectFromMethodParam(method, DynamicKeyGroup.class, objectsMethod);
return dynamicKeyGroup != null ? dynamicKeyGroup.getGroup().toString() : "";
}
private Observable getLoaderObservable(Method method, Object[] objectsMethod) {
Observable<?> observable = getObjectFromMethodParam(method, Observable.class, objectsMethod);
if (observable != null) return observable;
Single single = getObjectFromMethodParam(method, Single.class, objectsMethod);
if (single != null) return single.toObservable();
Maybe maybe = getObjectFromMethodParam(method, Maybe.class, objectsMethod);
if (maybe != null) return maybe.toObservable();
Flowable flowable = getObjectFromMethodParam(method, Flowable.class, objectsMethod);
if (flowable != null) return flowable.toObservable();
String errorMessage =
method.getName() + io.rx_cache2.internal.Locale.NOT_REACTIVE_TYPE_FOR_LOADER_WAS_FOUND;
throw new IllegalArgumentException(errorMessage);
}
private Long getLifeTimeCache(Method method) {
LifeCache lifeCache = method.getAnnotation(LifeCache.class);
if (lifeCache == null) return null;
return lifeCache.timeUnit().toMillis(lifeCache.duration());
}
private boolean getExpirable(Method method) {
Expirable expirable = method.getAnnotation(Expirable.class);
if (expirable != null) return expirable.value();
return true;
}
private boolean isEncrypted(Method method) {
Encrypt encrypt = method.getAnnotation(Encrypt.class);
if (encrypt != null) return true;
return false;
}
private boolean requiredDetailResponse(Method method) {
if (method.getReturnType() == Observable.class || method.getReturnType() == Single.class
|| method.getReturnType() == Maybe.class || method.getReturnType() == Flowable.class) {
return method.getGenericReturnType().toString().contains(Reply.class.getName());
}
String errorMessage = method.getName() + io.rx_cache2.internal.Locale.INVALID_RETURN_TYPE;
throw new IllegalArgumentException(errorMessage);
}
private EvictProvider evictProvider(Method method, Object[] objectsMethod) {
EvictProvider evictProvider =
getObjectFromMethodParam(method, EvictProvider.class, objectsMethod);
if (evictProvider != null) {
return evictProvider;
} else {
return new EvictProvider(false);
}
}
private <T> T getObjectFromMethodParam(Method method, Class<T> expectedClass,
Object[] objectsMethod) {
int countSameObjectsType = 0;
T expectedObject = null;
for (Object objectParam : objectsMethod) {
if (expectedClass.isAssignableFrom(objectParam.getClass())) {
expectedObject = (T) objectParam;
countSameObjectsType++;
}
}
if (countSameObjectsType > 1) {
String errorMessage =
method.getName()
+ io.rx_cache2.internal.Locale.JUST_ONE_INSTANCE
+ expectedObject.getClass().getSimpleName();
throw new IllegalArgumentException(errorMessage);
}
return expectedObject;
}
private ConfigProvider loadConfigProviderMethod(Method method) {
ConfigProvider result;
synchronized (configProviderMethodCache) {
result = configProviderMethodCache.get(method);
if (result == null) {
result = new ConfigProvider(getProviderKey(method),
null, getLifeTimeCache(method),
requiredDetailResponse(method), getExpirable(method), isEncrypted(method),
null, null, null, null);
configProviderMethodCache.put(method, result);
}
}
return result;
}
}