View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.myfaces.tobago.renderkit.html;
21  
22  import org.apache.myfaces.tobago.internal.context.DateTimeI18n;
23  import org.apache.myfaces.tobago.layout.AutoLayoutToken;
24  import org.apache.myfaces.tobago.layout.LayoutToken;
25  import org.apache.myfaces.tobago.layout.LayoutTokens;
26  import org.apache.myfaces.tobago.layout.MeasureLayoutToken;
27  import org.apache.myfaces.tobago.layout.RelativeLayoutToken;
28  import org.slf4j.Logger;
29  import org.slf4j.LoggerFactory;
30  
31  import java.util.ArrayList;
32  import java.util.List;
33  import java.util.Map;
34  import java.util.StringTokenizer;
35  
36  public class JsonUtils {
37  
38    private static final Logger LOG = LoggerFactory.getLogger(JsonUtils.class);
39  
40    private JsonUtils() {
41    }
42  
43    private static void encode(final StringBuilder builder, final String name, final String[] value) {
44      builder.append("\"");
45      builder.append(name);
46      builder.append("\":");
47      encode(builder, value);
48      builder.append(",");
49    }
50  
51    public static void encode(StringBuilder builder, String[] value) {
52      builder.append("[");
53      boolean colon = false;
54      for (final String item : value) {
55        if (colon) {
56          builder.append(",");
57        }
58        builder.append("\"");
59        builder.append(item);
60        builder.append("\"");
61        colon = true;
62      }
63      builder.append("]");
64    }
65  
66    public static void encode(StringBuilder builder, List<Integer> value) {
67      builder.append("[");
68      boolean colon = false;
69      for (final Integer item : value) {
70        if (colon) {
71          builder.append(",");
72        }
73        builder.append(item);
74        colon = true;
75      }
76      builder.append("]");
77    }
78  
79    private static void encode(final StringBuilder builder, final String name, final Boolean value) {
80      builder.append("\"");
81      builder.append(name);
82      builder.append("\":");
83      builder.append(Boolean.toString(value));
84      builder.append(",");
85    }
86  
87    private static void encode(final StringBuilder builder, final String name, final Integer value) {
88      builder.append("\"");
89      builder.append(name);
90      builder.append("\":");
91      builder.append(Integer.toString(value));
92      builder.append(",");
93    }
94  
95    private static void encode(final StringBuilder builder, final String name, String value) {
96      value = value.replaceAll("\\\"", "\\\\\\\""); // todo: optimize
97      builder.append("\"");
98      builder.append(name);
99      builder.append("\":\"");
100     builder.append(value);
101     builder.append("\",");
102   }
103 
104   public static String encode(final CommandMap commandMap) {
105     final StringBuilder builder = new StringBuilder();
106     builder.append("{");
107     final int initialLength = builder.length();
108 
109     final Command click = commandMap.getClick();
110     if (click != null) {
111       encode(builder, "click", click);
112     }
113 
114     final Map<String, Command> other = commandMap.getOther();
115     if (other != null) {
116       for(final Map.Entry<String, Command> entry : other.entrySet()) {
117         encode(builder, entry.getKey(), entry.getValue());
118       }
119     }
120 
121     if (builder.length() - initialLength > 0) {
122       assert builder.charAt(builder.length() - 1) == ',';
123       builder.deleteCharAt(builder.length() - 1);
124     }
125 
126     builder.append("}");
127     return builder.toString();
128   }
129 
130   private static void encode(final StringBuilder builder, final String name, final Command command) {
131     builder.append("\"");
132     builder.append(name);
133     builder.append("\":{");
134     final int initialLength = builder.length();
135 
136     final String action = command.getAction();
137     if (action != null) {
138       encode(builder, "action", action);
139     }
140     final Boolean transition = command.getTransition();
141     if (transition != null && !transition) { // true is the default, so encoding is needed.
142       encode(builder, "transition", transition);
143     }
144     final String target = command.getTarget();
145     if (target != null) {
146       encode(builder, "target", target);
147     }
148     final String partially = command.getPartially();
149     if (partially != null) {
150       encode(builder, "partially", partially);
151     }
152     final String execute = command.getExecute();
153     if (execute != null) {
154       encode(builder, "execute", execute);
155     }
156     final String render = command.getRender();
157     if (render != null) {
158       encode(builder, "render", render);
159     }
160     final Collapse collapse = command.getCollapse();
161     if (collapse != null) {
162       encode(builder, "collapse", collapse);
163     }
164     final String focus = command.getFocus();
165     if (focus != null) {
166       encode(builder, "focus", focus);
167     }
168     final String confirmation = command.getConfirmation();
169     if (confirmation != null) {
170       encode(builder, "confirmation", confirmation);
171     }
172     final Integer delay  = command.getDelay();
173     if (delay != null) {
174       encode(builder, "delay", delay);
175     }
176     final Boolean omit = command.getOmit();
177     if (omit != null && omit) { // false is the default, so encoding is needed.
178       encode(builder, "omit", true);
179     }
180 
181     if (builder.length() - initialLength > 0) {
182       assert builder.charAt(builder.length() - 1) == ',';
183       builder.deleteCharAt(builder.length() - 1);
184     }
185 
186     builder.append("},");
187   }
188 
189   private static void encode(final StringBuilder builder, final String name, final Collapse collapse) {
190     builder.append("\"");
191     builder.append(name);
192     builder.append("\":{");
193     final int initialLength = builder.length();
194 
195     final Collapse.Action action = collapse.getAction();
196     if (action != null) {
197       encode(builder, "transition", action.name());
198     }
199     final String forId = collapse.getFor();
200     if (forId != null) {
201       encode(builder, "forId", forId);
202     }
203     if (builder.length() - initialLength > 0) {
204       assert builder.charAt(builder.length() - 1) == ',';
205       builder.deleteCharAt(builder.length() - 1);
206     }
207 
208     builder.append("},");
209   }
210 
211   public static String encode(final DateTimeI18n dateTimeI18n) {
212     final StringBuilder builder = new StringBuilder();
213     builder.append("{");
214     final int initialLength = builder.length();
215 
216     encode(builder, "monthNames", dateTimeI18n.getMonthNames());
217     encode(builder, "monthNamesShort", dateTimeI18n.getMonthNamesShort());
218     encode(builder, "dayNames", dateTimeI18n.getDayNames());
219     encode(builder, "dayNamesShort", dateTimeI18n.getDayNamesShort());
220     encode(builder, "dayNamesMin", dateTimeI18n.getDayNamesMin());
221     encode(builder, "firstDay", dateTimeI18n.getFirstDay());
222 
223     if (builder.length() - initialLength > 0) {
224       assert builder.charAt(builder.length() - 1) == ',';
225       builder.deleteCharAt(builder.length() - 1);
226     }
227     builder.append("}");
228     return builder.toString();
229   }
230 
231   public static String encode(final String[] strings) {
232     if (strings == null) {
233       return null;
234     }
235     final StringBuilder builder = new StringBuilder();
236     encode(builder, strings);
237     return builder.toString();
238   }
239 
240   public static String encode(final List<Integer> integers) {
241     if (integers == null) {
242       return null;
243     }
244     final StringBuilder builder = new StringBuilder();
245     encode(builder, integers);
246     return builder.toString();
247   }
248 
249   public static void encode(final LayoutTokens bankHeads, final StringBuilder builder) {
250     builder.append("[");
251     for (final LayoutToken token : bankHeads.getTokens()) {
252       if (token instanceof RelativeLayoutToken) {
253         final int factor = ((RelativeLayoutToken) token).getFactor();
254         builder.append(factor);
255       } else if (token instanceof AutoLayoutToken) {
256         builder.append("\"auto\"");
257       } else if (token instanceof MeasureLayoutToken) {
258         builder.append("{\"measure\":\"");
259         builder.append(((MeasureLayoutToken) token).getMeasure());
260         builder.append("\"}");
261       } else {
262         LOG.warn("Not supported: " + token);
263       }
264       builder.append(',');
265     }
266     if (builder.charAt(builder.length() - 1) == ',') {
267       builder.deleteCharAt(builder.length() - 1);
268     }
269     builder.append("]");
270   }
271 
272   public static List<Integer> decodeIntegerArray(String json) {
273     json = json.trim();
274     final List<Integer> result = new ArrayList<Integer>();
275     if (json.length() < 2 || json.charAt(0) != '[' || json.charAt(json.length() - 1) != ']') {
276       LOG.error("Can't parse JSON array: no surrounding square brackets []: '{}'", json);
277     } else {
278       json = json.substring(1, json.length() - 1);
279       final StringTokenizer tokenizer = new StringTokenizer(json, ",");
280       while (tokenizer.hasMoreTokens()) {
281         final String token = tokenizer.nextToken().trim();
282         try {
283           result.add(Integer.parseInt(token));
284         } catch (NumberFormatException e) {
285           LOG.error("Can't parse JSON array: not an integer token: '{}'", token);
286           // ignoring so far
287         }
288       }
289     }
290     return result;
291   }
292 }