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