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