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