/** * Copyright (c) 2013-2016 Angelo ZERR. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Angelo Zerr <angelo.zerr@gmail.com> - initial API and implementation */ package org.eclipse.json.impl.schema; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.eclipse.json.provisonnal.com.eclipsesource.json.JsonArray; import org.eclipse.json.provisonnal.com.eclipsesource.json.JsonObject; import org.eclipse.json.provisonnal.com.eclipsesource.json.JsonValue; import org.eclipse.json.schema.IJSONSchemaDocument; import org.eclipse.json.schema.IJSONSchemaNode; import org.eclipse.json.schema.IJSONSchemaProperty; import org.eclipse.json.schema.JSONSchemaType; @SuppressWarnings("serial") public class JSONSchemaNode extends JsonObject implements IJSONSchemaNode { private Map<String, JsonValue> definitions; private final IJSONSchemaNode parent; private final Map<String, IJSONSchemaProperty> properties; private JsonObject jsonObject; protected final String description; protected JSONSchemaType[] type; protected String defaultValue; private List<String> enumList; public JSONSchemaNode(JsonObject jsonObject, IJSONSchemaNode parent) { this.parent = parent; this.jsonObject = jsonObject; if (this instanceof IJSONSchemaDocument) { definitions = new HashMap<String, JsonValue>(); addDefinitions(); resolveReferences(jsonObject); } this.properties = new HashMap<String, IJSONSchemaProperty>(); walk(jsonObject, this); this.description = jsonObject.getString("description", null); //$NON-NLS-1$ this.type = getType(jsonObject.get(TYPE)); JsonValue value = jsonObject.get("default"); //$NON-NLS-1$ if (value != null) { defaultValue = removeQuote(value); } value = jsonObject.get(ENUM); if (value instanceof JsonArray) { JsonArray array = (JsonArray) value; List<JsonValue> items = array.values(); for (JsonValue v:items) { if (v != null) { if (type == null || type.length == 0) { String str = v.toString(); if (str.startsWith(QUOTE) && str.endsWith(QUOTE)) { type = new JSONSchemaType[] {JSONSchemaType.String}; } } addEnum(removeQuote(v)); } } } } private void resolveReferences(JsonObject json) { Iterator<Member> members = json.iterator(); while (members.hasNext()) { Member member = members.next(); JsonValue value = member.getValue(); resolveReferences(json, member.getName(), value); } } private void resolveReferences(JsonObject parent, String name, JsonValue value) { if (value instanceof JsonObject) { JsonObject json = value.asObject(); String ref = json.getString(REF, null); if (ref != null && ref.startsWith(DEFINITIONS)) { String r = ref.substring(DEFINITIONS.length()); JsonValue v = definitions.get(r); parent.set(name, v); //json.remove(REF); } else { Iterator<Member> members = json.iterator(); while (members.hasNext()) { Member member = members.next(); JsonValue v = member.getValue(); resolveReferences(json, member.getName(), v); } } } else if (value instanceof JsonArray) { JsonArray jsonArray = (JsonArray) value; for (int i = 0; i < jsonArray.size(); i++) { JsonValue item = jsonArray.get(i); if (item instanceof JsonObject) { JsonObject json = item.asObject(); String ref = json.getString(REF, null); if (ref != null && ref.startsWith(DEFINITIONS)) { String r = ref.substring(DEFINITIONS.length()); JsonValue v = definitions.get(r); jsonArray.set(i, v); } else { resolveReferences(json); } } } } } private void addDefinitions() { JsonValue defs = jsonObject.get("definitions"); //$NON-NLS-1$ if (defs instanceof JsonObject) { Iterator<Member> members = ((JsonObject) defs).iterator(); while (members.hasNext()) { Member member = members.next(); JsonValue value = member.getValue(); if (value instanceof JsonObject) { definitions.put(member.getName(), member.getValue()); } } } } private void walk(JsonObject json, IJSONSchemaNode schemaNode) { JsonObject properties = (JsonObject) json.get(PROPERTIES); addProperties(schemaNode, properties); add(json, schemaNode, ALL_OF); add(json, schemaNode, ANY_OF); add(json, schemaNode, ONE_OF); JsonValue notMember = json.get(NOT); if (notMember != null) { walk(notMember.asObject(), schemaNode); } } private void add(JsonObject jsonObject, IJSONSchemaNode schemaNode, String pref) { JsonValue values = jsonObject.get(pref); if (values instanceof JsonArray) { JsonArray array = (JsonArray) values; Iterator<JsonValue> iter = array.iterator(); while (iter.hasNext()) { JsonValue value = iter.next(); if (value != null) { walk(value.asObject(), schemaNode); } } } } private void addProperties(IJSONSchemaNode schemaNode, JsonObject properties) { if (properties == null) { return; } Iterator<Member> members = properties.iterator(); while (members.hasNext()) { Member member = members.next(); schemaNode .addProperty(new JSONSchemaProperty(member.getName(), (JsonObject) member.getValue(), schemaNode)); } } @Override public void addProperty(IJSONSchemaProperty property) { properties.put(property.getName(), property); } @Override public IJSONSchemaNode getParent() { return parent; } @Override public IJSONSchemaProperty[] getPropertyValues() { return properties.values().toArray(IJSONSchemaProperty.EMPTY_PROPERTY); } @Override public JsonObject getJsonObject() { return jsonObject; } @Override public void setJsonObject(JsonObject jsonObject) { this.jsonObject = jsonObject; } @Override public Map<String, IJSONSchemaProperty> getProperties() { return properties; } protected String[] getRequired(JsonValue value) { if (value == null) { return null; } List<String> names = new ArrayList<String>(); if (value.isString()) { String s = value.asString(); names.add(s); } else if (value.isArray()) { JsonArray array = (JsonArray) value; for (JsonValue item : array) { if (item.isString()) { String s = item.asString(); names.add(s); } } } return names.toArray(new String[0]); } protected String removeQuote(JsonValue value) { String str = value.toString(); if (str.startsWith(QUOTE)) { str = str.substring(1); } if (str.endsWith(QUOTE)) { str = str.substring(0, str.length()-1); } return str; } public static JSONSchemaType[] getType(JsonValue value) { if (value == null) { return JSONSchemaType.EMPTY_TYPES; } JSONSchemaType t = null; List<JSONSchemaType> types = new ArrayList<JSONSchemaType>(); if (value.isString()) { t = JSONSchemaType.getType(value.asString()); if (t != null) { types.add(t); } } else if (value.isArray()) { JsonArray array = (JsonArray) value; for (JsonValue item : array) { t = JSONSchemaType.getType(item.asString()); if (t != null) { types.add(t); } } } return types.toArray(JSONSchemaType.EMPTY_TYPES); } @Override public String getDescription() { return description; } @Override public JSONSchemaType[] getType() { return type; } @Override public JSONSchemaType getFirstType() { if (type == null) { return null; } if (type.length == 0) { return null; } return type[0]; } @Override public String getDefaultValue() { return defaultValue; } @Override public List<String> getEnumList() { return enumList; } public void addEnum(String item) { if (enumList == null) { enumList = new LinkedList<String>(); } this.enumList.add(item); } @Override public IJSONSchemaDocument getSchemaDocument() { if (this instanceof IJSONSchemaDocument) { return (IJSONSchemaDocument) this; } IJSONSchemaNode p = getParent(); if (p != null) { return p.getSchemaDocument(); } return null; } }