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