/* * Copyright 2008 the original author or authors. * * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.rioproject.util; import com.sun.jini.config.ConfigUtil; import com.sun.jini.start.ServiceDescriptor; import org.rioproject.RioVersion; import org.rioproject.config.Constants; import org.rioproject.net.HostUtil; import org.rioproject.start.RioServiceDescriptor; import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * Provides utilities to obtain {@link com.sun.jini.start.ServiceDescriptor} instances * for Rio services. * * @author Dennis Reedy */ @SuppressWarnings("PMD.AvoidThrowingRawExceptionTypes") public final class ServiceDescriptorUtil { /* Port value obtained from invoking the getStartupPort() method */ private static int port = 0; /* * Cannot instantiate this utility */ private ServiceDescriptorUtil() { } static int getStartupPort() throws IOException { if(port==0) { if(System.getProperty(Constants.PORT_RANGE)!=null) { port = PortUtil.getPortFromRange(System.getProperty(Constants.PORT_RANGE)); } else { port = PortUtil.getAnonymousPort(); } } return(port); } /** * Get the {@link com.sun.jini.start.ServiceDescriptor} instance for * <tt>org.rioproject.tools.webster.Webster</tt>. * * @param policy The security policy file to use * @param sPort The port webster should use * @param roots The roots webster should serve * @param putDirectory The directory name that Webster will enable put file support * * @return The {@link com.sun.jini.start.ServiceDescriptor} instance for * webster using a specified port. The <tt>webster-${rio-version}.jar</tt> file will be * loaded from <tt>rio.home/lib</tt> * * @throws IOException If there are problems getting the anonymous port * @throws RuntimeException If the<tt>rio.home</tt> system property is not * set */ public static ServiceDescriptor getWebster(final String policy, final String sPort, final String[] roots, final String putDirectory) throws IOException { String[] options = null; if(putDirectory!=null) { options = new String[2]; options[0] = "-putDirectory"; options[1] = putDirectory; } return(getWebster(policy, sPort, roots, options, false)); } /** * Get the {@link com.sun.jini.start.ServiceDescriptor} instance for * <tt>org.rioproject.tools.webster.Webster</tt>. * * @param policy The security policy file to use * @param roots The roots webster should serve * @return The {@link com.sun.jini.start.ServiceDescriptor} instance for * webster using an anonymous port. The <tt>webster-${rio-version}.jar</tt> file will be * loaded from <tt>rio.home/lib</tt> * * @throws IOException If there are problems getting the anonymous port * @throws RuntimeException If the<tt>rio.home</tt> system property is not * set */ public static ServiceDescriptor getWebster(final String policy, final String[] roots) throws IOException { return(getWebster(policy, "0", roots)); } /** * Get the {@link com.sun.jini.start.ServiceDescriptor} instance for * <tt>org.rioproject.tools.webster.Webster</tt>. * * @param policy The security policy file to use * @param sPort The port webster should use * @param roots The roots webster should serve * @return The {@link com.sun.jini.start.ServiceDescriptor} instance for * webster using a specified port. The <tt>webster-${rio-version}.jar</tt> file will be * loaded from <tt>rio.home/lib</tt> * * @throws IOException If there are problems getting the anonymous port * @throws RuntimeException If the<tt>rio.home</tt> system property is not * set */ public static ServiceDescriptor getWebster(final String policy, final String sPort, final String[] roots) throws IOException { return(getWebster(policy, sPort, roots, false)); } /** * Get the {@link com.sun.jini.start.ServiceDescriptor} instance for * <tt>org.rioproject.tools.webster.Webster</tt>. * * @param policy The security policy file to use * @param sPort The port webster should use * @param roots The roots webster should serve * @param options Options for Webster to use * @return The {@link com.sun.jini.start.ServiceDescriptor} instance for * webster using a specified port. The <tt>webster-${rio-version}.jar</tt> file will be * loaded from <tt>rio.home/lib</tt> * * @throws IOException If there are problems getting the anonymous port * @throws RuntimeException If the<tt>rio.home</tt> system property is not * set */ public static ServiceDescriptor getWebster(final String policy, final String sPort, final String[] roots, final String[] options) throws IOException { return(getWebster(policy, sPort, roots, options, false)); } /** * Get the {@link com.sun.jini.start.ServiceDescriptor} instance for * <tt>org.rioproject.tools.webster.Webster</tt> * * @param policy The security policy file to use * @param sPort The port webster should use * @param roots The roots webster should serve * @param debug If true, set the <tt>org.rioproject.tools.debug</tt> property * @return The {@link com.sun.jini.start.ServiceDescriptor} instance for * webster using a specified port. The <tt>webster-${rio-version}.jar</tt> file will be * loaded from <tt>rio.home/lib</tt> * * @throws IOException If there are problems getting the anonymous port */ public static ServiceDescriptor getWebster(final String policy, final String sPort, final String[] roots, final boolean debug) throws IOException { String rioHome = System.getProperty("rio.home", RioHome.get()); if(rioHome==null) throw new RuntimeException("rio.home property not declared or derivable"); String webster = rioHome+File.separator+"lib"+File.separator+createVersionedJar("webster"); return(getWebster(policy, sPort, roots, null, debug, webster)); } /** * Get the {@link com.sun.jini.start.ServiceDescriptor} instance for * <tt>org.rioproject.tools.webster.Webster</tt> * * @param policy The security policy file to use * @param sPort The port webster should use * @param roots The roots webster should serve * @param options Options for Webster to use * @param debug If true, set the <tt>org.rioproject.tools.debug</tt> property * @return The {@link com.sun.jini.start.ServiceDescriptor} instance for * webster using a specified port. The <tt>webster-${rio-version}.jar</tt> file will be * loaded from <tt>rio.home/lib</tt> * * @throws IOException If there are problems getting the anonymous port */ public static ServiceDescriptor getWebster(final String policy, final String sPort, final String[] roots, final String[] options, final boolean debug) throws IOException { String rioHome = System.getProperty("rio.home", RioHome.get()); if(rioHome==null) throw new RuntimeException("rio.home property not declared or derivable"); String webster = rioHome+File.separator+"lib"+File.separator+createVersionedJar("webster"); return(getWebster(policy, sPort, roots, options, debug, webster)); } /** * Get the {@link com.sun.jini.start.ServiceDescriptor} instance for * <tt>org.rioproject.tools.webster.Webster</tt> * * @param policy The security policy file to use * @param sPort The port webster should use * @param roots The roots webster should serve * @param options Options for Webster to use * @param debug If true, set the <tt>org.rioproject.tools.debug</tt> property * @param webster The location an name of the webster jar * @return The {@link com.sun.jini.start.ServiceDescriptor} instance for * webster using a specified port. The <tt>webster-${rio-version}.jar</tt> file will be * loaded from <tt>rio.home/lib</tt> * * @throws IOException If there are problems getting the anonymous port * @throws IllegalArgumentException If the<tt>rio.home</tt> system property is not set */ public static ServiceDescriptor getWebster(final String policy, final String sPort, final String[] roots, final String[] options, final boolean debug, final String webster) throws IOException { if(webster==null) throw new IllegalArgumentException("webster jar cannot be null"); String portOptionArg = "-port"; String portArg; if(sPort.contains("-")) { portOptionArg = "-portRange"; portArg = sPort; } else { try { int p = Integer.parseInt(sPort); port = p==0?getStartupPort():p; portArg = Integer.toString(port); } catch(NumberFormatException e) { throw new RuntimeException("invalid port ["+sPort+"]"); } } String websterRoots = ConfigUtil.concat(roots); String websterClass = "org.rioproject.tools.webster.Webster"; if(debug) { System.setProperty("org.rioproject.tools.webster.debug", "1"); } String address = HostUtil.getHostAddressFromProperty("java.rmi.server.hostname"); List<String> optionsList = new ArrayList<String>(); if(options!=null) { Collections.addAll(optionsList, options); } if(!optionsList.contains("-roots")) { optionsList.add("-roots"); optionsList.add(websterRoots); } if(!optionsList.contains("-bindAddress")) { optionsList.add("-bindAddress"); optionsList.add(address); } optionsList.add(portOptionArg); optionsList.add(portArg); return(new RioServiceDescriptor("", policy, webster, websterClass, optionsList.toArray(new String[optionsList.size()]))); } /** * Get the {@link com.sun.jini.start.ServiceDescriptor} instance for * <tt>org.rioproject.cybernode.Cybernode</tt>. * * @param policy The security policy file to use * @param cybernodeConfig The configuration file the Cybernode will use * @return The {@link com.sun.jini.start.ServiceDescriptor} instance for * the Cybernode using an anonymous port. The <tt>cybernode-service-${rio-version}.jar</tt> file * will be loaded from <tt>rio.home/lib</tt> * * @throws IOException If there are problems getting the anonymous port * @throws RuntimeException If the<tt>rio.home</tt> system property is not * set */ public static ServiceDescriptor getCybernode(final String policy, final String... cybernodeConfig) throws IOException { String cybernodeClasspath = getCybernodeClasspath(); String cybernodeCodebase = getCybernodeCodebase(); String implClass = "org.rioproject.cybernode.service.CybernodeImpl"; return(new RioServiceDescriptor(cybernodeCodebase, policy, cybernodeClasspath, implClass, cybernodeConfig)); } public static String getCybernodeClasspath() throws IOException { String rioHome = System.getProperty("rio.home", RioHome.get()); if(rioHome == null) throw new RuntimeException("rio.home property not declared or derivable"); List<String> jarList = new ArrayList<String>(); jarList.add(createVersionedJar("cybernode-service")); if(System.getProperty("rio.test.attach")!=null) { System.setProperty(Constants.RESOLVER_JAR, getProjectResolverLocation(rioHome)); jarList.add(createVersionedJar("rio-test")); } StringBuilder classPath = new StringBuilder(); classPath.append(makePath(rioHome+File.separator+"lib", jarList.toArray(new String[jarList.size()]))); return classPath.toString(); } public static String getCybernodeCodebase() throws UnknownHostException { return createAnnotatedArtifactURL(String.format("artifact:org.rioproject.cybernode/cybernode-proxy/%s", RioVersion.VERSION)); } static String getProjectResolverLocation(final String rioHome) { StringBuilder sb = new StringBuilder(); sb.append(rioHome).append(File.separator) .append("lib").append(File.separator) .append("resolver").append(File.separator) .append(createVersionedJar("resolver-project")); return sb.toString(); } /** * Get the {@link com.sun.jini.start.ServiceDescriptor} instance for * <tt>org.rioproject.monitor.ProvisionMonitor</tt>. * * @param policy The security policy file to use * @param monitorConfig The configuration options the Monitor will use * @return The {@link com.sun.jini.start.ServiceDescriptor} instance for * the Monitor using an anonymous port. The <tt>monitor-service-${rio-version}.jar</tt> file will * be loaded from <tt>rio.home/lib</tt> * * @throws IOException If there are problems getting the anonymous port * @throws RuntimeException If the<tt>rio.home</tt> system property is not * set */ public static ServiceDescriptor getMonitor(final String policy, final String... monitorConfig) throws IOException { String rioHome = System.getProperty("rio.home", RioHome.get()); if(rioHome == null) throw new RuntimeException("rio.home property not declared or derivable"); List<String> jarList = new ArrayList<String>(); jarList.add(createVersionedJar("monitor-service")); if(System.getProperty("rio.test.attach")!=null) { System.setProperty(Constants.RESOLVER_JAR, getProjectResolverLocation(rioHome)); jarList.add(createVersionedJar("rio-test")); } StringBuilder classPath = new StringBuilder(); classPath.append(makePath(rioHome+File.separator+"lib", jarList.toArray(new String[jarList.size()]))); String implClass = "org.rioproject.monitor.service.ProvisionMonitorImpl"; String monitorCodebase = createAnnotatedArtifactURL(String.format("artifact:org.rioproject.monitor/monitor-proxy/%s", RioVersion.VERSION)); return (new RioServiceDescriptor(monitorCodebase, policy, classPath.toString(), implClass, monitorConfig)); } static String createAnnotatedArtifactURL(final String artifact) throws UnknownHostException { return String.format("%s;http://%s:%s", artifact, HostUtil.getHostAddressFromProperty("java.rmi.server.hostname"), port); } /** * Get the {@link com.sun.jini.start.ServiceDescriptor} instance for * the Jini Lookup Service (Reggie). * * @param policy The security policy file to use * @return The {@link com.sun.jini.start.ServiceDescriptor} instance for * Reggie using an anonymous port. The <tt>reggie-${river-version}.jar</tt> file will * be loaded from <tt>rio.home/lib</tt> * @param lookupConfig The configuration options Reggie will use * * @throws IOException If there are problems getting the anonymous port * @throws RuntimeException If the<tt>rio.home</tt> system property is not * set */ public static ServiceDescriptor getLookup(final String policy, final String... lookupConfig) throws IOException { String rioHome = System.getProperty("rio.home", RioHome.get()); if(rioHome == null) throw new RuntimeException("rio.home property not declared or derivable"); String reggieClasspath = FileHelper.find(new File(rioHome, "lib"), "reggie").getPath(); File reggieDL = FileHelper.find(new File(rioHome, "lib-dl"), "reggie-dl"); //String reggieCodebase = "artifact:org.apache.river/reggie-dl/"+ FileHelper.getJarVersion(reggieDL.getName()); String reggieCodebase = createAnnotatedArtifactURL(String.format("artifact:org.apache.river/reggie-dl/%s", FileHelper.getJarVersion(reggieDL.getName()))); String implClass = "com.sun.jini.reggie.TransientRegistrarImpl"; return (new RioServiceDescriptor(reggieCodebase, policy, reggieClasspath, implClass, lookupConfig)); } /** * Check if the default InetAddress to use is a loopback address * * @throws UnknownHostException If the host cannot be resolved */ public static void checkForLoopback() throws UnknownHostException { InetAddress address = HostUtil.getInetAddressFromProperty(Constants.RMI_HOST_ADDRESS); if(address.isLoopbackAddress()) { StringBuilder builder = new StringBuilder(); builder.append("\n"); builder.append("*******************************************************************************\n"); builder.append("* The network interface to be used has a loopback address of "); builder.append(address.getHostAddress()).append(".\n"); builder.append("* You may encounter issues communicating to services outside of your machine.\n"); builder.append("*******************************************************************************\n"); LoggerFactory.getLogger("org.rioproject").warn(builder.toString()); } } protected static String makePath(final String dir, final String... jars) { StringBuilder sb = new StringBuilder(); for(String jar : jars) { if(sb.length()>0) sb.append(File.pathSeparator); sb.append(dir).append(File.separator).append(jar); } return sb.toString(); } private static String createVersionedJar(String name) { return String.format("%s-%s.jar", name, RioVersion.VERSION); } }