/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.gecko.sync; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.mozilla.gecko.R; import org.mozilla.gecko.sync.repositories.NullCursorException; import org.mozilla.gecko.sync.repositories.android.ClientsDatabaseAccessor; import org.mozilla.gecko.sync.repositories.domain.ClientRecord; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.net.Uri; /** * Process commands received from Sync clients. *
* We need a command processor at two different times: *
GlobalSession
instance as a parameter.SendTabActivity
.)
* Any existing registration is overwritten.
*
* @param commandType
* the name of the command, i.e., "displayURI".
* @param command
* the CommandRunner
instance that should handle the
* command.
*/
public void registerCommand(String commandType, CommandRunner command) {
commands.put(commandType, command);
}
/**
* Process a command in the context of the given global session.
*
* @param session
* the GlobalSession
instance currently executing.
* @param unparsedCommand
* command as a ExtendedJSONObject
instance.
*/
public void processCommand(final GlobalSession session, ExtendedJSONObject unparsedCommand) {
Command command = parseCommand(unparsedCommand);
if (command == null) {
Logger.debug(LOG_TAG, "Invalid command: " + unparsedCommand + " will not be processed.");
return;
}
CommandRunner executableCommand = commands.get(command.commandType);
if (executableCommand == null) {
Logger.debug(LOG_TAG, "Command \"" + command.commandType + "\" not registered and will not be processed.");
return;
}
executableCommand.executeCommand(session, command.getArgsList());
}
/**
* Parse a JSON command into a ParsedCommand object for easier handling.
*
* @param unparsedCommand - command as ExtendedJSONObject
* @return - null if command is invalid, else return ParsedCommand with
* no null attributes.
*/
protected static Command parseCommand(ExtendedJSONObject unparsedCommand) {
String type = (String) unparsedCommand.get("command");
if (type == null) {
return null;
}
try {
JSONArray unparsedArgs = unparsedCommand.getArray("args");
if (unparsedArgs == null) {
return null;
}
return new Command(type, unparsedArgs);
} catch (NonArrayJSONException e) {
Logger.debug(LOG_TAG, "Unable to parse args array. Invalid command");
return null;
}
}
@SuppressWarnings("unchecked")
public void sendURIToClientForDisplay(String uri, String clientID, String title, String sender, Context context) {
Logger.info(LOG_TAG, "Sending URI to client: " + uri + " -> " + clientID + " (" + title + ")");
JSONArray args = new JSONArray();
args.add(uri);
args.add(sender);
args.add(title);
Command displayURICommand = new Command("displayURI", args);
this.sendCommand(clientID, displayURICommand, context);
}
/**
* Validates and sends a command to a client or all clients.
*
* Calling this does not actually sync the command data to the server. If the
* client already has the command/args pair, it won't receive a duplicate
* command.
*
* @param clientID
* Client ID to send command to. If null, send to all remote
* clients.
* @param command
* Command to invoke on remote clients
*/
public void sendCommand(String clientID, Command command, Context context) {
Logger.debug(LOG_TAG, "In sendCommand.");
CommandRunner commandData = commands.get(command.commandType);
// Don't send commands that we don't know about.
if (commandData == null) {
Logger.error(LOG_TAG, "Unknown command to send: " + command);
return;
}
// Don't send a command with the wrong number of arguments.
if (!commandData.argumentsAreValid(command.getArgsList())) {
Logger.error(LOG_TAG, "Expected " + commandData.argCount + " args for '" +
command + "', but got " + command.args);
return;
}
if (clientID != null) {
this.sendCommandToClient(clientID, command, context);
return;
}
ClientsDatabaseAccessor db = new ClientsDatabaseAccessor(context);
try {
Map