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 boolean isPropertyDeprecated(List<Map<String, String>> rows, String name) { 199 for (Map<String, String> row : rows) { 200 boolean deprecated = false; 201 boolean found = false; 202 if (row.containsKey("name")) { 203 found = name.equals(row.get("name")); 204 } 205 if (row.containsKey("deprecated")) { 206 deprecated = "true".equals(row.get("deprecated")); 207 } 208 if (found) { 209 return deprecated; 210 } 211 } 212 return false; 213 } 214 215 public static String getPropertyKind(List<Map<String, String>> rows, String name) { 216 for (Map<String, String> row : rows) { 217 String kind = null; 218 boolean found = false; 219 if (row.containsKey("name")) { 220 found = name.equals(row.get("name")); 221 } 222 if (row.containsKey("kind")) { 223 kind = row.get("kind"); 224 } 225 if (found) { 226 return kind; 227 } 228 } 229 return null; 230 } 231 232 public static boolean isPropertyBoolean(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 "boolean".equals(type); 244 } 245 } 246 return false; 247 } 248 249 public static boolean isPropertyInteger(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 "integer".equals(type); 261 } 262 } 263 return false; 264 } 265 266 public static boolean isPropertyNumber(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 "number".equals(type); 278 } 279 } 280 return false; 281 } 282 283 public static boolean isPropertyObject(List<Map<String, String>> rows, String name) { 284 for (Map<String, String> row : rows) { 285 String type = null; 286 boolean found = false; 287 if (row.containsKey("name")) { 288 found = name.equals(row.get("name")); 289 } 290 if (row.containsKey("type")) { 291 type = row.get("type"); 292 } 293 if (found) { 294 return "object".equals(type); 295 } 296 } 297 return false; 298 } 299 300 public static String getPropertyDefaultValue(List<Map<String, String>> rows, String name) { 301 for (Map<String, String> row : rows) { 302 String defaultValue = null; 303 boolean found = false; 304 if (row.containsKey("name")) { 305 found = name.equals(row.get("name")); 306 } 307 if (row.containsKey("defaultValue")) { 308 defaultValue = row.get("defaultValue"); 309 } 310 if (found) { 311 return defaultValue; 312 } 313 } 314 return null; 315 } 316 317 public static String stripOptionalPrefixFromName(List<Map<String, String>> rows, String name) { 318 for (Map<String, String> row : rows) { 319 String optionalPrefix = null; 320 boolean found = false; 321 if (row.containsKey("optionalPrefix")) { 322 optionalPrefix = row.get("optionalPrefix"); 323 } 324 if (row.containsKey("name")) { 325 if (optionalPrefix != null && name.startsWith(optionalPrefix)) { 326 name = name.substring(optionalPrefix.length()); 327 // try again 328 return stripOptionalPrefixFromName(rows, name); 329 } else { 330 found = name.equals(row.get("name")); 331 } 332 } 333 if (found) { 334 return name; 335 } 336 } 337 return name; 338 } 339 340 public static String getPropertyEnum(List<Map<String, String>> rows, String name) { 341 for (Map<String, String> row : rows) { 342 String enums = null; 343 boolean found = false; 344 if (row.containsKey("name")) { 345 found = name.equals(row.get("name")); 346 } 347 if (row.containsKey("enum")) { 348 enums = row.get("enum"); 349 } 350 if (found) { 351 return enums; 352 } 353 } 354 return null; 355 } 356 357 public static String getPropertyPrefix(List<Map<String, String>> rows, String name) { 358 for (Map<String, String> row : rows) { 359 String prefix = null; 360 boolean found = false; 361 if (row.containsKey("name")) { 362 found = name.equals(row.get("name")); 363 } 364 if (row.containsKey("prefix")) { 365 prefix = row.get("prefix"); 366 } 367 if (found) { 368 return prefix; 369 } 370 } 371 return null; 372 } 373 374 public static boolean isPropertyMultiValue(List<Map<String, String>> rows, String name) { 375 for (Map<String, String> row : rows) { 376 boolean multiValue = false; 377 boolean found = false; 378 if (row.containsKey("name")) { 379 found = name.equals(row.get("name")); 380 } 381 if (row.containsKey("multiValue")) { 382 multiValue = "true".equals(row.get("multiValue")); 383 } 384 if (found) { 385 return multiValue; 386 } 387 } 388 return false; 389 } 390 391 public static String getPropertyNameFromNameWithPrefix(List<Map<String, String>> rows, String name) { 392 for (Map<String, String> row : rows) { 393 String propertyName = null; 394 boolean found = false; 395 if (row.containsKey("name")) { 396 propertyName = row.get("name"); 397 } 398 if (row.containsKey("prefix")) { 399 String preifx = row.get("prefix"); 400 found = name.startsWith(preifx); 401 } 402 if (found) { 403 return propertyName; 404 } 405 } 406 return null; 407 } 408 409 public static Map<String, String> getRow(List<Map<String, String>> rows, String key) { 410 for (Map<String, String> row : rows) { 411 if (key.equals(row.get("name"))) { 412 return row; 413 } 414 } 415 return null; 416 } 417 418 public static Set<String> getNames(List<Map<String, String>> rows) { 419 Set<String> answer = new LinkedHashSet<>(); 420 for (Map<String, String> row : rows) { 421 if (row.containsKey("name")) { 422 answer.add(row.get("name")); 423 } 424 } 425 return answer; 426 } 427 428}