001package org.hl7.fhir.dstu3.context;
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.io.ByteArrayInputStream;
025import java.io.File;
026import java.io.FileInputStream;
027import java.io.FileNotFoundException;
028import java.io.IOException;
029import java.io.InputStream;
030import java.net.URISyntaxException;
031import java.util.ArrayList;
032import java.util.Arrays;
033import java.util.Collections;
034import java.util.HashMap;
035import java.util.HashSet;
036import java.util.List;
037import java.util.Map;
038import java.util.Set;
039import java.util.zip.ZipEntry;
040import java.util.zip.ZipInputStream;
041
042import org.apache.commons.io.IOUtils;
043import org.hl7.fhir.dstu3.conformance.ProfileUtilities;
044import org.hl7.fhir.dstu3.conformance.ProfileUtilities.ProfileKnowledgeProvider;
045import org.hl7.fhir.dstu3.context.IWorkerContext.ILoggingService.LogCategory;
046import org.hl7.fhir.dstu3.formats.IParser;
047import org.hl7.fhir.dstu3.formats.JsonParser;
048import org.hl7.fhir.dstu3.formats.ParserType;
049import org.hl7.fhir.dstu3.formats.XmlParser;
050import org.hl7.fhir.dstu3.model.Bundle;
051import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
052import org.hl7.fhir.dstu3.model.CodeSystem;
053import org.hl7.fhir.dstu3.model.ConceptMap;
054import org.hl7.fhir.dstu3.model.ElementDefinition.ElementDefinitionBindingComponent;
055import org.hl7.fhir.dstu3.model.MetadataResource;
056import org.hl7.fhir.dstu3.model.NamingSystem;
057import org.hl7.fhir.dstu3.model.NamingSystem.NamingSystemIdentifierType;
058import org.hl7.fhir.dstu3.model.NamingSystem.NamingSystemUniqueIdComponent;
059import org.hl7.fhir.dstu3.model.OperationDefinition;
060import org.hl7.fhir.dstu3.model.Questionnaire;
061import org.hl7.fhir.dstu3.model.Resource;
062import org.hl7.fhir.dstu3.model.ResourceType;
063import org.hl7.fhir.dstu3.model.SearchParameter;
064import org.hl7.fhir.dstu3.model.StructureDefinition;
065import org.hl7.fhir.dstu3.model.StructureDefinition.StructureDefinitionKind;
066import org.hl7.fhir.dstu3.model.StructureDefinition.TypeDerivationRule;
067import org.hl7.fhir.dstu3.model.StructureMap;
068import org.hl7.fhir.dstu3.model.StructureMap.StructureMapModelMode;
069import org.hl7.fhir.dstu3.model.StructureMap.StructureMapStructureComponent;
070import org.hl7.fhir.dstu3.model.ValueSet;
071import org.hl7.fhir.dstu3.terminologies.ValueSetExpansionCache;
072import org.hl7.fhir.dstu3.utils.INarrativeGenerator;
073import org.hl7.fhir.dstu3.utils.IResourceValidator;
074import org.hl7.fhir.dstu3.utils.NarrativeGenerator;
075import org.hl7.fhir.dstu3.utils.client.FHIRToolingClient;
076import org.hl7.fhir.exceptions.DefinitionException;
077import org.hl7.fhir.exceptions.FHIRException;
078import org.hl7.fhir.exceptions.FHIRFormatError;
079import org.hl7.fhir.utilities.CSFileInputStream;
080import org.hl7.fhir.utilities.OIDUtils;
081import org.hl7.fhir.utilities.Utilities;
082import org.hl7.fhir.utilities.cache.NpmPackage;
083import org.hl7.fhir.utilities.validation.ValidationMessage;
084import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
085import org.hl7.fhir.utilities.validation.ValidationMessage.Source;
086
087import ca.uhn.fhir.parser.DataFormatException;
088
089/*
090 * This is a stand alone implementation of worker context for use inside a tool.
091 * It loads from the validation package (validation-min.xml.zip), and has a 
092 * very light client to connect to an open unauthenticated terminology service
093 */
094
095public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerContext, ProfileKnowledgeProvider {
096
097  public interface IContextResourceLoader {
098    Bundle loadBundle(InputStream stream, boolean isJson) throws FHIRException, IOException;
099  }
100
101  public interface IValidatorFactory {
102    IResourceValidator makeValidator(IWorkerContext ctxts) throws FHIRException;
103  }
104
105  // all maps are to the full URI
106        private Map<String, StructureDefinition> structures = new HashMap<String, StructureDefinition>();
107        private List<NamingSystem> systems = new ArrayList<NamingSystem>();
108        private Questionnaire questionnaire;
109        private Map<String, byte[]> binaries = new HashMap<String, byte[]>();
110  private String version;
111  private String revision;
112  private String date;
113  private IValidatorFactory validatorFactory;
114  
115        // -- Initializations
116        /**
117         * Load the working context from the validation pack
118         * 
119         * @param path
120         *           filename of the validation pack
121         * @return
122         * @throws IOException 
123         * @throws FileNotFoundException 
124         * @throws FHIRException 
125         * @throws Exception
126         */
127  public static SimpleWorkerContext fromPack(String path) throws FileNotFoundException, IOException, FHIRException {
128    SimpleWorkerContext res = new SimpleWorkerContext();
129    res.loadFromPack(path, null);
130    return res;
131  }
132
133  public static SimpleWorkerContext fromPackage(NpmPackage pi, boolean allowDuplicates) throws FileNotFoundException, IOException, FHIRException {
134    SimpleWorkerContext res = new SimpleWorkerContext();
135    res.setAllowLoadingDuplicates(allowDuplicates);
136    res.loadFromPackage(pi, null);
137    return res;
138  }
139
140  public static SimpleWorkerContext fromPackage(NpmPackage pi) throws FileNotFoundException, IOException, FHIRException {
141    SimpleWorkerContext res = new SimpleWorkerContext();
142    res.loadFromPackage(pi, null);
143    return res;
144  }
145
146  public static SimpleWorkerContext fromPackage(NpmPackage pi, IContextResourceLoader loader) throws FileNotFoundException, IOException, FHIRException {
147    SimpleWorkerContext res = new SimpleWorkerContext();
148    res.setAllowLoadingDuplicates(true);
149    res.version = pi.getNpm().get("version").getAsString();
150    res.loadFromPackage(pi, loader);
151    return res;
152  }
153
154  public static SimpleWorkerContext fromPack(String path, boolean allowDuplicates) throws FileNotFoundException, IOException, FHIRException {
155    SimpleWorkerContext res = new SimpleWorkerContext();
156    res.allowLoadingDuplicates = allowDuplicates;
157    res.loadFromPack(path, null);
158    return res;
159  }
160
161  public static SimpleWorkerContext fromPack(String path, IContextResourceLoader loader) throws FileNotFoundException, IOException, FHIRException {
162    SimpleWorkerContext res = new SimpleWorkerContext();
163    res.loadFromPack(path, loader);
164    return res;
165  }
166
167        public static SimpleWorkerContext fromClassPath() throws IOException, FHIRException {
168                SimpleWorkerContext res = new SimpleWorkerContext();
169                res.loadFromStream(SimpleWorkerContext.class.getResourceAsStream("validation.json.zip"), null);
170                return res;
171        }
172
173         public static SimpleWorkerContext fromClassPath(String name) throws IOException, FHIRException {
174           InputStream s = SimpleWorkerContext.class.getResourceAsStream("/"+name);
175            SimpleWorkerContext res = new SimpleWorkerContext();
176           res.loadFromStream(s, null);
177            return res;
178          }
179
180        public static SimpleWorkerContext fromDefinitions(Map<String, byte[]> source) throws IOException, FHIRException {
181                SimpleWorkerContext res = new SimpleWorkerContext();
182                for (String name : source.keySet()) {
183                  res.loadDefinitionItem(name, new ByteArrayInputStream(source.get(name)), null);
184                }
185                return res;
186        }
187
188  public static SimpleWorkerContext fromDefinitions(Map<String, byte[]> source, IContextResourceLoader loader) throws FileNotFoundException, IOException, FHIRException  {
189    SimpleWorkerContext res = new SimpleWorkerContext();
190    for (String name : source.keySet()) { 
191      try {
192        res.loadDefinitionItem(name, new ByteArrayInputStream(source.get(name)), loader);
193      } catch (Exception e) {
194        System.out.println("Error loading "+name+": "+e.getMessage());
195        throw new FHIRException("Error loading "+name+": "+e.getMessage(), e);
196      }
197    }
198    return res;
199  }
200        private void loadDefinitionItem(String name, InputStream stream, IContextResourceLoader loader) throws IOException, FHIRException {
201    if (name.endsWith(".xml"))
202      loadFromFile(stream, name, loader);
203    else if (name.endsWith(".json"))
204      loadFromFileJson(stream, name, loader);
205    else if (name.equals("version.info"))
206      readVersionInfo(stream);
207    else
208      loadBytes(name, stream);
209  }
210
211        public String connectToTSServer(String url) throws URISyntaxException {
212          txServer = new FHIRToolingClient(url);
213          txServer.setTimeout(30000);
214          return txServer.getCapabilitiesStatementQuick().getSoftware().getVersion();
215        }
216
217        public void loadFromFile(InputStream stream, String name, IContextResourceLoader loader) throws IOException, FHIRException {
218                Resource f;
219                try {
220                  if (loader != null)
221                    f = loader.loadBundle(stream, false);
222                  else {
223                    XmlParser xml = new XmlParser();
224                    f = xml.parse(stream);
225                  }
226    } catch (DataFormatException e1) {
227      throw new org.hl7.fhir.exceptions.FHIRFormatError("Error parsing "+name+":" +e1.getMessage(), e1);
228    } catch (Exception e1) {
229                        throw new org.hl7.fhir.exceptions.FHIRFormatError("Error parsing "+name+":" +e1.getMessage(), e1);
230                }
231                if (f instanceof Bundle) {
232                  Bundle bnd = (Bundle) f;
233                  for (BundleEntryComponent e : bnd.getEntry()) {
234                    if (e.getFullUrl() == null) {
235                      logger.logDebugMessage(LogCategory.CONTEXT, "unidentified resource in " + name+" (no fullUrl)");
236                    }
237                    seeResource(e.getFullUrl(), e.getResource());
238                  }
239                } else if (f instanceof MetadataResource) {
240                  MetadataResource m = (MetadataResource) f;
241                  seeResource(m.getUrl(), m);
242                }
243        }
244
245  private void loadFromFileJson(InputStream stream, String name, IContextResourceLoader loader) throws IOException, FHIRException {
246    Bundle f;
247    try {
248      if (loader != null)
249        f = loader.loadBundle(stream, true);
250      else {
251        JsonParser json = new JsonParser();
252        Resource r = json.parse(stream);
253        if (r instanceof Bundle)
254        f = (Bundle) r;
255        else {
256          f = new Bundle();
257          f.addEntry().setResource(r);
258        }
259      }
260    } catch (FHIRFormatError e1) {
261      throw new org.hl7.fhir.exceptions.FHIRFormatError(e1.getMessage(), e1);
262    }
263    for (BundleEntryComponent e : f.getEntry()) {
264      if (e.getFullUrl() == null && logger != null) {
265        logger.logDebugMessage(LogCategory.CONTEXT, "unidentified resource in " + name+" (no fullUrl)");
266      }
267      seeResource(e.getFullUrl(), e.getResource());
268    }
269  }
270
271        public void seeResource(String url, Resource r) throws FHIRException {
272    if (r instanceof StructureDefinition)
273      seeProfile(url, (StructureDefinition) r);
274    else if (r instanceof ValueSet)
275      seeValueSet(url, (ValueSet) r);
276    else if (r instanceof CodeSystem)
277      seeCodeSystem(url, (CodeSystem) r);
278    else if (r instanceof OperationDefinition)
279      seeOperationDefinition(url, (OperationDefinition) r);
280    else if (r instanceof ConceptMap)
281      maps.put(((ConceptMap) r).getUrl(), (ConceptMap) r);
282    else if (r instanceof StructureMap)
283      transforms.put(((StructureMap) r).getUrl(), (StructureMap) r);
284    else if (r instanceof NamingSystem)
285        systems.add((NamingSystem) r);
286        }
287        
288        private void seeOperationDefinition(String url, OperationDefinition r) {
289    operations.put(r.getUrl(), r);
290  }
291
292  public void seeValueSet(String url, ValueSet vs) throws DefinitionException {
293          if (Utilities.noString(url))
294            url = vs.getUrl();
295                if (valueSets.containsKey(vs.getUrl()) && !allowLoadingDuplicates)
296                        throw new DefinitionException("Duplicate Profile " + vs.getUrl());
297                valueSets.put(vs.getId(), vs);
298                valueSets.put(vs.getUrl(), vs);
299                if (!vs.getUrl().equals(url))
300                        valueSets.put(url, vs);
301        }
302
303        public void seeProfile(String url, StructureDefinition p) throws FHIRException {
304    if (Utilities.noString(url))
305      url = p.getUrl();
306    
307    if (!p.hasSnapshot() && p.getKind() != StructureDefinitionKind.LOGICAL) {
308      if (!p.hasBaseDefinition())
309        throw new DefinitionException("Profile "+p.getName()+" ("+p.getUrl()+") has no base and no snapshot");
310      StructureDefinition sd = fetchResource(StructureDefinition.class, p.getBaseDefinition());
311      if (sd == null)
312        throw new DefinitionException("Profile "+p.getName()+" ("+p.getUrl()+") base "+p.getBaseDefinition()+" could not be resolved");
313      List<ValidationMessage> msgs = new ArrayList<ValidationMessage>();
314      List<String> errors = new ArrayList<String>();
315      ProfileUtilities pu = new ProfileUtilities(this, msgs, this);
316      pu.sortDifferential(sd, p, url, errors);
317      for (String err : errors)
318        msgs.add(new ValidationMessage(Source.ProfileValidator, IssueType.EXCEPTION,p.getUserString("path"), "Error sorting Differential: "+err, ValidationMessage.IssueSeverity.ERROR));
319      pu.generateSnapshot(sd, p, p.getUrl(), p.getName());
320      for (ValidationMessage msg : msgs) {
321        if (msg.getLevel() == ValidationMessage.IssueSeverity.ERROR || msg.getLevel() == ValidationMessage.IssueSeverity.FATAL)
322          throw new DefinitionException("Profile "+p.getName()+" ("+p.getUrl()+"). Error generating snapshot: "+msg.getMessage());
323      }
324      if (!p.hasSnapshot())
325        throw new DefinitionException("Profile "+p.getName()+" ("+p.getUrl()+"). Error generating snapshot");
326      pu = null;
327    }
328                if (structures.containsKey(p.getUrl()) && !allowLoadingDuplicates)
329                        throw new DefinitionException("Duplicate structures " + p.getUrl());
330                structures.put(p.getId(), p);
331                structures.put(p.getUrl(), p);
332                if (!p.getUrl().equals(url))
333                        structures.put(url, p);
334        }
335
336        private void loadFromPack(String path, IContextResourceLoader loader) throws FileNotFoundException, IOException, FHIRException {
337                loadFromStream(new CSFileInputStream(path), loader);
338        }
339
340        public void loadFromPackage(NpmPackage pi, IContextResourceLoader loader, String... types) throws FileNotFoundException, IOException, FHIRException {
341          if (types.length == 0)
342            types = new String[] { "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire","ConceptMap","StructureMap", "NamingSystem"};
343          for (String s : pi.listResources(types)) {
344      loadDefinitionItem(s, pi.load("package", s), loader);
345          }
346          version = pi.version();
347        }
348
349  public void loadFromFile(String file, IContextResourceLoader loader) throws IOException, FHIRException {
350    loadDefinitionItem(file, new CSFileInputStream(file), loader);
351  }
352  
353        private void loadFromStream(InputStream stream, IContextResourceLoader loader) throws IOException, FHIRException {
354                ZipInputStream zip = new ZipInputStream(stream);
355                ZipEntry ze;
356                while ((ze = zip.getNextEntry()) != null) {
357      loadDefinitionItem(ze.getName(), zip, loader);
358                        zip.closeEntry();
359                }
360                zip.close();
361        }
362
363  private void readVersionInfo(InputStream stream) throws IOException, DefinitionException {
364    byte[] bytes = IOUtils.toByteArray(stream);
365    binaries.put("version.info", bytes);
366
367    String[] vi = new String(bytes).split("\\r?\\n");
368    for (String s : vi) {
369      if (s.startsWith("version=")) {
370        if (version == null)
371        version = s.substring(8);
372        else if (!version.equals(s.substring(8))) 
373          throw new DefinitionException("Version mismatch. The context has version "+version+" loaded, and the new content being loaded is version "+s.substring(8));
374      }
375      if (s.startsWith("revision="))
376        revision = s.substring(9);
377      if (s.startsWith("date="))
378        date = s.substring(5);
379    }
380  }
381
382        private void loadBytes(String name, InputStream stream) throws IOException {
383    byte[] bytes = IOUtils.toByteArray(stream);
384          binaries.put(name, bytes);
385  }
386
387        @Override
388        public IParser getParser(ParserType type) {
389                switch (type) {
390                case JSON: return newJsonParser();
391                case XML: return newXmlParser();
392                default:
393                        throw new Error("Parser Type "+type.toString()+" not supported");
394                }
395        }
396
397        @Override
398        public IParser getParser(String type) {
399                if (type.equalsIgnoreCase("JSON"))
400                        return new JsonParser();
401                if (type.equalsIgnoreCase("XML"))
402                        return new XmlParser();
403                throw new Error("Parser Type "+type.toString()+" not supported");
404        }
405
406        @Override
407        public IParser newJsonParser() {
408                return new JsonParser();
409        }
410        @Override
411        public IParser newXmlParser() {
412                return new XmlParser();
413        }
414
415        @Override
416        public <T extends Resource> boolean hasResource(Class<T> class_, String uri) {
417                try {
418                        return fetchResource(class_, uri) != null;
419                } catch (Exception e) {
420                        return false;
421                }
422        }
423
424        @Override
425        public INarrativeGenerator getNarrativeGenerator(String prefix, String basePath) {
426                return new NarrativeGenerator(prefix, basePath, this);
427        }
428
429        @Override
430        public IResourceValidator newValidator() throws FHIRException {
431          if (validatorFactory == null)
432            throw new Error("No validator configured");
433          return validatorFactory.makeValidator(this);
434        }
435
436  @Override
437  public <T extends Resource> T fetchResource(Class<T> class_, String uri) {
438    try {
439      return fetchResourceWithException(class_, uri);
440    } catch (FHIRException e) {
441      throw new Error(e);
442    }
443  }
444        @SuppressWarnings("unchecked")
445        @Override
446        public <T extends Resource> T fetchResourceWithException(Class<T> class_, String uri) throws FHIRException {
447    if (class_ == null) {
448      return null;      
449    }
450
451          if (class_ == Questionnaire.class)
452            return (T) questionnaire;
453          
454                if (class_ == StructureDefinition.class && !uri.contains("/"))
455                        uri = "http://hl7.org/fhir/StructureDefinition/"+uri;
456
457                if (uri.startsWith("http:") || uri.startsWith("urn:") ) {
458                        if (uri.contains("#"))
459                                uri = uri.substring(0, uri.indexOf("#"));
460                        if (class_ == Resource.class) {
461        if (structures.containsKey(uri))
462          return (T) structures.get(uri);
463        if (valueSets.containsKey(uri))
464          return (T) valueSets.get(uri);
465        if (codeSystems.containsKey(uri))
466          return (T) codeSystems.get(uri);
467        if (operations.containsKey(uri))
468          return (T) operations.get(uri);
469        if (searchParameters.containsKey(uri))
470          return (T) searchParameters.get(uri);
471        if (maps.containsKey(uri))
472          return (T) maps.get(uri);
473        if (transforms.containsKey(uri))
474          return (T) transforms.get(uri);
475        return null;      
476                        }
477                        if (class_ == StructureDefinition.class) {
478                                if (structures.containsKey(uri))
479                                        return (T) structures.get(uri);
480                                else
481                                        return null;
482                        } else if (class_ == ValueSet.class) {
483                                if (valueSets.containsKey(uri))
484                                        return (T) valueSets.get(uri);
485                                else
486                                        return null;      
487                        } else if (class_ == CodeSystem.class) {
488                                if (codeSystems.containsKey(uri))
489                                        return (T) codeSystems.get(uri);
490                                else
491                                        return null;      
492      } else if (class_ == OperationDefinition.class) {
493        OperationDefinition od = operations.get(uri);
494        return (T) od;
495      } else if (class_ == SearchParameter.class) {
496        SearchParameter od = searchParameters.get(uri);
497        return (T) od;
498                        } else if (class_ == ConceptMap.class) {
499                                if (maps.containsKey(uri))
500                                        return (T) maps.get(uri);
501                                else
502                                        return null;      
503      } else if (class_ == StructureMap.class) {
504        if (transforms.containsKey(uri))
505          return (T) transforms.get(uri);
506        else
507          return null;      
508                        }
509                }
510                
511                throw new FHIRException("fetching "+class_.getName()+" not done yet for URI '"+uri+"'");
512        }
513
514
515
516        public int totalCount() {
517                return valueSets.size() +  maps.size() + structures.size() + transforms.size();
518        }
519
520        public void setCache(ValueSetExpansionCache cache) {
521          this.expansionCache = cache;  
522        }
523
524  @Override
525  public List<String> getResourceNames() {
526    List<String> result = new ArrayList<String>();
527    for (StructureDefinition sd : structures.values()) {
528      if (sd.getKind() == StructureDefinitionKind.RESOURCE && sd.getDerivation() == TypeDerivationRule.SPECIALIZATION)
529        result.add(sd.getName());
530    }
531    Collections.sort(result);
532    return result;
533  }
534
535  @Override
536  public List<String> getTypeNames() {
537    List<String> result = new ArrayList<String>();
538    for (StructureDefinition sd : structures.values()) {
539      if (sd.getKind() != StructureDefinitionKind.LOGICAL && sd.getDerivation() == TypeDerivationRule.SPECIALIZATION)
540        result.add(sd.getName());
541    }
542    Collections.sort(result);
543    return result;
544  }
545
546  @Override
547  public String getAbbreviation(String name) {
548    return "xxx";
549  }
550
551  @Override
552  public boolean isDatatype(String typeSimple) {
553    // TODO Auto-generated method stub
554    return false;
555  }
556
557  @Override
558  public boolean isResource(String t) {
559    StructureDefinition sd;
560    try {
561      sd = fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/"+t);
562    } catch (Exception e) {
563      return false;
564    }
565    if (sd == null)
566      return false;
567    if (sd.getDerivation() == TypeDerivationRule.CONSTRAINT)
568      return false;
569    return sd.getKind() == StructureDefinitionKind.RESOURCE;
570  }
571
572  @Override
573  public boolean hasLinkFor(String typeSimple) {
574    return false;
575  }
576
577  @Override
578  public String getLinkFor(String corePath, String typeSimple) {
579    return null;
580  }
581
582  @Override
583  public BindingResolution resolveBinding(StructureDefinition profile, ElementDefinitionBindingComponent binding, String path) {
584    return null;
585  }
586
587  @Override
588  public String getLinkForProfile(StructureDefinition profile, String url) {
589    return null;
590  }
591
592  public Questionnaire getQuestionnaire() {
593    return questionnaire;
594  }
595
596  public void setQuestionnaire(Questionnaire questionnaire) {
597    this.questionnaire = questionnaire;
598  }
599
600  @Override
601  public Set<String> typeTails() {
602    return new HashSet<String>(Arrays.asList("Integer","UnsignedInt","PositiveInt","Decimal","DateTime","Date","Time","Instant","String","Uri","Oid","Uuid","Id","Boolean","Code","Markdown","Base64Binary","Coding","CodeableConcept","Attachment","Identifier","Quantity","SampledData","Range","Period","Ratio","HumanName","Address","ContactPoint","Timing","Reference","Annotation","Signature","Meta"));
603  }
604
605  @Override
606  public List<StructureDefinition> allStructures() {
607    List<StructureDefinition> result = new ArrayList<StructureDefinition>();
608    Set<StructureDefinition> set = new HashSet<StructureDefinition>();
609    for (StructureDefinition sd : structures.values()) {
610      if (!set.contains(sd)) {
611        result.add(sd);
612        set.add(sd);
613      }
614    }
615    return result;
616  }
617
618        @Override
619  public List<MetadataResource> allConformanceResources() {
620    List<MetadataResource> result = new ArrayList<MetadataResource>();
621    result.addAll(structures.values());
622    result.addAll(codeSystems.values());
623    result.addAll(valueSets.values());
624    result.addAll(maps.values());
625    result.addAll(transforms.values());
626    return result;
627  }
628
629        @Override
630        public String oid2Uri(String oid) {
631                String uri = OIDUtils.getUriForOid(oid);
632                if (uri != null)
633                        return uri;
634                for (NamingSystem ns : systems) {
635                        if (hasOid(ns, oid)) {
636                                uri = getUri(ns);
637                                if (uri != null)
638                                        return null;
639                        }
640                }
641                return null;
642  }
643
644        private String getUri(NamingSystem ns) {
645                for (NamingSystemUniqueIdComponent id : ns.getUniqueId()) {
646                        if (id.getType() == NamingSystemIdentifierType.URI)
647                                return id.getValue();
648                }
649                return null;
650        }
651
652        private boolean hasOid(NamingSystem ns, String oid) {
653                for (NamingSystemUniqueIdComponent id : ns.getUniqueId()) {
654                        if (id.getType() == NamingSystemIdentifierType.OID && id.getValue().equals(oid))
655                                return true;
656                }
657                return false;
658        }
659
660
661
662
663  public void loadFromFolder(String folder) throws FileNotFoundException, Exception {
664    for (String n : new File(folder).list()) {
665      if (n.endsWith(".json")) 
666        loadFromFile(Utilities.path(folder, n), new JsonParser());
667      else if (n.endsWith(".xml")) 
668        loadFromFile(Utilities.path(folder, n), new XmlParser());
669    }
670  }
671  
672  private void loadFromFile(String filename, IParser p) throws FileNotFoundException, Exception {
673        Resource r; 
674        try {
675                r = p.parse(new FileInputStream(filename));
676      if (r.getResourceType() == ResourceType.Bundle) {
677        for (BundleEntryComponent e : ((Bundle) r).getEntry()) {
678          seeResource(null, e.getResource());
679        }
680     } else {
681       seeResource(null, r);
682     }
683        } catch (Exception e) {
684        return;
685    }
686  }
687
688
689  public Map<String, byte[]> getBinaries() {
690    return binaries;
691  }
692
693
694  @Override
695  public boolean prependLinks() {
696    return false;
697  }
698
699  @Override
700  public boolean hasCache() {
701    return false;
702  }
703
704  @Override
705  public String getVersion() {
706    return version+"-"+revision;
707  }
708
709  public Map<String, StructureMap> getTransforms() {
710    return transforms;
711  }
712  
713  public List<StructureMap> findTransformsforSource(String url) {
714    List<StructureMap> res = new ArrayList<StructureMap>();
715    for (StructureMap map : transforms.values()) {
716      boolean match = false;
717      boolean ok = true;
718      for (StructureMapStructureComponent t : map.getStructure()) {
719        if (t.getMode() == StructureMapModelMode.SOURCE) {
720          match = match || t.getUrl().equals(url);
721          ok = ok && t.getUrl().equals(url);
722        }
723      }
724      if (match && ok)
725        res.add(map);
726    }
727    return res;
728  }
729
730  public IValidatorFactory getValidatorFactory() {
731    return validatorFactory;
732  }
733
734  public void setValidatorFactory(IValidatorFactory validatorFactory) {
735    this.validatorFactory = validatorFactory;
736  }
737
738 
739  
740}