Search in sources :

Example 11 with Binary

use of org.hl7.fhir.r4.model.Binary in project org.hl7.fhir.core by hapifhir.

the class BinaryRenderer method text.

private void text(XhtmlNode x, Binary bin) {
    String content = "\r\n" + getBinContentAsString(bin);
    XhtmlNode pre = x.pre();
    pre.code(content);
}
Also used : XhtmlNode(org.hl7.fhir.utilities.xhtml.XhtmlNode)

Example 12 with Binary

use of org.hl7.fhir.r4.model.Binary in project geoprism-registry by terraframe.

the class FhirBulkDataImporter method synchronize.

public void synchronize() {
    PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
    HttpClientBuilder builder = HttpClientBuilder.create();
    builder.setConnectionManager(connectionManager);
    CloseableHttpClient myClient = builder.build();
    FhirContext ctx = FhirContext.forR4();
    String statusUrl = initiateBulkExport(myClient, ctx);
    if (statusUrl != null) {
        final List<String> outputs = getExportResults(myClient, statusUrl);
        IGenericClient client = ctx.newRestfulGenericClient(this.system.getUrl());
        for (String binaryUrl : outputs) {
            Binary binary = client.fetchResourceFromUrl(Binary.class, binaryUrl);
            String base64 = binary.getContentAsBase64();
            byte[] result = Base64.getDecoder().decode(base64);
            IParser parser = ctx.newJsonParser();
            String message = new String(result);
            try (BufferedReader reader = new BufferedReader(new StringReader(message))) {
                String line = null;
                while ((line = reader.readLine()) != null) {
                    IBaseResource resource = parser.parseResource(line);
                    IIdType id = resource.getIdElement();
                    String resourceType = id.getResourceType();
                    if (resourceType.equals(ResourceTypes.LOCATION.toCode())) {
                        Location location = (Location) resource;
                        this.processor.process(location);
                    } else if (resourceType.equals(ResourceTypes.ORGANIZATION.toCode())) {
                        Organization organization = (Organization) resource;
                        this.processor.process(organization);
                    }
                }
            } catch (IOException e) {
                throw new ProgrammingErrorException(e);
            }
        }
    }
}
Also used : CloseableHttpClient(org.apache.http.impl.client.CloseableHttpClient) FhirContext(ca.uhn.fhir.context.FhirContext) Organization(org.hl7.fhir.r4.model.Organization) IGenericClient(ca.uhn.fhir.rest.client.api.IGenericClient) HttpClientBuilder(org.apache.http.impl.client.HttpClientBuilder) IOException(java.io.IOException) ProgrammingErrorException(com.runwaysdk.dataaccess.ProgrammingErrorException) PoolingHttpClientConnectionManager(org.apache.http.impl.conn.PoolingHttpClientConnectionManager) BufferedReader(java.io.BufferedReader) StringReader(java.io.StringReader) Binary(org.hl7.fhir.r4.model.Binary) IBaseResource(org.hl7.fhir.instance.model.api.IBaseResource) IParser(ca.uhn.fhir.parser.IParser) IIdType(org.hl7.fhir.instance.model.api.IIdType) Location(org.hl7.fhir.r4.model.Location)

Example 13 with Binary

use of org.hl7.fhir.r4.model.Binary in project hapi-fhir-jpaserver-starter by hapifhir.

the class BaseJpaRestfulServer method initialize.

@SuppressWarnings("unchecked")
@Override
protected void initialize() throws ServletException {
    super.initialize();
    /*
     * Create a FhirContext object that uses the version of FHIR
     * specified in the properties file.
     */
    // Customize supported resource types
    List<String> supportedResourceTypes = appProperties.getSupported_resource_types();
    if (!supportedResourceTypes.isEmpty()) {
        if (!supportedResourceTypes.contains("SearchParameter")) {
            supportedResourceTypes.add("SearchParameter");
        }
        daoRegistry.setSupportedResourceTypes(supportedResourceTypes);
    }
    setFhirContext(fhirSystemDao.getContext());
    /*
     * Order matters - the MDM provider registers itself on the resourceProviderFactory - hence the loading must be done
     * ahead of provider registration
     */
    if (appProperties.getMdm_enabled())
        mdmProviderProvider.get().loadProvider();
    registerProviders(resourceProviderFactory.createProviders());
    registerProvider(jpaSystemProvider);
    /*
     * The conformance provider exports the supported resources, search parameters, etc for
     * this server. The JPA version adds resourceProviders counts to the exported statement, so it
     * is a nice addition.
     *
     * You can also create your own subclass of the conformance provider if you need to
     * provide further customization of your server's CapabilityStatement
     */
    FhirVersionEnum fhirVersion = fhirSystemDao.getContext().getVersion().getVersion();
    if (fhirVersion == FhirVersionEnum.DSTU2) {
        JpaConformanceProviderDstu2 confProvider = new JpaConformanceProviderDstu2(this, fhirSystemDao, daoConfig);
        confProvider.setImplementationDescription("HAPI FHIR DSTU2 Server");
        setServerConformanceProvider(confProvider);
    } else {
        if (fhirVersion == FhirVersionEnum.DSTU3) {
            JpaConformanceProviderDstu3 confProvider = new JpaConformanceProviderDstu3(this, fhirSystemDao, daoConfig, searchParamRegistry);
            confProvider.setImplementationDescription("HAPI FHIR DSTU3 Server");
            setServerConformanceProvider(confProvider);
        } else if (fhirVersion == FhirVersionEnum.R4) {
            JpaCapabilityStatementProvider confProvider = new JpaCapabilityStatementProvider(this, fhirSystemDao, daoConfig, searchParamRegistry, myValidationSupport);
            confProvider.setImplementationDescription("HAPI FHIR R4 Server");
            setServerConformanceProvider(confProvider);
        } else if (fhirVersion == FhirVersionEnum.R5) {
            JpaCapabilityStatementProvider confProvider = new JpaCapabilityStatementProvider(this, fhirSystemDao, daoConfig, searchParamRegistry, myValidationSupport);
            confProvider.setImplementationDescription("HAPI FHIR R5 Server");
            setServerConformanceProvider(confProvider);
        } else {
            throw new IllegalStateException();
        }
    }
    if (appProperties.getEtag_support_enabled() == false)
        setETagSupport(ETagSupportEnum.DISABLED);
    /*
     * This server tries to dynamically generate narratives
     */
    FhirContext ctx = getFhirContext();
    INarrativeGenerator theNarrativeGenerator = appProperties.getNarrative_enabled() ? new DefaultThymeleafNarrativeGenerator() : new NullNarrativeGenerator();
    ctx.setNarrativeGenerator(theNarrativeGenerator);
    /*
     * Default to JSON and pretty printing
     */
    setDefaultPrettyPrint(appProperties.getDefault_pretty_print());
    /*
     * Default encoding
     */
    setDefaultResponseEncoding(appProperties.getDefault_encoding());
    /*
     * This configures the server to page search results to and from
     * the database, instead of only paging them to memory. This may mean
     * a performance hit when performing searches that return lots of results,
     * but makes the server much more scalable.
     */
    setPagingProvider(databaseBackedPagingProvider);
    /*
     * This interceptor formats the output using nice colourful
     * HTML output when the request is detected to come from a
     * browser.
     */
    ResponseHighlighterInterceptor responseHighlighterInterceptor = new ResponseHighlighterInterceptor();
    this.registerInterceptor(responseHighlighterInterceptor);
    if (appProperties.getFhirpath_interceptor_enabled()) {
        registerInterceptor(new FhirPathFilterInterceptor());
    }
    /*
     * Add some logging for each request
     */
    LoggingInterceptor loggingInterceptor = new LoggingInterceptor();
    loggingInterceptor.setLoggerName(appProperties.getLogger().getName());
    loggingInterceptor.setMessageFormat(appProperties.getLogger().getFormat());
    loggingInterceptor.setErrorMessageFormat(appProperties.getLogger().getError_format());
    loggingInterceptor.setLogExceptions(appProperties.getLogger().getLog_exceptions());
    this.registerInterceptor(loggingInterceptor);
    /*
     * If you are hosting this server at a specific DNS name, the server will try to
     * figure out the FHIR base URL based on what the web container tells it, but
     * this doesn't always work. If you are setting links in your search bundles that
     * just refer to "localhost", you might want to use a server address strategy:
     */
    String serverAddress = appProperties.getServer_address();
    if (!Strings.isNullOrEmpty(serverAddress)) {
        setServerAddressStrategy(new HardcodedServerAddressStrategy(serverAddress));
    } else if (appProperties.getUse_apache_address_strategy()) {
        boolean useHttps = appProperties.getUse_apache_address_strategy_https();
        setServerAddressStrategy(useHttps ? ApacheProxyAddressStrategy.forHttps() : ApacheProxyAddressStrategy.forHttp());
    } else {
        setServerAddressStrategy(new IncomingRequestAddressStrategy());
    }
    /*
     * If you are using DSTU3+, you may want to add a terminology uploader, which allows
     * uploading of external terminologies such as Snomed CT. Note that this uploader
     * does not have any security attached (any anonymous user may use it by default)
     * so it is a potential security vulnerability. Consider using an AuthorizationInterceptor
     * with this feature.
     */
    if (ctx.getVersion().getVersion().isEqualOrNewerThan(FhirVersionEnum.DSTU3)) {
        // <-- ENABLED RIGHT NOW
        registerProvider(myApplicationContext.getBean(TerminologyUploaderProvider.class));
    }
    // manual triggering of a subscription delivery, enable this provider
    if (true) {
        // <-- ENABLED RIGHT NOW
        registerProvider(myApplicationContext.getBean(SubscriptionTriggeringProvider.class));
    }
    // to your specific needs
    if (appProperties.getCors() != null) {
        ourLog.info("CORS is enabled on this server");
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedHeader(HttpHeaders.ORIGIN);
        config.addAllowedHeader(HttpHeaders.ACCEPT);
        config.addAllowedHeader(HttpHeaders.CONTENT_TYPE);
        config.addAllowedHeader(HttpHeaders.AUTHORIZATION);
        config.addAllowedHeader(HttpHeaders.CACHE_CONTROL);
        config.addAllowedHeader("x-fhir-starter");
        config.addAllowedHeader("X-Requested-With");
        config.addAllowedHeader("Prefer");
        List<String> allAllowedCORSOrigins = appProperties.getCors().getAllowed_origin();
        allAllowedCORSOrigins.forEach(config::addAllowedOriginPattern);
        ourLog.info("CORS allows the following origins: " + String.join(", ", allAllowedCORSOrigins));
        config.addExposedHeader("Location");
        config.addExposedHeader("Content-Location");
        config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH", "HEAD"));
        config.setAllowCredentials(appProperties.getCors().getAllow_Credentials());
        // Create the interceptor and register it
        CorsInterceptor interceptor = new CorsInterceptor(config);
        registerInterceptor(interceptor);
    } else {
        ourLog.info("CORS is disabled on this server");
    }
    // will activate them and match results against them
    if (appProperties.getSubscription() != null) {
        // Subscription debug logging
        interceptorService.registerInterceptor(new SubscriptionDebugLogInterceptor());
    }
    if (appProperties.getAllow_cascading_deletes()) {
        CascadingDeleteInterceptor cascadingDeleteInterceptor = new CascadingDeleteInterceptor(ctx, daoRegistry, interceptorBroadcaster);
        getInterceptorService().registerInterceptor(cascadingDeleteInterceptor);
    }
    // Binary Storage
    if (appProperties.getBinary_storage_enabled()) {
        getInterceptorService().registerInterceptor(binaryStorageInterceptor);
    }
    if (validatorModule != null) {
        if (appProperties.getValidation().getRequests_enabled()) {
            RequestValidatingInterceptor interceptor = new RequestValidatingInterceptor();
            interceptor.setFailOnSeverity(ResultSeverityEnum.ERROR);
            interceptor.setValidatorModules(Collections.singletonList(validatorModule));
            registerInterceptor(interceptor);
        }
        if (appProperties.getValidation().getResponses_enabled()) {
            ResponseValidatingInterceptor interceptor = new ResponseValidatingInterceptor();
            interceptor.setFailOnSeverity(ResultSeverityEnum.ERROR);
            interceptor.setValidatorModules(Collections.singletonList(validatorModule));
            registerInterceptor(interceptor);
        }
    }
    // GraphQL
    if (appProperties.getGraphql_enabled()) {
        if (fhirVersion.isEqualOrNewerThan(FhirVersionEnum.DSTU3)) {
            registerProvider(graphQLProvider.get());
        }
    }
    if (appProperties.getAllowed_bundle_types() != null) {
        daoConfig.setBundleTypesAllowedForStorage(appProperties.getAllowed_bundle_types().stream().map(BundleType::toCode).collect(Collectors.toSet()));
    }
    daoConfig.setDeferIndexingForCodesystemsOfSize(appProperties.getDefer_indexing_for_codesystems_of_size());
    if (appProperties.getOpenapi_enabled()) {
        registerInterceptor(new OpenApiInterceptor());
    }
    // Bulk Export
    if (appProperties.getBulk_export_enabled()) {
        registerProvider(bulkDataExportProvider);
    }
    // valueSet Operations i.e $expand
    registerProvider(myValueSetOperationProvider);
    // reindex Provider $reindex
    registerProvider(reindexProvider);
    // Partitioning
    if (appProperties.getPartitioning() != null) {
        registerInterceptor(new RequestTenantPartitionInterceptor());
        setTenantIdentificationStrategy(new UrlBaseTenantIdentificationStrategy());
        registerProviders(partitionManagementProvider);
    }
    if (appProperties.getClient_id_strategy() == DaoConfig.ClientIdStrategyEnum.ANY) {
        daoConfig.setResourceServerIdStrategy(DaoConfig.IdStrategyEnum.UUID);
        daoConfig.setResourceClientIdStrategy(appProperties.getClient_id_strategy());
    }
    // Parallel Batch GET execution settings
    daoConfig.setBundleBatchPoolSize(appProperties.getBundle_batch_pool_size());
    daoConfig.setBundleBatchPoolSize(appProperties.getBundle_batch_pool_max_size());
    if (appProperties.getImplementationGuides() != null) {
        Map<String, AppProperties.ImplementationGuide> guides = appProperties.getImplementationGuides();
        for (Map.Entry<String, AppProperties.ImplementationGuide> guide : guides.entrySet()) {
            PackageInstallationSpec packageInstallationSpec = new PackageInstallationSpec().setPackageUrl(guide.getValue().getUrl()).setName(guide.getValue().getName()).setVersion(guide.getValue().getVersion()).setInstallMode(PackageInstallationSpec.InstallModeEnum.STORE_AND_INSTALL);
            if (appProperties.getInstall_transitive_ig_dependencies()) {
                packageInstallationSpec.setFetchDependencies(true);
                packageInstallationSpec.setDependencyExcludes(ImmutableList.of("hl7.fhir.r2.core", "hl7.fhir.r3.core", "hl7.fhir.r4.core", "hl7.fhir.r5.core"));
            }
            packageInstallerSvc.install(packageInstallationSpec);
        }
    }
    if (factory != null) {
        interceptorService.registerInterceptor(factory.buildUsingStoredStructureDefinitions());
    }
    if (appProperties.getLastn_enabled()) {
        daoConfig.setLastNEnabled(true);
    }
    daoConfig.setStoreResourceInLuceneIndex(appProperties.getStore_resource_in_lucene_index_enabled());
    daoConfig.getModelConfig().setNormalizedQuantitySearchLevel(appProperties.getNormalized_quantity_search_level());
    daoConfig.getModelConfig().setIndexOnContainedResources(appProperties.getEnable_index_contained_resource());
}
Also used : FhirContext(ca.uhn.fhir.context.FhirContext) SubscriptionDebugLogInterceptor(ca.uhn.fhir.jpa.subscription.util.SubscriptionDebugLogInterceptor) FhirVersionEnum(ca.uhn.fhir.context.FhirVersionEnum) BundleType(org.hl7.fhir.r4.model.Bundle.BundleType) DefaultThymeleafNarrativeGenerator(ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator) UrlBaseTenantIdentificationStrategy(ca.uhn.fhir.rest.server.tenant.UrlBaseTenantIdentificationStrategy) RequestTenantPartitionInterceptor(ca.uhn.fhir.rest.server.interceptor.partition.RequestTenantPartitionInterceptor) JpaConformanceProviderDstu3(ca.uhn.fhir.jpa.provider.dstu3.JpaConformanceProviderDstu3) CascadingDeleteInterceptor(ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor) INarrativeGenerator(ca.uhn.fhir.narrative.INarrativeGenerator) PackageInstallationSpec(ca.uhn.fhir.jpa.packages.PackageInstallationSpec) CorsConfiguration(org.springframework.web.cors.CorsConfiguration) NullNarrativeGenerator(ca.uhn.fhir.narrative2.NullNarrativeGenerator) OpenApiInterceptor(ca.uhn.fhir.rest.openapi.OpenApiInterceptor)

Example 14 with Binary

use of org.hl7.fhir.r4.model.Binary in project geoprism-registry by terraframe.

the class AbstractFhirResourceProcessor method getGeometry.

protected Geometry getGeometry(Location location, ServerGeoObjectType type) {
    Extension extension = location.getExtensionByUrl("http://hl7.org/fhir/StructureDefinition/location-boundary-geojson");
    if (extension != null) {
        Attachment value = (Attachment) extension.getValue();
        if (value.hasData()) {
            Decoder decoder = Base64.getDecoder();
            byte[] binary = decoder.decode(value.getDataElement().getValueAsString());
            String geojson = new String(binary);
            GeoJsonReader reader = new GeoJsonReader();
            try {
                return reader.read(geojson);
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
    }
    return null;
}
Also used : Extension(org.hl7.fhir.r4.model.Extension) GeoJsonReader(com.vividsolutions.jts.io.geojson.GeoJsonReader) Attachment(org.hl7.fhir.r4.model.Attachment) ParseException(com.vividsolutions.jts.io.ParseException) Decoder(java.util.Base64.Decoder)

Example 15 with Binary

use of org.hl7.fhir.r4.model.Binary in project kindling by HL7.

the class ResourceValidator method check.

public void check(List<ValidationMessage> errors, String name, ResourceDefn rd) throws Exception {
    for (String s : rd.getHints()) hint(errors, IssueType.INFORMATIONAL, rd.getName(), false, s);
    rule(errors, IssueType.STRUCTURE, rd.getName(), !name.equals("Metadata"), "The name 'Metadata' is not a legal name for a resource");
    rule(errors, IssueType.STRUCTURE, rd.getName(), !name.equals("History"), "The name 'History' is not a legal name for a resource");
    rule(errors, IssueType.STRUCTURE, rd.getName(), !name.equals("Tag"), "The name 'Tag' is not a legal name for a resource");
    rule(errors, IssueType.STRUCTURE, rd.getName(), !name.equals("Tags"), "The name 'Tags' is not a legal name for a resource");
    rule(errors, IssueType.STRUCTURE, rd.getName(), !name.equals("MailBox"), "The name 'MailBox' is not a legal name for a resource");
    rule(errors, IssueType.STRUCTURE, rd.getName(), !name.equals("Validation"), "The name 'Validation' is not a legal name for a resource");
    rule(errors, IssueType.REQUIRED, rd.getName(), name.equals("Parameters") || translations.hasTranslation(name), "The name '" + name + "' is not found in the file translations.xml");
    rule(errors, IssueType.STRUCTURE, rd.getName(), name.length() > 1 && Character.isUpperCase(name.charAt(0)), "Resource Name must start with an uppercase alpha character");
    rule(errors, IssueType.STRUCTURE, rd.getName(), !Utilities.noString(rd.getFmmLevel()), "Resource must have a maturity level");
    // too many downstream issues in the parsers, and it would only happen as a transient thing when designing the resources
    rule(errors, IssueType.REQUIRED, rd.getName(), rd.getRoot().getElements().size() > 0, "A resource must have at least one element in it before the build can proceed");
    // too many downstream issues in the parsers, and it would only happen as a transient thing when designing the resources
    rule(errors, IssueType.REQUIRED, rd.getName(), rd.getWg() != null, "A resource must have a designated owner");
    rule(errors, IssueType.REQUIRED, rd.getName(), !Utilities.noString(rd.getRoot().getW5()), "A resource must have a W5 category");
    rd.getRoot().setMinCardinality(0);
    rd.getRoot().setMaxCardinality(Integer.MAX_VALUE);
    // pattern related rules
    buildW5Mappings(rd.getRoot(), true);
    if ((isWorkflowPattern(rd, "Event") || isWorkflowPattern(rd, "Request")) && hasPatient(rd)) {
        rule(errors, IssueType.STRUCTURE, rd.getName(), rd.getSearchParams().containsKey("patient"), "An 'event' or 'request' resource must have a search parameter 'patient'");
    }
    if (suppressedwarning(errors, IssueType.REQUIRED, rd.getName(), hasW5Mappings(rd) || rd.getName().equals("Binary") || rd.getName().equals("OperationOutcome") || rd.getName().equals("Parameters"), "A resource must have w5 mappings")) {
        String w5Order = listW5Elements(rd);
        String w5CorrectOrder = listW5Correct(rd);
        if (!w5Order.equals(w5CorrectOrder)) {
            warning(errors, IssueType.REQUIRED, rd.getName(), false, "Resource elements are out of order. The correct order is '" + w5CorrectOrder + "' but the actual order is '" + w5Order + "'");
        // System.out.println("Resource "+parent.getName()+": elements are out of order. The correct order is '"+w5CorrectOrder+"' but the actual order is '"+w5Order+"'");
        }
        if (!Utilities.noString(rd.getProposedOrder())) {
            w5Order = listW5Elements(rd, rd.getProposedOrder());
            if (!w5Order.equals(w5CorrectOrder)) {
                rule(errors, IssueType.REQUIRED, rd.getName(), false, "Proposed Resource elements are out of order. The correct order is '" + w5CorrectOrder + "' but the proposed order is '" + w5Order + "'");
            } else
                System.out.println("Proposed order for " + rd.getName() + ": build order ok");
        }
    }
    if (Utilities.noString(rd.getEnteredInErrorStatus()))
        if (hasStatus(rd, "entered-in-error"))
            rd.setEnteredInErrorStatus(".status = entered-in-error");
        else if (hasStatus(rd, "retired"))
            rd.setEnteredInErrorStatus(".status = retired");
        else if (hasActivFalse(rd))
            rd.setEnteredInErrorStatus(".active = false");
        else
            // too many downstream issues in the parsers, and it would only happen as a transient thing when designing the resources
            warning(errors, IssueType.REQUIRED, rd.getName(), false, "A resource must have an 'entered in error' status");
    String s = rd.getRoot().getMapping(Definitions.RIM_MAPPING);
    hint(errors, IssueType.REQUIRED, rd.getName(), !Utilities.noString(s), "RIM Mapping is required");
    for (Operation op : rd.getOperations()) {
        warning(errors, IssueType.BUSINESSRULE, rd.getName() + ".$" + op.getName(), hasOpExample(op.getExamples(), false), "Operation must have an example request");
        warning(errors, IssueType.BUSINESSRULE, rd.getName() + ".$" + op.getName(), hasOpExample(op.getExamples(), true), "Operation must have an example response");
    }
    List<String> vsWarns = new ArrayList<String>();
    int vsWarnings = checkElement(errors, rd.getName(), rd.getRoot(), rd, null, s == null || !s.equalsIgnoreCase("n/a"), false, hasSummary(rd.getRoot()), vsWarns, true, rd.getStatus());
    if (!resourceIsTechnical(name)) {
        // these are exempt because identification is tightly managed
        ElementDefn id = rd.getRoot().getElementByName(definitions, "identifier", true, false);
        if (id == null)
            warning(errors, IssueType.STRUCTURE, rd.getName(), false, "All resources should have an identifier");
        else
            rule(errors, IssueType.STRUCTURE, rd.getName(), id.typeCode().equals("Identifier"), "If a resource has an element named identifier, it must have a type 'Identifier'");
    }
    rule(errors, IssueType.STRUCTURE, rd.getName(), rd.getRoot().getElementByName(definitions, "text", true, false) == null, "Element named \"text\" not allowed");
    rule(errors, IssueType.STRUCTURE, rd.getName(), rd.getRoot().getElementByName(definitions, "contained", true, false) == null, "Element named \"contained\" not allowed");
    if (rd.getRoot().getElementByName(definitions, "subject", true, false) != null && rd.getRoot().getElementByName(definitions, "subject", true, false).typeCode().startsWith("Reference"))
        rule(errors, IssueType.STRUCTURE, rd.getName(), rd.getSearchParams().containsKey("subject"), "A resource that contains a subject reference must have a search parameter 'subject'");
    ElementDefn ped = rd.getRoot().getElementByName(definitions, "patient", true, false);
    if (ped != null && ped.typeCode().startsWith("Reference")) {
        SearchParameterDefn spd = rd.getSearchParams().get("patient");
        if (rule(errors, IssueType.STRUCTURE, rd.getName(), spd != null, "A resource that contains a patient reference must have a search parameter 'patient'"))
            rule(errors, IssueType.STRUCTURE, rd.getName(), (spd.getTargets().size() == 1 && spd.getTargets().contains("Patient")) || (ped.getTypes().get(0).getParams().size() == 1 && ped.getTypes().get(0).getParams().get(0).equals("Patient")), "A Patient search parameter must only refer to patient");
    }
    ElementDefn sed = rd.getRoot().getElementByName(definitions, "subject", true, false);
    if (sed != null && sed.typeCode().startsWith("Reference") && sed.typeCode().contains("Patient"))
        warning(errors, IssueType.STRUCTURE, rd.getName(), rd.getSearchParams().containsKey("patient"), "A resource that contains a subject that can be a patient reference must have a search parameter 'patient'");
    if (rd.getRoot().getElementByName(definitions, "identifier", true, false) != null) {
        warning(errors, IssueType.STRUCTURE, rd.getName(), rd.getSearchParams().containsKey("identifier"), "A resource that contains an identifier must have a search parameter 'identifier'");
    }
    if (rd.getRoot().getElementByName(definitions, "status", true, false) != null) {
        // todo: change to a warning post STU3
        hint(errors, IssueType.STRUCTURE, rd.getName(), rd.getSearchParams().containsKey("status"), "A resource that contains a status element must have a search parameter 'status'");
    }
    if (rd.getRoot().getElementByName(definitions, "url", true, false) != null) {
        warning(errors, IssueType.STRUCTURE, rd.getName(), rd.getSearchParams().containsKey("url"), "A resource that contains a url element must have a search parameter 'url'");
    }
    checkSearchParams(errors, rd);
    for (Operation op : rd.getOperations()) {
        rule(errors, IssueType.STRUCTURE, rd.getName() + "/$" + op.getName(), !parentHasOp(rd.getRoot().typeCode(), op.getName()), "Duplicate Operation Name $" + op.getName() + " on " + rd.getName());
    }
    for (Compartment c : definitions.getCompartments()) {
        if (rule(errors, IssueType.STRUCTURE, rd.getName(), name.equals("Parameters") || c.getResources().containsKey(rd), "Resource not entered in resource map for compartment '" + c.getTitle() + "' (compartments.xml)")) {
            String param = c.getResources().get(rd);
            if (!Utilities.noString(param)) {
                // rule(errors, IssueType.STRUCTURE, parent.getName(), param.equals("{def}") || parent.getSearchParams().containsKey(c.getName()), "Resource "+parent.getName()+" in compartment " +c.getName()+" must have a search parameter named "+c.getName().toLowerCase()+")");
                for (String p : param.split("\\|")) {
                    String pn = p.trim();
                    if (pn.contains("."))
                        pn = pn.substring(0, pn.indexOf("."));
                    rule(errors, IssueType.STRUCTURE, rd.getName(), Utilities.noString(pn) || pn.equals("{def}") || rd.getSearchParams().containsKey(pn), "Resource " + rd.getName() + " in compartment " + c.getName() + ": parameter " + param + " was not found (" + pn + ")");
                }
            }
        }
    }
    // Remove suppressed messages
    List<ValidationMessage> suppressed = new ArrayList<ValidationMessage>();
    for (ValidationMessage em : errors) {
        if (isSuppressedMessage(em.getDisplay())) {
            suppressed.add(em);
        }
    }
    errors.removeAll(suppressed);
    // last check: if maturity level is
    int warnings = 0;
    int hints = 0;
    for (ValidationMessage em : errors) {
        if (em.getLevel() == IssueSeverity.WARNING)
            warnings++;
        else if (em.getLevel() == IssueSeverity.INFORMATION)
            hints++;
    }
    boolean ok = warnings == 0 || "0".equals(rd.getFmmLevel());
    if (rule(errors, IssueType.STRUCTURE, rd.getName(), ok, "Resource " + rd.getName() + " (FMM=" + rd.getFmmLevel() + ") cannot have an FMM level >1 (" + rd.getFmmLevel() + ") if it has warnings"))
        rule(errors, IssueType.STRUCTURE, rd.getName(), vsWarnings == 0 || "0".equals(rd.getFmmLevel()), "Resource " + rd.getName() + " (FMM=" + rd.getFmmLevel() + ") cannot have an FMM level >1 (" + rd.getFmmLevel() + ") if it has linked value set warnings (" + vsWarns.toString() + ")");
    ok = hints == 0 || Integer.parseInt(rd.getFmmLevel()) < 3;
    rule(errors, IssueType.STRUCTURE, rd.getName(), ok, "Resource " + rd.getName() + " (FMM=" + rd.getFmmLevel() + ") cannot have an FMM level >2 (" + rd.getFmmLevel() + ") if it has informational hints");
// if (isInterface(rd.getRoot().typeCode())) {
// checkInterface(errors, rd, definitions.getBaseResources().get(rd.getRoot().typeCode()));
// }
}
Also used : ValidationMessage(org.hl7.fhir.utilities.validation.ValidationMessage)

Aggregations

XhtmlNode (org.hl7.fhir.utilities.xhtml.XhtmlNode)11 IBaseBinary (org.hl7.fhir.instance.model.api.IBaseBinary)5 ArrayList (java.util.ArrayList)4 FhirContext (ca.uhn.fhir.context.FhirContext)3 IOException (java.io.IOException)3 Test (org.junit.jupiter.api.Test)3 FhirVersionEnum (ca.uhn.fhir.context.FhirVersionEnum)2 CascadingDeleteInterceptor (ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor)2 DefaultThymeleafNarrativeGenerator (ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator)2 FileInputStream (java.io.FileInputStream)2 HashMap (java.util.HashMap)2 ResourceDefn (org.hl7.fhir.definitions.model.ResourceDefn)2 Turtle (org.hl7.fhir.dstu3.utils.formats.Turtle)2 Complex (org.hl7.fhir.dstu3.utils.formats.Turtle.Complex)2 Attachment (org.hl7.fhir.r4.model.Attachment)2 Binary (org.hl7.fhir.r4.model.Binary)2 Bundle (org.hl7.fhir.r4.model.Bundle)2 BundleType (org.hl7.fhir.r4.model.Bundle.BundleType)2 DocumentReference (org.hl7.fhir.r4.model.DocumentReference)2 ListResource (org.hl7.fhir.r4.model.ListResource)2