com.yourmediashelf.fedora.cargo.FedoraHome.java Source code

Java tutorial

Introduction

Here is the source code for com.yourmediashelf.fedora.cargo.FedoraHome.java

Source

/**
 * Copyright (C) 2012 MediaShelf <http://www.yourmediashelf.com/>
 *
 * This file is part of fedora-cargo-plugin.
 *
 * fedora-cargo-plugin is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * fedora-cargo-plugin is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with fedora-cargo-plugin.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.yourmediashelf.fedora.cargo;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;

import org.apache.commons.io.IOUtils;

import com.yourmediashelf.fedora.cargo.fcfg.ModuleConfiguration;
import com.yourmediashelf.fedora.cargo.fcfg.ServerConfiguration;
import com.yourmediashelf.fedora.cargo.fcfg.ServerConfigurationParser;

public class FedoraHome {

    private final InstallOptions _opts;

    private final File _installDir;

    private boolean _usingAkubra;

    public FedoraHome(InstallOptions opts) {
        _opts = opts;
        _installDir = new File(_opts.getValue(InstallOptions.FEDORA_HOME));
    }

    public void install() throws InstallationFailedException {
        configure();
    }

    /**
     * Sets various configuration files based on InstallOptions
     * 
     * @throws InstallationFailedException
     */
    private void configure() throws InstallationFailedException {
        configureFCFG();
        if (_usingAkubra) {
            configureAkubra();
        }
        configureSpringProperties();
        configureSpringAuth();
        configureSpringTestConfigs();
    }

    private void configureFCFG() throws InstallationFailedException {
        System.out.println("\tConfiguring fedora.fcfg");
        File fcfgBase = new File(_installDir, "server/fedora-internal-use/config/fedora-base.fcfg");
        File fcfg = new File(_installDir, "server/config/fedora.fcfg");

        Properties props = new Properties();
        if (_opts.getValue(InstallOptions.TOMCAT_HTTP_PORT) != null) {
            props.put("server:fedoraServerPort", _opts.getValue(InstallOptions.TOMCAT_HTTP_PORT));
        }
        if (_opts.getValue(InstallOptions.TOMCAT_SHUTDOWN_PORT) != null) {
            props.put("server:fedoraShutdownPort", _opts.getValue(InstallOptions.TOMCAT_SHUTDOWN_PORT));
        }
        if (_opts.getValue(InstallOptions.TOMCAT_SSL_PORT) != null) {
            props.put("server:fedoraRedirectPort", _opts.getValue(InstallOptions.TOMCAT_SSL_PORT));
        }
        if (_opts.getValue(InstallOptions.FEDORA_SERVERHOST) != null) {
            props.put("server:fedoraServerHost", _opts.getValue(InstallOptions.FEDORA_SERVERHOST));
        }

        if (_opts.getValue(InstallOptions.FEDORA_APP_SERVER_CONTEXT) != null) {
            props.put("server:fedoraAppServerContext", _opts.getValue(InstallOptions.FEDORA_APP_SERVER_CONTEXT));
        }

        String database = _opts.getValue(InstallOptions.DATABASE);
        String dbPoolName = "";
        String backslashIsEscape = "true";
        if (database.equals(InstallOptions.DERBY) || database.equals(InstallOptions.INCLUDED)) {
            dbPoolName = "localDerbyPool";
            backslashIsEscape = "false";
        } else if (database.equals(InstallOptions.MYSQL)) {
            dbPoolName = "localMySQLPool";
        } else if (database.equals(InstallOptions.ORACLE)) {
            dbPoolName = "localOraclePool";
            backslashIsEscape = "false";
        } else if (database.equals(InstallOptions.POSTGRESQL)) {
            dbPoolName = "localPostgreSQLPool";
        } else {
            throw new InstallationFailedException("unable to configure for unknown database: " + database);
        }
        props.put("module.org.fcrepo.server.storage.DOManager:storagePool", dbPoolName);
        props.put("module.org.fcrepo.server.search.FieldSearch:connectionPool", dbPoolName);
        props.put("module.org.fcrepo.server.storage.ConnectionPoolManager:poolNames", dbPoolName);
        props.put("module.org.fcrepo.server.storage.ConnectionPoolManager:defaultPoolName", dbPoolName);
        props.put("module.org.fcrepo.server.storage.lowlevel.ILowlevelStorage:backslash_is_escape",
                backslashIsEscape);
        props.put("datastore." + dbPoolName + ":jdbcURL", _opts.getValue(InstallOptions.DATABASE_JDBCURL));
        props.put("datastore." + dbPoolName + ":dbUsername", _opts.getValue(InstallOptions.DATABASE_USERNAME));
        props.put("datastore." + dbPoolName + ":dbPassword", _opts.getValue(InstallOptions.DATABASE_PASSWORD));
        props.put("datastore." + dbPoolName + ":jdbcDriverClass",
                _opts.getValue(InstallOptions.DATABASE_DRIVERCLASS));

        if (_opts.getBooleanValue(InstallOptions.XACML_ENABLED, true)) {
            props.put("module.org.fcrepo.server.security.Authorization:ENFORCE-MODE", "enforce-policies");
        } else {
            props.put("module.org.fcrepo.server.security.Authorization:ENFORCE-MODE", "permit-all-requests");
        }

        if (_opts.getBooleanValue(InstallOptions.RI_ENABLED, true)) {
            props.put("module.org.fcrepo.server.resourceIndex.ResourceIndex:level", "1");
        } else {
            props.put("module.org.fcrepo.server.resourceIndex.ResourceIndex:level", "0");
        }

        if (_opts.getBooleanValue(InstallOptions.MESSAGING_ENABLED, false)) {
            props.put("module.org.fcrepo.server.messaging.Messaging:enabled", String.valueOf(true));
            props.put("module.org.fcrepo.server.messaging.Messaging:java.naming.provider.url",
                    _opts.getValue(InstallOptions.MESSAGING_URI));
        } else {
            props.put("module.org.fcrepo.server.messaging.Messaging:enabled", String.valueOf(false));
        }

        props.put("module.org.fcrepo.server.access.Access:doMediateDatastreams",
                _opts.getValue(InstallOptions.APIA_AUTH_REQUIRED));

        // FeSL AuthZ needs a management decorator for syncing the policy cache
        // with policies in objects
        if (_opts.getBooleanValue(InstallOptions.FESL_AUTHZ_ENABLED, false)) {
            // NOTE: assumes messaging decorator only is present in
            // fedora-base.fcfg as decorator1
            props.put("module.org.fcrepo.server.management.Management:decorator2",
                    "org.fcrepo.server.security.xacml.pdp.decorator.PolicyIndexInvocationHandler");
        }

        try {
            FileInputStream fis = new FileInputStream(fcfgBase);
            ServerConfiguration config = new ServerConfigurationParser(fis).parse();
            config.applyProperties(props);

            // If using akubra-fs, set the class of the module and clear params.
            String llStoreType = _opts.getValue(InstallOptions.LLSTORE_TYPE);
            if (llStoreType == null || llStoreType.equals("akubra-fs")) {
                ModuleConfiguration mConfig = config
                        .getModuleConfiguration("org.fcrepo.server.storage.lowlevel.ILowlevelStorage");
                config.getModuleConfigurations().remove(mConfig);
                _usingAkubra = true;
            }

            config.serialize(new FileOutputStream(fcfg));
        } catch (IOException e) {
            throw new InstallationFailedException(e.getMessage(), e);
        }
    }

    private void configureAkubra() throws InstallationFailedException {
        // Rewrite server/config/akubra-llstore.xml replacing the
        // /tmp/[object|datastream]Store constructor-arg values
        // with $FEDORA_HOME/data/[object|datastream]Store
        BufferedReader reader = null;
        PrintWriter writer = null;
        try {
            File file = new File(_installDir, "server/config/spring/akubra-llstore.xml");
            reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));

            File dataDir = new File(_installDir, "data");
            String oPath = dataDir.getPath() + File.separator + "objectStore";
            String dPath = dataDir.getPath() + File.separator + "datastreamStore";
            StringBuilder xml = new StringBuilder();

            String line = reader.readLine();
            while (line != null) {
                if (line.indexOf("/tmp/objectStore") != -1) {
                    line = "    <constructor-arg value=\"" + oPath + "\"/>";
                } else if (line.indexOf("/tmp/datastreamStore") != -1) {
                    line = "    <constructor-arg value=\"" + dPath + "\"/>";
                }
                xml.append(line + "\n");
                line = reader.readLine();
            }
            reader.close();

            writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"));
            writer.print(xml.toString());
            writer.close();
        } catch (IOException e) {
            IOUtils.closeQuietly(reader);
            IOUtils.closeQuietly(writer);
            throw new InstallationFailedException(e.getClass().getName() + ":" + e.getMessage());
        }
    }

    private void configureSpringProperties() throws InstallationFailedException {
        Properties springProps = new Properties();

        /* Set up ssl configuration */
        springProps.put("fedora.port", _opts.getValue(InstallOptions.TOMCAT_HTTP_PORT, "8080"));
        if (_opts.getBooleanValue(InstallOptions.SSL_AVAILABLE, false)) {
            springProps.put("fedora.port.secure", _opts.getValue(InstallOptions.TOMCAT_SSL_PORT, "8443"));
        } else {
            springProps.put("fedora.port.secure", _opts.getValue(InstallOptions.TOMCAT_HTTP_PORT, "8080"));
        }

        springProps.put("security.ssl.api.access",
                _opts.getBooleanValue(InstallOptions.APIA_SSL_REQUIRED, false) ? "REQUIRES_SECURE_CHANNEL"
                        : "ANY_CHANNEL");
        springProps.put("security.ssl.api.management",
                _opts.getBooleanValue(InstallOptions.APIM_SSL_REQUIRED, false) ? "REQUIRES_SECURE_CHANNEL"
                        : "ANY_CHANNEL");
        springProps.put("security.ssl.api.default", "ANY_CHANNEL");

        springProps.put("security.fesl.authN.jaas.apia.enabled",
                _opts.getValue(InstallOptions.APIA_AUTH_REQUIRED, "false"));

        springProps.put("security.fesl.authZ.enabled", _opts.getValue(InstallOptions.FESL_AUTHZ_ENABLED, "false"));

        /* Set up authN, authZ filter configuration */
        StringBuilder filters = new StringBuilder();
        if (_opts.getBooleanValue(InstallOptions.FESL_AUTHN_ENABLED, true)) {
            filters.append("AuthFilterJAAS");
        } else {
            filters.append("SetupFilter,XmlUserfileFilter,EnforceAuthnFilter,FinalizeFilter");
        }

        if (_opts.getBooleanValue(InstallOptions.FESL_AUTHZ_ENABLED, false)) {
            filters.append(",PEPFilter");
        }

        springProps.put("security.auth.filters", filters.toString());

        FileOutputStream out = null;
        try {
            out = new FileOutputStream(new File(_installDir, "server/config/spring/web/web.properties"));
            springProps.store(out, "Spring override properties");
        } catch (IOException e) {
            throw new InstallationFailedException(e.getMessage(), e);
        } finally {
            IOUtils.closeQuietly(out);
        }
    }

    /*
     * This is an ugly workaround for the fact that spring security namespace
     * config does not support property substitution into lists of beans. It is
     * also ugly because
     */
    private void configureSpringAuth() throws InstallationFailedException {
        String PATTERN = "${security.auth.filters}";
        String PATTERN_APIA = "${security.auth.filters.apia}";
        String PATTERN_REST = "${security.auth.filters.rest}";

        boolean fesl_authn_enabled = _opts.getBooleanValue(InstallOptions.FESL_AUTHN_ENABLED, true);
        boolean apia_auth_required = _opts.getBooleanValue(InstallOptions.APIA_AUTH_REQUIRED, false);
        boolean upstream_auth_enabled = _opts.getBooleanValue(InstallOptions.UPSTREAM_AUTH_ENABLED, false);

        StringBuilder filters = new StringBuilder();
        StringBuilder filters_apia = new StringBuilder();
        StringBuilder filters_rest = new StringBuilder();

        boolean needsbugFix = false;

        if (fesl_authn_enabled) {
            filters.append("AuthFilterJAAS");
            filters_apia.append("AuthFilterJAAS");
            filters_rest.append("AuthFilterJAAS");
        } else if (upstream_auth_enabled) {
            // use upstream auth filter and nothing else
            String upstreamAuthFilter = "UpstreamAuthFilter";
            filters.append(upstreamAuthFilter);
            filters_apia.append(upstreamAuthFilter);
            filters_rest.append(upstreamAuthFilter);
        } else {
            filters.append("SetupFilter,XmlUserfileFilter,EnforceAuthnFilter,FinalizeFilter");
            if (apia_auth_required) {
                filters_apia.append("SetupFilter,XmlUserfileFilter,EnforceAuthnFilter,FinalizeFilter");
                filters_rest.append("SetupFilter,XmlUserfileFilter,EnforceAuthnFilter,FinalizeFilter");
            } else {
                filters_apia.append("");
                filters_rest.append("SetupFilter,XmlUserfileFilter,RestApiAuthnFilter,FinalizeFilter");
            }

            needsbugFix = true;
        }

        if (_opts.getBooleanValue(InstallOptions.FESL_AUTHZ_ENABLED, false)) {
            filters.append(",PEPFilter");
            filters_apia.append(",PEPFilter");
            filters_rest.append(",PEPFilter");
            copyFESLConfigs();
        }

        FileInputStream springConfig = null;
        PrintWriter writer = null;
        try {
            File xmlFile = new File(_installDir, "server/config/spring/web/security.xml");
            springConfig = new FileInputStream(xmlFile);
            String content = IOUtils.toString(springConfig).replace(PATTERN, filters)
                    .replace(PATTERN_APIA, filters_apia).replace(PATTERN_REST, filters_rest);

            if (!needsbugFix) {
                /* Delete classic authN bugfix when not applicable */
                content = content.replaceFirst("(?s)<!-- BUG.+?/BUG -->", "");
            }

            springConfig.close();

            writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(xmlFile), "UTF-8"));
            writer.print(content);
            writer.close();
        } catch (Exception e) {
            IOUtils.closeQuietly(springConfig);
            IOUtils.closeQuietly(writer);
            throw new InstallationFailedException(e.getMessage(), e);
        }
    }

    private void copyFESLConfigs() throws InstallationFailedException {
        File feslWebDir = new File(_installDir, "server/config/spring/fesl/web");
        File feslModuleDir = new File(_installDir, "server/config/spring/fesl/module");
        File webDir = new File(_installDir, "server/config/spring/web");
        File moduleDir = new File(_installDir, "server/config/spring");

        for (File beanDef : feslWebDir.listFiles()) {
            if (beanDef.isFile()) {
                FileReader reader = null;
                FileWriter writer = null;
                try {
                    File copy = new File(webDir, beanDef.getName());
                    reader = new FileReader(beanDef);
                    writer = new FileWriter(copy);
                    IOUtils.copy(reader, writer);
                    writer.flush();
                } catch (Exception e) {
                    throw new InstallationFailedException(e.getMessage(), e);
                } finally {
                    IOUtils.closeQuietly(writer);
                    IOUtils.closeQuietly(reader);
                }
            }
        }
        for (File beanDef : feslModuleDir.listFiles()) {
            if (beanDef.isFile()) {
                FileReader reader = null;
                FileWriter writer = null;
                try {
                    File copy = new File(moduleDir, beanDef.getName());
                    reader = new FileReader(beanDef);
                    writer = new FileWriter(copy);
                    IOUtils.copy(reader, writer);
                    writer.flush();
                } catch (Exception e) {
                    throw new InstallationFailedException(e.getMessage(), e);
                } finally {
                    IOUtils.closeQuietly(writer);
                    IOUtils.closeQuietly(reader);
                }
            }
        }
    }

    private void configureSpringTestConfigs() throws InstallationFailedException {
        if (_opts.getBooleanValue(InstallOptions.TEST_SPRING_CONFIGS, false)) {
            FileInputStream springConfig = null;
            PrintWriter writer = null;
            try {
                File springDir = new File(_installDir, "server/config/spring");
                for (File file : springDir.listFiles()) {
                    if (file.isFile()) {
                        springConfig = new FileInputStream(file);
                        String content = IOUtils.toString(springConfig);
                        content = content.replaceAll("(?s)<!-- TESTONLY(.+?)/TESTONLY -->", "$1");
                        springConfig.close();

                        writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"));
                        writer.print(content);
                        writer.close();
                    }
                }
            } catch (Exception e) {
                IOUtils.closeQuietly(springConfig);
                IOUtils.closeQuietly(writer);
                throw new InstallationFailedException(e.getMessage(), e);
            }
        }
    }

    public static Map<String, String> loadMap(File f) throws IOException {
        return loadMap(new FileInputStream(f));
    }

    public static Map<String, String> loadMap(InputStream in) throws IOException {
        Properties props = new Properties();
        try {
            props.load(in);
        } finally {
            in.close();
        }
        return loadMap(props);
    }

    /**
     * Loads a Map from the given Properties file.
     *
     * @param props
     *        the Properties file to parse.
     * @return a Map<String, String> representing the given Properties file.
     * @throws IOException
     * @see java.util.Properties
     * @see java.util.Map
     */
    public static Map<String, String> loadMap(Properties props) throws IOException {
        Map<String, String> map = new HashMap<String, String>();
        Set<Entry<Object, Object>> entrySet = props.entrySet();
        for (Entry<Object, Object> entry : entrySet) {
            // The casts to String should always succeed
            map.put((String) entry.getKey(), (String) entry.getValue());
        }
        return map;
    }

    /**
     * Command-line entry point.
     */
    public static void main(String[] args) throws Exception {
        InstallOptions opts;
        Map<String, String> props = new HashMap<String, String>();
        for (String file : args) {
            props.putAll(loadMap(new File(file)));
        }
        opts = new InstallOptions(props);
        FedoraHome fh = new FedoraHome(opts);
        fh.install();
    }

}