1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.jclouds.http.functions;
20
21 import static com.google.common.base.Preconditions.checkNotNull;
22
23 import java.io.IOException;
24 import java.io.InputStreamReader;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Set;
28 import java.util.concurrent.atomic.AtomicReference;
29
30 import org.jclouds.http.HttpResponse;
31 import org.jclouds.json.internal.GsonWrapper;
32
33 import com.google.common.base.Function;
34 import com.google.common.collect.ImmutableList;
35 import com.google.common.collect.ImmutableMap;
36 import com.google.common.collect.ImmutableSet;
37 import com.google.common.io.Closeables;
38 import com.google.gson.stream.JsonReader;
39 import com.google.gson.stream.JsonToken;
40 import com.google.inject.TypeLiteral;
41
42
43
44
45 public class ParseFirstJsonValueNamed<T> implements Function<HttpResponse, T> {
46
47 private final GsonWrapper json;
48 private final TypeLiteral<T> type;
49 private final String name;
50
51 public ParseFirstJsonValueNamed(GsonWrapper json, TypeLiteral<T> type, String name) {
52 this.json = checkNotNull(json, "json");
53 this.type = checkNotNull(type, "type");
54 this.name = checkNotNull(name, "name");
55 }
56
57 @Override
58 public T apply(HttpResponse arg0) {
59 if (arg0.getPayload() == null)
60 return nothing();
61 JsonReader reader = null;
62 try {
63 reader = new JsonReader(new InputStreamReader(arg0.getPayload().getInput()));
64
65 reader.setLenient(true);
66 AtomicReference<String> name = new AtomicReference<String>();
67 JsonToken token = reader.peek();
68 for (; token != JsonToken.END_DOCUMENT && nnn(this.name, reader, token, name); token = skipAndPeek(token,
69 reader))
70 ;
71 if (name.get().equals(this.name)) {
72 return json.delegate().<T>fromJson(reader, type.getType());
73 } else {
74 return nothing();
75 }
76 } catch (IOException e) {
77 throw new RuntimeException(String.format(
78 "error reading from stream, parsing object named %s from http response %s", this.name, arg0), e);
79 } finally {
80 Closeables.closeQuietly(reader);
81 arg0.getPayload().release();
82 }
83 }
84
85 @SuppressWarnings("unchecked")
86 protected T nothing() {
87 if (type.getRawType().isAssignableFrom(Set.class))
88 return (T) ImmutableSet.of();
89 else if (type.getRawType().isAssignableFrom(List.class))
90 return (T) ImmutableList.of();
91 else if (type.getRawType().isAssignableFrom(Map.class))
92 return (T) ImmutableMap.of();
93 return null;
94 }
95
96 protected boolean nnn(String toFind, JsonReader reader, JsonToken token, AtomicReference<String> name)
97 throws IOException {
98 if (token == JsonToken.NAME) {
99 String name2 = reader.nextName();
100 if (toFind.equals(name2)) {
101 name.set(name2);
102 return false;
103 }
104 }
105 return true;
106
107 }
108
109 public JsonToken skipAndPeek(JsonToken token, JsonReader reader) throws IOException {
110 switch (token) {
111 case BEGIN_ARRAY:
112 reader.beginArray();
113 break;
114 case END_ARRAY:
115 reader.endArray();
116 break;
117 case BEGIN_OBJECT:
118 reader.beginObject();
119 break;
120 case END_OBJECT:
121 reader.endObject();
122 break;
123 case NAME:
124
125 break;
126 case STRING:
127 reader.nextString();
128 break;
129 case NUMBER:
130 reader.nextString();
131 break;
132 case BOOLEAN:
133 reader.nextBoolean();
134 break;
135 case NULL:
136 reader.nextNull();
137 break;
138 case END_DOCUMENT:
139 break;
140 }
141 return reader.peek();
142 }
143 }