View Javadoc
1   /*
2    * Portions of this software was developed by employees of the National Institute
3    * of Standards and Technology (NIST), an agency of the Federal Government and is
4    * being made available as a public service. Pursuant to title 17 United States
5    * Code Section 105, works of NIST employees are not subject to copyright
6    * protection in the United States. This software may be subject to foreign
7    * copyright. Permission in the United States and in foreign countries, to the
8    * extent that NIST may hold copyright, to use, copy, modify, create derivative
9    * works, and distribute this software and its documentation without fee is hereby
10   * granted on a non-exclusive basis, provided that this notice and disclaimer
11   * of warranty appears in all copies.
12   *
13   * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER
14   * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY
15   * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF
16   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM
17   * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE
18   * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE.  IN NO EVENT
19   * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT,
20   * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM,
21   * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY,
22   * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR
23   * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT
24   * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER.
25   */
26  
27  package gov.nist.secauto.metaschema.databind.model;
28  
29  import gov.nist.secauto.metaschema.core.model.INamedInstance;
30  import gov.nist.secauto.metaschema.core.util.ObjectUtils;
31  import gov.nist.secauto.metaschema.databind.io.BindingException;
32  
33  import java.lang.reflect.Field;
34  import java.lang.reflect.ParameterizedType;
35  import java.lang.reflect.Type;
36  import java.util.Map;
37  import java.util.Set;
38  
39  import javax.xml.namespace.QName;
40  
41  import edu.umd.cs.findbugs.annotations.NonNull;
42  import edu.umd.cs.findbugs.annotations.Nullable;
43  
44  public interface IBoundNamedInstance extends INamedInstance {
45  
46    @Override
47    default String getName() {
48      // delegate to the definition
49      return getDefinition().getName();
50    }
51  
52    @Override
53    default @NonNull Map<QName, Set<String>> getProperties() {
54      // TODO: implement
55      throw new UnsupportedOperationException();
56    }
57  
58    /**
59     * Get the {@link IClassBinding} for the Java class within which this property
60     * exists.
61     *
62     * @return the containing class's binding
63     */
64    @NonNull
65    IClassBinding getParentClassBinding();
66  
67    /**
68     * Gets the bound Java field associated with this property.
69     *
70     * @return the Java field
71     */
72    @NonNull
73    Field getField();
74  
75    @NonNull
76    default String getJavaFieldName() {
77      return ObjectUtils.notNull(getField().getName());
78    }
79  
80    /**
81     * Get the actual Java type of the underlying bound object.
82     * <p>
83     * This may be the same as the what is returned by {@link #getItemType()}, or
84     * may be a Java collection class.
85     *
86     * @return the raw type of the bound object
87     */
88    @SuppressWarnings("null")
89    @NonNull
90    default Type getType() {
91      return getField().getGenericType();
92    }
93  
94    /**
95     * Get the item type of the bound object. An item type is the primitive or
96     * specialized type that represents that data associated with this binding.
97     *
98     * @return the item type of the bound object
99     */
100   @NonNull
101   default Class<?> getItemType() {
102     return (Class<?>) getType();
103   }
104 
105   /**
106    * Get the current value from the provided {@code parentInstance} object. The
107    * provided object must be of the type associated with the definition containing
108    * this property.
109    *
110    * @param parentInstance
111    *          the object associated with the definition containing this property
112    * @return the value if available, or {@code null} otherwise
113    */
114   @Override
115   default Object getValue(@NonNull Object parentInstance) {
116     Field field = getField();
117     boolean accessable = field.canAccess(parentInstance);
118     field.setAccessible(true); // NOPMD - intentional
119     Object retval;
120     try {
121       Object result = field.get(parentInstance);
122       retval = result;
123     } catch (IllegalArgumentException | IllegalAccessException ex) {
124       throw new IllegalArgumentException(
125           String.format("Unable to get the value of field '%s' in class '%s'.", field.getName(),
126               field.getDeclaringClass().getName()),
127           ex);
128     } finally {
129       field.setAccessible(accessable); // NOPMD - intentional
130     }
131     return retval;
132   }
133 
134   /**
135    * Set the provided value on the provided object. The provided object must be of
136    * the item's type associated with this property.
137    *
138    * @param parentInstance
139    *          the object
140    * @param value
141    *          a value, which may be a simple {@link Type} or a
142    *          {@link ParameterizedType} for a collection
143    */
144   default void setValue(@NonNull Object parentInstance, Object value) {
145     Field field = getField();
146     boolean accessable = field.canAccess(parentInstance);
147     field.setAccessible(true); // NOPMD - intentional
148     try {
149       field.set(parentInstance, value);
150     } catch (IllegalArgumentException | IllegalAccessException ex) {
151       throw new IllegalArgumentException(
152           String.format(
153               "Unable to set the value of field '%s' in class '%s'. Perhaps this is a data type adapter problem on the declared class?",
154               field.getName(),
155               field.getDeclaringClass().getName()),
156           ex);
157     } finally {
158       field.setAccessible(accessable); // NOPMD - intentional
159     }
160   }
161 
162   @Nullable
163   Object defaultValue() throws BindingException;
164 
165   /**
166    * Copy this instance from one parent object to another.
167    *
168    * @param fromInstance
169    *          the object to copy from
170    * @param toInstance
171    *          the object to copy to
172    * @throws BindingException
173    *           if an error occurred while processing the object bindings
174    */
175   void copyBoundObject(@NonNull Object fromInstance, @NonNull Object toInstance) throws BindingException;
176 }