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