blob: 91f70f9d3bd436cc44a31dbd2c4387286bb5c180 [file] [log] [blame]
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.tradefed.command.remote;
import com.android.tradefed.log.LogUtil.CLog;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Encapsulates data for a remote operation sent over the wire.
*/
abstract class RemoteOperation {
private static final String TYPE = "type";
private static final String VERSION = "version";
static final int CURRENT_PROTOCOL_VERSION = 1;
@SuppressWarnings("serial")
static class RemoteException extends Exception {
RemoteException(Throwable t) {
super(t);
}
RemoteException(String msg) {
super(msg);
}
}
/**
* Represents all types of remote operations that can be performed
*/
enum OperationType {
ALLOCATE_DEVICE, FREE_DEVICE, CLOSE, ADD_COMMAND
}
/**
* Create and populate a {@link RemoteOperation} from given data.
*
* @param data the data to parse
* @throws RemoteException
*/
final static RemoteOperation createRemoteOpFromString(String data) throws RemoteException {
try {
JSONObject jsonData = new JSONObject(data);
int protocolVersion = jsonData.getInt(VERSION);
// to keep things simple for now, just barf when protocol version is unknown
if (protocolVersion != CURRENT_PROTOCOL_VERSION) {
throw new RemoteException(String.format(
"Remote operation has unknown version '%d'. Expected '%d'",
protocolVersion, CURRENT_PROTOCOL_VERSION));
}
OperationType op = OperationType.valueOf(jsonData.getString(TYPE));
RemoteOperation rc = null;
switch (op) {
case ALLOCATE_DEVICE:
rc = new AllocateDeviceOp();
break;
case FREE_DEVICE:
rc = new FreeDeviceOp();
break;
case CLOSE:
rc = new CloseOp();
break;
case ADD_COMMAND:
rc = new AddCommandOp();
break;
default:
throw new RemoteException(String.format("unknown remote command '%s'", data));
}
rc.unpackFromJson(jsonData);
return rc;
} catch (JSONException e) {
throw new RemoteException(e);
}
}
protected abstract OperationType getType();
/**
* Abstract method to allow sub-classes to parse additional data from payload.
*
* @param json
* @throws RemoteException, JSONException
*/
protected abstract void unpackFromJson(JSONObject json) throws RemoteException, JSONException;
/**
* Return the RemoteCommand data in its wire protocol format
* @return
*/
String pack() throws RemoteException {
JSONObject j = new JSONObject();
try {
j.put(VERSION, CURRENT_PROTOCOL_VERSION);
j.put(TYPE, getType().toString());
packIntoJson(j);
} catch (JSONException e) {
CLog.e("Failed to serialize RemoteOperation", e);
}
return j.toString();
}
/**
* Callback to add subclass specific data to the JSON object
* @param j
* @throws JSONException
*/
protected abstract void packIntoJson(JSONObject j) throws JSONException;
}