Package ca.uhn.fhir.validation

Source Code of ca.uhn.fhir.validation.SchemaBaseValidator$MyResourceResolver

package ca.uhn.fhir.validation;

/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.xml.XMLConstants;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.apache.commons.io.IOUtils;
import org.w3c.dom.ls.LSInput;
import org.w3c.dom.ls.LSResourceResolver;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu.resource.OperationOutcome.Issue;
import ca.uhn.fhir.model.dstu.valueset.IssueSeverityEnum;

class SchemaBaseValidator implements IValidator {
  private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SchemaBaseValidator.class);
  private static final Set<String> SCHEMA_NAMES;

  static {
    HashSet<String> sn = new HashSet<String>();
    sn.add("xml.xsd");
    sn.add("xhtml1-strict.xsd");
    sn.add("fhir-single.xsd");
    sn.add("tombstone.xsd");
    sn.add("opensearch.xsd");
    sn.add("opensearchscore.xsd");
    sn.add("xmldsig-core-schema.xsd");
    SCHEMA_NAMES = Collections.unmodifiableSet(sn);
  }

  private Map<String, Schema> myKeyToSchema = new HashMap<String, Schema>();

  private void doValidate(ValidationContext<?> theContext, String schemaName) {
    Schema schema = loadSchema("dstu", schemaName);

    try {
      Validator validator = schema.newValidator();
      MyErrorHandler handler = new MyErrorHandler(theContext);
      validator.setErrorHandler(handler);
      validator.validate(new StreamSource(new StringReader(theContext.getXmlEncodedResource())));
    } catch (SAXException e) {
      throw new ConfigurationException("Could not apply schema file", e);
    } catch (IOException e) {
      // This shouldn't happen since we're using a string source
      throw new ConfigurationException("Could not load/parse schema file", e);
    }
  }

  private Schema loadSchema(String theVersion, String theSchemaName) {
    String key = theVersion + "-" + theSchemaName;

    synchronized (myKeyToSchema) {
      Schema schema = myKeyToSchema.get(key);
      if (schema != null) {
        return schema;
      }

      Source baseSource = loadXml("dstu", null, theSchemaName);

      SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
      schemaFactory.setResourceResolver(new MyResourceResolver("dstu"));

      try {
        schema = schemaFactory.newSchema(new Source[] { baseSource });
      } catch (SAXException e) {
        throw new ConfigurationException("Could not load/parse schema file", e);
      }
      myKeyToSchema.put(key, schema);
      return schema;
    }
  }

  private Source loadXml(String theVersion, String theSystemId, String theSchemaName) {
    String pathToBase = "ca/uhn/fhir/model/" + theVersion + "/schema/" + theSchemaName;
    InputStream baseIs = FhirValidator.class.getClassLoader().getResourceAsStream(pathToBase);
    if (baseIs == null) {
      throw new ValidationFailureException("No FHIR-BASE schema found");
    }
    Source baseSource = new StreamSource(baseIs, theSystemId);
    return baseSource;
  }

  @Override
  public void validateBundle(ValidationContext<Bundle> theContext) {
    doValidate(theContext, "fhir-atom-single.xsd");
  }

  @Override
  public void validateResource(ValidationContext<IResource> theContext) {
    doValidate(theContext, "fhir-single.xsd");
  }

  private static class MyErrorHandler implements org.xml.sax.ErrorHandler {

    private ValidationContext<?> myContext;

    public MyErrorHandler(ValidationContext<?> theContext) {
      myContext = theContext;
    }

    private void addIssue(SAXParseException theException, IssueSeverityEnum severity) {
      Issue issue = myContext.getOperationOutcome().addIssue();
      issue.setSeverity(severity);
      issue.setDetails(theException.getLocalizedMessage());
      issue.addLocation().setValue("Line[" + theException.getLineNumber() + "] Col[" + theException.getColumnNumber() + "]");
    }

    @Override
    public void error(SAXParseException theException) throws SAXException {
      addIssue(theException, IssueSeverityEnum.ERROR);
    }

    @Override
    public void fatalError(SAXParseException theException) throws SAXException {
      addIssue(theException, IssueSeverityEnum.FATAL);
    }

    @Override
    public void warning(SAXParseException theException) throws SAXException {
      addIssue(theException, IssueSeverityEnum.WARNING);
    }

  }

  private static final class MyResourceResolver implements LSResourceResolver {
    private String myVersion;

    private MyResourceResolver(String theVersion) {
      myVersion = theVersion;
    }

    @Override
    public LSInput resolveResource(String theType, String theNamespaceURI, String thePublicId, String theSystemId, String theBaseURI) {
      if (theSystemId != null && SCHEMA_NAMES.contains(theSystemId)) {
        LSInputImpl input = new LSInputImpl();
        input.setPublicId(thePublicId);
        input.setSystemId(theSystemId);
        input.setBaseURI(theBaseURI);
        String pathToBase = "ca/uhn/fhir/model/" + myVersion + "/schema/" + theSystemId;
        InputStream baseIs = FhirValidator.class.getClassLoader().getResourceAsStream(pathToBase);
        if (baseIs == null) {
          throw new ValidationFailureException("No FHIR-BASE schema found");
        }

        ourLog.debug("Loading schema: {}", theSystemId);
        byte[] schema;
        try {
          schema = IOUtils.toByteArray(new InputStreamReader(baseIs, "UTF-8"));
        } catch (IOException e) {
          throw new ValidationFailureException("Failed to load schema " + theSystemId, e);
        }

        // Account for BOM in UTF-8 text (this seems to choke Java 6's built in XML reader)
        int offset = 0;
        if (schema[0] == (byte) 0xEF && schema[1] == (byte) 0xBB && schema[2] == (byte) 0xBF) {
          offset = 3;
        }

        try {
          input.setCharacterStream(new InputStreamReader(new ByteArrayInputStream(schema, offset, schema.length - offset), "UTF-8"));
        } catch (UnsupportedEncodingException e) {
          throw new ValidationFailureException("Failed to load schema " + theSystemId, e);
        }

        return input;

      }

      throw new ConfigurationException("Unknown schema: " + theBaseURI);
    }
  }

}
TOP

Related Classes of ca.uhn.fhir.validation.SchemaBaseValidator$MyResourceResolver

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.