import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.Calendar;
import java.util.HashMap;
import java.util.LinkedHashMap;
import org.apache.xmlrpc.XmlRpcException;
import org.apache.xmlrpc.XmlRpcRequest;
import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;
import org.apache.xmlrpc.client.XmlRpcClientException;
import org.apache.xmlrpc.client.XmlRpcCommonsTransport;
import org.apache.xmlrpc.client.XmlRpcCommonsTransportFactory;
import org.apache.xmlrpc.client.XmlRpcTransport;
/**
* The OBALogic is the connector with VCL server It will be responsible to
* sending and receiving the request from client to VCL server
*
* @author Minh Tuan PHAM, Ruowen Wang
*/
public class OBALogic {
private String username;
private String password;
private XmlRpcClient client;
private String errMsg;
public OBALogic(final String username, final String password) {
this.username = username;
this.password = password;
XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
try {
config.setServerURL(new URL(
"https://vcl.ncsu.edu/scheduling/index.php?mode=xmlrpccall"));
} catch (MalformedURLException e) {
e.printStackTrace();
}
this.client = new XmlRpcClient();
this.client.setConfig(config);
// implement transport factory
XmlRpcCommonsTransportFactory xmlRpcTransportFactory = new XmlRpcCommonsTransportFactory(
client) {
@Override
public XmlRpcTransport getTransport() {
return new XmlRpcCommonsTransport(this) {
@Override
protected void initHttpHeaders(XmlRpcRequest pRequest)
throws XmlRpcClientException {
super.initHttpHeaders(pRequest);
// add custom header, with UnityID authentication
super.setRequestHeader("X-User", username);
super.setRequestHeader("X-Pass", password);
super.setRequestHeader("X-APIVERSION", "2");
}
};
}
};
client.setTransportFactory(xmlRpcTransportFactory);
}
private Object xmlRPCcall(String op_name, Object[] params) {
Object result = null;
try {
result = client.execute(op_name, params);
if (result instanceof HashMap) {
// do nothing
return (HashMap) result;
} else {
Object[] result_array = (Object[]) result;
// for (int i = 0; i < result_array.length; i++)
// System.out.println(result_array[i]);
return result_array;
}
} catch (XmlRpcException e) {
System.err.println("XML RPC Call Error!");
// e.printStackTrace();
}
return result;
}
/**
* This method try to send a reservation request to the VCL server If
* success: return the request_id If failed: return the value -1 and an
* error message in the variable errMsg of class
*
* @param imageid
* @param start
* @param duration
* multiple of 15
* @return request_id or -1.
*/
public int addRequest(int imageid, Calendar start, int duration) {
Object[] params = new Object[3];
params[0] = imageid;
params[1] = (int) (start.getTimeInMillis() / 1000L);
int unroundedMinutes = start.get(Calendar.MINUTE);
if (unroundedMinutes == 0 || unroundedMinutes % 15 == 0)
params[2] = duration;
else
params[2] = duration + 15;
HashMap result = (HashMap) xmlRPCcall("XMLRPCaddRequest", params);
if (result.get("status").equals("success")) {
System.out.print("Succeed in making a reservation: "
+ result.get("requestid") + "\n");
return Integer.parseInt((String) result.get("requestid"));
} else {
if (result.get("status").equals("notavailable")) {
errMsg = "No computers were available for the request";
} else {
errMsg = (String) result.get("errormsg");
}
System.out.print(errMsg + "\n");
return -1;
}
}
/**
* This method checks request status
*
* @param request_id
* @return <"error", errormsg> : errormsg may be request error or failed
* request <"ready"> <"loading",estimated time> <"timeout"> :
* request timeout because of no connection in the limit time
* <"future">
*/
public String[] getRequestStatus(int requestID) {
Object[] params = new Object[1];
params[0] = Integer.toString(requestID);
String[] res = new String[2];
HashMap result = (HashMap) xmlRPCcall("XMLRPCgetRequestStatus", params);
res[0] = (String) result.get("status");
if (result.get("status").equals("error")) {
res[1] = (String) result.get("errormsg");
} else if (result.get("status").equals("loading")) {
res[1] = Integer.toString((Integer) result.get("time"));
}
return res;
}
/**
* This method send a request canceling an reservation This method may be
* quite tricky, because it need to differentiate between a requesting
* reservation and a successfully requested reservation in both case, it
* should cancel the reservation
*
* @return If success: true If failed: return false and an error message
* message in the variable errMsg of class
*/
public boolean endRequest(int requestid) {
Object[] params = new Object[1];
params[0] = requestid;
HashMap result = (HashMap) xmlRPCcall("XMLRPCendRequest", params);
if (result.get("status").equals("success")) {
System.out.println("End reservation, request id: " + requestid);
return true;
} else {
System.err.println("Fail to end reservation, request id: "
+ requestid);
errMsg = (String) result.get("errormsg");
return false;
}
}
/**
* This method send a request extending the reservation
*
* @param requestid
* @param extendTime
* Time in minutes to extend the reservation
* @return If success: true If failed: return false and an error message
* message in the variable errMsg of class
*/
public boolean extendReservation(int requestid, int extendTime) {
Object[] params = new Object[2];
params[0] = requestid;
params[1] = extendTime;
HashMap result = (HashMap) xmlRPCcall("XMLRPCextendRequest", params);
if (result.get("status").equals("success")) {
System.out.println("Extend reservation, request id: " + requestid);
return true;
} else {
System.err.println("Fail to extend reservation, request id: "
+ requestid);
errMsg = (String) result.get("errormsg");
return false;
}
}
/**
* Send request to the VCL server and ask for ALL the informations of the
* current Reservation this function need to fill all the fields each
* OBABean: request_id, image_name, image_id, etc.
*
* @return the ArrayList of all the OBABean or null
*/
public HashMap<Integer, OBABean> getCurrentReservations() {
Object[] params = new Object[0];
HashMap result = (HashMap) xmlRPCcall("XMLRPCgetRequestIds", params);
HashMap<Integer, OBABean> reservationList = new HashMap<Integer, OBABean>();
if (result.get("status").equals("success")) {
Object[] res = (Object[]) result.get("requests");
for (int i = 0; i < res.length; i++) {
Calendar start = Calendar.getInstance();
int start_long = (Integer) ((HashMap) res[i]).get("start");
;
start.setTimeInMillis(start_long * 1000);
System.out.println(start.getTime().toString());
Calendar end = Calendar.getInstance();
int end_long = (Integer) ((HashMap) res[i]).get("end");
;
end.setTimeInMillis(end_long * 1000);
System.out.println(end.getTime().toString());
int duration = (end_long - start_long) / 60;
int requestid = Integer.parseInt((String) ((HashMap) res[i])
.get("requestid"));
int imageid = Integer.parseInt((String) ((HashMap) res[i])
.get("imageid"));
String imagename = (String) ((HashMap) res[i]).get("imagename");
int status = OBABean.UNKNOWN_STATUS;
int login_mode = -1;
String[] req_status = getRequestStatus(requestid);
String[] conn_data = new String[3];
boolean isReserved = req_status[0].equals("ready");
if (isReserved) {
conn_data = getConnectData(requestid);
// Ruowen: I don't think we can simply assign login mode
// based on password pattern.
// Tuan : keep it for now until we have better solution
if (conn_data[2] == this.password) { login_mode =
OBABean.SSH_LOGIN; } else { login_mode =
OBABean.RDP_LOGIN; }
} else {
conn_data[0] = null;
conn_data[1] = null;
conn_data[2] = null;
}
if (req_status[0].equals("ready"))
status = OBABean.READY;
if (req_status[0].equals("loading"))
status = OBABean.LOADING;
if (req_status[0].equals("timedout"))
status = OBABean.TIMEDOUT;
if (req_status[0].equals("future"))
status = OBABean.FUTURE;
if (req_status[0].equals("failed"))
status = OBABean.FAILED;
OBABean newBean = new OBABean(imageid, imagename, conn_data[1],
conn_data[2], requestid, conn_data[0],
Platform.Windows, start, end, duration, status,
isReserved, null, false);
reservationList.put(requestid, newBean);
}
return reservationList;
} else {
System.err.println("Cannot get my requests: " + "\n");
errMsg = (String) result.get("errormsg");
return null;
}
}
/**
* This method send a request to VCL server to get the connection data for a
* requestID This method should be called only after the request status
* checking
*
* @param requestID
* @param ip
* address of connecting user's compute
*
* @return a String[] with [0] = serverIP - address of the reserved machine
* [1] = user - user to use when connecting to the machine [2] =
* password - password to use when connecting to the machine null if
* failed
*/
public String[] getConnectData(int requestID) {
InetAddress addr;
String ipAddr;
try {
// TODO Americo previously had issue with the getLocalHost, we need
// to fix it
addr = InetAddress.getLocalHost();
// Get IP Address
ipAddr = addr.getHostAddress();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
Object[] params = { requestID, ipAddr };
HashMap result = (HashMap) xmlRPCcall("XMLRPCgetRequestConnectData",
params);
String[] conn_data = null;
if (result.get("status").equals("ready")) {
conn_data = new String[3];
conn_data[0] = (String) result.get("serverIP");
conn_data[1] = (String) result.get("user");
conn_data[2] = (String) result.get("password");
System.out.println("Reserved IP: " + conn_data[0]);
System.out.println("Username: " + conn_data[1]);
if (conn_data[2].equals("")) {
conn_data[2] = this.password;
System.out.println("Password: (use your campus password)");
} else {
System.out.println("Password: " + conn_data[2]);
}
} else if (result.get("status").equals("notready")) {
System.err.println("The reservation is not ready.");
} else {
System.err.println("Fail to get the connect data.");
}
return conn_data;
}
/**
* This method send a request to the server to get all the accessible Images
* for this user. We must use LinkedHashMap to keep the order.
*
* @return HashMap <"ImageID", "ImageName">
*/
public LinkedHashMap<Integer, String> getAvailableImages() {
Object[] params = new Object[0];
Object[] result = (Object[]) xmlRPCcall("XMLRPCgetImages", params);
LinkedHashMap<Integer, String> res = new LinkedHashMap<Integer, String>(
result.length);
for (int i = 0; i < result.length; i++) {
res.put((Integer) ((HashMap) result[i]).get("id"),
(String) ((HashMap) result[i]).get("name"));
// System.out.print(((HashMap) result[i]).get("name") + "\n");
// res.put((Integer) result[i].get("id"),
// (String) result[i].get("image"));
}
return res;
}
/**
* Check username, password
*
* @return
*/
public boolean loginCheck() {
HashMap result = (HashMap) xmlRPCcall("XMLRPCtest", null);
if (result != null && result.get("status").equals("success")) {
return true;
}
return false;
}
// private HashMap parseResult(Object[] result) {
// HashMap<String, Object> resultHash = new HashMap<String, Object>();
//
// for(Object each_obj : result) {
// Object[] each_obj_array = (Object[])each_obj;
// resultHash.put((String)each_obj_array[0], each_obj_array[1]);
// }
//
// return resultHash;
// }
public String[] getPercentageStatus(OBABean one_OBA_bean) {
int request_id = one_OBA_bean.getRequestId();
int initial_loading_time = one_OBA_bean.getInitialLoadingTime();
int complete_percent = -1;
String remain_time_str = null;
// Check whether the reservation is ready HashMap status =
String[] req_status = getRequestStatus(request_id);
if (req_status[0].equals("ready")) {
complete_percent = 100;
remain_time_str = "Ready";
} else if (req_status[0].equals("loading")) {
remain_time_str = req_status[1];
int remain_time = Integer.parseInt(remain_time_str);
if (initial_loading_time < 0) {
one_OBA_bean.setInitialLoadingTime(remain_time);
initial_loading_time = remain_time;
}
complete_percent = (int) (((float) initial_loading_time - (float) remain_time)
/ (float) initial_loading_time * 100.0);
} else if (req_status[0].equals("future")) {
return req_status;
} else {
System.err.println("Fail to make a reservation.");
return req_status;
}
return new String[] { Integer.toString(complete_percent),
remain_time_str };
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public int updateStatus(OBABean aBean) {
String[] req_status = getRequestStatus(aBean.getRequestId());
if (req_status[0].equals("ready")) {
aBean.setStatus(OBABean.READY);
} else if (req_status[0].equals("loading")) {
aBean.setStatus(OBABean.LOADING);
} else if (req_status[0].equals("future")) {
aBean.setStatus(OBABean.FUTURE);
} else if (req_status[0].equals("timedout")) {
aBean.setStatus(OBABean.TIMEDOUT);
} else if (req_status[0].equals("failed")) {
aBean.setStatus(OBABean.FAILED);
} else {
System.err.println("Fail to update the status of OBABean.");
aBean.setStatus(OBABean.UNKNOWN_STATUS);
}
return aBean.getStatus();
}
}