All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.helger.phive.ves.engine.load.DefaultVESLoaderSchematron Maven / Gradle / Ivy

/*
 * Copyright (C) 2023-2024 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * 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.
 */
package com.helger.phive.ves.engine.load;

import java.util.List;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.helger.commons.ValueEnforcer;
import com.helger.commons.collection.impl.CommonsArrayList;
import com.helger.commons.collection.impl.CommonsHashMap;
import com.helger.commons.collection.impl.ICommonsList;
import com.helger.commons.collection.impl.ICommonsMap;
import com.helger.commons.error.SingleError;
import com.helger.commons.error.level.EErrorLevel;
import com.helger.commons.error.list.ErrorList;
import com.helger.commons.io.resource.IReadableResource;
import com.helger.commons.string.StringHelper;
import com.helger.diver.repo.IRepoStorageBase;
import com.helger.diver.repo.IRepoStorageReadItem;
import com.helger.diver.repo.RepoStorageKey;
import com.helger.diver.repo.RepoStorageReadableResource;
import com.helger.phive.api.executor.IValidationExecutor;
import com.helger.phive.ves.v10.VesCustomErrorType;
import com.helger.phive.ves.v10.VesOutputType;
import com.helger.phive.ves.v10.VesSchematronType;
import com.helger.phive.xml.schematron.CustomErrorDetails;
import com.helger.phive.xml.schematron.ESchematronEngine;
import com.helger.phive.xml.schematron.ValidationExecutorSchematron;
import com.helger.phive.xml.source.IValidationSourceXML;
import com.helger.xml.namespace.MapBasedNamespaceContext;

/**
 * The default implementation of {@link IVESLoaderSchematron} for Schematron
 * validation.
 *
 * @author Philip Helger
 */
public class DefaultVESLoaderSchematron implements IVESLoaderSchematron
{
  public static final String RESOURCE_TYPE_SCH = "sch";
  public static final String FILE_EXT_SCH = '.' + RESOURCE_TYPE_SCH;
  public static final String RESOURCE_TYPE_XSLT = "xslt";
  public static final String FILE_EXT_XSLT = '.' + RESOURCE_TYPE_XSLT;

  private static final Logger LOGGER = LoggerFactory.getLogger (DefaultVESLoaderSchematron.class);

  @Nonnull
  public ICommonsList > loadSchematrons (@Nonnull final IRepoStorageBase aRepo,
                                                                                    @Nonnull final List  aSCHList,
                                                                                    @Nullable final LoadedVES.RequiredVES aLoadingRequiredVES,
                                                                                    @Nonnull final ErrorList aErrorList,
                                                                                    @Nonnull final IVESAsyncLoader aAsyncLoader)
  {
    ValueEnforcer.notNull (aRepo, "Repo");
    ValueEnforcer.notEmptyNoNullValue (aSCHList, "SCHList");
    ValueEnforcer.notNull (aErrorList, "ErrorList");
    ValueEnforcer.notNull (aAsyncLoader, "AsyncLoader");

    final ICommonsList > ret = new CommonsArrayList <> ();

    for (final VesSchematronType aSCH : aSCHList)
    {
      final RepoStorageKey aSCHKey = VESLoader.createRepoStorageKey (aSCH.getResource ());

      // Read referenced Item
      final IRepoStorageReadItem aSCHItem = aRepo.read (aSCHKey);
      if (aSCHItem == null)
      {
        aErrorList.add (SingleError.builderError ()
                                   .errorFieldName (aSCHKey.getPath ())
                                   .errorText ("Failed to load Schematron artifact from repository")
                                   .build ());
        continue;
      }

      // Readable resource from repository content
      final IReadableResource aRepoRes = new RepoStorageReadableResource (aSCHKey, aSCHItem.getContent ());

      // Resolve Namespace Context
      final MapBasedNamespaceContext aNSCtx = new MapBasedNamespaceContext ();
      VESLoader.internalWrapNamespaceList (aSCH.getNamespaces (), aNSCtx);

      final ValidationExecutorSchematron aExecutorSCH;
      final String sResourceType = aSCH.getResource ().getType ();
      switch (sResourceType)
      {
        case RESOURCE_TYPE_SCH:
        {
          // Resolve Schematron Engine
          final String sEngine = aSCH.getEngine ();
          final ESchematronEngine eEngine = ESchematronEngine.getFromIDOrNull (sEngine);
          if (eEngine == null)
          {
            aErrorList.add (SingleError.builderError ()
                                       .errorText ("Schematron engine '" +
                                                   sEngine +
                                                   "' is unknown. Valid IDs are: " +
                                                   StringHelper.imploder ()
                                                               .source (ESchematronEngine.values (),
                                                                        x -> "'" + x.getID () + "'")
                                                               .separator (", ")
                                                               .build ())
                                       .build ());
            continue;
          }

          switch (eEngine)
          {
            case PURE:
              aExecutorSCH = ValidationExecutorSchematron.createPure (aRepoRes, aNSCtx);
              break;
            case ISO_SCHEMATRON:
              aExecutorSCH = ValidationExecutorSchematron.createSCH (aRepoRes, aNSCtx);
              break;
            case SCHXSLT:
              aExecutorSCH = ValidationExecutorSchematron.createSchXslt (aRepoRes, aNSCtx);
              break;
            default:
              throw new IllegalStateException ("Unsupported Schematron engine " + eEngine);
          }
          break;
        }
        case RESOURCE_TYPE_XSLT:
        {
          // Indicate a potential error
          if (StringHelper.hasText (aSCH.getEngine ()))
          {
            aErrorList.add (SingleError.builderWarn ()
                                       .errorText ("Schematron resource type '" +
                                                   sResourceType +
                                                   "' does not support the 'engine' element")
                                       .build ());
          }

          // Simple
          aExecutorSCH = ValidationExecutorSchematron.createXSLT (aRepoRes, aNSCtx);
          break;
        }
        default:
        {
          aErrorList.add (SingleError.builderError ()
                                     .errorText ("Unsupported Schematron resource type '" + sResourceType + "' found")
                                     .build ());
          continue;
        }
      }

      final ICommonsMap  aCustomErrorDetails = new CommonsHashMap <> ();

      // Is something defined at the Schematron itself?
      if (aSCH.getOutput () != null)
      {
        final VesOutputType aOutput = aSCH.getOutput ();

        // Check for custom error levels
        if (aOutput.hasCustomErrorEntries ())
          for (final VesCustomErrorType aCustomError : aOutput.getCustomError ())
          {
            final String sKey = aCustomError.getId ();
            final EErrorLevel eErrorLevel = VESLoader.internalWrapErrorLevel (aCustomError.getLevel ());
            if (StringHelper.hasText (sKey) && eErrorLevel != null)
              aCustomErrorDetails.put (sKey,
                                       new CustomErrorDetails (eErrorLevel,
                                                               aCustomError.getErrorTextPrefix (),
                                                               aCustomError.getErrorTextSuffix ()));
          }
      }

      // Are we changing the output levels on a "required" resource?
      if (aLoadingRequiredVES != null && aLoadingRequiredVES.getOutput ().customErrorDetails ().isNotEmpty ())
      {
        // These ones overwrite the original ones
        aCustomErrorDetails.putAll (aLoadingRequiredVES.getOutput ().customErrorDetails ());
      }

      if (aCustomErrorDetails.isNotEmpty ())
        aExecutorSCH.addCustomErrorDetails (aCustomErrorDetails);

      LOGGER.info ("Loaded ValidationExecutorSchematron using resource type '" +
                   sResourceType +
                   "' and path '" +
                   aSCHKey.getPath () +
                   "'");
      ret.add (aExecutorSCH);
    }

    return ret;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy