/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the Common Development
* and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at
* src/com/vodafone360/people/VODAFONE.LICENSE.txt or
* http://github.com/360/360-Engine-for-Android
* See the License for the specific language governing permissions and
* limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each file and
* include the License file at src/com/vodafone360/people/VODAFONE.LICENSE.txt.
* If applicable, add the following below this CDDL HEADER, with the fields
* enclosed by brackets "[]" replaced with your own identifying information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
* Copyright 2010 Vodafone Sales & Services Ltd. All rights reserved.
* Use is subject to license terms.
*/
package com.vodafone360.people.service.io;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.vodafone360.people.datatypes.BaseDataType;
import com.vodafone360.people.engine.BaseEngine;
import com.vodafone360.people.engine.EngineManager;
import com.vodafone360.people.engine.EngineManager.EngineId;
import com.vodafone360.people.service.ServiceStatus;
import com.vodafone360.people.utils.LogUtils;
/**
* Queue of responses received from server. These may be either responses to
* requests issued by the People client or unsolicited ('Push') messages. The
* content of these Responses will have already been decoded by the
* DecoderThread and converted to data-types understood by the People Client.
*/
public class ResponseQueue {
/**
* The list of responses held by this queue. An array-list of Responses.
*/
private final List<DecodedResponse> mResponses = new ArrayList<DecodedResponse>();
/**
* The engine manager holding the various engines to cross check where
* responses belong to.
*/
private EngineManager mEngMgr = null;
/**
* Class encapsulating a decoded response from the server A Response
* contains; a request id which should match a request id from a request
* issued by the People Client (responses to non-RPG requests or
* non-solicited messages will not have a request id), the request data, a
* list of decoded BaseDataTypes generated from the response content and an
* engine id informing the framework which engine the response should be
* routed to.
*/
public static class DecodedResponse {
public static enum ResponseType {
/** An unknown response in case anything went wrong. */
UNKNOWN,
/** A response for a request that timed out. */
SERVER_ERROR,
/** A response that timed out before it arrived from the server. */
TIMED_OUT_RESPONSE,
/** Represents a push message that was pushed by the server */
PUSH_MESSAGE,
/** The response type for available identities. */
GET_AVAILABLE_IDENTITIES_RESPONSE,
/** The response type for my identities. */
GET_MY_IDENTITIES_RESPONSE,
/** The response type for set identity capability */
SET_IDENTITY_CAPABILITY_RESPONSE,
/** The response type for validate identity credentials */
VALIDATE_IDENTITY_CREDENTIALS_RESPONSE,
/** The response type for get activities calls. */
GET_ACTIVITY_RESPONSE,
/** The response type for get session by credentials calls. */
LOGIN_RESPONSE,
/** The response type for bulkupdate contacts calls. */
BULKUPDATE_CONTACTS_RESPONSE,
/** The response type for get contacts changes calls. */
GET_CONTACTCHANGES_RESPONSE,
/** The response type for get get me calls. */
GETME_RESPONSE,
/** The response type for get contact group relation calls. */
GET_CONTACT_GROUP_RELATIONS_RESPONSE,
/** The response type for get groups calls. */
GET_GROUPS_RESPONSE,
/** The response type for add contact calls. */
ADD_CONTACT_RESPONSE,
/** The response type for signup user crypted calls. */
SIGNUP_RESPONSE,
/** The response type for get public key calls. */
RETRIEVE_PUBLIC_KEY_RESPONSE,
/** The response type for delete contacts calls. */
DELETE_CONTACT_RESPONSE,
/** The response type for delete contact details calls. */
DELETE_CONTACT_DETAIL_RESPONSE,
/** The response type for get presence calls. */
GET_PRESENCE_RESPONSE,
/** The response type for create conversation calls. */
CREATE_CONVERSATION_RESPONSE,
/** The response type for get t&cs. */
GET_T_AND_C_RESPONSE,
/** The response type for get privacy statement. */
GET_PRIVACY_STATEMENT_RESPONSE,
/** The response type for removing the identity. */
DELETE_IDENTITY_RESPONSE;
// TODO add more types here and remove them from the BaseDataType. Having them in ONE location is better than in dozens!!!
}
/** The type of the response (e.g. GET_AVAILABLE_IDENTITIES_RESPONSE). */
private int mResponseType;
/** The request ID the response came in for. */
public Integer mReqId;
/** The response items (e.g. identities of a getAvailableIdentities call) to store for the response. */
public List<BaseDataType> mDataTypes = new ArrayList<BaseDataType>();
/** The ID of the engine the response should be worked off in. */
public EngineId mSource;
/**
* Constructs a response object with request ID, the data and the engine
* ID the response belongs to.
*
* @param reqId The corresponding request ID for the response.
* @param data The data of the response.
* @param source The originating engine ID.
* @param responseType The response type. Values can be found in Response.ResponseType.
*
*/
public DecodedResponse(Integer reqId, List<BaseDataType> data, EngineId source, final int responseType) {
mReqId = reqId;
mDataTypes = data;
mSource = source;
mResponseType = responseType;
}
/**
* The response type for this response. The types are defined in Response.ResponseType.
*
* @return The response type of this response (e.g. GET_AVAILABLE_IDENTITIES_RESPONSE).
*/
public int getResponseType() {
return mResponseType;
}
}
/**
* Protected constructor to highlight the singleton nature of this class.
*/
protected ResponseQueue() {
}
/**
* Gets an instance of the ResponseQueue as part of the singleton pattern.
*
* @return The instance of ResponseQueue.
*/
public static ResponseQueue getInstance() {
return ResponseQueueHolder.rQueue;
}
/**
* Use Initialization on demand holder pattern
*/
private static class ResponseQueueHolder {
private static final ResponseQueue rQueue = new ResponseQueue();
}
/**
* Adds a response item to the queue.
*
* @param reqId The request ID to add the response for.
* @param data The response data to add to the queue.
* @param source The corresponding engine that fired off the request for the
* response.
*/
public void addToResponseQueue(final DecodedResponse response) {
synchronized (QueueManager.getInstance().lock) {
ServiceStatus status = BaseEngine.getResponseStatus(BaseDataType.UNKNOWN_DATA_TYPE, response.mDataTypes);
if (status == ServiceStatus.ERROR_INVALID_SESSION) {
EngineManager em = EngineManager.getInstance();
if (em != null) {
LogUtils.logE("Logging out the current user because of invalide session");
em.getLoginEngine().logoutAndRemoveUser();
return;
}
}
synchronized (mResponses) {
mResponses.add(response);
}
Request request = RequestQueue.getInstance().removeRequest(response.mReqId);
if (request != null) {
// we suppose the response being handled by the same engine
// that issued the request with the given id
response.mSource = request.mEngineId;
}
mEngMgr = EngineManager.getInstance();
if (mEngMgr != null) {
mEngMgr.onCommsInMessage(response.mSource);
}
}
}
/**
* Retrieves the next response from the response list if there is one and it is equal to the
* passed engine ID.
*
* @param source The originating engine id that requested this response.
* @return Response The first response that matches the given engine or null
* if no response was found.
*/
public DecodedResponse getNextResponse(EngineId source) {
DecodedResponse resp = null;
synchronized (mResponses) {
Iterator<DecodedResponse> iterator = mResponses.iterator();
while (iterator.hasNext()) {
resp = iterator.next();
if ((null != resp) && (resp.mSource == source)) {
// remove response if the source engine is equal to the response's engine
iterator.remove();
if (source != null) {
LogUtils.logV("ResponseQueue.getNextResponse() Returning a response to engine["
+ source.name() + "]");
}
return resp;
} else if ((null == resp) || (null == resp.mSource)) {
LogUtils.logE("Either the response or its source was null. Response: " + resp);
}
}
}
return null;
}
/**
* Test if we have response for the specified request id.
*
* @param reqId Request ID.
* @return true If we have a response for this ID.
*/
protected synchronized boolean responseExists(int reqId) {
boolean exists = false;
synchronized (mResponses) {
int responseCount = mResponses.size();
for (int i = 0; i < responseCount; i++) {
if (mResponses.get(i).mReqId != null && mResponses.get(i).mReqId.intValue() == reqId) {
exists = true;
break;
}
}
}
return exists;
}
/**
* Clear response queue holding any stale responses.
*/
public void clearResponseQueue() {
mResponses.clear();
}
}