001package org.hl7.fhir.dstu3.model; 002 003/* 004 Copyright (c) 2011+, HL7, Inc. 005 All rights reserved. 006 007 Redistribution and use in source and binary forms, with or without modification, 008 are permitted provided that the following conditions are met: 009 010 * Redistributions of source code must retain the above copyright notice, this 011 list of conditions and the following disclaimer. 012 * Redistributions in binary form must reproduce the above copyright notice, 013 this list of conditions and the following disclaimer in the documentation 014 and/or other materials provided with the distribution. 015 * Neither the name of HL7 nor the names of its contributors may be used to 016 endorse or promote products derived from this software without specific 017 prior written permission. 018 019 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 022 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 023 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 024 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 025 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 026 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 027 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 028 POSSIBILITY OF SUCH DAMAGE. 029 030 */ 031 032 033 034import java.util.ArrayList; 035import java.util.Collection; 036import java.util.HashSet; 037import java.util.List; 038import java.util.Set; 039 040import org.hl7.fhir.dstu3.context.IWorkerContext; 041import org.hl7.fhir.dstu3.model.ElementDefinition.ElementDefinitionBindingComponent; 042import org.hl7.fhir.dstu3.model.ExpressionNode.CollectionStatus; 043import org.hl7.fhir.exceptions.DefinitionException; 044import org.hl7.fhir.utilities.Utilities; 045 046public class TypeDetails { 047 public static class ProfiledType { 048 private String uri; 049 private List<String> profiles; // or, not and 050 private List<ElementDefinitionBindingComponent> bindings; 051 052 public ProfiledType(String n) { 053 uri = ns(n); 054 } 055 056 public String getUri() { 057 return uri; 058 } 059 060 public boolean hasProfiles() { 061 return profiles != null && profiles.size() > 0; 062 } 063 public List<String> getProfiles() { 064 return profiles; 065 } 066 067 public boolean hasBindings() { 068 return bindings != null && bindings.size() > 0; 069 } 070 public List<ElementDefinitionBindingComponent> getBindings() { 071 return bindings; 072 } 073 074 public static String ns(String n) { 075 return Utilities.isAbsoluteUrl(n) ? n : "http://hl7.org/fhir/StructureDefinition/"+n; 076 } 077 078 public void addProfile(String profile) { 079 profiles = new ArrayList<String>(); 080 profiles.add(profile); 081 } 082 083 public void addBinding(ElementDefinitionBindingComponent binding) { 084 bindings = new ArrayList<ElementDefinitionBindingComponent>(); 085 bindings.add(binding); 086 } 087 088 public boolean hasBinding(ElementDefinitionBindingComponent b) { 089 return false; // todo: do we need to do this? 090 } 091 } 092 093 private List<ProfiledType> types = new ArrayList<ProfiledType>(); 094 private CollectionStatus collectionStatus; 095 public TypeDetails(CollectionStatus collectionStatus, String... names) { 096 super(); 097 this.collectionStatus = collectionStatus; 098 for (String n : names) { 099 this.types.add(new ProfiledType(n)); 100 } 101 } 102 public TypeDetails(CollectionStatus collectionStatus, Set<String> names) { 103 super(); 104 this.collectionStatus = collectionStatus; 105 for (String n : names) { 106 addType(new ProfiledType(n)); 107 } 108 } 109 public TypeDetails(CollectionStatus collectionStatus, ProfiledType pt) { 110 super(); 111 this.collectionStatus = collectionStatus; 112 this.types.add(pt); 113 } 114 public String addType(String n) { 115 ProfiledType pt = new ProfiledType(n); 116 String res = pt.uri; 117 addType(pt); 118 return res; 119 } 120 public String addType(String n, String p) { 121 ProfiledType pt = new ProfiledType(n); 122 pt.addProfile(p); 123 String res = pt.uri; 124 addType(pt); 125 return res; 126 } 127 public void addType(ProfiledType pt) { 128 for (ProfiledType et : types) { 129 if (et.uri.equals(pt.uri)) { 130 if (pt.profiles != null) { 131 for (String p : pt.profiles) { 132 if (et.profiles == null) 133 et.profiles = new ArrayList<String>(); 134 if (!et.profiles.contains(p)) 135 et.profiles.add(p); 136 } 137 } 138 if (pt.bindings != null) { 139 for (ElementDefinitionBindingComponent b : pt.bindings) { 140 if (et.bindings == null) 141 et.bindings = new ArrayList<ElementDefinitionBindingComponent>(); 142 if (!et.hasBinding(b)) 143 et.bindings.add(b); 144 } 145 } 146 return; 147 } 148 } 149 types.add(pt); 150 } 151 152 public void addTypes(Collection<String> names) { 153 for (String n : names) 154 addType(new ProfiledType(n)); 155 } 156 157 public boolean hasType(IWorkerContext context, String... tn) { 158 for (String n: tn) { 159 String t = ProfiledType.ns(n); 160 if (typesContains(t)) 161 return true; 162 } 163 for (String n: tn) { 164 String id = n.contains("#") ? n.substring(0, n.indexOf("#")) : n; 165 String tail = null; 166 if (n.contains("#")) { 167 tail = n.substring( n.indexOf("#")+1); 168 tail = tail.substring(tail.indexOf(".")); 169 } 170 String t = ProfiledType.ns(n); 171 StructureDefinition sd = context.fetchResource(StructureDefinition.class, t); 172 while (sd != null) { 173 if (tail == null && typesContains(sd.getUrl())) 174 return true; 175 if (tail != null && typesContains(sd.getUrl()+"#"+sd.getType()+tail)) 176 return true; 177 if (sd.hasBaseDefinition()) 178 sd = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition()); 179 else 180 sd = null; 181 } 182 } 183 return false; 184 } 185 186 private boolean typesContains(String t) { 187 for (ProfiledType pt : types) 188 if (pt.uri.equals(t)) 189 return true; 190 return false; 191 } 192 193 public void update(TypeDetails source) { 194 for (ProfiledType pt : source.types) 195 addType(pt); 196 if (collectionStatus == null) 197 collectionStatus = source.collectionStatus; 198 else if (source.collectionStatus == CollectionStatus.UNORDERED) 199 collectionStatus = source.collectionStatus; 200 else 201 collectionStatus = CollectionStatus.ORDERED; 202 } 203 public TypeDetails union(TypeDetails right) { 204 TypeDetails result = new TypeDetails(null); 205 if (right.collectionStatus == CollectionStatus.UNORDERED || collectionStatus == CollectionStatus.UNORDERED) 206 result.collectionStatus = CollectionStatus.UNORDERED; 207 else 208 result.collectionStatus = CollectionStatus.ORDERED; 209 for (ProfiledType pt : types) 210 result.addType(pt); 211 for (ProfiledType pt : right.types) 212 result.addType(pt); 213 return result; 214 } 215 216 public boolean hasNoTypes() { 217 return types.isEmpty(); 218 } 219 public Set<String> getTypes() { 220 Set<String> res = new HashSet<String>(); 221 for (ProfiledType pt : types) 222 res.add(pt.uri); 223 return res; 224 } 225 public TypeDetails toSingleton() { 226 TypeDetails result = new TypeDetails(CollectionStatus.SINGLETON); 227 result.types.addAll(types); 228 return result; 229 } 230 public CollectionStatus getCollectionStatus() { 231 return collectionStatus; 232 } 233 public boolean hasType(Set<String> tn) { 234 for (String n: tn) { 235 String t = ProfiledType.ns(n); 236 if (typesContains(t)) 237 return true; 238 } 239 return false; 240 } 241 public String describe() { 242 return getTypes().toString(); 243 } 244 public String getType() { 245 for (ProfiledType pt : types) 246 return pt.uri; 247 return null; 248 } 249 @Override 250 public String toString() { 251 return (collectionStatus == null ? collectionStatus.SINGLETON.toString() : collectionStatus.toString()) + getTypes().toString(); 252 } 253 public String getTypeCode() throws DefinitionException { 254 if (types.size() != 1) 255 throw new DefinitionException("Multiple types? ("+types.toString()+")"); 256 for (ProfiledType pt : types) 257 if (pt.uri.startsWith("http://hl7.org/fhir/StructureDefinition/")) 258 return pt.uri.substring(40); 259 else 260 return pt.uri; 261 return null; 262 } 263 public List<ProfiledType> getProfiledTypes() { 264 return types; 265 } 266 public boolean hasBinding() { 267 for (ProfiledType pt : types) { 268 if (pt.hasBindings()) 269 return true; 270 } 271 return false; 272 } 273 public ElementDefinitionBindingComponent getBinding() { 274 for (ProfiledType pt : types) { 275 for (ElementDefinitionBindingComponent b : pt.getBindings()) 276 return b; 277 } 278 return null; 279 } 280}