com.helger.schematron.schxslt.xslt2.SchematronResourceSchXslt_XSLT2Cache Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ph-schematron-schxslt Show documentation
Show all versions of ph-schematron-schxslt Show documentation
Library for validating XML documents using the SchXslt implementation
/*
* Copyright (C) 2020-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.schematron.schxslt.xslt2;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.helger.commons.ValueEnforcer;
import com.helger.commons.collection.impl.CommonsHashMap;
import com.helger.commons.collection.impl.ICommonsMap;
import com.helger.commons.concurrent.SimpleReadWriteLock;
import com.helger.commons.io.resource.IReadableResource;
import com.helger.commons.string.StringHelper;
import com.helger.xml.serialize.write.XMLWriter;
/**
* Factory for creating {@link SchematronProviderXSLTFromSchXslt_XSLT2} objects.
*
* @author Philip Helger
*/
@ThreadSafe
public final class SchematronResourceSchXslt_XSLT2Cache
{
private static final Logger LOGGER = LoggerFactory.getLogger (SchematronResourceSchXslt_XSLT2Cache.class);
private static final SimpleReadWriteLock RW_LOCK = new SimpleReadWriteLock ();
@GuardedBy ("RW_LOCK")
private static final ICommonsMap MAP = new CommonsHashMap <> ();
private SchematronResourceSchXslt_XSLT2Cache ()
{}
/**
* Create a new Schematron validator for the passed resource.
*
* @param aSchematronResource
* The resource of the Schematron rules. May not be null
.
* @param aTransformerCustomizer
* The XSLT transformer customizer to be used. May not be
* null
.
* @return null
if the passed Schematron resource does not exist
* or is invalid.
*/
@Nullable
public static SchematronProviderXSLTFromSchXslt_XSLT2 createSchematronXSLTProvider (@Nonnull final IReadableResource aSchematronResource,
@Nonnull final TransformerCustomizerSchXslt_XSLT2 aTransformerCustomizer)
{
if (LOGGER.isDebugEnabled ())
LOGGER.debug ("Compiling Schematron instance " + aSchematronResource.toString ());
final SchematronProviderXSLTFromSchXslt_XSLT2 aXSLTPreprocessor = new SchematronProviderXSLTFromSchXslt_XSLT2 (aSchematronResource,
aTransformerCustomizer);
// This is the call to convert Schematron to XSLT
aXSLTPreprocessor.convertSchematronToXSLT ();
if (!aXSLTPreprocessor.isValidSchematron ())
{
// Schematron is invalid -> parsing failed
LOGGER.warn ("The Schematron resource '" + aSchematronResource.getResourceID () + "' is invalid!");
if (LOGGER.isDebugEnabled () && aXSLTPreprocessor.getXSLTDocument () != null)
{
// Log the created XSLT document for better error tracking
LOGGER.debug (" Created XSLT document:\n" + XMLWriter.getNodeAsString (aXSLTPreprocessor.getXSLTDocument ()));
}
return null;
}
// If it is a valid schematron, there must be a result XSLT present!
if (aXSLTPreprocessor.getXSLTDocument () == null)
throw new IllegalStateException ("No XSLT document retrieved from Schematron resource '" +
aSchematronResource.getResourceID () +
"'!");
if (LOGGER.isDebugEnabled ())
LOGGER.debug ("Finished compiling Schematron instance " + aSchematronResource.toString ());
// Create the main validator for the schematron
return aXSLTPreprocessor;
}
/**
* Get the Schematron validator for the passed resource. If no custom
* parameter are present, the result is cached. The respective cache key is a
* combination of the Schematron resource path, the phase and the language
* code.
*
* @param aSchematronResource
* The resource of the Schematron rules. May not be null
.
* @param aTransformerCustomizer
* The XSLT transformer customizer to be used. May not be
* null
.
* @return null
if the passed Schematron resource does not exist
* or is invalid.
*/
@Nullable
public static SchematronProviderXSLTFromSchXslt_XSLT2 getSchematronXSLTProvider (@Nonnull final IReadableResource aSchematronResource,
@Nonnull final TransformerCustomizerSchXslt_XSLT2 aTransformerCustomizer)
{
ValueEnforcer.notNull (aSchematronResource, "SchematronResource");
ValueEnforcer.notNull (aTransformerCustomizer, "TransformerCustomizer");
if (!aSchematronResource.exists ())
{
LOGGER.warn ("Schematron resource " + aSchematronResource + " does not exist!");
return null;
}
if (!aTransformerCustomizer.canCacheResult ())
{
// Create new object and return without cache handling because the custom
// parameters may have side effects on the created XSLT!
return createSchematronXSLTProvider (aSchematronResource, aTransformerCustomizer);
}
// Determine the unique resource ID for caching
final String sCacheKey = StringHelper. getImploded (':',
aSchematronResource.getResourceID (),
StringHelper.getNotNull (aTransformerCustomizer.getPhase ()),
StringHelper.getNotNull (aTransformerCustomizer.getLanguageCode ()));
// Validator already in the cache?
SchematronProviderXSLTFromSchXslt_XSLT2 aProvider = RW_LOCK.readLockedGet ( () -> MAP.get (sCacheKey));
if (aProvider == null)
{
// Check again in write lock
aProvider = RW_LOCK.writeLockedGet ( () -> MAP.get (sCacheKey));
if (aProvider == null)
{
// Create new object outside of the write lock
final SchematronProviderXSLTFromSchXslt_XSLT2 aProviderNew = createSchematronXSLTProvider (aSchematronResource,
aTransformerCustomizer);
if (aProviderNew != null)
{
// Put in cache
RW_LOCK.writeLocked ( () -> MAP.put (sCacheKey, aProviderNew));
}
aProvider = aProviderNew;
}
}
return aProvider;
}
/**
* Clear the internal cache.
*/
public static void clearCache ()
{
RW_LOCK.writeLocked (MAP::clear);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy