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 }