WIP
[maven-thymeleaf-skin] / src / main / java / de / juplo / thymeleaf / ImportVariablesAttrProcessor.java
1 package de.juplo.thymeleaf;
2
3
4 import com.fasterxml.jackson.core.JsonFactory;
5 import com.fasterxml.jackson.core.JsonLocation;
6 import com.fasterxml.jackson.core.JsonParser;
7 import com.fasterxml.jackson.core.JsonToken;
8 import com.fasterxml.jackson.databind.ObjectMapper;
9 import java.io.IOException;
10 import java.io.InputStream;
11 import java.time.format.DateTimeFormatter;
12 import java.util.LinkedHashMap;
13 import java.util.LinkedList;
14 import java.util.List;
15 import java.util.Map;
16 import org.slf4j.Logger;
17 import org.slf4j.LoggerFactory;
18
19
20
21 /**
22  *
23  * @author kai
24  */
25 public class ImportVariablesAttrProcessor
26 {
27   private static final Logger LOG =
28       LoggerFactory.getLogger(ImportVariablesAttrProcessor.class);
29   private static final DateTimeFormatter FORMATTER =
30       DateTimeFormatter.ofPattern("dd.MM");
31   private static final ObjectMapper MAPPER = new ObjectMapper();
32   private static final JsonFactory FACTORY = new JsonFactory();
33
34
35   public Object processAttribute(InputStream is)
36   {
37       try
38       {
39         /** Read the JSON and create the variables */
40         JsonParser parser = FACTORY.createParser(is);
41
42         JsonToken token = parser.nextToken();
43
44         if (token == null)
45         {
46           LOG.warn("empty input-stream");
47           return null;
48         }
49
50         Object result = convert(parser);
51
52         if (parser.nextToken() != null)
53           fail(parser, "unexpected data after parsed variables");
54
55         return result;
56       }
57       catch (IOException e)
58       {
59         LOG.error("cannot parse input-stream as JSON: {}", e.getMessage());
60         throw new RuntimeException(e);
61       }
62   }
63
64
65   static Object convert(JsonParser parser) throws IOException
66   {
67     JsonToken token = parser.getCurrentToken();
68     if (token == null)
69       fail(parser, "unexpected EOF");
70
71     switch (token)
72     {
73       case VALUE_STRING:       return parser.getText();
74       case VALUE_NUMBER_INT:   return parser.getIntValue();
75       case VALUE_NUMBER_FLOAT: return parser.getDoubleValue();
76       case START_OBJECT:       return convertObject(parser);
77       case START_ARRAY:        return convertArray(parser);
78       case VALUE_TRUE:         return Boolean.TRUE;
79       case VALUE_FALSE:        return Boolean.FALSE;
80       case VALUE_NULL:         return null;
81     }
82
83     fail(parser, "unexpected token " + token.toString());
84     return null; // << Will never be reached, because fail always throws an exception
85   }
86
87   static Map<String, Object> convertObject(JsonParser parser) throws IOException
88   {
89     JsonToken token = parser.nextToken();
90     if (token == null)
91       fail(parser, "unexpected EOF");
92
93     Map<String, Object> map = new LinkedHashMap<>();
94
95     while (!JsonToken.END_OBJECT.equals(token))
96     {
97       if (!JsonToken.FIELD_NAME.equals(token))
98         fail(parser, "expected a field-name");
99
100       String name = parser.getText();
101       parser.nextToken();
102       Object value = convert(parser);
103       map.put(name, value);
104
105       token = parser.nextToken();
106       if (token == null)
107         fail(parser, "unexpected EOF");
108     }
109
110     return map;
111   }
112
113   static List<Object> convertArray(JsonParser parser) throws IOException
114   {
115     JsonToken token = parser.nextToken();
116     if (token == null)
117       fail(parser, "unexpected EOF");
118
119     List<Object> list = new LinkedList<>();
120
121     while (!JsonToken.END_ARRAY.equals(token))
122     {
123       list.add(convert(parser));
124
125       token = parser.nextToken();
126       if (token == null)
127         fail(parser, "unexpected EOF");
128     }
129
130     return list;
131   }
132
133   static void fail(JsonParser parser, String message)
134   {
135     JsonLocation location = parser.getCurrentLocation();
136     LOG.error(
137         "{} at char-offset {} (line {}, column {})",
138         message,
139         location.getCharOffset(),
140         location.getLineNr(),
141         location.getColumnNr()
142         );
143     throw new RuntimeException("Cannot parse JSON: " + message);
144   }
145 }