James Moger
2012-10-22 eba89539a29deba954035056437279088c3e047b
commit | author | age
93f0b1 1 /*
JM 2  * Copyright 2011 gitblit.com.
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 package com.gitblit.utils;
17
18 import java.io.BufferedReader;
31abc2 19 import java.io.IOException;
93f0b1 20 import java.io.InputStream;
JM 21 import java.io.InputStreamReader;
22 import java.io.OutputStream;
23 import java.lang.reflect.Type;
24 import java.net.HttpURLConnection;
25 import java.net.URLConnection;
f146f2 26 import java.text.DateFormat;
JM 27 import java.text.ParseException;
28 import java.text.SimpleDateFormat;
93f0b1 29 import java.util.Collection;
f146f2 30 import java.util.Date;
JM 31 import java.util.Locale;
93f0b1 32 import java.util.Map;
f146f2 33 import java.util.TimeZone;
31abc2 34
20714a 35 import com.gitblit.Constants.AccessPermission;
31abc2 36 import com.gitblit.GitBlitException.ForbiddenException;
8b7636 37 import com.gitblit.GitBlitException.NotAllowedException;
31abc2 38 import com.gitblit.GitBlitException.UnauthorizedException;
b2fde8 39 import com.gitblit.GitBlitException.UnknownRequestException;
93f0b1 40 import com.gitblit.models.RepositoryModel;
JM 41 import com.gitblit.models.UserModel;
0f43a5 42 import com.google.gson.ExclusionStrategy;
JM 43 import com.google.gson.FieldAttributes;
93f0b1 44 import com.google.gson.Gson;
JM 45 import com.google.gson.GsonBuilder;
f146f2 46 import com.google.gson.JsonDeserializationContext;
JM 47 import com.google.gson.JsonDeserializer;
48 import com.google.gson.JsonElement;
49 import com.google.gson.JsonPrimitive;
50 import com.google.gson.JsonSerializationContext;
51 import com.google.gson.JsonSerializer;
52 import com.google.gson.JsonSyntaxException;
93f0b1 53 import com.google.gson.reflect.TypeToken;
JM 54
55 /**
31abc2 56  * Utility methods for json calls to a Gitblit server.
93f0b1 57  * 
JM 58  * @author James Moger
59  * 
60  */
61 public class JsonUtils {
62
63     public static final Type REPOSITORIES_TYPE = new TypeToken<Map<String, RepositoryModel>>() {
64     }.getType();
65
66     public static final Type USERS_TYPE = new TypeToken<Collection<UserModel>>() {
67     }.getType();
68
69     /**
70      * Creates JSON from the specified object.
71      * 
72      * @param o
73      * @return json
74      */
75     public static String toJsonString(Object o) {
f146f2 76         String json = gson().toJson(o);
93f0b1 77         return json;
JM 78     }
79
80     /**
81      * Convert a json string to an object of the specified type.
82      * 
83      * @param json
84      * @param clazz
85      * @return an object
86      */
87     public static <X> X fromJsonString(String json, Class<X> clazz) {
f146f2 88         return gson().fromJson(json, clazz);
93f0b1 89     }
31abc2 90
93f0b1 91     /**
JM 92      * Convert a json string to an object of the specified type.
93      * 
94      * @param json
95      * @param clazz
96      * @return an object
97      */
98     public static <X> X fromJsonString(String json, Type type) {
f146f2 99         return gson().fromJson(json, type);
93f0b1 100     }
JM 101
102     /**
103      * Reads a gson object from the specified url.
104      * 
105      * @param url
106      * @param type
31abc2 107      * @return the deserialized object
JM 108      * @throws {@link IOException}
93f0b1 109      */
31abc2 110     public static <X> X retrieveJson(String url, Type type) throws IOException,
JM 111             UnauthorizedException {
112         return retrieveJson(url, type, null, null);
113     }
0f43a5 114
df162c 115     /**
JM 116      * Reads a gson object from the specified url.
117      * 
118      * @param url
119      * @param type
120      * @return the deserialized object
121      * @throws {@link IOException}
122      */
123     public static <X> X retrieveJson(String url, Class<? extends X> clazz) throws IOException,
124             UnauthorizedException {
125         return retrieveJson(url, clazz, null, null);
126     }
31abc2 127
JM 128     /**
129      * Reads a gson object from the specified url.
130      * 
131      * @param url
132      * @param type
133      * @param username
134      * @param password
135      * @return the deserialized object
136      * @throws {@link IOException}
137      */
138     public static <X> X retrieveJson(String url, Type type, String username, char[] password)
139             throws IOException {
140         String json = retrieveJsonString(url, username, password);
93f0b1 141         if (StringUtils.isEmpty(json)) {
JM 142             return null;
143         }
f146f2 144         return gson().fromJson(json, type);
93f0b1 145     }
8b7636 146
da0269 147     /**
JM 148      * Reads a gson object from the specified url.
149      * 
150      * @param url
151      * @param clazz
152      * @param username
153      * @param password
154      * @return the deserialized object
155      * @throws {@link IOException}
156      */
157     public static <X> X retrieveJson(String url, Class<X> clazz, String username, char[] password)
158             throws IOException {
159         String json = retrieveJsonString(url, username, password);
160         if (StringUtils.isEmpty(json)) {
161             return null;
162         }
163         return gson().fromJson(json, clazz);
164     }
93f0b1 165
JM 166     /**
167      * Retrieves a JSON message.
168      * 
169      * @param url
170      * @return the JSON message as a string
31abc2 171      * @throws {@link IOException}
93f0b1 172      */
31abc2 173     public static String retrieveJsonString(String url, String username, char[] password)
JM 174             throws IOException {
0f43a5 175         try {
565ee0 176             URLConnection conn = ConnectionUtils.openReadConnection(url, username, password);
31abc2 177             InputStream is = conn.getInputStream();
0f43a5 178             BufferedReader reader = new BufferedReader(new InputStreamReader(is,
JM 179                     ConnectionUtils.CHARSET));
31abc2 180             StringBuilder json = new StringBuilder();
JM 181             char[] buffer = new char[4096];
182             int len = 0;
183             while ((len = reader.read(buffer)) > -1) {
184                 json.append(buffer, 0, len);
185             }
186             is.close();
187             return json.toString();
188         } catch (IOException e) {
189             if (e.getMessage().indexOf("401") > -1) {
190                 // unauthorized
191                 throw new UnauthorizedException(url);
192             } else if (e.getMessage().indexOf("403") > -1) {
193                 // requested url is forbidden by the requesting user
194                 throw new ForbiddenException(url);
8b7636 195             } else if (e.getMessage().indexOf("405") > -1) {
JM 196                 // requested url is not allowed by the server
197                 throw new NotAllowedException(url);
198             } else if (e.getMessage().indexOf("501") > -1) {
199                 // requested url is not recognized by the server
200                 throw new UnknownRequestException(url);
31abc2 201             }
JM 202             throw e;
93f0b1 203         }
JM 204     }
205
206     /**
207      * Sends a JSON message.
208      * 
209      * @param url
210      *            the url to write to
211      * @param json
212      *            the json message to send
213      * @return the http request result code
31abc2 214      * @throws {@link IOException}
93f0b1 215      */
31abc2 216     public static int sendJsonString(String url, String json) throws IOException {
JM 217         return sendJsonString(url, json, null, null);
218     }
219
220     /**
221      * Sends a JSON message.
222      * 
223      * @param url
224      *            the url to write to
225      * @param json
226      *            the json message to send
227      * @param username
228      * @param password
229      * @return the http request result code
230      * @throws {@link IOException}
231      */
232     public static int sendJsonString(String url, String json, String username, char[] password)
233             throws IOException {
234         try {
565ee0 235             byte[] jsonBytes = json.getBytes(ConnectionUtils.CHARSET);
JM 236             URLConnection conn = ConnectionUtils.openConnection(url, username, password);
237             conn.setRequestProperty("Content-Type", "text/plain;charset=" + ConnectionUtils.CHARSET);
31abc2 238             conn.setRequestProperty("Content-Length", "" + jsonBytes.length);
JM 239
240             // write json body
241             OutputStream os = conn.getOutputStream();
242             os.write(jsonBytes);
243             os.close();
244
245             int status = ((HttpURLConnection) conn).getResponseCode();
246             return status;
247         } catch (IOException e) {
248             if (e.getMessage().indexOf("401") > -1) {
249                 // unauthorized
250                 throw new UnauthorizedException(url);
251             } else if (e.getMessage().indexOf("403") > -1) {
252                 // requested url is forbidden by the requesting user
253                 throw new ForbiddenException(url);
8b7636 254             } else if (e.getMessage().indexOf("405") > -1) {
JM 255                 // requested url is not allowed by the server
256                 throw new NotAllowedException(url);
b2fde8 257             } else if (e.getMessage().indexOf("501") > -1) {
JM 258                 // requested url is not recognized by the server
259                 throw new UnknownRequestException(url);
31abc2 260             }
JM 261             throw e;
262         }
93f0b1 263     }
JM 264
f146f2 265     // build custom gson instance with GMT date serializer/deserializer
JM 266     // http://code.google.com/p/google-gson/issues/detail?id=281
0f43a5 267     public static Gson gson(ExclusionStrategy... strategies) {
f146f2 268         GsonBuilder builder = new GsonBuilder();
JM 269         builder.registerTypeAdapter(Date.class, new GmtDateTypeAdapter());
20714a 270         builder.registerTypeAdapter(AccessPermission.class, new AccessPermissionTypeAdapter());
f146f2 271         builder.setPrettyPrinting();
0f43a5 272         if (!ArrayUtils.isEmpty(strategies)) {
JM 273             builder.setExclusionStrategies(strategies);
274         }
f146f2 275         return builder.create();
JM 276     }
277
278     private static class GmtDateTypeAdapter implements JsonSerializer<Date>, JsonDeserializer<Date> {
279         private final DateFormat dateFormat;
280
281         private GmtDateTypeAdapter() {
282             dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
283             dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
284         }
285
286         @Override
287         public synchronized JsonElement serialize(Date date, Type type,
288                 JsonSerializationContext jsonSerializationContext) {
289             synchronized (dateFormat) {
290                 String dateFormatAsString = dateFormat.format(date);
291                 return new JsonPrimitive(dateFormatAsString);
292             }
293         }
294
295         @Override
296         public synchronized Date deserialize(JsonElement jsonElement, Type type,
297                 JsonDeserializationContext jsonDeserializationContext) {
298             try {
299                 synchronized (dateFormat) {
35a71b 300                     Date date = dateFormat.parse(jsonElement.getAsString());                    
JM 301                     return new Date((date.getTime() / 1000) * 1000);
f146f2 302                 }
JM 303             } catch (ParseException e) {
304                 throw new JsonSyntaxException(jsonElement.getAsString(), e);
305             }
93f0b1 306         }
JM 307     }
20714a 308     
JM 309     private static class AccessPermissionTypeAdapter implements JsonSerializer<AccessPermission>, JsonDeserializer<AccessPermission> {
310
311         private AccessPermissionTypeAdapter() {
312         }
313
314         @Override
315         public synchronized JsonElement serialize(AccessPermission permission, Type type,
316                 JsonSerializationContext jsonSerializationContext) {
317             return new JsonPrimitive(permission.code);
318         }
319
320         @Override
321         public synchronized AccessPermission deserialize(JsonElement jsonElement, Type type,
322                 JsonDeserializationContext jsonDeserializationContext) {
323             return AccessPermission.fromCode(jsonElement.getAsString());                    
324         }
325     }
0f43a5 326
JM 327     public static class ExcludeField implements ExclusionStrategy {
328
329         private Class<?> c;
330         private String fieldName;
331
332         public ExcludeField(String fqfn) throws SecurityException, NoSuchFieldException,
333                 ClassNotFoundException {
334             this.c = Class.forName(fqfn.substring(0, fqfn.lastIndexOf(".")));
335             this.fieldName = fqfn.substring(fqfn.lastIndexOf(".") + 1);
336         }
337
338         public boolean shouldSkipClass(Class<?> arg0) {
339             return false;
340         }
341
342         public boolean shouldSkipField(FieldAttributes f) {
343             return (f.getDeclaringClass() == c && f.getName().equals(fieldName));
344         }
345     }
93f0b1 346 }