001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.camel.runtimecatalog; 018 019import java.util.ArrayList; 020import java.util.LinkedHashMap; 021import java.util.LinkedHashSet; 022import java.util.List; 023import java.util.Map; 024import java.util.Set; 025 026import org.json.simple.JsonObject; 027import org.json.simple.Jsoner; 028 029public final class JSonSchemaHelper { 030 031 private JSonSchemaHelper() { 032 } 033 034 /** 035 * Parses the json schema to split it into a list or rows, where each row contains key value pairs with the metadata 036 * 037 * @param group the group to parse from such as <tt>component</tt>, <tt>componentProperties</tt>, or <tt>properties</tt>. 038 * @param json the json 039 * @return a list of all the rows, where each row is a set of key value pairs with metadata 040 * @throws RuntimeException is thrown if error parsing the json data 041 */ 042 @SuppressWarnings("unchecked") 043 public static List<Map<String, String>> parseJsonSchema(String group, String json, boolean parseProperties) { 044 List<Map<String, String>> answer = new ArrayList<>(); 045 if (json == null) { 046 return answer; 047 } 048 049 // convert into a List<Map<String, String>> structure which is expected as output from this parser 050 try { 051 JsonObject output = (JsonObject) Jsoner.deserialize(json); 052 for (String key : output.keySet()) { 053 Map row = output.getMap(key); 054 if (key.equals(group)) { 055 if (parseProperties) { 056 // flattern each entry in the row with name as they key, and its value as the content (its a map also) 057 for (Object obj : row.entrySet()) { 058 Map.Entry entry = (Map.Entry) obj; 059 Map<String, String> newRow = new LinkedHashMap(); 060 newRow.put("name", entry.getKey().toString()); 061 062 Map newData = transformMap((Map) entry.getValue()); 063 newRow.putAll(newData); 064 answer.add(newRow); 065 } 066 } else { 067 // flattern each entry in the row as a list of single Map<key, value> elements 068 Map newData = transformMap(row); 069 for (Object obj : newData.entrySet()) { 070 Map.Entry entry = (Map.Entry) obj; 071 Map<String, String> newRow = new LinkedHashMap<>(); 072 newRow.put(entry.getKey().toString(), entry.getValue().toString()); 073 answer.add(newRow); 074 } 075 } 076 } 077 } 078 } catch (Exception e) { 079 // wrap parsing exceptions as runtime 080 throw new RuntimeException("Cannot parse json", e); 081 } 082 083 return answer; 084 } 085 086 private static Map<String, String> transformMap(Map jsonMap) { 087 Map<String, String> answer = new LinkedHashMap<>(); 088 089 for (Object rowObj : jsonMap.entrySet()) { 090 Map.Entry rowEntry = (Map.Entry) rowObj; 091 // if its a list type then its an enum, and we need to parse it as a single line separated with comma 092 // to be backwards compatible 093 Object newValue = rowEntry.getValue(); 094 if (newValue instanceof List) { 095 List list = (List) newValue; 096 CollectionStringBuffer csb = new CollectionStringBuffer(","); 097 for (Object line : list) { 098 csb.append(line); 099 } 100 newValue = csb.toString(); 101 } 102 // ensure value is escaped 103 String value = escapeJson(newValue.toString()); 104 answer.put(rowEntry.getKey().toString(), value); 105 } 106 107 return answer; 108 } 109 110 private static String escapeJson(String value) { 111 // need to safe encode \r as \\r so its escaped 112 // need to safe encode \n as \\n so its escaped 113 // need to safe encode \t as \\t so its escaped 114 return value 115 .replaceAll("\\\\r", "\\\\\\r") 116 .replaceAll("\\\\n", "\\\\\\n") 117 .replaceAll("\\\\t", "\\\\\\t"); 118 } 119 120 public static boolean isComponentLenientProperties(List<Map<String, String>> rows) { 121 for (Map<String, String> row : rows) { 122 if (row.containsKey("lenientProperties")) { 123 return "true".equals(row.get("lenientProperties")); 124 } 125 } 126 return false; 127 } 128 129 public static boolean isComponentConsumerOnly(List<Map<String, String>> rows) { 130 for (Map<String, String> row : rows) { 131 if (row.containsKey("consumerOnly")) { 132 return "true".equals(row.get("consumerOnly")); 133 } 134 } 135 return false; 136 } 137 138 public static boolean isComponentProducerOnly(List<Map<String, String>> rows) { 139 for (Map<String, String> row : rows) { 140 if (row.containsKey("producerOnly")) { 141 return "true".equals(row.get("producerOnly")); 142 } 143 } 144 return false; 145 } 146 147 public static boolean isPropertyConsumerOnly(List<Map<String, String>> rows, String name) { 148 for (Map<String, String> row : rows) { 149 String labels = null; 150 boolean found = false; 151 if (row.containsKey("name")) { 152 found = name.equals(row.get("name")); 153 } 154 if (row.containsKey("label")) { 155 labels = row.get("label"); 156 } 157 if (found) { 158 return labels != null && labels.contains("consumer"); 159 } 160 } 161 return false; 162 } 163 164 public static boolean isPropertyProducerOnly(List<Map<String, String>> rows, String name) { 165 for (Map<String, String> row : rows) { 166 String labels = null; 167 boolean found = false; 168 if (row.containsKey("name")) { 169 found = name.equals(row.get("name")); 170 } 171 if (row.containsKey("label")) { 172 labels = row.get("label"); 173 } 174 if (found) { 175 return labels != null && labels.contains("producer"); 176 } 177 } 178 return false; 179 } 180 181 public static boolean isPropertyRequired(List<Map<String, String>> rows, String name) { 182 for (Map<String, String> row : rows) { 183 boolean required = false; 184 boolean found = false; 185 if (row.containsKey("name")) { 186 found = name.equals(row.get("name")); 187 } 188 if (row.containsKey("required")) { 189 required = "true".equals(row.get("required")); 190 } 191 if (found) { 192 return required; 193 } 194 } 195 return false; 196 } 197 198 public static String getPropertyKind(List<Map<String, String>> rows, String name) { 199 for (Map<String, String> row : rows) { 200 String kind = null; 201 boolean found = false; 202 if (row.containsKey("name")) { 203 found = name.equals(row.get("name")); 204 } 205 if (row.containsKey("kind")) { 206 kind = row.get("kind"); 207 } 208 if (found) { 209 return kind; 210 } 211 } 212 return null; 213 } 214 215 public static boolean isPropertyBoolean(List<Map<String, String>> rows, String name) { 216 for (Map<String, String> row : rows) { 217 String type = null; 218 boolean found = false; 219 if (row.containsKey("name")) { 220 found = name.equals(row.get("name")); 221 } 222 if (row.containsKey("type")) { 223 type = row.get("type"); 224 } 225 if (found) { 226 return "boolean".equals(type); 227 } 228 } 229 return false; 230 } 231 232 public static boolean isPropertyInteger(List<Map<String, String>> rows, String name) { 233 for (Map<String, String> row : rows) { 234 String type = null; 235 boolean found = false; 236 if (row.containsKey("name")) { 237 found = name.equals(row.get("name")); 238 } 239 if (row.containsKey("type")) { 240 type = row.get("type"); 241 } 242 if (found) { 243 return "integer".equals(type); 244 } 245 } 246 return false; 247 } 248 249 public static boolean isPropertyNumber(List<Map<String, String>> rows, String name) { 250 for (Map<String, String> row : rows) { 251 String type = null; 252 boolean found = false; 253 if (row.containsKey("name")) { 254 found = name.equals(row.get("name")); 255 } 256 if (row.containsKey("type")) { 257 type = row.get("type"); 258 } 259 if (found) { 260 return "number".equals(type); 261 } 262 } 263 return false; 264 } 265 266 public static boolean isPropertyObject(List<Map<String, String>> rows, String name) { 267 for (Map<String, String> row : rows) { 268 String type = null; 269 boolean found = false; 270 if (row.containsKey("name")) { 271 found = name.equals(row.get("name")); 272 } 273 if (row.containsKey("type")) { 274 type = row.get("type"); 275 } 276 if (found) { 277 return "object".equals(type); 278 } 279 } 280 return false; 281 } 282 283 public static String getPropertyDefaultValue(List<Map<String, String>> rows, String name) { 284 for (Map<String, String> row : rows) { 285 String defaultValue = null; 286 boolean found = false; 287 if (row.containsKey("name")) { 288 found = name.equals(row.get("name")); 289 } 290 if (row.containsKey("defaultValue")) { 291 defaultValue = row.get("defaultValue"); 292 } 293 if (found) { 294 return defaultValue; 295 } 296 } 297 return null; 298 } 299 300 public static String stripOptionalPrefixFromName(List<Map<String, String>> rows, String name) { 301 for (Map<String, String> row : rows) { 302 String optionalPrefix = null; 303 boolean found = false; 304 if (row.containsKey("optionalPrefix")) { 305 optionalPrefix = row.get("optionalPrefix"); 306 } 307 if (row.containsKey("name")) { 308 if (optionalPrefix != null && name.startsWith(optionalPrefix)) { 309 name = name.substring(optionalPrefix.length()); 310 // try again 311 return stripOptionalPrefixFromName(rows, name); 312 } else { 313 found = name.equals(row.get("name")); 314 } 315 } 316 if (found) { 317 return name; 318 } 319 } 320 return name; 321 } 322 323 public static String getPropertyEnum(List<Map<String, String>> rows, String name) { 324 for (Map<String, String> row : rows) { 325 String enums = null; 326 boolean found = false; 327 if (row.containsKey("name")) { 328 found = name.equals(row.get("name")); 329 } 330 if (row.containsKey("enum")) { 331 enums = row.get("enum"); 332 } 333 if (found) { 334 return enums; 335 } 336 } 337 return null; 338 } 339 340 public static String getPropertyPrefix(List<Map<String, String>> rows, String name) { 341 for (Map<String, String> row : rows) { 342 String prefix = null; 343 boolean found = false; 344 if (row.containsKey("name")) { 345 found = name.equals(row.get("name")); 346 } 347 if (row.containsKey("prefix")) { 348 prefix = row.get("prefix"); 349 } 350 if (found) { 351 return prefix; 352 } 353 } 354 return null; 355 } 356 357 public static boolean isPropertyMultiValue(List<Map<String, String>> rows, String name) { 358 for (Map<String, String> row : rows) { 359 boolean multiValue = false; 360 boolean found = false; 361 if (row.containsKey("name")) { 362 found = name.equals(row.get("name")); 363 } 364 if (row.containsKey("multiValue")) { 365 multiValue = "true".equals(row.get("multiValue")); 366 } 367 if (found) { 368 return multiValue; 369 } 370 } 371 return false; 372 } 373 374 public static String getPropertyNameFromNameWithPrefix(List<Map<String, String>> rows, String name) { 375 for (Map<String, String> row : rows) { 376 String propertyName = null; 377 boolean found = false; 378 if (row.containsKey("name")) { 379 propertyName = row.get("name"); 380 } 381 if (row.containsKey("prefix")) { 382 String preifx = row.get("prefix"); 383 found = name.startsWith(preifx); 384 } 385 if (found) { 386 return propertyName; 387 } 388 } 389 return null; 390 } 391 392 public static Map<String, String> getRow(List<Map<String, String>> rows, String key) { 393 for (Map<String, String> row : rows) { 394 if (key.equals(row.get("name"))) { 395 return row; 396 } 397 } 398 return null; 399 } 400 401 public static Set<String> getNames(List<Map<String, String>> rows) { 402 Set<String> answer = new LinkedHashSet<>(); 403 for (Map<String, String> row : rows) { 404 if (row.containsKey("name")) { 405 answer.add(row.get("name")); 406 } 407 } 408 return answer; 409 } 410 411}