/* * 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(); } }