Java tutorial
/****************************************************************************/ /* File: ExistRepository.java */ /* Author: F. Georges - H2O Consulting */ /* Date: 2010-09-22 */ /* Tags: */ /* Copyright (c) 2010 Florent Georges (see end of file.) */ /* ------------------------------------------------------------------------ */ package org.exist.repo; import java.io.File; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.net.URI; import java.net.URISyntaxException; import java.util.*; import javax.xml.transform.stream.StreamSource; import org.apache.commons.io.FileUtils; import org.apache.log4j.Logger; import org.exist.EXistException; import org.exist.storage.BrokerPool; import org.exist.storage.NativeBroker; import org.exist.util.Configuration; import org.exist.xquery.Module; import org.exist.xquery.XPathException; import org.exist.xquery.XQueryContext; import org.expath.pkg.repo.FileSystemStorage; import org.expath.pkg.repo.FileSystemStorage.FileSystemResolver; import org.expath.pkg.repo.Package; import org.expath.pkg.repo.Packages; import org.expath.pkg.repo.PackageException; import org.expath.pkg.repo.Repository; import org.expath.pkg.repo.URISpace; /** * A repository as viewed by eXist. * * @author Florent Georges * @author Wolfgang Meier * @since 2010-09-22 */ public class ExistRepository extends Observable { public final static String EXPATH_REPO_DIR = "expathrepo"; public final static String EXPATH_REPO_DEFAULT = "webapp/WEB-INF/" + EXPATH_REPO_DIR; public final static Logger LOG = Logger.getLogger(ExistRepository.class); public ExistRepository(FileSystemStorage storage) throws PackageException { myParent = new Repository(storage); myParent.registerExtension(new ExistPkgExtension()); } public Repository getParentRepo() { return myParent; } public Module resolveJavaModule(String namespace, XQueryContext ctxt) throws XPathException { // the URI URI uri; try { uri = new URI(namespace); } catch (final URISyntaxException ex) { throw new XPathException("Invalid URI: " + namespace, ex); } for (final Packages pp : myParent.listPackages()) { final Package pkg = pp.latest(); final ExistPkgInfo info = (ExistPkgInfo) pkg.getInfo("exist"); if (info != null) { final String clazz = info.getJava(uri); if (clazz != null) { return getModule(clazz, namespace, ctxt); } } } return null; } /** * Load a module instance from its class name. Check the namespace is consistent. */ private Module getModule(String name, String namespace, XQueryContext ctxt) throws XPathException { try { final Class clazz = Class.forName(name); final Module module = instantiateModule(clazz); final String ns = module.getNamespaceURI(); if (!ns.equals(namespace)) { throw new XPathException("The namespace in the Java module " + "does not match the namespace in the package descriptor: " + namespace + " - " + ns); } return ctxt.loadBuiltInModule(namespace, name); } catch (final ClassNotFoundException ex) { throw new XPathException("Cannot find module class from EXPath repository: " + name, ex); } catch (final InstantiationException ex) { throw new XPathException("Problem instantiating module class from EXPath repository: " + name, ex); } catch (final IllegalAccessException ex) { throw new XPathException("Problem instantiating module class from EXPath repository: " + name, ex); } catch (final InvocationTargetException ex) { throw new XPathException("Problem instantiating module class from EXPath repository: " + name, ex); } catch (final ClassCastException ex) { throw new XPathException("The class configured in EXPath repository is not a Module: " + name, ex); } catch (final IllegalArgumentException ex) { throw new XPathException("Illegal argument passed to the module ctor", ex); } } /** * Try to instantiate the class using the constructor with a Map parameter, * or the default constructor. */ private Module instantiateModule(Class clazz) throws XPathException, InstantiationException, IllegalAccessException, InvocationTargetException { try { final Constructor ctor = clazz.getConstructor(Map.class); return (Module) ctor.newInstance(EMPTY_MAP); } catch (final NoSuchMethodException ex) { try { final Constructor ctor = clazz.getConstructor(); return (Module) ctor.newInstance(); } catch (final NoSuchMethodException exx) { throw new XPathException("Cannot find suitable constructor " + "for module from expath repository", exx); } } } public File resolveXQueryModule(String namespace) throws XPathException { // the URI URI uri; try { uri = new URI(namespace); } catch (final URISyntaxException ex) { throw new XPathException("Invalid URI: " + namespace, ex); } for (final Packages pp : myParent.listPackages()) { final Package pkg = pp.latest(); // FIXME: Rely on having a file system storage, that's probably a bad design! final FileSystemResolver resolver = (FileSystemResolver) pkg.getResolver(); final ExistPkgInfo info = (ExistPkgInfo) pkg.getInfo("exist"); if (info != null) { final String f = info.getXQuery(uri); if (f != null) { return resolver.resolveComponentAsFile(f); } } String sysid = null; // declared here to be used in catch try { final StreamSource src = pkg.resolve(namespace, URISpace.XQUERY); if (src != null) { sysid = src.getSystemId(); return new File(new URI(sysid)); } } catch (final URISyntaxException ex) { throw new XPathException("Error parsing the URI of the query library: " + sysid, ex); } catch (final PackageException ex) { throw new XPathException("Error resolving the query library: " + namespace, ex); } } return null; } public List<URI> getJavaModules() { final List<URI> modules = new ArrayList<URI>(13); for (final Packages pp : myParent.listPackages()) { final Package pkg = pp.latest(); final ExistPkgInfo info = (ExistPkgInfo) pkg.getInfo("exist"); if (info != null) { modules.addAll(info.getJavaModules()); } } return modules; } public static ExistRepository getRepository(Configuration config) throws PackageException { final File expathDir = getRepositoryDir(config); LOG.info("Using directory " + expathDir.getAbsolutePath() + " for expath package repository"); final FileSystemStorage storage = new FileSystemStorage(expathDir); return new ExistRepository(storage); } public static File getRepositoryDir(Configuration config) { String dataDirPath = (String) config.getProperty(BrokerPool.PROPERTY_DATA_DIR); if (dataDirPath == null) { dataDirPath = NativeBroker.DEFAULT_DATA_DIR; } final File dataDir = new File(dataDirPath); final File expathDir = new File(dataDir, EXPATH_REPO_DIR); if (!expathDir.exists()) { moveOldRepo(config.getExistHome(), expathDir); } expathDir.mkdir(); return expathDir; } private static void moveOldRepo(File home, File newRepo) { File repo_dir = null; if (home != null) { if ("WEB-INF".equals(home.getName())) { repo_dir = new File(home, EXPATH_REPO_DIR); } else { repo_dir = new File(home, EXPATH_REPO_DEFAULT); } } else { repo_dir = new File(System.getProperty("java.io.tmpdir"), EXPATH_REPO_DIR); } if (repo_dir.exists() && repo_dir.canRead()) { LOG.info( "Found old expathrepo directory. Moving to new default location: " + newRepo.getAbsolutePath()); try { FileUtils.moveDirectory(repo_dir, newRepo); } catch (final IOException e) { LOG.error("Failed to move old expathrepo directory to new default location. Keeping it.", e); } } } public void reportAction(Action action, String packageURI) { notifyObservers(new Notification(action, packageURI)); setChanged(); } /** The wrapped EXPath repository. */ private Repository myParent; /** An empty map for constructors expecting a parameter map. */ private static final Map<String, List<Object>> EMPTY_MAP = new HashMap<String, List<Object>>(); public enum Action { INSTALL, UNINSTALL } public final static class Notification { private Action action; private String packageURI; public Notification(Action action, String packageURI) { this.action = action; this.packageURI = packageURI; } public Action getAction() { return action; } public String getPackageURI() { return packageURI; } } } /* ------------------------------------------------------------------------ */ /* 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. */ /* ------------------------------------------------------------------------ */