001package org.hl7.fhir.dstu3.model; 002 003/*- 004 * #%L 005 * org.hl7.fhir.dstu3 006 * %% 007 * Copyright (C) 2014 - 2019 Health Level 7 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 023 024import java.util.ArrayList; 025import java.util.Collection; 026import java.util.HashSet; 027import java.util.List; 028import java.util.Set; 029 030import org.hl7.fhir.dstu3.context.IWorkerContext; 031import org.hl7.fhir.dstu3.model.ElementDefinition.ElementDefinitionBindingComponent; 032import org.hl7.fhir.dstu3.model.ExpressionNode.CollectionStatus; 033import org.hl7.fhir.exceptions.DefinitionException; 034import org.hl7.fhir.utilities.Utilities; 035 036public class TypeDetails { 037 public static class ProfiledType { 038 private String uri; 039 private List<String> profiles; // or, not and 040 private List<ElementDefinitionBindingComponent> bindings; 041 042 public ProfiledType(String n) { 043 uri = ns(n); 044 } 045 046 public String getUri() { 047 return uri; 048 } 049 050 public boolean hasProfiles() { 051 return profiles != null && profiles.size() > 0; 052 } 053 public List<String> getProfiles() { 054 return profiles; 055 } 056 057 public boolean hasBindings() { 058 return bindings != null && bindings.size() > 0; 059 } 060 public List<ElementDefinitionBindingComponent> getBindings() { 061 return bindings; 062 } 063 064 public static String ns(String n) { 065 return Utilities.isAbsoluteUrl(n) ? n : "http://hl7.org/fhir/StructureDefinition/"+n; 066 } 067 068 public void addProfile(String profile) { 069 profiles = new ArrayList<String>(); 070 profiles.add(profile); 071 } 072 073 public void addBinding(ElementDefinitionBindingComponent binding) { 074 bindings = new ArrayList<ElementDefinitionBindingComponent>(); 075 bindings.add(binding); 076 } 077 078 public boolean hasBinding(ElementDefinitionBindingComponent b) { 079 return false; // todo: do we need to do this? 080 } 081 } 082 083 private List<ProfiledType> types = new ArrayList<ProfiledType>(); 084 private CollectionStatus collectionStatus; 085 public TypeDetails(CollectionStatus collectionStatus, String... names) { 086 super(); 087 this.collectionStatus = collectionStatus; 088 for (String n : names) { 089 this.types.add(new ProfiledType(n)); 090 } 091 } 092 public TypeDetails(CollectionStatus collectionStatus, Set<String> names) { 093 super(); 094 this.collectionStatus = collectionStatus; 095 for (String n : names) { 096 addType(new ProfiledType(n)); 097 } 098 } 099 public TypeDetails(CollectionStatus collectionStatus, ProfiledType pt) { 100 super(); 101 this.collectionStatus = collectionStatus; 102 this.types.add(pt); 103 } 104 public String addType(String n) { 105 ProfiledType pt = new ProfiledType(n); 106 String res = pt.uri; 107 addType(pt); 108 return res; 109 } 110 public String addType(String n, String p) { 111 ProfiledType pt = new ProfiledType(n); 112 pt.addProfile(p); 113 String res = pt.uri; 114 addType(pt); 115 return res; 116 } 117 public void addType(ProfiledType pt) { 118 for (ProfiledType et : types) { 119 if (et.uri.equals(pt.uri)) { 120 if (pt.profiles != null) { 121 for (String p : pt.profiles) { 122 if (et.profiles == null) 123 et.profiles = new ArrayList<String>(); 124 if (!et.profiles.contains(p)) 125 et.profiles.add(p); 126 } 127 } 128 if (pt.bindings != null) { 129 for (ElementDefinitionBindingComponent b : pt.bindings) { 130 if (et.bindings == null) 131 et.bindings = new ArrayList<ElementDefinitionBindingComponent>(); 132 if (!et.hasBinding(b)) 133 et.bindings.add(b); 134 } 135 } 136 return; 137 } 138 } 139 types.add(pt); 140 } 141 142 public void addTypes(Collection<String> names) { 143 for (String n : names) 144 addType(new ProfiledType(n)); 145 } 146 147 public boolean hasType(IWorkerContext context, String... tn) { 148 for (String n: tn) { 149 String t = ProfiledType.ns(n); 150 if (typesContains(t)) 151 return true; 152 } 153 for (String n: tn) { 154 String id = n.contains("#") ? n.substring(0, n.indexOf("#")) : n; 155 String tail = null; 156 if (n.contains("#")) { 157 tail = n.substring( n.indexOf("#")+1); 158 tail = tail.substring(tail.indexOf(".")); 159 } 160 String t = ProfiledType.ns(n); 161 StructureDefinition sd = context.fetchResource(StructureDefinition.class, t); 162 while (sd != null) { 163 if (tail == null && typesContains(sd.getUrl())) 164 return true; 165 if (tail != null && typesContains(sd.getUrl()+"#"+sd.getType()+tail)) 166 return true; 167 if (sd.hasBaseDefinition()) 168 sd = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition()); 169 else 170 sd = null; 171 } 172 } 173 return false; 174 } 175 176 private boolean typesContains(String t) { 177 for (ProfiledType pt : types) 178 if (pt.uri.equals(t)) 179 return true; 180 return false; 181 } 182 183 public void update(TypeDetails source) { 184 for (ProfiledType pt : source.types) 185 addType(pt); 186 if (collectionStatus == null) 187 collectionStatus = source.collectionStatus; 188 else if (source.collectionStatus == CollectionStatus.UNORDERED) 189 collectionStatus = source.collectionStatus; 190 else 191 collectionStatus = CollectionStatus.ORDERED; 192 } 193 public TypeDetails union(TypeDetails right) { 194 TypeDetails result = new TypeDetails(null); 195 if (right.collectionStatus == CollectionStatus.UNORDERED || collectionStatus == CollectionStatus.UNORDERED) 196 result.collectionStatus = CollectionStatus.UNORDERED; 197 else 198 result.collectionStatus = CollectionStatus.ORDERED; 199 for (ProfiledType pt : types) 200 result.addType(pt); 201 for (ProfiledType pt : right.types) 202 result.addType(pt); 203 return result; 204 } 205 206 public boolean hasNoTypes() { 207 return types.isEmpty(); 208 } 209 public Set<String> getTypes() { 210 Set<String> res = new HashSet<String>(); 211 for (ProfiledType pt : types) 212 res.add(pt.uri); 213 return res; 214 } 215 public TypeDetails toSingleton() { 216 TypeDetails result = new TypeDetails(CollectionStatus.SINGLETON); 217 result.types.addAll(types); 218 return result; 219 } 220 public CollectionStatus getCollectionStatus() { 221 return collectionStatus; 222 } 223 public boolean hasType(Set<String> tn) { 224 for (String n: tn) { 225 String t = ProfiledType.ns(n); 226 if (typesContains(t)) 227 return true; 228 } 229 return false; 230 } 231 public String describe() { 232 return getTypes().toString(); 233 } 234 public String getType() { 235 for (ProfiledType pt : types) 236 return pt.uri; 237 return null; 238 } 239 @Override 240 public String toString() { 241 return (collectionStatus == null ? collectionStatus.SINGLETON.toString() : collectionStatus.toString()) + getTypes().toString(); 242 } 243 public String getTypeCode() throws DefinitionException { 244 if (types.size() != 1) 245 throw new DefinitionException("Multiple types? ("+types.toString()+")"); 246 for (ProfiledType pt : types) 247 if (pt.uri.startsWith("http://hl7.org/fhir/StructureDefinition/")) 248 return pt.uri.substring(40); 249 else 250 return pt.uri; 251 return null; 252 } 253 public List<ProfiledType> getProfiledTypes() { 254 return types; 255 } 256 public boolean hasBinding() { 257 for (ProfiledType pt : types) { 258 if (pt.hasBindings()) 259 return true; 260 } 261 return false; 262 } 263 public ElementDefinitionBindingComponent getBinding() { 264 for (ProfiledType pt : types) { 265 for (ElementDefinitionBindingComponent b : pt.getBindings()) 266 return b; 267 } 268 return null; 269 } 270}