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; 025import java.util.regex.Matcher; 026import java.util.regex.Pattern; 027 028public final class JSonSchemaHelper { 029 030 // 0 = text, 1 = enum, 2 = boolean, 3 = integer or number 031 private static final Pattern PATTERN = Pattern.compile("\"(.+?)\"|\\[(.+)\\]|(true|false)|(-?\\d+\\.?\\d*)"); 032 private static final String QUOT = """; 033 034 private JSonSchemaHelper() { 035 } 036 037 /** 038 * Parses the json schema to split it into a list or rows, where each row contains key value pairs with the metadata 039 * 040 * @param group the group to parse from such as <tt>component</tt>, <tt>componentProperties</tt>, or <tt>properties</tt>. 041 * @param json the json 042 * @return a list of all the rows, where each row is a set of key value pairs with metadata 043 */ 044 public static List<Map<String, String>> parseJsonSchema(String group, String json, boolean parseProperties) { 045 List<Map<String, String>> answer = new ArrayList<Map<String, String>>(); 046 if (json == null) { 047 return answer; 048 } 049 050 boolean found = false; 051 052 // parse line by line 053 String[] lines = json.split("\n"); 054 for (String line : lines) { 055 // we need to find the group first 056 if (!found) { 057 String s = line.trim(); 058 found = s.startsWith("\"" + group + "\":") && s.endsWith("{"); 059 continue; 060 } 061 062 // we should stop when we end the group 063 if (line.equals(" },") || line.equals(" }")) { 064 break; 065 } 066 067 // need to safe encode \" so we can parse the line 068 line = line.replaceAll("\"\\\\\"\"", '"' + QUOT + '"'); 069 070 Map<String, String> row = new LinkedHashMap<String, String>(); 071 Matcher matcher = PATTERN.matcher(line); 072 073 String key; 074 if (parseProperties) { 075 // when parsing properties the first key is given as name, so the first parsed token is the value of the name 076 key = "name"; 077 } else { 078 key = null; 079 } 080 while (matcher.find()) { 081 if (key == null) { 082 key = matcher.group(1); 083 } else { 084 String value = matcher.group(1); 085 if (value != null) { 086 // its text based 087 value = value.trim(); 088 // decode 089 value = value.replaceAll(QUOT, "\""); 090 value = decodeJson(value); 091 } 092 if (value == null) { 093 // not text then its maybe an enum? 094 value = matcher.group(2); 095 if (value != null) { 096 // its an enum so strip out " and trim spaces after comma 097 value = value.replaceAll("\"", ""); 098 value = value.replaceAll(", ", ","); 099 value = value.trim(); 100 } 101 } 102 if (value == null) { 103 // not text then its maybe a boolean? 104 value = matcher.group(3); 105 } 106 if (value == null) { 107 // not text then its maybe a integer? 108 value = matcher.group(4); 109 } 110 if (value != null) { 111 row.put(key, value); 112 } 113 // reset 114 key = null; 115 } 116 } 117 if (!row.isEmpty()) { 118 answer.add(row); 119 } 120 } 121 122 return answer; 123 } 124 125 private static String decodeJson(String value) { 126 // json encodes a \ as \\ so we need to decode from \\ back to \ 127 if ("\\\\".equals(value)) { 128 value = "\\"; 129 } 130 return value; 131 } 132 133 public static boolean isComponentLenientProperties(List<Map<String, String>> rows) { 134 for (Map<String, String> row : rows) { 135 if (row.containsKey("lenientProperties")) { 136 return "true".equals(row.get("lenientProperties")); 137 } 138 } 139 return false; 140 } 141 142 public static boolean isComponentConsumerOnly(List<Map<String, String>> rows) { 143 for (Map<String, String> row : rows) { 144 if (row.containsKey("consumerOnly")) { 145 return "true".equals(row.get("consumerOnly")); 146 } 147 } 148 return false; 149 } 150 151 public static boolean isComponentProducerOnly(List<Map<String, String>> rows) { 152 for (Map<String, String> row : rows) { 153 if (row.containsKey("producerOnly")) { 154 return "true".equals(row.get("producerOnly")); 155 } 156 } 157 return false; 158 } 159 160 public static boolean isPropertyConsumerOnly(List<Map<String, String>> rows, String name) { 161 for (Map<String, String> row : rows) { 162 String labels = null; 163 boolean found = false; 164 if (row.containsKey("name")) { 165 found = name.equals(row.get("name")); 166 } 167 if (row.containsKey("label")) { 168 labels = row.get("label"); 169 } 170 if (found) { 171 return labels != null && labels.contains("consumer"); 172 } 173 } 174 return false; 175 } 176 177 public static boolean isPropertyProducerOnly(List<Map<String, String>> rows, String name) { 178 for (Map<String, String> row : rows) { 179 String labels = null; 180 boolean found = false; 181 if (row.containsKey("name")) { 182 found = name.equals(row.get("name")); 183 } 184 if (row.containsKey("label")) { 185 labels = row.get("label"); 186 } 187 if (found) { 188 return labels != null && labels.contains("producer"); 189 } 190 } 191 return false; 192 } 193 194 public static boolean isPropertyRequired(List<Map<String, String>> rows, String name) { 195 for (Map<String, String> row : rows) { 196 boolean required = false; 197 boolean found = false; 198 if (row.containsKey("name")) { 199 found = name.equals(row.get("name")); 200 } 201 if (row.containsKey("required")) { 202 required = "true".equals(row.get("required")); 203 } 204 if (found) { 205 return required; 206 } 207 } 208 return false; 209 } 210 211 public static String getPropertyKind(List<Map<String, String>> rows, String name) { 212 for (Map<String, String> row : rows) { 213 String kind = null; 214 boolean found = false; 215 if (row.containsKey("name")) { 216 found = name.equals(row.get("name")); 217 } 218 if (row.containsKey("kind")) { 219 kind = row.get("kind"); 220 } 221 if (found) { 222 return kind; 223 } 224 } 225 return null; 226 } 227 228 public static boolean isPropertyBoolean(List<Map<String, String>> rows, String name) { 229 for (Map<String, String> row : rows) { 230 String type = null; 231 boolean found = false; 232 if (row.containsKey("name")) { 233 found = name.equals(row.get("name")); 234 } 235 if (row.containsKey("type")) { 236 type = row.get("type"); 237 } 238 if (found) { 239 return "boolean".equals(type); 240 } 241 } 242 return false; 243 } 244 245 public static boolean isPropertyInteger(List<Map<String, String>> rows, String name) { 246 for (Map<String, String> row : rows) { 247 String type = null; 248 boolean found = false; 249 if (row.containsKey("name")) { 250 found = name.equals(row.get("name")); 251 } 252 if (row.containsKey("type")) { 253 type = row.get("type"); 254 } 255 if (found) { 256 return "integer".equals(type); 257 } 258 } 259 return false; 260 } 261 262 public static boolean isPropertyNumber(List<Map<String, String>> rows, String name) { 263 for (Map<String, String> row : rows) { 264 String type = null; 265 boolean found = false; 266 if (row.containsKey("name")) { 267 found = name.equals(row.get("name")); 268 } 269 if (row.containsKey("type")) { 270 type = row.get("type"); 271 } 272 if (found) { 273 return "number".equals(type); 274 } 275 } 276 return false; 277 } 278 279 public static boolean isPropertyObject(List<Map<String, String>> rows, String name) { 280 for (Map<String, String> row : rows) { 281 String type = null; 282 boolean found = false; 283 if (row.containsKey("name")) { 284 found = name.equals(row.get("name")); 285 } 286 if (row.containsKey("type")) { 287 type = row.get("type"); 288 } 289 if (found) { 290 return "object".equals(type); 291 } 292 } 293 return false; 294 } 295 296 public static String getPropertyDefaultValue(List<Map<String, String>> rows, String name) { 297 for (Map<String, String> row : rows) { 298 String defaultValue = null; 299 boolean found = false; 300 if (row.containsKey("name")) { 301 found = name.equals(row.get("name")); 302 } 303 if (row.containsKey("defaultValue")) { 304 defaultValue = row.get("defaultValue"); 305 } 306 if (found) { 307 return defaultValue; 308 } 309 } 310 return null; 311 } 312 313 public static String stripOptionalPrefixFromName(List<Map<String, String>> rows, String name) { 314 for (Map<String, String> row : rows) { 315 String optionalPrefix = null; 316 boolean found = false; 317 if (row.containsKey("optionalPrefix")) { 318 optionalPrefix = row.get("optionalPrefix"); 319 } 320 if (row.containsKey("name")) { 321 if (optionalPrefix != null && name.startsWith(optionalPrefix)) { 322 name = name.substring(optionalPrefix.length()); 323 // try again 324 return stripOptionalPrefixFromName(rows, name); 325 } else { 326 found = name.equals(row.get("name")); 327 } 328 } 329 if (found) { 330 return name; 331 } 332 } 333 return name; 334 } 335 336 public static String getPropertyEnum(List<Map<String, String>> rows, String name) { 337 for (Map<String, String> row : rows) { 338 String enums = null; 339 boolean found = false; 340 if (row.containsKey("name")) { 341 found = name.equals(row.get("name")); 342 } 343 if (row.containsKey("enum")) { 344 enums = row.get("enum"); 345 } 346 if (found) { 347 return enums; 348 } 349 } 350 return null; 351 } 352 353 public static String getPropertyPrefix(List<Map<String, String>> rows, String name) { 354 for (Map<String, String> row : rows) { 355 String prefix = null; 356 boolean found = false; 357 if (row.containsKey("name")) { 358 found = name.equals(row.get("name")); 359 } 360 if (row.containsKey("prefix")) { 361 prefix = row.get("prefix"); 362 } 363 if (found) { 364 return prefix; 365 } 366 } 367 return null; 368 } 369 370 public static boolean isPropertyMultiValue(List<Map<String, String>> rows, String name) { 371 for (Map<String, String> row : rows) { 372 boolean multiValue = false; 373 boolean found = false; 374 if (row.containsKey("name")) { 375 found = name.equals(row.get("name")); 376 } 377 if (row.containsKey("multiValue")) { 378 multiValue = "true".equals(row.get("multiValue")); 379 } 380 if (found) { 381 return multiValue; 382 } 383 } 384 return false; 385 } 386 387 public static String getPropertyNameFromNameWithPrefix(List<Map<String, String>> rows, String name) { 388 for (Map<String, String> row : rows) { 389 String propertyName = null; 390 boolean found = false; 391 if (row.containsKey("name")) { 392 propertyName = row.get("name"); 393 } 394 if (row.containsKey("prefix")) { 395 String preifx = row.get("prefix"); 396 found = name.startsWith(preifx); 397 } 398 if (found) { 399 return propertyName; 400 } 401 } 402 return null; 403 } 404 405 public static Map<String, String> getRow(List<Map<String, String>> rows, String key) { 406 for (Map<String, String> row : rows) { 407 if (key.equals(row.get("name"))) { 408 return row; 409 } 410 } 411 return null; 412 } 413 414 public static Set<String> getNames(List<Map<String, String>> rows) { 415 Set<String> answer = new LinkedHashSet<String>(); 416 for (Map<String, String> row : rows) { 417 if (row.containsKey("name")) { 418 answer.add(row.get("name")); 419 } 420 } 421 return answer; 422 } 423 424}