00328b60d9bcd584b94b1e1649eaabf07ca0265c
[moon.git] /
1 /*
2  * Copyright (c) 2014 Red Hat, Inc.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.aaa.idpmapping;
10
11 import java.io.BufferedReader;
12 import java.io.IOException;
13 import java.io.StringReader;
14 import java.io.StringWriter;
15 import java.nio.charset.StandardCharsets;
16 import java.nio.file.Files;
17 import java.nio.file.Path;
18 import java.util.ArrayList;
19 import java.util.HashMap;
20 import java.util.LinkedHashMap;
21 import java.util.List;
22 import java.util.Map;
23 import javax.json.Json;
24 import javax.json.JsonValue;
25 import javax.json.stream.JsonGenerator;
26 import javax.json.stream.JsonGeneratorFactory;
27 import javax.json.stream.JsonLocation;
28 import javax.json.stream.JsonParser;
29 import javax.json.stream.JsonParser.Event;
30
31 /**
32  * Converts between JSON and the internal data structures used in the
33  * RuleProcessor.
34  *
35  * @author John Dennis <jdennis@redhat.com>
36  */
37
38 public class IdpJson {
39
40     public IdpJson() {
41     }
42
43     public Object loadJson(java.io.Reader in) {
44         JsonParser parser = Json.createParser(in);
45         Event event = null;
46
47         // Prime the pump. Get the first item from the parser.
48         event = parser.next();
49
50         // Act on first item.
51         return loadJsonItem(parser, event);
52     }
53
54     public Object loadJson(Path filename) throws IOException {
55         BufferedReader reader = Files.newBufferedReader(filename, StandardCharsets.UTF_8);
56         return loadJson(reader);
57     }
58
59     public Object loadJson(String string) {
60         StringReader reader = new StringReader(string);
61         return loadJson(reader);
62     }
63
64     /*
65      * Process current parser item indicated by event. Consumes exactly the
66      * number of parser events necessary to load the item. Caller must advance
67      * the parser via parser.next() after this method returns.
68      */
69     private Object loadJsonItem(JsonParser parser, Event event) {
70         switch (event) {
71         case START_OBJECT: {
72             return loadJsonObject(parser, event);
73         }
74         case START_ARRAY: {
75             return loadJsonArray(parser, event);
76         }
77         case VALUE_NULL: {
78             return null;
79         }
80         case VALUE_NUMBER: {
81             if (parser.isIntegralNumber()) {
82                 return parser.getLong();
83             } else {
84                 return parser.getBigDecimal().doubleValue();
85             }
86         }
87         case VALUE_STRING: {
88             return parser.getString();
89         }
90         case VALUE_TRUE: {
91             return Boolean.TRUE;
92         }
93         case VALUE_FALSE: {
94             return Boolean.FALSE;
95         }
96         default: {
97             JsonLocation location = parser.getLocation();
98             throw new IllegalStateException(String.format(
99                     "unknown JSON parsing event %s, location(line=%d column=%d offset=%d)", event,
100                     location.getLineNumber(), location.getColumnNumber(),
101                     location.getStreamOffset()));
102         }
103         }
104     }
105
106     private List<Object> loadJsonArray(JsonParser parser, Event event) {
107         List<Object> list = new ArrayList<Object>();
108
109         if (event != Event.START_ARRAY) {
110             JsonLocation location = parser.getLocation();
111             throw new IllegalStateException(
112                     String.format(
113                             "expected JSON parsing event to be START_ARRAY, not %s location(line=%d column=%d offset=%d)",
114                             event, location.getLineNumber(), location.getColumnNumber(),
115                             location.getStreamOffset()));
116         }
117         event = parser.next(); // consume START_ARRAY
118         while (event != Event.END_ARRAY) {
119             Object obj;
120
121             obj = loadJsonItem(parser, event);
122             list.add(obj);
123             event = parser.next(); // next array item or END_ARRAY
124         }
125         return list;
126     }
127
128     private Map<String, Object> loadJsonObject(JsonParser parser, Event event) {
129         Map<String, Object> map = new LinkedHashMap<String, Object>();
130
131         if (event != Event.START_OBJECT) {
132             JsonLocation location = parser.getLocation();
133             throw new IllegalStateException(String.format(
134                     "expected JSON parsing event to be START_OBJECT, not %s, ",
135                     "location(line=%d column=%d offset=%d)", event, location.getLineNumber(),
136                     location.getColumnNumber(), location.getStreamOffset()));
137         }
138         event = parser.next(); // consume START_OBJECT
139         while (event != Event.END_OBJECT) {
140             if (event == Event.KEY_NAME) {
141                 String key;
142                 Object value;
143
144                 key = parser.getString();
145                 event = parser.next(); // consume key
146                 value = loadJsonItem(parser, event);
147                 map.put(key, value);
148             } else {
149                 JsonLocation location = parser.getLocation();
150                 throw new IllegalStateException(
151                         String.format(
152                                 "expected JSON parsing event to be KEY_NAME, not %s, location(line=%d column=%d offset=%d)",
153                                 event, location.getLineNumber(), location.getColumnNumber(),
154                                 location.getStreamOffset()));
155
156             }
157             event = parser.next(); // next key or END_OBJECT
158         }
159         return map;
160     }
161
162     public String dumpJson(Object obj) {
163         Map<String, Object> properties = new HashMap<String, Object>(1);
164         properties.put(JsonGenerator.PRETTY_PRINTING, true);
165         JsonGeneratorFactory generatorFactory = Json.createGeneratorFactory(properties);
166         StringWriter stringWriter = new StringWriter();
167         JsonGenerator generator = generatorFactory.createGenerator(stringWriter);
168
169         dumpJsonItem(generator, obj);
170         generator.close();
171         return stringWriter.toString();
172     }
173
174     private void dumpJsonItem(JsonGenerator generator, Object obj) {
175         // ordered by expected occurrence
176         if (obj instanceof String) {
177             generator.write((String) obj);
178         } else if (obj instanceof List) {
179             generator.writeStartArray();
180             @SuppressWarnings("unchecked")
181             List<Object> list = (List<Object>) obj;
182             dumpJsonArray(generator, list);
183         } else if (obj instanceof Map) {
184             generator.writeStartObject();
185             @SuppressWarnings("unchecked")
186             Map<String, Object> map = (Map<String, Object>) obj;
187             dumpJsonObject(generator, map);
188         } else if (obj instanceof Long) {
189             generator.write(((Long) obj).longValue());
190         } else if (obj instanceof Boolean) {
191             generator.write(((Boolean) obj).booleanValue());
192         } else if (obj == null) {
193             generator.writeNull();
194         } else if (obj instanceof Double) {
195             generator.write(((Double) obj).doubleValue());
196         } else {
197             throw new IllegalStateException(
198                     String.format(
199                             "unsupported data type, must be String, Long, Double, Boolean, List, Map, or null, not %s",
200                             obj.getClass().getSimpleName()));
201         }
202     }
203
204     private void dumpJsonArray(JsonGenerator generator, List<Object> list) {
205         for (Object obj : list) {
206             dumpJsonItem(generator, obj);
207         }
208         generator.writeEnd();
209     }
210
211     private void dumpJsonObject(JsonGenerator generator, Map<String, Object> map) {
212
213         for (Map.Entry<String, Object> entry : map.entrySet()) {
214             String key = entry.getKey();
215             Object obj = entry.getValue();
216
217             // ordered by expected occurrence
218             if (obj instanceof String) {
219                 generator.write(key, (String) obj);
220             } else if (obj instanceof List) {
221                 generator.writeStartArray(key);
222                 @SuppressWarnings("unchecked")
223                 List<Object> list = (List<Object>) obj;
224                 dumpJsonArray(generator, list);
225             } else if (obj instanceof Map) {
226                 generator.writeStartObject(key);
227                 @SuppressWarnings("unchecked")
228                 Map<String, Object> map1 = (Map<String, Object>) obj;
229                 dumpJsonObject(generator, map1);
230             } else if (obj instanceof Long) {
231                 generator.write(key, ((Long) obj).longValue());
232             } else if (obj instanceof Boolean) {
233                 generator.write(key, ((Boolean) obj).booleanValue());
234             } else if (obj == null) {
235                 generator.write(key, JsonValue.NULL);
236             } else if (obj instanceof Double) {
237                 generator.write(key, ((Double) obj).doubleValue());
238             } else {
239                 throw new IllegalStateException(
240                         String.format(
241                                 "unsupported data type, must be String, Long, Double, Boolean, List, Map, or null, not %s",
242                                 obj.getClass().getSimpleName()));
243             }
244         }
245         generator.writeEnd();
246     }
247
248 }