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

org.openehealth.ipf.commons.xml.AbstractCachingXmlProcessor Maven / Gradle / Ivy

There is a newer version: 5.0-m3
Show newest version
/*
 * Copyright 2014 the original author or authors.
 *
 * 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 org.openehealth.ipf.commons.xml;

import javax.xml.transform.stream.StreamSource;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;

/**
 * Abstract parent class for XML validators, transmogrifiers, and other classes
 * which cache static external resources in memory.
 * 
* On the basis of validator/transmogrifier parameters (Object... params), * instances of this class determine: *
    *
  • Location of the raw resource (i.e. an unparsed XSLT document as opposed * to its compiled representation in memory) — method {@link #resourceLocation(Object...)}, *
  • Parameters of resource instantiation (compilation) and execution (application) — * method {@link #resourceParameters(Object...)}, *
  • Key to store the compiled resource in the cache — * method {@link #resourceCacheKey(Object...)}. *
* The main method to get a ready-to-use resource instance is {@link #resource(Object...)}, * which takes over instantiation, initialization, caching, and other aspects of resource * lifecycle. For resource instantiation step, it calls the {@link #createResource(Object...)} * method, which is truly resource-type specific and thus declared as abstract * in the given base class. * * @param resource type. */ abstract public class AbstractCachingXmlProcessor { public static final String RESOURCE_LOCATION = "org.openehealth.ipf.commons.xml.ResourceLocation"; protected static abstract class Loader { private S loaded; abstract protected S load() throws RuntimeException; synchronized S get() { if (loaded == null) loaded = load(); return loaded; } } /** * Constructor. * * @param classLoader class loader, may be null. */ protected AbstractCachingXmlProcessor(ClassLoader classLoader) { super(); } /** * @return static cache for the configured resource type. * Note that the returned Map is not necessarily synchronized. */ abstract protected ConcurrentMap> getCache(); /** * Extracts (constructs) resource location from validator/transmogrifier parameters. * * @param params validator/transmogrifier parameters. * @return resource location as a String. */ protected String resourceLocation(Object... params) { if (params[0] instanceof String) { return (String) params[0]; } else if (params[0] instanceof Map) { return (String) ((Map) params[0]).get(RESOURCE_LOCATION); } else if (params[0] instanceof SchematronProfile) { var p = (SchematronProfile) params[0]; return p.getRules(); } throw new IllegalStateException("Cannot extract resource location"); } /** * Extracts (constructs) resource cache key validator/transmogrifier parameters. *

* Per default, the key equals to the resource location. * * @param params validator/transmogrifier parameters. * @return cache key as a String. */ protected String resourceCacheKey(Object... params) { return resourceLocation(params); } /** * Extracts (constructs) resource creation/application parameters from * validator/transmogrifier parameters. * * @param params validator/transmogrifier parameters. * @return resource creation/application parameters as a Map, * or null if not found. */ protected Map resourceParameters(Object... params) { if (params[0] instanceof Map) { return (Map) params[0]; } else if (params[0] instanceof SchematronProfile) { var p = (SchematronProfile) params[0]; return p.getParameters(); } else if (params.length > 1 && params[1] instanceof Map) { return (Map) params[1]; } return null; } /** * Retrieves from the cache and returns the resource with the given location and * further attributes. If necessary, creates the resource by means of * {@link #createResource(Object...)} and stores it into the cache. * The cache key is a combination of the location and further attributes. *

* This method MUST be re-entrant, its result MUST be thread-safe. * * @param params validator/transmogrifier parameters. * @return resource instance. * @throws Exception */ protected T resource(final Object... params) throws Exception { var key = resourceCacheKey(params); getCache().putIfAbsent(key, new Loader<>() { @Override protected T load() throws RuntimeException { return createResource(params); } }); return getCache().get(key).get(); } /** * Creates a ready-to-use resource (e.g. an XML Schema instance) for the given key. * Insertion into the cache will happen externally, this method's purpose * is only to instantiate the resource to be cached. *

* This method does not need to be re-entrant, but its result MUST be thread-safe. * * @param params validator/transmogrifier parameters. * @return resource of the configured type. */ abstract protected T createResource(Object... params); /** * Loads the resource into memory and returns it as a Stream. *

* This method does not need to be re-entrant. * * @param params validator/transmogrifier parameters. * @return resource of the configured type. */ protected StreamSource resourceContent(Object... params) { var location = resourceLocation(params); URL url; try { if (location.startsWith("/")) { url = getClass().getResource(location); } else { try { // Try to parse the location as a URL... url = new URL(location); } catch (MalformedURLException ex) { // No URL -> resolve as resource path. url = getClass().getClassLoader().getResource(location); if (url == null) throw new IOException("Location not found"); } } return new StreamSource(url.openStream(), url.toExternalForm()); } catch (IOException e) { throw new IllegalArgumentException("The resource " + location + " is not valid", e); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy