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