/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.eas.client;
import com.eas.client.cache.ActualCacheEntry;
import com.eas.client.report.Report;
import com.eas.client.threetier.PlatypusConnection;
import com.eas.client.threetier.requests.RPCRequest;
import com.eas.client.threetier.requests.ServerModuleStructureRequest;
import com.eas.script.JsObjectException;
import com.eas.script.Scripts;
import java.util.Date;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.internal.runtime.JSType;
/**
*
* @author mg
*/
public class RemoteServerModulesProxy implements ServerModulesProxy{
public static final String LENGTH_PROP_NAME = "length";
public static final String CREATE_MODULE_RESPONSE_FUNCTIONS_PROP = "functions";
public static final String CREATE_MODULE_RESPONSE_IS_PERMITTED_PROP = "isPermitted";
private static final String NEITHER_SM_INFO = "Neither cached nor network server module info found";
protected Map<String, ActualCacheEntry<ServerModuleInfo>> entries = new ConcurrentHashMap<>();
protected PlatypusConnection conn;
public RemoteServerModulesProxy(PlatypusConnection aConn) {
super();
conn = aConn;
}
@Override
public ServerModuleInfo getCachedStructure(String aName) throws Exception {
ActualCacheEntry<ServerModuleInfo> entry = entries.get(aName);
if (entry != null) {
return entry.getValue();
} else {
return null;
}
}
@Override
public ServerModuleInfo getServerModuleStructure(String aName, Scripts.Space aSpace, Consumer<ServerModuleInfo> onSuccess, Consumer<Exception> onFailure) throws Exception {
Date localTimeStamp = null;
ActualCacheEntry<ServerModuleInfo> entry = entries.get(aName);
if (entry != null) {
localTimeStamp = entry.getTimeStamp();
}
ServerModuleStructureRequest request = new ServerModuleStructureRequest(aName, localTimeStamp);
if (onSuccess != null) {
conn.enqueueRequest(request, aSpace, (ServerModuleStructureRequest.Response response) -> {
String infoJson = response.getInfoJson();
if (infoJson != null) {
ServerModuleInfo info = readInfo(aName, (JSObject)aSpace.parseJson(infoJson));
entries.put(aName, new ActualCacheEntry<>(info, response.getTimeStamp()));
onSuccess.accept(info);
} else {
assert entry != null : NEITHER_SM_INFO;
onSuccess.accept(entry.getValue());
}
}, (Exception ex) -> {
onFailure.accept(ex);
});
return null;
} else {
ServerModuleStructureRequest.Response response = conn.executeRequest(request);
String infoJson = response.getInfoJson();
if (infoJson != null) {
ServerModuleInfo info = readInfo(aName, (JSObject)aSpace.parseJson(infoJson));
entries.put(aName, new ActualCacheEntry<>(info, response.getTimeStamp()));
return info;
} else {
assert entry != null : NEITHER_SM_INFO;
return entry.getValue();
}
}
}
private ServerModuleInfo readInfo(String aModuleName, JSObject jsProxy) {
Set<String> functions = new HashSet<>();
JSObject jsFunctions = (JSObject) jsProxy.getMember(CREATE_MODULE_RESPONSE_FUNCTIONS_PROP);
int length = JSType.toInteger(jsFunctions.getMember(LENGTH_PROP_NAME));
for (int i = 0; i < length; i++) {
String fName = JSType.toString(jsFunctions.getSlot(i));
functions.add(fName);
}
boolean permitted = JSType.toBoolean(jsProxy.getMember(CREATE_MODULE_RESPONSE_IS_PERMITTED_PROP));
return new ServerModuleInfo(aModuleName, functions, permitted);
}
@Override
public Object callServerModuleMethod(String aModuleName, String aMethodName, Scripts.Space aSpace, JSObject onSuccess, JSObject onFailure, Object... aArguments) throws Exception {
if (onSuccess != null) {
executeServerModuleMethod(aModuleName, aMethodName, aSpace, (Object aResult) -> {
onSuccess.call(null, new Object[]{aResult});
}, (Exception ex) -> {
if (onFailure != null) {
onFailure.call(null, new Object[]{ex instanceof JsObjectException ? ((JsObjectException)ex).getData() : ex.getMessage()});
}
}, aArguments);
return null;
} else {
return executeServerModuleMethod(aModuleName, aMethodName, aSpace, null, null, aArguments);
}
}
public Object executeServerModuleMethod(String aModuleName, String aMethodName, Scripts.Space aSpace, Consumer<Object> onSuccess, Consumer<Exception> onFailure, Object... aArguments) throws Exception {
String[] argumentsJsons = new String[aArguments.length];
for (int i = 0; i < argumentsJsons.length; i++) {
argumentsJsons[i] = aSpace.toJson(aArguments[i]);
}
final RPCRequest request = new RPCRequest(aModuleName, aMethodName, argumentsJsons);
if (onSuccess != null) {
conn.<RPCRequest.Response>enqueueRequest(request, aSpace, (RPCRequest.Response aResponse) -> {
Object sResult = adoptRPCResponse(aResponse, aSpace);
onSuccess.accept(sResult);
}, onFailure);
return null;
} else {
RPCRequest.Response response = conn.executeRequest(request);
Object sResult = adoptRPCResponse(response, aSpace);
return sResult;
}
}
private Object adoptRPCResponse(RPCRequest.Response aResponse, Scripts.Space aSpace) {
Object sResult;
Object rpcResult = aResponse.getResult();
if(rpcResult instanceof String){
sResult = aSpace.parseJsonWithDates((String)rpcResult);
}else if(rpcResult instanceof Report){
Report report = (Report)rpcResult;
sResult = report.getPublished();
}else{
sResult = rpcResult;
}
return sResult;
}
}