/* Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved. Contact: SYSTAP, LLC DBA Blazegraph 2501 Calvert ST NW #106 Washington, DC 20008 licenses@blazegraph.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package com.bigdata.util.config; import java.io.IOException; import net.jini.url.httpmd.HttpmdUtil; import org.apache.log4j.Level; import org.apache.log4j.Logger; /** * Utility class that provides a set of static convenience methods * related to configuration and deployment of the Bigdata services. * Although useful in general, the methods in this utility class may be * particularly useful when employed from within a Jini configuration * file. * <p> * This class cannot be instantiated. */ public class ConfigurationUtil { private static final Logger logger = LogUtil.getLog4jLogger( ConfigurationUtil.class ); /** * Concatenates the given <code>String</code> arrays, returning * the result in a new <code>String</code> array. */ public static String[] concat(String[] a, String[] b) { String[] result = new String[a.length + b.length]; System.arraycopy(a, 0, result, 0, a.length); System.arraycopy(b, 0, result, a.length, b.length); return result; } /** * Creates and returns a <code>String</code> array consisting of the * contents of the given <code>prevArgList</code> and the arguments * reference in the given <code>argString</code>. * <p> * Note that the contents of the <code>argString</code> parameter is * <code>split</code> on the RS (<i>record separator</i>) control * character ("\036"). */ public static String[] createArgList(String[] prevArgList, String argString) { if(argString.matches("^[ \t]*$")) return prevArgList; String[] newArgs = argString.split("\036"); return concat(prevArgList, newArgs); } /** * Using the given parameters in the appropriate manner, this method * constructs and returns a <code>String</code> whose value is a valid * Java RMI <i>codebase</i> specification. This method returns a * codebase supporting one of two possible protocols: the standard * <i>http</i> protocol, or the Jini <i>httpmd</i> protocol; which * was created to support codebase integrity when running a remote * service configured for secure code downloading. * <p> * The <code>mdAlgorithm</code> parameter is used to indicate to * this method which type of codebase should be constructed and * returned. If <code>null</code> is input to <code>mdAlgorithm</code>, * or if it has one of the values "none", "off", or "" (the empty * <code>String</code>), then this method will construct and returned * a standard HTTP-based codebase; otherwise, an HTTPMD-based codebase * will constructed and returned. * <p> * Note that the <code>name</code> parameter is handled specially by * this method. The value input to that <code>String</code> parameter * is interpretted in one of two ways by this method: * <p><ul> * <li> The name of the local <i>network interface</i> over which the * class server will communicate with clients requesting the * associated service's downloadable classes through the codebase * returned by this method. * <li> The local <i>or remote</i> IP address or name of the <i>host</i> * on which the class server is running and serving the * associated service's classes. * </ul></p> * * This method first treats the value of the <code>name</code> parameter * as a network interface, attempting to determine that interface's * corresponding IP address. Should that attempt fail, then this method * then assumes that the caller intended this parameter to be interpretted * as an IP address or host name; in which case, this method uses * the value of the parameter as the <i>address/host</i> component of * codebase being constructed. * <p> * This method is intended to provide a convenient mechanism for * constructing a service's codebase from within a Jini configuration * file. To support both development and deployment scenarios, it * is important to be able to flexibly construct such codebases from * either a local network interface specification or from a * specification that represents the name of a remote host running * a shared codebase class server on the appropriate network. * * @param name <code>String</code> referencing either a network * interface, IP address, or host name, each of which * will be used either to determine the appropriate * value, or as the actual value, for the * <i>address/host</i> component of the returned * codebase. * * @param jarFile <code>String</code> value that is used for the * <i>jar</i> component of the returned codebase; * which references the JAR file containing the * downloadable classes that make up the desired * service codebase. * * @param port <code>int</code> value that is used for the * <i>port</i> component of the returned codebase; * which is the port on which the class server will * listen for download requests from clients of the * associated service. * * @param srcRoot <code>String</code> value that is used when * computing an HTTPMD-based codebase. The value * of this parameter references the root directory * path (or URL of the directory) containing the JAR * file(s) (or class file(s)) containing the * downloadable classes that make up the desired * service codebase. This parameter is typically the * root directory from which the class server will * serve the service's <i>downloadable JAR files</i>. * Note that this parameter is not used in the * construction of the returned codebase if the * <code>mdAlgorithm</code> parameter is * <code>null</code> or if it has one of the values * "none", "off", or "" (the empty <code>String</code>). * * @param mdAlgorithm <code>String</code> value indicating the * message digest algorithm to use when constructing * an HTTPMD-based codebase (for example, "sha", * "md5", etc.). Note that if this parameter is * <code>null</code>, then this method will * contruct an HTTP-based codebase. * * @return a <code>String</code> whose value is a valid Java RMI * <i>codebase</i> specification represented in either * standard <i>http</i> protocol format, or Jini <i>httpmd</i> * protocol format. * * @throws IOException if an I/O exception occurs while reading data * from the <code>srcRoot</code>. * * @throws NullPointerException if <code>null</code> is input for * <code>name</code> or <code>jarFile</code>, and/or * <code>null</code> is input for <code>srcRoot</code> * when <code>mdAlgorithm</code> is non-<code>null</code> * and is not equal to "none", "off", or "" (note that if * <code>mdAlgorithm</code> is <code>null</code> or equal to * "none", "off", or "", then <code>srcRoot</code> can take * any value, including <code>null</code>). * * @throws IllegalArgumentException if the value input for * <code>port</code> is negtive. */ public static String computeCodebase(String name, String jarFile, int port, String srcRoot, String mdAlgorithm) throws IOException { if(name == null) throw new NullPointerException("name cannot be null"); if(jarFile == null) throw new NullPointerException ("jarFile cannot be null"); if(port < 0) throw new IllegalArgumentException ("port cannot be negative"); boolean doHttpmd = true; if( (mdAlgorithm == null) || (("").equals(mdAlgorithm)) || (("off").equals(mdAlgorithm)) || (("none").equals(mdAlgorithm)) ) { doHttpmd = false; } if( doHttpmd && (srcRoot == null) ) { throw new NullPointerException ("srcRoot cannot be null when constructing " +"an HTTPMD codebase"); } String codebase = null; String ipAddr = name; // Determine if name is a Nic name or a host name try { ipAddr = NicUtil.getIpAddress(name); } catch(Exception e) { // must be a hostname logger.log(Level.TRACE, name+" - not a valid " +"network interface, assuming host name"); } // Construct the codebase, either httpmd or http if(doHttpmd) { String httpmdUrl = "httpmd://"+ipAddr+":"+port+"/"+jarFile+";"+mdAlgorithm+"=0"; codebase = HttpmdUtil.computeDigestCodebase(srcRoot, httpmdUrl);; } else {//use httpmd codebase = "http://"+ipAddr+":"+port+"/"+jarFile; } logger.log(Level.TRACE, "codebase = "+codebase); return codebase; } /** * Convenience method that ultimately calls the primary 5-argument * version of this method. This method allows one to input a * <code>String</code> value for the port to use when constructing * the codebase; which can be useful when invoking this method * from a Jini configuration file. * * @throws NumberFormatException if the value input for <code>port</code> * does not contain a parsable <code>int</code>. */ public static String computeCodebase(String name, String jarFile, String port, String srcRoot, String mdAlgorithm) throws IOException { return computeCodebase(name, jarFile, Integer.parseInt(port), srcRoot, mdAlgorithm); } /** * Convenient three-argument version of <code>computeCodebase</code> * that will always return a codebase <code>String</code> represented * in standard <i>http</i> protocol format. */ public static String computeCodebase(String name, String jarFile, int port) throws IOException { return computeCodebase(name, jarFile, port, null, null); } /** * Convenient three-argument version of <code>computeCodebase</code> * that takes a <code>String</code> value for the <code>port</code> * parameter, always return a codebase <code>String</code> represented * in standard <i>http</i> protocol format. * * @throws NumberFormatException if the value input for <code>port</code> * does not contain a parsable <code>int</code>. */ public static String computeCodebase(String name, String jarFile, String port) throws IOException { return computeCodebase(name, jarFile, Integer.parseInt(port)); } }