001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.dto.jsonschema; 014 015import static org.apache.juneau.internal.StringUtils.*; 016import java.io.*; 017import java.net.*; 018import java.util.concurrent.*; 019 020import org.apache.juneau.*; 021import org.apache.juneau.json.*; 022 023/** 024 * A container for retrieving JSON {@link Schema} objects by URI. 025 * 026 * <p> 027 * Subclasses must implement one of the following methods to load schemas from external sources: 028 * <ul class='spaced-list'> 029 * <li> 030 * {@link #getReader(URI)} - If schemas should be loaded from readers and automatically parsed. 031 * <li> 032 * {@link #load(URI)} - If you want control over construction of {@link Schema} objects. 033 * </ul> 034 * 035 * <h5 class='section'>See Also:</h5> 036 * <ul class='doctree'> 037 * <li class='jp'><a class='doclink' href='package-summary.html#TOC'>org.apache.juneau.dto.jsonschema</a> 038 * </ul> 039 */ 040public abstract class SchemaMap extends ConcurrentHashMap<URI,Schema> { 041 042 private static final long serialVersionUID = 1L; 043 044 /** 045 * Return the {@link Schema} object at the specified URI. 046 * 047 * <p> 048 * If this schema object has not been loaded yet, calls {@link #load(URI)}. 049 * 050 * <p> 051 * The value can be of any of the following types: {@link URI}, {@link URL}, {@link String}. 052 * Strings must be valid URIs. 053 * 054 * <p> 055 * URIs defined by {@link UriResolver} can be used for values. 056 * 057 * @param uri The URI of the schema to retrieve. 058 * @return The Schema, or <jk>null</jk> if schema was not located and could not be loaded. 059 */ 060 @Override /* Map */ 061 public Schema get(Object uri) { 062 URI u = toURI(uri); 063 Schema s = super.get(u); 064 if (s != null) 065 return s; 066 synchronized(this) { 067 s = load(u); 068 if (s != null) { 069 // Note: Can't use add(Schema...) since the ID property may not be set. 070 s.setSchemaMap(this); 071 put(u, s); 072 } 073 return s; 074 } 075 } 076 077 /** 078 * Convenience method for pre-populating this map with the specified schemas. 079 * 080 * <p> 081 * The schemas passed in through this method MUST have their ID properties set. 082 * 083 * @param schemas The set of schemas to add to this map. 084 * @return This object (for method chaining). 085 * @throws RuntimeException If one or more schema objects did not have their ID property set. 086 */ 087 public SchemaMap add(Schema...schemas) { 088 for (Schema schema : schemas) { 089 if (schema.getId() == null) 090 throw new RuntimeException("Schema with no ID passed to SchemaMap.add(Schema...)"); 091 put(schema.getId(), schema); 092 schema.setSchemaMap(this); 093 } 094 return this; 095 } 096 097 /** 098 * Subclasses must implement either this method or {@link #getReader(URI)} to load the schema with the specified URI. 099 * 100 * <p> 101 * It's up to the implementer to decide where these come from. 102 * 103 * <p> 104 * The default implementation calls {@link #getReader(URI)} and parses the schema document. 105 * If {@link #getReader(URI)} returns <jk>null</jk>, this method returns <jk>null</jk> indicating this is an 106 * unreachable document. 107 * 108 * @param uri The URI to load the schema from. 109 * @return The parsed schema. 110 */ 111 public Schema load(URI uri) { 112 try (Reader r = getReader(uri)) { 113 if (r == null) 114 return null; 115 return JsonParser.DEFAULT.parse(r, Schema.class); 116 } catch (Exception e) { 117 throw new RuntimeException(e); 118 } 119 } 120 121 /** 122 * Subclasses must implement either this method or {@link #load(URI)} to load the schema with the specified URI. 123 * 124 * <p> 125 * It's up to the implementer to decide where these come from. 126 * 127 * <p> 128 * The default implementation returns <jk>null</jk>. 129 * 130 * @param uri The URI to connect to and retrieve the contents. 131 * @return The reader from reading the specified URI. 132 */ 133 public Reader getReader(URI uri) { 134 return null; 135 } 136}