View Javadoc
1   /*
2    * (c) Copyright 2006-2020 by rapiddweller GmbH & Volker Bergmann. All rights reserved.
3    *
4    * Redistribution and use in source and binary forms, with or without
5    * modification, is permitted under the terms of the
6    * GNU General Public License.
7    *
8    * For redistributing this software or a derivative work under a license other
9    * than the GPL-compatible Free Software License as defined by the Free
10   * Software Foundation or approved by OSI, you must first obtain a commercial
11   * license to this software product from rapiddweller GmbH & Volker Bergmann.
12   *
13   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14   * WITHOUT A WARRANTY OF ANY KIND. ALL EXPRESS OR IMPLIED CONDITIONS,
15   * REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF
16   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE
17   * HEREBY EXCLUDED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24   * POSSIBILITY OF SUCH DAMAGE.
25   */
26  
27  package com.rapiddweller.model.data;
28  
29  import com.rapiddweller.common.ConfigurationError;
30  import com.rapiddweller.platform.java.BeanDescriptorProvider;
31  import com.rapiddweller.script.PrimitiveType;
32  import org.apache.logging.log4j.LogManager;
33  import org.apache.logging.log4j.Logger;
34  
35  import java.util.HashMap;
36  import java.util.Map;
37  
38  /**
39   * Merges and organizes entity definitions of different systems.<br/><br/>
40   * Created: 25.08.2007 20:40:17
41   *
42   * @author Volker Bergmann
43   * @since 0.3
44   */
45  public class DataModel {
46  
47    private final Logger logger = LogManager.getLogger(DataModel.class);
48  
49    private final Map<String, DescriptorProvider> providers;
50  
51    private boolean acceptUnknownPrimitives;
52  
53    /**
54     * Instantiates a new Data model.
55     */
56    public DataModel() {
57      this.acceptUnknownPrimitives = false;
58      this.providers = new HashMap<>();
59      new PrimitiveDescriptorProvider(this);
60      new BeanDescriptorProvider(this);
61    }
62  
63    private static TypeDescriptor searchCaseInsensitive(
64        DescriptorProvider provider, String name) {
65      for (TypeDescriptor type : provider.getTypeDescriptors()) {
66        if (type.getName().equals(name)) {
67          return type;
68        }
69      }
70      return null;
71    }
72  
73    /**
74     * Sets accept unknown primitives.
75     *
76     * @param acceptUnknownPrimitives the accept unknown primitives
77     */
78    public void setAcceptUnknownPrimitives(boolean acceptUnknownPrimitives) {
79      this.acceptUnknownPrimitives = acceptUnknownPrimitives;
80    }
81  
82    /**
83     * Add descriptor provider.
84     *
85     * @param provider the provider
86     */
87    public void addDescriptorProvider(DescriptorProvider provider) {
88      addDescriptorProvider(provider, true);
89    }
90  
91    /**
92     * Add descriptor provider.
93     *
94     * @param provider the provider
95     * @param validate the validate
96     */
97    public void addDescriptorProvider(DescriptorProvider provider,
98                                      boolean validate) {
99      providers.put(provider.getId(), provider);
100     provider.setDataModel(this);
101     if (validate) {
102       validate();
103     }
104   }
105 
106   /**
107    * Gets descriptor provider.
108    *
109    * @param id the id
110    * @return the descriptor provider
111    */
112   public DescriptorProvider getDescriptorProvider(String id) {
113     return providers.get(id);
114   }
115 
116   /**
117    * Remove descriptor provider.
118    *
119    * @param id the id
120    */
121   public void removeDescriptorProvider(String id) {
122     providers.remove(id);
123   }
124 
125   /**
126    * Gets type descriptor.
127    *
128    * @param typeId the type id
129    * @return the type descriptor
130    */
131   public TypeDescriptor getTypeDescriptor(String typeId) {
132     if (typeId == null) {
133       return null;
134     }
135     String namespace = null;
136     String name = typeId;
137     if (typeId.contains(":")) {
138       int i = typeId.indexOf(':');
139       namespace = typeId.substring(0, i);
140       name = typeId.substring(i + 1);
141     }
142     return getTypeDescriptor(namespace, name);
143   }
144 
145   /**
146    * Gets type descriptor.
147    *
148    * @param namespace the namespace
149    * @param name      the name
150    * @return the type descriptor
151    */
152   public TypeDescriptor getTypeDescriptor(String namespace, String name) {
153     if (name == null) {
154       return null;
155     }
156     if (namespace != null) {
157       DescriptorProvider provider = providers.get(namespace);
158       if (provider != null) {
159         // first, search case-sensitive
160         TypeDescriptor typeDescriptor =
161             provider.getTypeDescriptor(name);
162         if (typeDescriptor != null) {
163           return typeDescriptor;
164         } else {
165           // not found yet, try it case-insensitive
166           return searchCaseInsensitive(provider, name);
167         }
168       }
169     }
170     // first, search case-sensitive
171     for (DescriptorProvider provider : providers.values()) {
172       TypeDescriptor descriptor = provider.getTypeDescriptor(name);
173       if (descriptor != null) {
174         return descriptor;
175       }
176     }
177     // not found yet, try it case-insensitive
178     for (DescriptorProvider provider : providers.values()) {
179       TypeDescriptor descriptor = searchCaseInsensitive(provider, name);
180       if (descriptor != null) {
181         return descriptor;
182       }
183     }
184     return null;
185   }
186 
187   // private helpers -------------------------------------------------------------------------------------------------
188 
189   /**
190    * Validate.
191    */
192   public void validate() {
193     for (DescriptorProvider provider : providers.values()) {
194       for (TypeDescriptor desc : provider.getTypeDescriptors()) {
195         validate(desc);
196       }
197     }
198   }
199 
200   private void validate(TypeDescriptor type) {
201     logger.debug("validating " + type);
202     if (type instanceof SimpleTypeDescriptor) {
203       validate((SimpleTypeDescriptor) type);
204     } else if (type instanceof ComplexTypeDescriptor) {
205       validate((ComplexTypeDescriptor) type);
206     } else if (type instanceof ArrayTypeDescriptor) {
207       validate((ArrayTypeDescriptor) type);
208     } else {
209       throw new UnsupportedOperationException(
210           "Descriptor type not supported: " + type.getClass());
211     }
212   }
213 
214   private void validate(SimpleTypeDescriptor desc) {
215     PrimitiveType primitiveType = desc.getPrimitiveType();
216     if (primitiveType == null && !acceptUnknownPrimitives) {
217       throw new ConfigurationError(
218           "No primitive type defined for simple type: " +
219               desc.getName());
220     }
221   }
222 
223   private void validate(ComplexTypeDescriptor desc) {
224     for (ComponentDescriptor component : desc.getComponents()) {
225       TypeDescriptor type = component.getTypeDescriptor();
226       if (type == null) {
227         throw new ConfigurationError(
228             "Type of component is not defined: " + desc.getName());
229       } else if (!(type instanceof ComplexTypeDescriptor)) {
230         validate(type);
231       }
232     }
233   }
234 
235   private void validate(ArrayTypeDescriptor desc) {
236     for (ArrayElementDescriptor element : desc.getElements()) {
237       TypeDescriptor type = element.getTypeDescriptor();
238       if (!(type instanceof ComplexTypeDescriptor)) {
239         validate(type);
240       }
241     }
242   }
243 
244   /**
245    * Gets primitive type descriptor.
246    *
247    * @param javaType the java type
248    * @return the primitive type descriptor
249    */
250   public SimpleTypeDescriptor getPrimitiveTypeDescriptor(Class<?> javaType) {
251     PrimitiveDescriptorProvider primitiveProvider =
252         (PrimitiveDescriptorProvider) providers
253             .get(PrimitiveDescriptorProvider.NAMESPACE);
254     return primitiveProvider.getPrimitiveTypeDescriptor(javaType);
255   }
256 
257   /**
258    * Gets bean descriptor provider.
259    *
260    * @return the bean descriptor provider
261    */
262   public BeanDescriptorProvider getBeanDescriptorProvider() {
263     return (BeanDescriptorProvider) providers
264         .get(BeanDescriptorProvider.NAMESPACE);
265   }
266 
267 }