package pl.edu.agh.service; import java.util.Random; import java.util.concurrent.Executors; import org.json.JSONException; import org.json.JSONObject; import pl.edu.agh.assembler.RoutingResultJSONAssembler; import pl.edu.agh.assembler.SimpleLocationInfoJSONAssembler; import pl.edu.agh.assembler.TrafficDataJSONAssembler; import pl.edu.agh.assembler.TrafficInfoJSONAssembler; import pl.edu.agh.jsonrpc.JSONRPCException; import pl.edu.agh.jsonrpc.JSONRPCSocketClient; import pl.edu.agh.jsonrpc.RawDataSocket; import pl.edu.agh.model.RoutingResult; import pl.edu.agh.model.SimpleLocationInfo; import pl.edu.agh.model.TrafficData; import android.util.Log; public class TrafficServiceStub extends AbstractServiceStub implements TrafficService, AsyncDataReceiver { public static final int AD_HOC_WAITING_FOR_RESPONSE_TIMEOUT = 30*100000; private TrafficDataJSONAssembler trafficDataJSONAssembler; private SimpleLocationInfoJSONAssembler simpleLocationInfoJSONAssembler; private RoutingResultJSONAssembler routingResultJSONAssembler; private AsyncDataListener asyncDataListener; private boolean waitingForBroadCast = false; private TrafficData lastReceivedAsyncData = null; private long lastRequestId = 0; private static final TrafficServiceStub INSTANCE = new TrafficServiceStub(); public static TrafficServiceStub getInstance() { return INSTANCE; } public static TrafficServiceStub getCopy() { return new TrafficServiceStub(); } private TrafficServiceStub() { super(SERVICE_NAME); simpleLocationInfoJSONAssembler = new SimpleLocationInfoJSONAssembler(); routingResultJSONAssembler = new RoutingResultJSONAssembler(simpleLocationInfoJSONAssembler); trafficDataJSONAssembler = new TrafficDataJSONAssembler(new TrafficInfoJSONAssembler( simpleLocationInfoJSONAssembler)); } @Override public RoutingResult calculateRoute(SimpleLocationInfo start, SimpleLocationInfo end, boolean useTrafficDataToRoute) throws JSONRPCException { try { JSONObject serializedStart = simpleLocationInfoJSONAssembler.serialize(start); JSONObject serializedEnd = simpleLocationInfoJSONAssembler.serialize(end); JSONObject serializedRoutingResult = rpcClient.callJSONObject(CALCULATE_ROUTE_METHOD, serializedStart, serializedEnd, useTrafficDataToRoute); return routingResultJSONAssembler.deserialize(serializedRoutingResult); } catch (JSONException ex) { throw new JSONRPCException("Error during (de)serialization", ex); } } @Override public TrafficData getTrafficData(SimpleLocationInfo location, double radius) throws JSONRPCException { try { JSONObject serializedLocation = simpleLocationInfoJSONAssembler.serialize(location); JSONObject serializedData = rpcClient.callJSONObject(GET_TRAFFIC_DATA_METHOD, serializedLocation, radius); return trafficDataJSONAssembler.deserialize(serializedData); } catch (JSONException ex) { throw new JSONRPCException("Error during (de)serialization", ex); } } public synchronized void dataReceived(TrafficData data) { lastReceivedAsyncData = data; waitingForBroadCast = false; this.notify(); } public synchronized boolean isInterested() { return waitingForBroadCast; } public long getRequestCode() { return lastRequestId; } @Override public TrafficData getTrafficDataViaAdHoc(SimpleLocationInfo location, double radius) throws JSONRPCException { try { lastRequestId = new Random(System.currentTimeMillis()).nextLong(); JSONObject serializedLocation = simpleLocationInfoJSONAssembler.serialize(location); Runnable timeoutTask = new Runnable() { public void run() { try { Thread.sleep(AD_HOC_WAITING_FOR_RESPONSE_TIMEOUT); } catch(InterruptedException e) { Log.i(Thread.currentThread().getName(), "thread interrupted", e); } finally { synchronized (TrafficServiceStub.this) { waitingForBroadCast = false; TrafficServiceStub.this.notify(); } } } }; waitingForBroadCast = true; Executors.newSingleThreadExecutor().execute(timeoutTask); asyncDataListener.registerReceiver(this); rpcAdHocClient.callJSONObject(GET_TRAFFIC_DATA_METHOD, serializedLocation, radius, lastRequestId); synchronized (this) { try { while(waitingForBroadCast) { this.wait(); } } catch(InterruptedException e) { Log.i(Thread.currentThread().getName(), "thread interrupted", e); } TrafficData response = lastReceivedAsyncData; lastReceivedAsyncData = null; return response; } } catch (JSONException ex) { throw new JSONRPCException("Error during (de)serialization", ex); } } @Override public void configAdHoc(RawDataSocket socket, AsyncDataListener listener) { this.rpcAdHocClient = new JSONRPCSocketClient(socket); this.asyncDataListener = listener; } }