00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 package com.github.rosjava.android_remocons.common_tools;
00019
00020 import android.os.AsyncTask;
00021 import android.util.Log;
00022
00023 import com.github.rosjava.android_apps.application_management.MasterId;
00024
00025 import org.ros.address.InetAddressFactory;
00026 import org.ros.android.NodeMainExecutorService;
00027 import org.ros.exception.RosRuntimeException;
00028 import org.ros.exception.ServiceNotFoundException;
00029 import org.ros.internal.node.client.ParameterClient;
00030 import org.ros.internal.node.server.NodeIdentifier;
00031 import org.ros.namespace.GraphName;
00032 import org.ros.node.AbstractNodeMain;
00033 import org.ros.node.ConnectedNode;
00034 import org.ros.node.Node;
00035 import org.ros.node.NodeConfiguration;
00036 import org.ros.node.service.ServiceClient;
00037 import org.ros.node.service.ServiceResponseListener;
00038
00039 import java.net.URI;
00040 import java.net.URISyntaxException;
00041
00042 import rocon_interaction_msgs.GetApp;
00043 import rocon_interaction_msgs.GetAppRequest;
00044 import rocon_interaction_msgs.GetAppResponse;
00045 import rocon_interaction_msgs.GetRolesAndApps;
00046 import rocon_interaction_msgs.GetRolesAndAppsRequest;
00047 import rocon_interaction_msgs.GetRolesAndAppsResponse;
00048 import rocon_interaction_msgs.RequestInteraction;
00049 import rocon_interaction_msgs.RequestInteractionRequest;
00050 import rocon_interaction_msgs.RequestInteractionResponse;
00051
00052 import static com.github.rosjava.android_remocons.common_tools.rocon.Constants.ANDROID_PLATFORM_INFO;
00053
00072 public class AppsManager extends AbstractNodeMain {
00073 public interface FailureHandler {
00077 void handleFailure(String reason);
00078 }
00079
00080
00081
00082 public static final String PACKAGE = com.github.rosjava.android_apps.application_management.AppManager.PACKAGE;
00083
00084 public enum Action {
00085 NONE, GET_APPS_FOR_ROLE, GET_APP_INFO, REQUEST_APP_USE
00086 };
00087
00088 private int app_hash;
00089 private String role;
00090 private Action action = Action.NONE;
00091 private rocon_interaction_msgs.RemoconApp app;
00092 private ConnectNodeThread connectThread;
00093 private ConnectedNode connectedNode;
00094 private NodeMainExecutorService nodeMainExecutorService;
00095 private FailureHandler failureCallback;
00096 private ServiceResponseListener<RequestInteractionResponse> requestServiceResponseListener;
00097 private ServiceResponseListener<GetRolesAndAppsResponse> getAppsServiceResponseListener;
00098 private ServiceResponseListener<GetAppResponse> appInfoServiceResponseListener;
00099
00100
00101 public AppsManager(FailureHandler failureCallback) {
00102 this.failureCallback = failureCallback;
00103 }
00104
00105 public void setupRequestService(ServiceResponseListener<RequestInteractionResponse> serviceResponseListener) {
00106 this.requestServiceResponseListener = serviceResponseListener;
00107 }
00108
00109 public void setupGetAppsService(ServiceResponseListener<GetRolesAndAppsResponse> serviceResponseListener) {
00110 this.getAppsServiceResponseListener = serviceResponseListener;
00111 }
00112
00113 public void setupAppInfoService(ServiceResponseListener<GetAppResponse> serviceResponseListener) {
00114 this.appInfoServiceResponseListener = serviceResponseListener;
00115 }
00116
00117 @Override
00118 protected void finalize() throws Throwable {
00119 super.finalize();
00120 shutdown();
00121 }
00122
00123 public void shutdown() {
00124 if (nodeMainExecutorService != null)
00125 nodeMainExecutorService.shutdownNodeMain(this);
00126 else
00127 Log.w("AppsMng", "Shutting down an uninitialized apps manager");
00128 }
00129
00130 public void getAppsForRole(final MasterId masterId, final String role) {
00131 this.action = Action.GET_APPS_FOR_ROLE;
00132 this.role = role;
00133
00134
00135
00136 if (this.connectedNode == null) {
00137 Log.d("AppsMng", "First action requested (" + this.action + "). Starting node...");
00138 new ConnectNodeThread(masterId).start();
00139 }
00140 else {
00141
00142
00143 new AsyncTask<Void, Void, Void>() {
00144 @Override
00145 protected Void doInBackground(Void... params) {
00146 getAppsForRole();
00147 return null;
00148 }
00149 }.execute();
00150 }
00151 }
00152
00153 public void requestAppUse(final MasterId masterId, final String role, final rocon_interaction_msgs.RemoconApp app) {
00154 this.action = Action.REQUEST_APP_USE;
00155 this.role = role;
00156 this.app = app;
00157
00158
00159
00160 if (this.connectedNode == null) {
00161 Log.d("AppsMng", "First action requested (" + this.action + "). Starting node...");
00162 new ConnectNodeThread(masterId).start();
00163 }
00164 else {
00165
00166
00167 new AsyncTask<Void, Void, Void>() {
00168 @Override
00169 protected Void doInBackground(Void... params) {
00170 requestAppUse();
00171 return null;
00172 }
00173 }.execute();
00174 }
00175 }
00176
00177 public void getAppInfo(final MasterId masterId, final int hash) {
00178 this.action = Action.GET_APP_INFO;
00179 this.app_hash = hash;
00180
00181
00182
00183 if (this.connectedNode == null) {
00184 Log.d("AppsMng", "First action requested (" + this.action + "). Starting node...");
00185 new ConnectNodeThread(masterId).start();
00186 }
00187 else {
00188
00189
00190 new AsyncTask<Void, Void, Void>() {
00191 @Override
00192 protected Void doInBackground(Void... params) {
00193 getAppInfo();
00194 return null;
00195 }
00196 }.execute();
00197 }
00198 }
00199
00200 private void getAppsForRole() {
00201
00202 ServiceClient<GetRolesAndAppsRequest, GetRolesAndAppsResponse> srvClient;
00203 try {
00204 Log.d("AppsMng", "List apps service client created [" + GET_ROLES_AND_APPS_SRV + "]");
00205 srvClient = connectedNode.newServiceClient(GET_ROLES_AND_APPS_SRV, GetRolesAndApps._TYPE);
00206 } catch (ServiceNotFoundException e) {
00207 Log.w("AppsMng", "List apps service not found [" + GET_ROLES_AND_APPS_SRV + "]");
00208 throw new RosRuntimeException(e);
00209 }
00210 final GetRolesAndAppsRequest request = srvClient.newMessage();
00211
00212 request.getRoles().add(role);
00213 request.setPlatformInfo(ANDROID_PLATFORM_INFO);
00214
00215 srvClient.call(request, getAppsServiceResponseListener);
00216 Log.d("AppsMng", "List apps service call done [" + GET_ROLES_AND_APPS_SRV + "]");
00217 }
00218
00219 private void requestAppUse() {
00220
00221 ServiceClient<RequestInteractionRequest, RequestInteractionResponse> srvClient;
00222 try {
00223 Log.d("AppsMng", "Request app service client created [" + REQUEST_INTERACTION_SRV + "]");
00224 srvClient = connectedNode.newServiceClient(REQUEST_INTERACTION_SRV, RequestInteraction._TYPE);
00225 } catch (ServiceNotFoundException e) {
00226 Log.w("AppsMng", "Request app service not found [" + REQUEST_INTERACTION_SRV + "]");
00227 throw new RosRuntimeException(e);
00228 }
00229 final RequestInteractionRequest request = srvClient.newMessage();
00230
00231 request.setRole(role);
00232 request.setApplication(app.getName());
00233 request.setServiceName(app.getServiceName());
00234 request.setPlatformInfo(ANDROID_PLATFORM_INFO);
00235
00236 srvClient.call(request, requestServiceResponseListener);
00237 Log.d("AppsMng", "Request app service call done [" + REQUEST_INTERACTION_SRV + "]");
00238 }
00239
00240 private void getAppInfo() {
00241
00242 ServiceClient<GetAppRequest, GetAppResponse> srvClient;
00243 try {
00244 Log.d("AppsMng", "Get app info service client created [" + GET_APP_INFO_SRV + "]");
00245 srvClient = connectedNode.newServiceClient(GET_APP_INFO_SRV, GetApp._TYPE);
00246 } catch (ServiceNotFoundException e) {
00247 Log.w("AppsMng", "Get app info not found [" + GET_APP_INFO_SRV + "]");
00248 throw new RosRuntimeException(e);
00249 }
00250 final GetAppRequest request = srvClient.newMessage();
00251
00252 request.setHash(app_hash);
00253 request.setPlatformInfo(ANDROID_PLATFORM_INFO);
00254
00255 srvClient.call(request, appInfoServiceResponseListener);
00256 Log.d("AppsMng", "Get app info service call done [" + GET_APP_INFO_SRV + "]");
00257 }
00258
00263 private class ConnectNodeThread extends Thread {
00264 private MasterId masterId;
00265
00266 public ConnectNodeThread(MasterId masterId) {
00267 this.masterId = masterId;
00268 setDaemon(true);
00269 setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
00270 @Override
00271 public void uncaughtException(Thread thread, Throwable ex) {
00272 failureCallback.handleFailure("exception: " + ex.getMessage());
00273 }
00274 });
00275 }
00276
00277 @Override
00278 public void run() {
00279 try {
00280 URI concertUri = new URI(masterId.getMasterUri());
00281
00282
00283
00284 ParameterClient paramClient = new ParameterClient(
00285 NodeIdentifier.forNameAndUri("/concert_checker", concertUri.toString()), concertUri);
00286 String name = (String) paramClient.getParam(GraphName.of(CONCERT_NAME_PARAM)).getResult();
00287 Log.i("ConcertRemocon", "Concert " + name + " found; retrieve additional information");
00288
00289 nodeMainExecutorService = new NodeMainExecutorService();
00290 NodeConfiguration nodeConfiguration = NodeConfiguration.newPublic(
00291 InetAddressFactory.newNonLoopback().getHostAddress(), concertUri);
00292 nodeMainExecutorService.execute(AppsManager.this, nodeConfiguration.setNodeName("apps_manager_node"));
00293
00294 } catch (URISyntaxException e) {
00295 Log.w("AppsMng", "invalid concert URI [" + masterId.getMasterUri() + "][" + e.toString() + "]");
00296 failureCallback.handleFailure("invalid concert URI");
00297 } catch (RuntimeException e) {
00298
00299 Log.w("AppsMng", "could not find concert [" + masterId.getMasterUri() + "][" + e.toString() + "]");
00300 failureCallback.handleFailure(e.toString());
00301 } catch (Throwable e) {
00302 Log.w("AppsMng", "exception while creating node in concert checker for URI " + masterId.getMasterUri(), e);
00303 failureCallback.handleFailure(e.toString());
00304 }
00305 }
00306 }
00307
00308 @Override
00309 public GraphName getDefaultNodeName() {
00310 return null;
00311 }
00312
00318 @Override
00319 public void onStart(final ConnectedNode connectedNode) {
00320 if (this.connectedNode != null) {
00321 Log.e("AppsMng", "App manager re-started before previous shutdown; ignoring...");
00322 return;
00323 }
00324
00325 this.connectedNode = connectedNode;
00326
00327 Log.d("AppsMng", "onStart() - " + action);
00328
00329 switch (action) {
00330 case NONE:
00331 Log.w("AppsMng", "Node started without specifying an action");
00332 break;
00333 case REQUEST_APP_USE:
00334 requestAppUse();
00335 break;
00336 case GET_APPS_FOR_ROLE:
00337 getAppsForRole();
00338 break;
00339 case GET_APP_INFO:
00340 getAppInfo();
00341 break;
00342 default:
00343 Log.w("AppsMng", "Unrecogniced action requested: " + action);
00344 }
00345
00346 Log.d("AppsMng", "Done");
00347 }
00348
00349 @Override
00350 public void onShutdown(Node node) {
00351 Log.d("AppsMng", "Shutdown connected node...");
00352 super.onShutdown(node);
00353
00354
00355 this.connectedNode = null;
00356 Log.d("AppsMng", "Done; shutdown apps manager node main");
00357 }
00358
00359 @Override
00360 public void onShutdownComplete(Node node) {
00361 super.onShutdownComplete(node);
00362 }
00363
00364 @Override
00365 public void onError(Node node, Throwable throwable) {
00366 super.onError(node, throwable);
00367
00368 Log.e("AppsMng", node.getName().toString() + " node error: " + throwable.getMessage());
00369 failureCallback.handleFailure(node.getName().toString() + " node error: " + throwable.toString());
00370 }
00371 }