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