org.exist.repo.ExistRepository.java Source code

Java tutorial

Introduction

Here is the source code for org.exist.repo.ExistRepository.java

Source

/****************************************************************************/
/*  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.                                                   */
/* ------------------------------------------------------------------------ */