
001package ca.uhn.fhir.context; 002 003/* 004 * #%L 005 * HAPI FHIR - Core Library 006 * %% 007 * Copyright (C) 2014 - 2022 Smile CDR, Inc. 008 * %% 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 * #L% 021 */ 022 023import ca.uhn.fhir.i18n.Msg; 024import ca.uhn.fhir.model.api.annotation.Child; 025import ca.uhn.fhir.model.api.annotation.Description; 026import ca.uhn.fhir.util.ParametersUtil; 027import ca.uhn.fhir.util.ValidateUtil; 028import org.apache.commons.lang3.Validate; 029import org.hl7.fhir.instance.model.api.IBase; 030 031import java.lang.reflect.Field; 032import java.util.ArrayList; 033import java.util.Collections; 034import java.util.List; 035import java.util.Optional; 036 037public abstract class BaseRuntimeDeclaredChildDefinition extends BaseRuntimeChildDefinition { 038 private final IAccessor myAccessor; 039 private final String myElementName; 040 private final Field myField; 041 private final String myFormalDefinition; 042 private final int myMax; 043 private final int myMin; 044 private final IMutator myMutator; 045 private final String myShortDefinition; 046 private String myBindingValueSet; 047 private boolean myModifier; 048 private boolean mySummary; 049 050 BaseRuntimeDeclaredChildDefinition(Field theField, Child theChildAnnotation, Description theDescriptionAnnotation, String theElementName) throws ConfigurationException { 051 super(); 052 Validate.notNull(theField, "No field specified"); 053 ValidateUtil.isGreaterThanOrEqualTo(theChildAnnotation.min(), 0, "Min must be >= 0"); 054 Validate.isTrue(theChildAnnotation.max() == -1 || theChildAnnotation.max() >= theChildAnnotation.min(), "Max must be >= Min (unless it is -1 / unlimited)"); 055 Validate.notBlank(theElementName, "Element name must not be blank"); 056 057 myField = theField; 058 myMin = theChildAnnotation.min(); 059 myMax = theChildAnnotation.max(); 060 mySummary = theChildAnnotation.summary(); 061 myModifier = theChildAnnotation.modifier(); 062 myElementName = theElementName; 063 if (theDescriptionAnnotation != null) { 064 myShortDefinition = theDescriptionAnnotation.shortDefinition(); 065 myFormalDefinition = ParametersUtil.extractDescription(theDescriptionAnnotation); 066 } else { 067 myShortDefinition = null; 068 myFormalDefinition = null; 069 } 070 071 myField.setAccessible(true); 072 if (List.class.equals(myField.getType())) { 073 // TODO: verify that generic type is IElement 074 myAccessor = new FieldListAccessor(); 075 myMutator = new FieldListMutator(); 076 } else { 077 myAccessor = new FieldPlainAccessor(); 078 myMutator = new FieldPlainMutator(); 079 } 080 081 } 082 083 @Override 084 public IAccessor getAccessor() { 085 return myAccessor; 086 } 087 088 public String getBindingValueSet() { 089 return myBindingValueSet; 090 } 091 092 void setBindingValueSet(String theBindingValueSet) { 093 myBindingValueSet = theBindingValueSet; 094 } 095 096 @Override 097 public String getElementName() { 098 return myElementName; 099 } 100 101 public Field getField() { 102 return myField; 103 } 104 105 public String getFormalDefinition() { 106 return myFormalDefinition; 107 } 108 109 @Override 110 public int getMax() { 111 return myMax; 112 } 113 114 @Override 115 public int getMin() { 116 return myMin; 117 } 118 119 @Override 120 public IMutator getMutator() { 121 return myMutator; 122 } 123 124 public String getShortDefinition() { 125 return myShortDefinition; 126 } 127 128 public boolean isModifier() { 129 return myModifier; 130 } 131 132 protected void setModifier(boolean theModifier) { 133 myModifier = theModifier; 134 } 135 136 @Override 137 public boolean isSummary() { 138 return mySummary; 139 } 140 141 private final class FieldListAccessor implements IAccessor { 142 @SuppressWarnings("unchecked") 143 @Override 144 public List<IBase> getValues(IBase theTarget) { 145 List<IBase> retVal = (List<IBase>) getFieldValue(theTarget, myField); 146 if (retVal == null) { 147 retVal = Collections.emptyList(); 148 } 149 return retVal; 150 } 151 152 } 153 154 protected final class FieldListMutator implements IMutator { 155 @Override 156 public void addValue(IBase theTarget, IBase theValue) { 157 addValue(theTarget, theValue, false); 158 } 159 160 private void addValue(IBase theTarget, IBase theValue, boolean theClear) { 161 @SuppressWarnings("unchecked") 162 List<IBase> existingList = (List<IBase>) getFieldValue(theTarget, myField); 163 if (existingList == null) { 164 existingList = new ArrayList<>(2); 165 setFieldValue(theTarget, existingList, myField); 166 } 167 if (theClear) { 168 existingList.clear(); 169 if (theValue == null) { 170 return; 171 } 172 } 173 existingList.add(theValue); 174 } 175 176 @Override 177 public void setValue(IBase theTarget, IBase theValue) { 178 addValue(theTarget, theValue, true); 179 } 180 } 181 182 private final class FieldPlainAccessor implements IAccessor { 183 @Override 184 public List<IBase> getValues(IBase theTarget) { 185 Object values = getFieldValue(theTarget, myField); 186 if (values == null) { 187 return Collections.emptyList(); 188 } 189 return Collections.singletonList((IBase) values); 190 } 191 192 @Override 193 public <T extends IBase> Optional<T> getFirstValueOrNull(IBase theTarget) { 194 return Optional.ofNullable(((T)getFieldValue(theTarget, myField))); 195 } 196 } 197 198 protected final class FieldPlainMutator implements IMutator { 199 @Override 200 public void addValue(IBase theTarget, IBase theValue) { 201 setFieldValue(theTarget, theValue, myField); 202 } 203 204 @Override 205 public void setValue(IBase theTarget, IBase theValue) { 206 addValue(theTarget, theValue); 207 } 208 } 209 210 private static void setFieldValue(IBase theTarget, Object theValue, Field theField) { 211 try { 212 theField.set(theTarget, theValue); 213 } catch (IllegalAccessException e) { 214 throw new ConfigurationException(Msg.code(1736) + "Failed to set value", e); 215 } 216 } 217 218 private static Object getFieldValue(IBase theTarget, Field theField) { 219 try { 220 return theField.get(theTarget); 221 } catch (IllegalAccessException e) { 222 throw new ConfigurationException(Msg.code(1737) + "Failed to get value", e); 223 } 224 } 225 226}