/* The contents of this file are subject to the license and copyright terms * detailed in the license directory at the root of the source tree (also * available online at http://fedora-commons.org/license/). */ package org.fcrepo.server.config; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Properties; import org.fcrepo.common.Constants; import org.fcrepo.server.utilities.StreamUtility; import org.fcrepo.utilities.ReadableByteArrayOutputStream; /** * Fedora server configuration. * * @author Chris Wilper */ public class ServerConfiguration extends Configuration implements Constants { private final String DEPRECATION_WARNING = "\n<!--\n\n" + "WARNING! ACHTUNG! ATTENZIONE!\n\n" + "This configuration file is considered a legacy service and will eventually be deprecated.\n" + "The recommended means of configuration is now Fedora's Spring configuration facility, as\n" + "documented here:\n\n" + "https://wiki.duraspace.org/display/FEDORA36/Spring+Configuration\n\n" + "and here:\n\n" + "https://wiki.duraspace.org/display/FEDORA36/Spring+Security\n\n" + "-->\n\n"; private String m_className; private final List<ModuleConfiguration> m_moduleConfigurations; private final List<DatastoreConfiguration> m_datastoreConfigurations; public ServerConfiguration(String className, List<Parameter> parameters, List<ModuleConfiguration> moduleConfigurations, List<DatastoreConfiguration> datastoreConfigurations) { super(parameters); m_className = className; m_moduleConfigurations = moduleConfigurations; m_datastoreConfigurations = datastoreConfigurations; } /** * Make an exact copy of this ServerConfiguration. */ public ServerConfiguration copy() throws IOException { ReadableByteArrayOutputStream out = new ReadableByteArrayOutputStream(); serialize(out); return new ServerConfigurationParser(out.toInputStream()).parse(); } /** * Apply the given properties to this ServerConfiguration. Trims leading and * trailing spaces from the property values before applying them. */ public void applyProperties(Properties props) { Iterator<?> iter = props.keySet().iterator(); while (iter.hasNext()) { String fullName = (String) iter.next(); String value = props.getProperty(fullName).trim(); if (fullName.indexOf(":") != -1 && value != null && value.length() > 0) { String name = fullName.substring(fullName.lastIndexOf(":") + 1); if (fullName.startsWith("server:")) { if (name.endsWith(".class")) { m_className = value; } else { setParameterValue(name, value, true); } } else if (fullName.startsWith("module.")) { String role = fullName.substring(7, fullName.lastIndexOf(":")); ModuleConfiguration module = getModuleConfiguration(role); if (module == null) { module = new ModuleConfiguration(new ArrayList<Parameter>(), role, null, null); m_moduleConfigurations.add(module); } if (name.endsWith(".class")) { module.setClassName(value); } else { module.setParameterValue(name, value, true); } } else if (fullName.startsWith("datastore.")) { String id = fullName.substring(10, fullName.lastIndexOf(":")); DatastoreConfiguration datastore = getDatastoreConfiguration(id); if (datastore == null) { datastore = new DatastoreConfiguration(new ArrayList<Parameter>(), id, null); m_datastoreConfigurations.add(datastore); } datastore.setParameterValue(name, value, true); } } } } public void serialize(OutputStream xmlStream) throws IOException { PrintStream out = new PrintStream(xmlStream); out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); out.println(DEPRECATION_WARNING); out.println("<server xmlns=\"" + FCFG.uri + "\" class=\"" + m_className + "\">"); // do server parameters first serializeParameters(getParameters(Parameter.class), 2, out); // next, modules Iterator<ModuleConfiguration> mIter = getModuleConfigurations().iterator(); while (mIter.hasNext()) { ModuleConfiguration mc = mIter.next(); out.println(" <module role=\"" + mc.getRole() + "\" class=\"" + mc.getClassName() + "\">"); String comment = strip(mc.getComment()); if (comment != null) { out.println(" <comment>" + comment + "</comment>"); } serializeParameters(mc.getParameters(Parameter.class), 4, out); out.println(" </module>"); } // finally, datastores Iterator<DatastoreConfiguration> dIter = getDatastoreConfigurations().iterator(); while (dIter.hasNext()) { DatastoreConfiguration dc = dIter.next(); out.println(" <datastore id=\"" + dc.getId() + "\">"); String comment = strip(dc.getComment()); if (comment != null) { out.println(" <comment>" + comment + "</comment>"); } serializeParameters(dc.getParameters(Parameter.class), 4, out); out.println(" </datastore>"); } out.println("</server>"); out.close(); } private void serializeParameters(Collection<Parameter> params, int indentBy, PrintStream out) { Iterator<Parameter> paramIter = params.iterator(); while (paramIter.hasNext()) { getParamXMLString(paramIter.next(), indentBy, out); out.append('\n'); } } private void spaces(int num, PrintStream out) { for (int i = 0; i < num; i++) { out.append(' '); } } private String getParamXMLString(Parameter p, int indentBy, PrintStream out) { spaces(indentBy, out); out.append("<param name=\""); out.append(p.getName()); out.append("\" value=\""); StreamUtility.enc(p.getValue(), out); out.append('"'); if (p.getIsFilePath() != false) { out.append(" isFilePath=\"true\""); } if (p.getProfileValues() != null) { Iterator<String> iter = p.getProfileValues().keySet().iterator(); while (iter.hasNext()) { String profileName = iter.next(); String profileVal = p.getProfileValues().get(profileName); out.append(" " + profileName + "value=\""); StreamUtility.enc(profileVal, out); out.append('"'); } } String comment = strip(p.getComment()); if (comment != null) { out.append(">\n"); spaces(indentBy + 2, out); out.append("<comment>"); StreamUtility.enc(comment, out); out.append("</comment>\n"); spaces(indentBy, out); out.append("</param>"); } else { out.append("/>"); } return out.toString(); } // strip leading and trailing whitespace and \n, return null if // resulting string is empty in incoming string is null. private static String strip(String in) { if (in == null) { return null; } String out = in.trim(); if (out.length() == 0) { return null; } else { return out; } } public String getClassName() { return m_className; } public List<ModuleConfiguration> getModuleConfigurations() { return m_moduleConfigurations; } public ModuleConfiguration getModuleConfiguration(String role) { for (int i = 0; i < m_moduleConfigurations.size(); i++) { ModuleConfiguration config = m_moduleConfigurations.get(i); if (config.getRole().equals(role)) { return config; } } return null; } public List<DatastoreConfiguration> getDatastoreConfigurations() { return m_datastoreConfigurations; } public DatastoreConfiguration getDatastoreConfiguration(String id) { for (int i = 0; i < m_datastoreConfigurations.size(); i++) { DatastoreConfiguration config = m_datastoreConfigurations.get(i); if (config.getId().equals(id)) { return config; } } return null; } /** * Deserialize, then output the given configuration. If two parameters are * given, the first one is the filename and the second is the properties * file to apply before re-serializing. */ public static void main(String[] args) throws Exception { if (args.length < 1 || args.length > 2) { throw new IOException("One or two arguments expected."); } ServerConfiguration config = new ServerConfigurationParser(new FileInputStream(new File(args[0]))) .parse(); if (args.length == 2) { Properties props = new Properties(); props.load(new FileInputStream(new File(args[1]))); config.applyProperties(props); } ByteArrayOutputStream out = new ByteArrayOutputStream(); config.serialize(out); String content = new String(out.toByteArray(), "UTF-8"); System.out.println(content); } }