001package ca.uhn.fhir.context; 002 003/* 004 * #%L 005 * HAPI FHIR - Core Library 006 * %% 007 * Copyright (C) 2014 - 2019 University Health Network 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 java.lang.reflect.Field; 024import java.util.ArrayList; 025import java.util.Collections; 026import java.util.List; 027 028import org.apache.commons.lang3.Validate; 029import org.hl7.fhir.instance.model.api.IBase; 030 031import ca.uhn.fhir.model.api.annotation.Child; 032import ca.uhn.fhir.model.api.annotation.Description; 033import ca.uhn.fhir.util.ValidateUtil; 034 035public abstract class BaseRuntimeDeclaredChildDefinition extends BaseRuntimeChildDefinition { 036 private final IAccessor myAccessor; 037 private String myBindingValueSet; 038 private final String myElementName; 039 private final Field myField; 040 private final String myFormalDefinition; 041 private final int myMax; 042 private final int myMin; 043 private boolean myModifier; 044 045 private final IMutator myMutator; 046 private final String myShortDefinition; 047 private boolean mySummary; 048 BaseRuntimeDeclaredChildDefinition(Field theField, Child theChildAnnotation, Description theDescriptionAnnotation, String theElementName) throws ConfigurationException { 049 super(); 050 Validate.notNull(theField, "No field speficied"); 051 ValidateUtil.isGreaterThanOrEqualTo(theChildAnnotation.min(), 0, "Min must be >= 0"); 052 Validate.isTrue(theChildAnnotation.max() == -1 || theChildAnnotation.max() >= theChildAnnotation.min(), "Max must be >= Min (unless it is -1 / unlimited)"); 053 Validate.notBlank(theElementName, "Element name must not be blank"); 054 055 myField = theField; 056 myMin = theChildAnnotation.min(); 057 myMax = theChildAnnotation.max(); 058 mySummary = theChildAnnotation.summary(); 059 myModifier = theChildAnnotation.modifier(); 060 myElementName = theElementName; 061 if (theDescriptionAnnotation != null) { 062 myShortDefinition = theDescriptionAnnotation.shortDefinition(); 063 myFormalDefinition = theDescriptionAnnotation.formalDefinition(); 064 } else { 065 myShortDefinition = null; 066 myFormalDefinition = null; 067 } 068 069 myField.setAccessible(true); 070 if (List.class.equals(myField.getType())) { 071 // TODO: verify that generic type is IElement 072 myAccessor = new FieldListAccessor(); 073 myMutator = new FieldListMutator(); 074 } else { 075 myAccessor = new FieldPlainAccessor(); 076 myMutator = new FieldPlainMutator(); 077 } 078 079 } 080 081 @Override 082 public IAccessor getAccessor() { 083 return myAccessor; 084 } 085 086 public String getBindingValueSet() { 087 return myBindingValueSet; 088 } 089 090 @Override 091 public String getElementName() { 092 return myElementName; 093 } 094 095 public Field getField() { 096 return myField; 097 } 098 099 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}