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.juneau.bean.openapi3;
018
019import static org.apache.juneau.commons.utils.AssertionUtils.*;
020import static org.apache.juneau.commons.utils.CollectionUtils.*;
021import static org.apache.juneau.commons.utils.ThrowableUtils.*;
022import static org.apache.juneau.commons.utils.Utils.*;
023import static org.apache.juneau.internal.ConverterUtils.*;
024
025import java.util.*;
026
027import org.apache.juneau.annotation.*;
028import org.apache.juneau.collections.*;
029import org.apache.juneau.json.*;
030
031/**
032 * Root class for all Swagger beans.
033 */
034@Bean
035public abstract class OpenApiElement {
036
037   private boolean strict;
038   private Map<String,Object> extra;
039
040   OpenApiElement() {}
041
042   OpenApiElement(OpenApiElement copyFrom) {
043      this.strict = copyFrom.strict;
044      this.extra = copyOf(copyFrom.extra);
045   }
046
047   /**
048    * Returns a copy of this swagger element as a modifiable map.
049    *
050    * <p>
051    * Each call produces a new map.
052    *
053    * @return A map containing all the values in this swagger element.
054    */
055   public JsonMap asMap() {
056      var m = new JsonMap();
057      for (var s : keySet())
058         m.put(s, get(s, Object.class));
059      return m;
060   }
061
062   /**
063    * Generic property keyset.
064    *
065    * @return
066    *    All the non-standard keys on this element.
067    *    <br>Never <jk>null</jk>.
068    */
069   @Beanp("*")
070   public Set<String> extraKeys() {
071      return extra == null ? Collections.emptySet() : extra.keySet();
072   }
073
074   /**
075    * Generic property getter.
076    *
077    * <p>
078    * Can be used to retrieve non-standard Swagger fields such as <js>"$ref"</js>.
079    *
080    * @param property The property name to retrieve.  Must not be <jk>null</jk>.
081    * @return The property value, or <jk>null</jk> if the property does not exist or is not set.
082    */
083   @Beanp("*")
084   public Object get(String property) {
085      assertArgNotNull("property", property);
086      return opt(extra).map(x -> x.get(property)).orElse(null);
087   }
088
089   /**
090    * Generic property getter.
091    *
092    * <p>
093    * Can be used to retrieve non-standard Swagger fields such as <js>"$ref"</js>.
094    *
095    * @param property The property name to retrieve.
096    * @param type The datatype to cast the value to.
097    * @param <T> The datatype to cast the value to.
098    * @return The property value, or <jk>null</jk> if the property does not exist or is not set.
099    */
100   public <T> T get(String property, Class<T> type) {
101      assertArgNotNull("property", property);
102      return toType(get(property), type);
103   }
104
105   /**
106    * Returns all the keys on this element.
107    *
108    * @return
109    *    All the keys on this element.
110    *    <br>Never <jk>null</jk>.
111    */
112   public Set<String> keySet() {
113      return extraKeys();
114   }
115
116   /**
117    * Generic property setter.
118    *
119    * <p>
120    * Can be used to set non-standard Swagger fields such as <js>"$ref"</js>.
121    *
122    * @param property The property name to set.  Must not be <jk>null</jk>.
123    * @param value The new value for the property.
124    * @return This object
125    * @throws RuntimeException if strict mode is enabled.
126    */
127   @Beanp("*")
128   public OpenApiElement set(String property, Object value) {
129      assertArgNotNull("property", property);
130      if (strict)
131         throw rex("Cannot set property ''{0}'' in strict mode.", property);
132      if (extra == null)
133         extra = map();
134      extra.put(property, value);
135      return this;
136   }
137
138   @Override /* Overridden from Object */
139   public String toString() {
140      return JsonSerializer.DEFAULT_SORTED.toString(this);
141   }
142
143   /**
144    * Returns <jk>true</jk> if contents should be validated per the Swagger spec.
145    *
146    * @return <jk>true</jk> if contents should be validated per the Swagger spec.
147    */
148   protected boolean isStrict() { return strict; }
149
150   /**
151    * Sets strict mode on this bean.
152    *
153    * @return This object
154    */
155   protected OpenApiElement strict() {
156      strict = true;
157      return this;
158   }
159
160   /**
161    * Sets strict mode on this bean.
162    *
163    * @param value
164    *    The new value for this property.
165    *    <br>Non-boolean values will be converted to boolean using <code>Boolean.<jsm>valueOf</jsm>(value.toString())</code>.
166    *    <br>Can be <jk>null</jk> (interpreted as <jk>false</jk>).
167    * @return This object
168    */
169   protected OpenApiElement strict(Object value) {
170      strict = nn(value) && toBoolean(value);
171      return this;
172   }
173}