Home | History | Annotate | Download | only in remote
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.tradefed.command.remote;
     18 
     19 import org.json.JSONException;
     20 import org.json.JSONObject;
     21 
     22 /**
     23  * Encapsulates data for a remote operation sent over the wire.
     24  */
     25 abstract class RemoteOperation<T> {
     26     private static final String TYPE = "type";
     27     private static final String VERSION = "version";
     28     /** represents json key for error message */
     29     static final String ERROR = "error";
     30 
     31     static final int CURRENT_PROTOCOL_VERSION = 8;
     32 
     33     /**
     34      * Represents all types of remote operations that can be performed
     35      */
     36     enum OperationType {
     37         ALLOCATE_DEVICE,
     38         FREE_DEVICE,
     39         CLOSE,
     40         ADD_COMMAND,
     41         START_HANDOVER,
     42         LIST_DEVICES,
     43         EXEC_COMMAND,
     44         GET_LAST_COMMAND_RESULT,
     45         HANDOVER_COMPLETE,
     46         ADD_COMMAND_FILE,
     47         HANDOVER_INIT_COMPLETE,
     48     }
     49 
     50     /**
     51      * Create and populate a {@link RemoteOperation} from given data.
     52      *
     53      * @param data the data to parse
     54      * @throws RemoteException
     55      */
     56     final static RemoteOperation<?> createRemoteOpFromString(String data) throws RemoteException {
     57         try {
     58             JSONObject jsonData = new JSONObject(data);
     59             int protocolVersion = jsonData.getInt(VERSION);
     60             // to keep things simple for now, just barf when protocol version is unknown
     61             if (protocolVersion != CURRENT_PROTOCOL_VERSION) {
     62                 throw new RemoteException(String.format(
     63                         "Remote operation has unknown version '%d'. Expected '%d'",
     64                         protocolVersion, CURRENT_PROTOCOL_VERSION));
     65             }
     66             OperationType op = OperationType.valueOf(jsonData.getString(TYPE));
     67             RemoteOperation<?> rc = null;
     68             switch (op) {
     69                 case ALLOCATE_DEVICE:
     70                     rc = AllocateDeviceOp.createFromJson(jsonData);
     71                     break;
     72                 case FREE_DEVICE:
     73                     rc = FreeDeviceOp.createFromJson(jsonData);
     74                     break;
     75                 case CLOSE:
     76                     rc = CloseOp.createFromJson(jsonData);
     77                     break;
     78                 case ADD_COMMAND:
     79                     rc = AddCommandOp.createFromJson(jsonData);
     80                     break;
     81                 case START_HANDOVER:
     82                     rc = StartHandoverOp.createFromJson(jsonData);
     83                     break;
     84                 case LIST_DEVICES:
     85                     rc = ListDevicesOp.createFromJson(jsonData);
     86                     break;
     87                 case EXEC_COMMAND:
     88                     rc = ExecCommandOp.createFromJson(jsonData);
     89                     break;
     90                 case GET_LAST_COMMAND_RESULT:
     91                     rc = GetLastCommandResultOp.createFromJson(jsonData);
     92                     break;
     93                 case HANDOVER_INIT_COMPLETE:
     94                     rc = HandoverInitCompleteOp.createFromJson(jsonData);
     95                     break;
     96                 case HANDOVER_COMPLETE:
     97                     rc = HandoverCompleteOp.createFromJson(jsonData);
     98                     break;
     99                 case ADD_COMMAND_FILE:
    100                     rc = AddCommandFileOp.createFromJson(jsonData);
    101                     break;
    102                 default:
    103                     throw new RemoteException(String.format("unknown remote command '%s'", data));
    104 
    105             }
    106             return rc;
    107         } catch (JSONException e) {
    108             throw new RemoteException(e);
    109         }
    110     }
    111 
    112     protected abstract OperationType getType();
    113 
    114     /**
    115      * Returns the RemoteCommand data in its wire protocol format
    116      */
    117     String pack() throws RemoteException {
    118         return pack(CURRENT_PROTOCOL_VERSION);
    119     }
    120 
    121     /**
    122      * Returns the RemoteCommand data in its wire protocol format, with given protocol version
    123      *
    124      * @VisibleForTesting
    125      */
    126     String pack(int protocolVersion) throws RemoteException {
    127         JSONObject j = new JSONObject();
    128         try {
    129             j.put(VERSION, protocolVersion);
    130             j.put(TYPE, getType().toString());
    131             packIntoJson(j);
    132         } catch (JSONException e) {
    133             throw new RemoteException("Failed to serialize RemoteOperation", e);
    134         }
    135         return j.toString();
    136     }
    137 
    138     /**
    139      * Callback to add subclass specific data to the JSON object
    140      *
    141      * @param j
    142      * @throws JSONException
    143      */
    144     protected abstract void packIntoJson(JSONObject j) throws JSONException;
    145 
    146     /**
    147      * Optional callback to parse additional response data from the JSON object
    148      *
    149      * @param j
    150      * @throws JSONException
    151      */
    152     protected T unpackResponseFromJson(JSONObject j) throws JSONException {
    153         return null;
    154     }
    155 
    156     /**
    157      * Parse out the remote op response data from string
    158      *
    159      * @param response
    160      * @throws JSONException
    161      */
    162     T unpackResponseFromString(String response) throws JSONException, RemoteException {
    163         JSONObject jsonData = new JSONObject(response);
    164         if (jsonData.has(ERROR)) {
    165             throw new RemoteException(jsonData.getString(ERROR));
    166         }
    167         return unpackResponseFromJson(jsonData);
    168     }
    169 }
    170