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