/****************************************************************************/ /* File: SaxonRepository.java */ /* Author: F. Georges */ /* Company: H2O Consulting */ /* Date: 2010-05-11 */ /* Tags: */ /* Copyright (c) 2010-2015 Florent Georges (see end of file.) */ /* ------------------------------------------------------------------------ */ package org.expath.pkg.saxon; import java.io.File; import java.net.URI; import java.util.HashMap; import java.util.Map; import javax.xml.transform.Source; import javax.xml.transform.URIResolver; import net.sf.saxon.Configuration; import net.sf.saxon.lib.ModuleURIResolver; import org.expath.pkg.repo.Package; import org.expath.pkg.repo.PackageException; import org.expath.pkg.repo.Packages; import org.expath.pkg.repo.Repository; import org.expath.pkg.repo.Storage; import org.expath.pkg.repo.URISpace; import org.expath.pkg.repo.UserInteractionStrategy; import org.expath.pkg.repo.tools.Logger; /** * Wrap an EXPath repository with Saxon-specific services. * * This handle for instance the extension functions written specifically for * Saxon in Java. * * TODO: Document the "override" mechanism. * * @author Florent Georges */ public class SaxonRepository { public SaxonRepository(Storage storage) throws PackageException { this(new Repository(storage)); } public SaxonRepository(Repository parent) throws PackageException { myParent = parent; parent.registerExtension(new SaxonPkgExtension()); } public Repository getUnderlyingRepo() { return myParent; } /** * Install a package from a file. * * @param pkg The package file (typically a {@code *.xar} or {@code *.xaw} file). * * @param force If false, an error is thrown if the package already exists. * If true, the package is first deleted from the repository if it already exists. * * @param interact How the repository interacts with the user. * * @return The freshly installed package. * * @throws PackageException If any error occurs. */ public Package installPackage(File pkg, boolean force, UserInteractionStrategy interact) throws PackageException { return myParent.installPackage(pkg, force, interact); } /** * Install a package from a URI location. * * @param pkg The package file (typically a {@code *.xar} or {@code *.xaw} file). * * @param force If false, an error is thrown if the package already exists. * If true, the package is first deleted from the repository if it already exists. * * @param interact How the repository interacts with the user. * * @return The freshly installed package. * * @throws PackageException If any error occurs. */ public Package installPackage(URI pkg, boolean force, UserInteractionStrategy interact) throws PackageException { return myParent.installPackage(pkg, force, interact); } /** * Remove a package from the repository, by name. * * If a package with that name does not exist, or if there are several * versions installed, this is an error (except if the package does not * exist and {@code force} is {@code true}, then simply returns {@code * false}). * * @param pkg The package name. * * @param force To silently ignore a non existing package (simply returns * {@code false} in that case). * * @param interact How the repository interacts with the user. * * @return True if the package has been successfully removed, false if not * (false is returned when the user canceled removing interactively, or if * the package does not exist and {@code force} is true). * * @throws PackageException If any error occurs during removal. */ public boolean removePackage(String pkg, boolean force, UserInteractionStrategy interact) throws PackageException { return myParent.removePackage(pkg, force, interact); } /** * Resolve a Saxon-specific stuff in this repository, in the specified space, return a File. * * TODO: FIXME: To handle empty wrappers, just forget about the generated * files and so on. Just return a StreamSource over a StringReader over * a generated string with the empty stylesheet or query module. That * small enough to be all dealt in memory, without filesystem access. Even * better! And no need for install step! * * TODO: Regarding versionning, see comments of {@link Repository#resolve(String,URISpace)} * (AKA we don't always want the latest version). */ public Source resolve(String href, URISpace space) throws PackageException { return myParent.resolve(href, space); } public ModuleURIResolver getModuleURIResolver() throws PackageException { Map<String, String> overrides = getOverrides(); return new PkgModuleResolver(overrides, this, myParent); } // Is 'space' required? Shouldn't that be always XSLT? Do we want to // support SCHEMATRON as well? If we keep 'space', do check this is an // acceptable value. public URIResolver getURIResolver(URISpace space) throws PackageException { Map<String, String> overrides = getOverrides(); URIResolver parent = new org.expath.pkg.repo.resolver.PkgURIResolver(myParent, space); return new PkgURIResolver(overrides, this, parent, space); } /** * TODO: Regarding versionning, see comments of {@link Repository#resolve(String,URISpace)} * (AKA we don't always want the latest version). */ public void registerExtensionFunctions(Configuration config) throws PackageException { for ( Packages pp : myParent.listPackages() ) { Package pkg = pp.latest(); SaxonPkgInfo info = (SaxonPkgInfo) pkg.getInfo("saxon"); if ( info != null ) { info.registerExtensionFunctions(config); } } } private static synchronized Map<String, String> getOverrides() throws PackageException { if ( OVERRIDES == null ) { OVERRIDES = parseOverrideProperty(); } return OVERRIDES; } /** * ... */ private static Map<String, String> parseOverrideProperty() throws PackageException { Map<String, String> res = new HashMap<String, String>(); String prop = System.getProperty(OVERRIDE_PROP); if ( prop == null || "".equals(prop) ) { return res; } LOG.fine("Property {0} value is: {1}", OVERRIDE_PROP, prop); for ( String override : prop.split(",") ) { // ignore empty one (so allow the prop ",something else") if ( override == null || "".equals(override) ) { continue; } String[] split = override.split("\\|"); if ( split == null || split.length != 2 ) { throw new PackageException("Wrong resolve value: " + prop); } res.put(split[0], split[1]); } return res; } /** The wrapped EXPath repository. */ private Repository myParent; /** The system property name for the overrides. */ private static final String OVERRIDE_PROP = "org.expath.pkg.saxon.resolve"; /** The cached overrides map. */ private static Map<String, String> OVERRIDES = null; /** The logger. */ private static final Logger LOG = Logger.getLogger(SaxonRepository.class); } /* ------------------------------------------------------------------------ */ /* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS COMMENT. */ /* */ /* The contents of this file are subject to the Mozilla Public License */ /* Version 1.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.mozilla.org/MPL/. */ /* */ /* Software distributed under the License is distributed on an "AS IS" */ /* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */ /* the License for the specific language governing rights and limitations */ /* under the License. */ /* */ /* The Original Code is: all this file. */ /* */ /* The Initial Developer of the Original Code is Florent Georges. */ /* */ /* Contributor(s): none. */ /* ------------------------------------------------------------------------ */