2 * Copyright 2011 Google Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com.google.ipc.invalidation.ticl.android2;
18 import com.google.common.base.Joiner;
19 import com.google.ipc.invalidation.common.CommonProtoStrings2;
20 import com.google.ipc.invalidation.util.TextBuilder;
21 import com.google.protobuf.ByteString;
22 import com.google.protobuf.InvalidProtocolBufferException;
23 import com.google.protos.ipc.invalidation.AndroidService.AndroidNetworkSendRequest;
24 import com.google.protos.ipc.invalidation.AndroidService.AndroidSchedulerEvent;
25 import com.google.protos.ipc.invalidation.AndroidService.ClientDowncall;
26 import com.google.protos.ipc.invalidation.AndroidService.ClientDowncall.AckDowncall;
27 import com.google.protos.ipc.invalidation.AndroidService.ClientDowncall.RegistrationDowncall;
28 import com.google.protos.ipc.invalidation.AndroidService.InternalDowncall;
29 import com.google.protos.ipc.invalidation.AndroidService.InternalDowncall.CreateClient;
30 import com.google.protos.ipc.invalidation.AndroidService.InternalDowncall.NetworkStatus;
31 import com.google.protos.ipc.invalidation.AndroidService.InternalDowncall.ServerMessage;
32 import com.google.protos.ipc.invalidation.AndroidService.ListenerUpcall;
33 import com.google.protos.ipc.invalidation.AndroidService.ListenerUpcall.ErrorUpcall;
34 import com.google.protos.ipc.invalidation.AndroidService.ListenerUpcall.InvalidateUpcall;
35 import com.google.protos.ipc.invalidation.AndroidService.ListenerUpcall.RegistrationFailureUpcall;
36 import com.google.protos.ipc.invalidation.AndroidService.ListenerUpcall.RegistrationStatusUpcall;
37 import com.google.protos.ipc.invalidation.AndroidService.ListenerUpcall.ReissueRegistrationsUpcall;
38 import com.google.protos.ipc.invalidation.Client.AckHandleP;
39 import com.google.protos.ipc.invalidation.ClientProtocol.ObjectIdP;
41 import android.content.Intent;
43 import java.util.List;
47 * Utilities to format Android protocol buffers and intents as compact strings suitable for logging.
48 * By convention, methods take a {@link TextBuilder} and the object to format and return the
49 * builder. Null object arguments are permitted.
51 * <p>{@link #toCompactString} methods immediately append a description of the object to the given
52 * {@link TextBuilder}s. {@link #toLazyCompactString} methods return an object that defers the work
53 * of formatting the provided argument until {@link Object#toString} is called.
56 public class AndroidStrings {
59 * String to return when the argument is unknown (suggests a new protocol field or invalid
62 static final String UNKNOWN_MESSAGE = "UNKNOWN@AndroidStrings";
65 * String to return when there is an error formatting an argument.
67 static final String ERROR_MESSAGE = "ERROR@AndroidStrings";
70 * Returns an object that lazily evaluates {@link #toCompactString} when {@link Object#toString}
73 public static Object toLazyCompactString(final Intent intent) {
76 public String toString() {
77 TextBuilder builder = new TextBuilder();
78 AndroidStrings.toCompactString(builder, intent);
79 return builder.toString();
84 /** Appends a description of the given client {@code downcall} to the given {@code builder}. */
85 public static TextBuilder toCompactString(TextBuilder builder,
86 ClientDowncall downcall) {
87 if (downcall == null) {
90 builder.append(ProtocolIntents.CLIENT_DOWNCALL_KEY).append("::");
91 if (downcall.hasStart()) {
92 builder.append("start()");
93 } else if (downcall.hasStop()) {
94 builder.append("stop()");
95 } else if (downcall.hasAck()) {
96 toCompactString(builder, downcall.getAck());
97 } else if (downcall.hasRegistrations()) {
98 toCompactString(builder, downcall.getRegistrations());
100 builder.append(UNKNOWN_MESSAGE);
105 /** Appends a description of the given {@code ack} downcall to the given {@code builder}. */
106 public static TextBuilder toCompactString(TextBuilder builder, AckDowncall ack) {
110 builder.append("ack(");
111 serializedAckHandleToCompactString(builder, ack.getAckHandle());
112 return builder.append(")");
116 * Appends a description of the given {@code registration} downcall to the given {@code builder}.
118 public static TextBuilder toCompactString(TextBuilder builder,
119 RegistrationDowncall registration) {
120 if (registration == null) {
123 List<ObjectIdP> objects;
124 if (registration.getRegistrationsCount() > 0) {
125 builder.append("register(");
126 objects = registration.getRegistrationsList();
128 builder.append("unregister(");
129 objects = registration.getUnregistrationsList();
131 return CommonProtoStrings2.toCompactStringForObjectIds(builder, objects).append(")");
134 /** Appends a description of the given internal {@code downcall} to the given {@code builder}. */
135 public static TextBuilder toCompactString(TextBuilder builder,
136 InternalDowncall downcall) {
137 if (downcall == null) {
140 builder.append(ProtocolIntents.INTERNAL_DOWNCALL_KEY).append("::");
141 if (downcall.hasServerMessage()) {
142 toCompactString(builder, downcall.getServerMessage());
143 } else if (downcall.hasNetworkStatus()) {
144 toCompactString(builder, downcall.getNetworkStatus());
145 } else if (downcall.hasNetworkAddrChange()) {
146 builder.append("newtworkAddrChange()");
147 } else if (downcall.hasCreateClient()) {
148 toCompactString(builder, downcall.getCreateClient());
150 builder.append(UNKNOWN_MESSAGE);
155 /** Appends a description of the given {@code serverMessage} to the given {@code builder}. */
156 public static TextBuilder toCompactString(TextBuilder builder,
157 ServerMessage serverMessage) {
158 if (serverMessage == null) {
161 return builder.append("serverMessage(").append(serverMessage.getData()).append(")");
164 /** Appends a description of the given {@code networkStatus} to the given {@code builder}. */
165 public static TextBuilder toCompactString(TextBuilder builder,
166 NetworkStatus networkStatus) {
167 if (networkStatus == null) {
170 return builder.append("networkStatus(isOnline = ").append(networkStatus.getIsOnline())
175 * Appends a description of the given {@code createClient} command to the given {@code builder}.
177 public static TextBuilder toCompactString(TextBuilder builder,
178 CreateClient createClient) {
179 if (createClient == null) {
182 return builder.append("createClient(type = ").append(createClient.getClientType())
183 .append(", name = ").append(createClient.getClientName()).append(", skipStartForTest = ")
184 .append(createClient.getSkipStartForTest()).append(")");
187 /** Appends a description of the given listener {@code upcall} to the given {@code builder}. */
188 public static TextBuilder toCompactString(TextBuilder builder,
189 ListenerUpcall upcall) {
190 if (upcall == null) {
193 builder.append(ProtocolIntents.LISTENER_UPCALL_KEY).append("::");
194 if (upcall.hasReady()) {
195 builder.append(".ready()");
196 } else if (upcall.hasInvalidate()) {
197 toCompactString(builder, upcall.getInvalidate());
198 } else if (upcall.hasRegistrationStatus()) {
199 toCompactString(builder, upcall.getRegistrationStatus());
200 } else if (upcall.hasRegistrationFailure()) {
201 toCompactString(builder, upcall.getRegistrationFailure());
202 } else if (upcall.hasReissueRegistrations()) {
203 toCompactString(builder, upcall.getReissueRegistrations());
204 } else if (upcall.hasError()) {
205 toCompactString(builder, upcall.getError());
207 builder.append(UNKNOWN_MESSAGE);
212 /** Appends a description of the given {@code invalidate} command to the given {@code builder}. */
213 public static TextBuilder toCompactString(TextBuilder builder,
214 InvalidateUpcall invalidate) {
215 if (invalidate == null) {
218 builder.append("invalidate(ackHandle = ");
219 serializedAckHandleToCompactString(builder, invalidate.getAckHandle());
220 builder.append(", ");
221 if (invalidate.hasInvalidation()) {
222 CommonProtoStrings2.toCompactString(builder, invalidate.getInvalidation());
223 } else if (invalidate.getInvalidateAll()) {
224 builder.append("ALL");
225 } else if (invalidate.hasInvalidateUnknown()) {
226 builder.append("UNKNOWN: ");
227 CommonProtoStrings2.toCompactString(builder, invalidate.getInvalidateUnknown());
229 return builder.append(")");
232 /** Appends a description of the given {@code status} upcall to the given {@code builder}. */
233 public static TextBuilder toCompactString(TextBuilder builder,
234 RegistrationStatusUpcall status) {
235 if (status == null) {
238 builder.append("registrationStatus(objectId = ");
239 CommonProtoStrings2.toCompactString(builder, status.getObjectId());
240 return builder.append(", isRegistered = ").append(status.getIsRegistered()).append(")");
243 /** Appends a description of the given {@code failure} upcall to the given {@code builder}. */
244 public static TextBuilder toCompactString(TextBuilder builder,
245 RegistrationFailureUpcall failure) {
246 if (failure == null) {
249 builder.append("registrationFailure(objectId = ");
250 CommonProtoStrings2.toCompactString(builder, failure.getObjectId());
251 return builder.append(", isTransient = ").append(failure.getTransient()).append(")");
255 * Appends a description of the given {@code reissue} registrations upcall to the given
258 public static TextBuilder toCompactString(TextBuilder builder,
259 ReissueRegistrationsUpcall reissue) {
260 if (reissue == null) {
263 builder.append("reissueRegistrations(prefix = ");
264 return builder.append(reissue.getPrefix()).append(", length = ").append(reissue.getLength())
268 /** Appends a description of the given {@code error} upcall to the given {@code builder}. */
269 public static TextBuilder toCompactString(TextBuilder builder, ErrorUpcall error) {
273 return builder.append("error(code = ").append(error.getErrorCode()).append(", message = ")
274 .append(error.getErrorMessage()).append(", isTransient = ").append(error.getIsTransient())
278 /** Appends a description of the given {@code request} to the given {@code builder}. */
279 public static TextBuilder toCompactString(TextBuilder builder,
280 AndroidNetworkSendRequest request) {
281 if (request == null) {
284 return builder.append(ProtocolIntents.OUTBOUND_MESSAGE_KEY).append("(")
285 .append(request.getMessage()).append(")");
288 /** Appends a description of the given (@code event} to the given {@code builder}. */
289 public static TextBuilder toCompactString(TextBuilder builder,
290 AndroidSchedulerEvent event) {
294 return builder.append(ProtocolIntents.SCHEDULER_KEY).append("(eventName = ")
295 .append(event.getEventName()).append(", ticlId = ").append(event.getTiclId()).append(")");
298 /** See spec in implementation notes. */
299 public static TextBuilder toCompactString(TextBuilder builder, AckHandleP ackHandle) {
300 if (ackHandle == null) {
303 return CommonProtoStrings2.toCompactString(builder.appendFormat("AckHandle: "),
304 ackHandle.getInvalidation());
308 * Appends a description of the given {@code intent} to the given {@code builder}. If the intent
309 * includes some recognized extras, formats the extra context as well.
311 public static TextBuilder toCompactString(TextBuilder builder, Intent intent) {
312 if (intent == null) {
315 builder.append("intent(");
317 if (!tryParseExtra(builder, intent)) {
318 builder.append(UNKNOWN_MESSAGE).append(", extras = ")
319 .append(Joiner.on(", ").join(intent.getExtras().keySet()));
321 } catch (InvalidProtocolBufferException exception) {
322 builder.append(ERROR_MESSAGE).append(" : ").append(exception);
324 return builder.append(")");
327 /** Appends a description of any known extra or appends 'UNKNOWN' if none are recognized. */
328 private static boolean tryParseExtra(TextBuilder builder, Intent intent)
329 throws InvalidProtocolBufferException {
332 data = intent.getByteArrayExtra(ProtocolIntents.SCHEDULER_KEY);
334 AndroidSchedulerEvent schedulerEvent = AndroidSchedulerEvent.parseFrom(data);
335 toCompactString(builder, schedulerEvent);
339 data = intent.getByteArrayExtra(ProtocolIntents.OUTBOUND_MESSAGE_KEY);
341 AndroidNetworkSendRequest outboundMessage = AndroidNetworkSendRequest.parseFrom(data);
342 toCompactString(builder, outboundMessage);
346 data = intent.getByteArrayExtra(ProtocolIntents.LISTENER_UPCALL_KEY);
348 ListenerUpcall upcall = ListenerUpcall.parseFrom(data);
349 toCompactString(builder, upcall);
353 data = intent.getByteArrayExtra(ProtocolIntents.INTERNAL_DOWNCALL_KEY);
355 InternalDowncall internalDowncall = InternalDowncall.parseFrom(data);
356 toCompactString(builder, internalDowncall);
360 data = intent.getByteArrayExtra(ProtocolIntents.CLIENT_DOWNCALL_KEY);
362 ClientDowncall clientDowncall = ClientDowncall.parseFrom(data);
363 toCompactString(builder, clientDowncall);
367 // Didn't recognize any intents.
371 /** Given serialized form of an ack handle, appends description to {@code builder}. */
372 private static TextBuilder serializedAckHandleToCompactString(
373 TextBuilder builder, ByteString serialized) {
374 if (serialized == null) {
377 // The ack handle is supposed by an AckHandleP!
379 AckHandleP ackHandle = AckHandleP.parseFrom(serialized);
380 return toCompactString(builder, ackHandle);
381 } catch (InvalidProtocolBufferException exception) {
382 // But it wasn't... Just log the raw bytes.
383 return builder.append(serialized);
387 private AndroidStrings() {
388 // Avoid instantiation.