View Javadoc
1   package ca.uhn.fhir.context;
2   
3   /*
4    * #%L
5    * HAPI FHIR - Core Library
6    * %%
7    * Copyright (C) 2014 - 2018 University Health Network
8    * %%
9    * Licensed under the Apache License, Version 2.0 (the "License");
10   * you may not use this file except in compliance with the License.
11   * You may obtain a copy of the License at
12   * 
13   *      http://www.apache.org/licenses/LICENSE-2.0
14   * 
15   * Unless required by applicable law or agreed to in writing, software
16   * distributed under the License is distributed on an "AS IS" BASIS,
17   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18   * See the License for the specific language governing permissions and
19   * limitations under the License.
20   * #L%
21   */
22  
23  import java.lang.reflect.Field;
24  import java.util.ArrayList;
25  import java.util.Collections;
26  import java.util.List;
27  
28  import org.apache.commons.lang3.Validate;
29  import org.hl7.fhir.instance.model.api.IBase;
30  
31  import ca.uhn.fhir.model.api.annotation.Child;
32  import ca.uhn.fhir.model.api.annotation.Description;
33  import ca.uhn.fhir.util.ValidateUtil;
34  
35  public abstract class BaseRuntimeDeclaredChildDefinition extends BaseRuntimeChildDefinition {
36  	private final IAccessor myAccessor;
37  	private String myBindingValueSet;
38  	private final String myElementName;
39  	private final Field myField;
40  	private final String myFormalDefinition;
41  	private final int myMax;
42  	private final int myMin;
43  	private boolean myModifier;
44  
45  	private final IMutator myMutator;
46  	private final String myShortDefinition;
47  	private boolean mySummary;
48  	BaseRuntimeDeclaredChildDefinition(Field theField, Child theChildAnnotation, Description theDescriptionAnnotation, String theElementName) throws ConfigurationException {
49  		super();
50  		Validate.notNull(theField, "No field speficied");
51  		ValidateUtil.isGreaterThanOrEqualTo(theChildAnnotation.min(), 0, "Min must be >= 0");
52  		Validate.isTrue(theChildAnnotation.max() == -1 || theChildAnnotation.max() >= theChildAnnotation.min(), "Max must be >= Min (unless it is -1 / unlimited)");
53  		Validate.notBlank(theElementName, "Element name must not be blank");
54  
55  		myField = theField;
56  		myMin = theChildAnnotation.min();
57  		myMax = theChildAnnotation.max();
58  		mySummary = theChildAnnotation.summary();
59  		myModifier = theChildAnnotation.modifier();
60  		myElementName = theElementName;
61  		if (theDescriptionAnnotation != null) {
62  			myShortDefinition = theDescriptionAnnotation.shortDefinition();
63  			myFormalDefinition = theDescriptionAnnotation.formalDefinition();
64  		} else {
65  			myShortDefinition = null;
66  			myFormalDefinition = null;
67  		}
68  
69  		myField.setAccessible(true);
70  		if (List.class.equals(myField.getType())) {
71  			// TODO: verify that generic type is IElement
72  			myAccessor = new FieldListAccessor();
73  			myMutator = new FieldListMutator();
74  		} else {
75  			myAccessor = new FieldPlainAccessor();
76  			myMutator = new FieldPlainMutator();
77  		}
78  
79  	}
80  
81  	@Override
82  	public IAccessor getAccessor() {
83  		return myAccessor;
84  	}
85  
86  	public String getBindingValueSet() {
87  		return myBindingValueSet;
88  	}
89  
90  	@Override
91  	public String getElementName() {
92  		return myElementName;
93  	}
94  
95  	public Field getField() {
96  		return myField;
97  	}
98  
99  	public String getFormalDefinition() {
100 		return myFormalDefinition;
101 	}
102 
103 	@Override
104 	public int getMax() {
105 		return myMax;
106 	}
107 
108 	@Override
109 	public int getMin() {
110 		return myMin;
111 	}
112 
113 	@Override
114 	public IMutator getMutator() {
115 		return myMutator;
116 	}
117 
118 	public String getShortDefinition() {
119 		return myShortDefinition;
120 	}
121 
122 	public BaseRuntimeElementDefinition<?> getSingleChildOrThrow() {
123 		if (getValidChildNames().size() != 1) {
124 			throw new IllegalStateException("This child has " + getValidChildNames().size() + " children, expected 1. This is a HAPI bug. Found: " + getValidChildNames());
125 		}
126 		return getChildByName(getValidChildNames().iterator().next());
127 	}
128 
129 	public boolean isModifier() {
130 		return myModifier;
131 	}
132 
133 	@Override
134 	public boolean isSummary() {
135 		return mySummary;
136 	}
137 
138 	void setBindingValueSet(String theBindingValueSet) {
139 		myBindingValueSet = theBindingValueSet;
140 	}
141 
142 	protected void setModifier(boolean theModifier) {
143 		myModifier = theModifier;
144 	}
145 
146 	private final class FieldListAccessor implements IAccessor {
147 		@SuppressWarnings("unchecked")
148 		@Override
149 		public List<IBase> getValues(Object theTarget) {
150 			List<IBase> retVal;
151 			try {
152 				retVal = (List<IBase>) myField.get(theTarget);
153 			} catch (Exception e) {
154 				throw new ConfigurationException("Failed to get value", e);
155 			}
156 			
157 			if (retVal == null) {
158 				retVal = Collections.emptyList();
159 			}
160 			return retVal;
161 		}
162 	}
163 
164 	protected final class FieldListMutator implements IMutator {
165 		@Override
166 		public void addValue(Object theTarget, IBase theValue) {
167 			addValue(theTarget, theValue, false);
168 		}
169 
170 		private void addValue(Object theTarget, IBase theValue, boolean theClear) {
171 			try {
172 				@SuppressWarnings("unchecked")
173 				List<IBase> existingList = (List<IBase>) myField.get(theTarget);
174 				if (existingList == null) {
175 					existingList = new ArrayList<IBase>(2);
176 					myField.set(theTarget, existingList);
177 				}
178 				if (theClear) {
179 					existingList.clear();
180 				}
181 				existingList.add(theValue);
182 			} catch (Exception e) {
183 				throw new ConfigurationException("Failed to set value", e);
184 			}
185 		}
186 
187 		@Override
188 		public void setValue(Object theTarget, IBase theValue) {
189 			addValue(theTarget, theValue, true);
190 		}
191 	}
192 
193 	private final class FieldPlainAccessor implements IAccessor {
194 		@Override
195 		public List<IBase> getValues(Object theTarget) {
196 			try {
197 				Object values = myField.get(theTarget);
198 				if (values == null) {
199 					return Collections.emptyList();
200 				}
201 				List<IBase> retVal = Collections.singletonList((IBase) values);
202 				return retVal;
203 			} catch (Exception e) {
204 				throw new ConfigurationException("Failed to get value", e);
205 			}
206 		}
207 	}
208 
209 	protected final class FieldPlainMutator implements IMutator {
210 		@Override
211 		public void addValue(Object theTarget, IBase theValue) {
212 			try {
213 				myField.set(theTarget, theValue);
214 			} catch (Exception e) {
215 				throw new ConfigurationException("Failed to set value", e);
216 			}
217 		}
218 
219 		@Override
220 		public void setValue(Object theTarget, IBase theValue) {
221 			addValue(theTarget, theValue);
222 		}
223 	}
224 
225 }