Upstream version 10.38.222.0
[platform/framework/web/crosswalk.git] / src / third_party / cacheinvalidation / src / java / com / google / ipc / invalidation / external / client / android / AndroidInvalidationListener.java
1 /*
2  * Copyright 2011 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.google.ipc.invalidation.external.client.android;
18
19 import com.google.ipc.invalidation.external.client.InvalidationListener;
20 import com.google.ipc.invalidation.external.client.SystemResources.Logger;
21 import com.google.ipc.invalidation.external.client.android.service.AndroidLogger;
22 import com.google.ipc.invalidation.external.client.android.service.Event;
23 import com.google.ipc.invalidation.external.client.android.service.Event.Action;
24 import com.google.ipc.invalidation.external.client.android.service.ListenerService;
25 import com.google.ipc.invalidation.external.client.android.service.Response;
26 import com.google.ipc.invalidation.external.client.types.AckHandle;
27 import com.google.ipc.invalidation.external.client.types.ErrorInfo;
28 import com.google.ipc.invalidation.external.client.types.Invalidation;
29 import com.google.ipc.invalidation.external.client.types.ObjectId;
30
31 import android.app.Service;
32 import android.content.Intent;
33 import android.os.Bundle;
34 import android.os.IBinder;
35
36 /**
37  * An abstract base class for implementing a {@link Service} component
38  * that handles events from the invalidation service. This class should be
39  * subclassed and concrete implementations of the {@link InvalidationListener}
40  * methods added to provide application-specific handling of invalidation
41  * events.
42  * <p>
43  * This implementing subclass should be registered in {@code
44  * AndroidManifest.xml} as a service of the invalidation
45  * listener binding intent, as in the following sample fragment:
46  *
47  * <pre>
48  * {@code
49  * <manifest ...>
50  *   <application ...>
51  *     ...
52  *     service android:name="com.myco.example.AppListenerService" ...>
53  *       <intent-filter>
54  *         <action android:name="com.google.ipc.invalidation.LISTENER"/>
55  *       </intent-filter>
56  *     </receiver>
57  *     ...
58  *   <application>
59  *   ...
60  * </manifest>
61  * }
62  * </pre>
63  *
64  */
65 public abstract class AndroidInvalidationListener extends Service
66     implements InvalidationListener {
67
68   /** Logger */
69   private static final Logger logger = AndroidLogger.forTag("InvListener");
70
71   /**
72    * Simple service stub that delegates back to methods on the service.
73    */
74   private final ListenerService.Stub listenerBinder = new ListenerService.Stub() {
75
76     @Override
77     public void handleEvent(Bundle input, Bundle output) {
78       AndroidInvalidationListener.this.handleEvent(input, output);
79     }
80   };
81
82   /** Lock over all state in this class. */
83   private final Object lock = new Object();
84
85   /** Whether the service is in the created state. */
86   private boolean isCreated = false;
87
88   @Override
89   public void onCreate() {
90     synchronized (lock) {
91       super.onCreate();
92       logger.fine("onCreate: %s", this.getClass());
93       this.isCreated = true;
94     }
95   }
96
97   @Override
98   public void onDestroy() {
99     synchronized (lock) {
100       logger.fine("onDestroy: %s", this.getClass());
101       this.isCreated = false;
102       super.onDestroy();
103     }
104   }
105
106   @Override
107   public IBinder onBind(Intent arg0) {
108     synchronized (lock) {
109       logger.fine("Binding: %s", arg0);
110       return listenerBinder;
111     }
112   }
113
114   /**
115    * Handles a {@link ListenerService#handleEvent} call received by the
116    * listener service.
117    *
118    * @param input bundle containing event parameters.
119    * @param output bundled used to return response to the invalidation service.
120    */
121   protected void handleEvent(Bundle input, Bundle output) {
122     synchronized (lock) {
123       if (!isCreated) {
124         logger.warning("Dropping bundle since not created: %s", input);
125         return;
126       }
127       Event event = new Event(input);
128       Response.Builder response = Response.newBuilder(event.getActionOrdinal(), output);
129       // All events should contain an action and client id
130       Action action = event.getAction();
131       String clientKey = event.getClientKey();
132       logger.fine("Received %s event for %s", action, clientKey);
133
134       AndroidInvalidationClient client = null;
135       try {
136         if (clientKey == null) {
137           throw new IllegalStateException("Missing client id:" + event);
138         }
139
140         // Obtain the client instance for the client receiving the event. Do not attempt to load it
141         // at the service: if a Ticl has been unloaded, the listener shouldn't resurrect it, because
142         // that can lead to a zombie client.
143         client = AndroidClientFactory.resume(this, clientKey, false);
144
145         // Determine the event type based upon the request action, extract parameters
146         // from extras, and invoke the listener event handler method.
147         logger.fine("%s event for %s", action, clientKey);
148         switch(action) {
149           case READY:
150           {
151             ready(client);
152             break;
153           }
154           case INVALIDATE:
155           {
156             Invalidation invalidation = event.getInvalidation();
157             AckHandle ackHandle = event.getAckHandle();
158             invalidate(client, invalidation, ackHandle);
159             break;
160           }
161           case INVALIDATE_UNKNOWN:
162           {
163             ObjectId objectId = event.getObjectId();
164             AckHandle ackHandle = event.getAckHandle();
165             invalidateUnknownVersion(client, objectId, ackHandle);
166             break;
167           }
168           case INVALIDATE_ALL:
169           {
170             AckHandle ackHandle = event.getAckHandle();
171             invalidateAll(client, ackHandle);
172             break;
173           }
174           case INFORM_REGISTRATION_STATUS:
175           {
176             ObjectId objectId = event.getObjectId();
177             RegistrationState state = event.getRegistrationState();
178             informRegistrationStatus(client, objectId, state);
179             break;
180           }
181           case INFORM_REGISTRATION_FAILURE:
182           {
183             ObjectId objectId = event.getObjectId();
184             String errorMsg = event.getError();
185             boolean isTransient = event.getIsTransient();
186             informRegistrationFailure(client, objectId, isTransient, errorMsg);
187             break;
188           }
189           case REISSUE_REGISTRATIONS:
190           {
191             byte[] prefix = event.getPrefix();
192             int prefixLength = event.getPrefixLength();
193             reissueRegistrations(client, prefix, prefixLength);
194             break;
195           }
196           case INFORM_ERROR:
197           {
198             ErrorInfo errorInfo = event.getErrorInfo();
199             informError(client, errorInfo);
200             break;
201           }
202           default:
203             logger.warning("Urecognized event: %s", event);
204         }
205         response.setStatus(Response.Status.SUCCESS);
206       } catch (RuntimeException re) {
207         // If an exception occurs during processing, log it, and store the
208         // result in the response sent back to the service.
209         logger.severe("Failure in handleEvent", re);
210         response.setError(re.getMessage());
211       } finally {
212         // Listeners will only use a client reference for the life of the event and release
213         // it immediately since there is no way to know if additional events are coming.
214         if (client != null) {
215           client.release();
216         }
217       }
218     }
219   }
220 }