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