/*
* Copyright 2011 Google Inc.
*
* 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.google.ipc.invalidation.external.client.android.service;
import com.google.ipc.invalidation.external.client.android.service.Request.Action;
import com.google.ipc.invalidation.external.client.types.AckHandle;
import com.google.ipc.invalidation.external.client.types.ObjectId;
import android.accounts.Account;
import android.os.Bundle;
/**
* A base class for message bundles sent to/from the invalidation service. This
* class provides the declaration of the base parameter names, a basic builder
* class for storing them in messages, and the accessor methods to read them.
*
*/
public abstract class Message {
protected final Bundle parameters;
/** The list of parameter names that are common across message types */
public static class Parameter {
protected Parameter() {} // can subclass but not instantiate
public static final String ACTION = "action";
public static final String ACCOUNT = "account";
public static final String AUTH_TYPE = "authType";
public static final String ACK_TOKEN = "ackToken";
public static final String CLIENT = "client";
public static final String OBJECT_ID = "objectId";
/** A string value describing any error in processing */
public static final String ERROR = "error";
}
/**
* A base builder class for constructing new messages and populating
* them with parameter values.
*
* @param <MessageType> the message type constructed by the builder
* @param <BuilderType> the concrete builder subtype
*/
protected abstract static class Builder<MessageType extends Message,
BuilderType extends Builder<?, ?>> {
protected final Bundle bundle;
// Typed pointer to 'this' that's set once in constructor for return by setters,
// to avoid unchecked warning suppression throughout the code
private BuilderType thisInstance;
@SuppressWarnings("unchecked")
protected Builder(int actionOrdinal, Bundle b) {
this.bundle = b;
this.thisInstance = (BuilderType) this; // requires unchecked but is safe
b.putInt(Parameter.ACTION, actionOrdinal);
}
/** Stores an account in the built parameters. */
public BuilderType setAccount(Account account) {
bundle.putParcelable(Parameter.ACCOUNT, account);
return thisInstance;
}
/** Stores an acknowledgement handle in the built parameters. */
public BuilderType setAckHandle(AckHandle ackHandle) {
bundle.putByteArray(Parameter.ACK_TOKEN, ackHandle.getHandleData());
return thisInstance;
}
/** Stores the authentication type in the built parameters */
public BuilderType setAuthType(String authType) {
bundle.putString(Parameter.AUTH_TYPE, authType);
return thisInstance;
}
/** Stores a client key in the built parameters. */
public BuilderType setClientKey(String clientKey) {
bundle.putString(Parameter.CLIENT, clientKey);
return thisInstance;
}
/** Stores an error message value within a response message.*/
public BuilderType setError(String message) {
bundle.putString(Parameter.ERROR, message);
return thisInstance;
}
/** Stores an object ID in the built parameters. */
public BuilderType setObjectId(ObjectId objectId) {
bundle.putParcelable(Parameter.OBJECT_ID, new ParcelableObjectId(objectId));
return thisInstance;
}
/**
* Returns the message associated with the builder. Concrete subclasses
* will override to return a concrete message instance.
*/
public abstract MessageType build();
}
/**
* Constructs a new message containing the the parameters in the provide bundle.
*/
protected Message(Bundle bundle) {
this.parameters = bundle;
}
/**
* Returns the parameter bundle associated with the message.
*/
public Bundle getBundle() {
return parameters;
}
/**
* Returns the action set on the message or {@code null} if not set. For
* request or event messages, this will be the action associated with the
* message. For response messages, it will be the action associated with the
* original request or event that is being responded to.
*/
public int getActionOrdinal() {
return parameters.getInt(Parameter.ACTION);
}
/** Returns the account set on the message or {@code null} if not set. */
public Account getAccount() {
return parameters.getParcelable(Parameter.ACCOUNT);
}
/** Returns the acknowledgement handle set on the message or {@code null} if not set */
public AckHandle getAckHandle() {
byte [] tokenData = parameters.getByteArray(Parameter.ACK_TOKEN);
return tokenData != null ? AckHandle.newInstance(tokenData) : null;
}
/** Returns the authentication type set on the message or {@code null} if not set */
public String getAuthType() {
return parameters.getString(Parameter.AUTH_TYPE);
}
/** Returns the client key set on the message or {@code null} if not set */
public String getClientKey() {
return parameters.getString(Parameter.CLIENT);
}
/**
* Returns the error message string or {@code null} if not present.
*/
public String getError() {
return parameters.getString(Parameter.ERROR);
}
/** Returns the object id set on the message or {@code null} if not set */
public ObjectId getObjectId() {
ParcelableObjectId parcelableObjectId = parameters.getParcelable(Parameter.OBJECT_ID);
return parcelableObjectId != null ? parcelableObjectId.objectId : null;
}
@Override
public String toString() {
String actionStr = (getActionOrdinal() < Action.values().length) ?
Action.values()[getActionOrdinal()].toString() : "invalid";
return "Message ACTION = " + actionStr + " CLIENT = " + getClientKey();
}
}