AppsManager.java
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2013, OSRF.
00003  * Copyright (c) 2013, Yujin Robot.
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
00006  * use this file except in compliance with the License. You may obtain a copy of
00007  * the License at
00008  *
00009  * http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
00013  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
00014  * License for the specific language governing permissions and limitations under
00015  * the License.
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     // unique identifier to key string variables between activities.
00081     // TODO I make it compatible current apps; not needed if we rewrite as concert apps
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();  // TODO not warrantied to be called, so user should call shutdown; finalize works at all in Android???  I think no....
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         // If this is the first action requested, we need a connected node, what must be done in a different thread
00135         // The requested action will be executed once we have a connected node (this object itself) in onStart method
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             // But we don't need all this if we already executed an action, and so have a connected node. Anyway,
00142             // we must execute any action asynchronously to avoid the android.os.NetworkOnMainThreadException
00143             new AsyncTask<Void, Void, Void>() {
00144                 @Override
00145                 protected Void doInBackground(Void... params) {
00146                     getAppsForRole();
00147                     return null;
00148                 }
00149             }.execute();  // TODO: can we use this to incorporate a timeout to service calls?
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         // If this is the first action requested, we need a connected node, what must be done in a different thread
00159         // The requested action will be executed once we have a connected node (this object itself) in onStart method
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             // But we don't need all this if we already executed an action, and so have a connected node. Anyway,
00166             // we must execute any action asynchronously to avoid the android.os.NetworkOnMainThreadException
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         // If this is the first action requested, we need a connected node, what must be done in a different thread
00182         // The requested action will be executed once we have a connected node (this object itself) in onStart method
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             // But we don't need all this if we already executed an action, and so have a connected node. Anyway,
00189             // we must execute any action asynchronously to avoid the android.os.NetworkOnMainThreadException
00190             new AsyncTask<Void, Void, Void>() {
00191                 @Override
00192                 protected Void doInBackground(Void... params) {
00193                     getAppInfo();
00194                     return null;
00195                 }
00196             }.execute();  // TODO: can we use this to incorporate a timeout to service calls?
00197         }
00198     }
00199 
00200     private void getAppsForRole() {
00201         // call get_roles_and_apps concert service
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); // TODO we should recover from this calling onFailure on listener
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         // call request_interaction concert service
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); // TODO we should recover from this calling onFailure on listener
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         // call get_app concert service
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); // TODO we should recover from this calling onFailure on listener
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                 // Check if the concert exists by looking for concert name parameter
00283                 // getParam throws when it can't find the parameter.
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                 // thrown if concert could not be found in the getParam call (from java.net.ConnectException)
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         // Required so we get reconnected the next time
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 }


android_remocons
Author(s): Daniel Stonier, Kazuto Murase
autogenerated on Sat Jun 8 2019 19:32:24