001 /* 002 * Copyright 2005 Stephen J. McConnell. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 013 * implied. 014 * 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019 package net.dpml.station.server; 020 021 import java.net.URI; 022 import java.net.URL; 023 import java.rmi.registry.Registry; 024 025 import net.dpml.cli.Option; 026 import net.dpml.cli.Group; 027 import net.dpml.cli.CommandLine; 028 import net.dpml.cli.OptionException; 029 import net.dpml.cli.commandline.Parser; 030 import net.dpml.cli.builder.ArgumentBuilder; 031 import net.dpml.cli.builder.GroupBuilder; 032 import net.dpml.cli.builder.DefaultOptionBuilder; 033 import net.dpml.cli.option.PropertyOption; 034 import net.dpml.cli.validation.URIValidator; 035 import net.dpml.cli.validation.NumberValidator; 036 037 import net.dpml.station.ApplicationRegistry; 038 039 import net.dpml.transit.Artifact; 040 import net.dpml.transit.model.TransitModel; 041 import net.dpml.transit.management.TransitController; 042 043 import net.dpml.util.Logger; 044 045 /** 046 * The RemoteStation is responsible for the establishment of 047 * callback monitors to external processes established by the 048 * station manager. 049 * 050 * @author <a href="http://www.dpml.net">Digital Product Meta Library</a> 051 * @version 1.0.3 052 */ 053 public class StationServerPlugin implements Runnable 054 { 055 private final Logger m_logger; 056 private final CommandLine m_line; 057 private final TransitModel m_model; 058 059 private RemoteStation m_station; 060 061 /** 062 * Creation of a new station server plugin for station commandline 063 * handling. 064 * @param logger the assigned logging channel 065 * @param model the transit model 066 * @param args the command line arguments array 067 * @exception Exception if an error occurs 068 */ 069 public StationServerPlugin( Logger logger, TransitModel model, String[] args ) throws Exception 070 { 071 m_logger = logger; 072 m_model = model; 073 074 // parse the command group model 075 076 Parser parser = new Parser(); 077 parser.setGroup( COMMAND_GROUP ); 078 try 079 { 080 m_line = parser.parse( args ); 081 } 082 catch( OptionException e ) 083 { 084 final String message = "Server commandline processing error."; 085 StringBuffer buffer = new StringBuffer( message ); 086 buffer.append( "\nArgument count: " + args.length ); 087 for( int i=0; i<args.length; i++ ) 088 { 089 buffer.append( "\n arg (" + i + "): [" + args[i] + "]" ); 090 } 091 String error = buffer.toString(); 092 throw new Exception( error, e ); 093 } 094 } 095 096 /** 097 * Start the thread. 098 */ 099 public void run() 100 { 101 try 102 { 103 // register MBeans 104 105 String jmxEnabled = System.getProperty( "dpml.transit.jmx.enabled" ); 106 if( "true".equals( jmxEnabled ) ) 107 { 108 try 109 { 110 new TransitController( m_logger, m_model ); 111 m_logger.info( "Transit controller established." ); 112 } 113 catch( NoClassDefFoundError ncdfe ) 114 { 115 if( m_logger.isWarnEnabled() ) 116 { 117 m_logger.warn( "JMX resources unavailable." ); 118 } 119 } 120 catch( ClassNotFoundException cnfe ) 121 { 122 if( m_logger.isWarnEnabled() ) 123 { 124 m_logger.warn( "JMX resources unavailable." ); 125 } 126 } 127 } 128 129 int port = getPortValue( m_line, Registry.REGISTRY_PORT ); 130 URI uri = (URI) m_line.getValue( URI_OPTION, null ); 131 if( null == uri ) 132 { 133 URL url = ApplicationRegistry.DEFAULT_STORAGE_URI.toURL(); 134 m_logger.info( "starting station on port: " + port ); 135 m_station = new RemoteStation( m_logger, m_model, port, url ); 136 Thread.currentThread().setContextClassLoader( ApplicationRegistry.class.getClassLoader() ); 137 setShutdownHook( m_station ); 138 } 139 else 140 { 141 if( Artifact.isRecognized( uri ) ) 142 { 143 URL url = Artifact.createArtifact( uri ).toURL(); 144 m_logger.info( 145 "starting station on port: " 146 + port 147 + " with registry " 148 + url ); 149 m_station = new RemoteStation( m_logger, m_model, port, url ); 150 } 151 else 152 { 153 URL url = uri.toURL(); 154 m_logger.info( 155 "starting station on port: " 156 + port 157 + " with registry " 158 + url ); 159 m_station = new RemoteStation( m_logger, m_model, port, url ); 160 } 161 } 162 } 163 catch( Exception e ) 164 { 165 final String error = 166 "Station startup failure."; 167 m_logger.error( error, e ); 168 } 169 } 170 171 private int getPortValue( CommandLine line, int defaultPort ) 172 { 173 if( line.hasOption( PORT_OPTION ) ) 174 { 175 Number number = (Number) line.getValue( PORT_OPTION, null ); 176 return number.intValue(); 177 } 178 else 179 { 180 return defaultPort; 181 } 182 } 183 184 private URI getRegistryURI( CommandLine line, URI uri ) 185 { 186 if( line.hasOption( URI_OPTION ) ) 187 { 188 return (URI) line.getValue( URI_OPTION, null ); 189 } 190 else 191 { 192 return uri; 193 } 194 } 195 196 /** 197 * Create a shutdown hook that will trigger shutdown of the station. 198 * @param station the station 199 */ 200 public static void setShutdownHook( final RemoteStation station ) 201 { 202 Runtime.getRuntime().addShutdownHook( new ShutdownHandler( station ) ); 203 } 204 205 private static final DefaultOptionBuilder OPTION_BUILDER = new DefaultOptionBuilder(); 206 private static final ArgumentBuilder ARGUMENT_BUILDER = new ArgumentBuilder(); 207 private static final GroupBuilder GROUP_BUILDER = new GroupBuilder(); 208 209 private static final PropertyOption PROPERTY_OPTION = new PropertyOption(); 210 private static final NumberValidator NUMBER_VALIDATOR = NumberValidator.getIntegerInstance(); 211 212 private static final Option PORT_OPTION = 213 ARGUMENT_BUILDER 214 .withDescription( "Port number." ) 215 .withName( "port" ) 216 .withMinimum( 0 ) 217 .withMaximum( 1 ) 218 .withValidator( NUMBER_VALIDATOR ) 219 .create(); 220 221 private static final Option URI_OPTION = 222 OPTION_BUILDER 223 .withShortName( "registry" ) 224 .withDescription( "Application registry store." ) 225 .withRequired( false ) 226 .withArgument( 227 ARGUMENT_BUILDER 228 .withDescription( "Local or remote artifact reference." ) 229 .withName( "artifact" ) 230 .withMinimum( 1 ) 231 .withMaximum( 1 ) 232 .withValidator( new URIValidator() ) 233 .create() ) 234 .create(); 235 236 private static final Group COMMAND_GROUP = 237 GROUP_BUILDER 238 .withName( "options" ) 239 .withOption( PORT_OPTION ) 240 .withOption( URI_OPTION ) 241 .withOption( PROPERTY_OPTION ) 242 .create(); 243 244 /** 245 * Shutdown handler implementation. 246 */ 247 private static class ShutdownHandler extends Thread 248 { 249 private final RemoteStation m_station; 250 251 /** 252 * Creation of a new shutdown handler. 253 * @param station the station to shutdown 254 */ 255 ShutdownHandler( final RemoteStation station ) 256 { 257 m_station = station; 258 } 259 260 public void run() 261 { 262 m_station.shutdown(); 263 } 264 } 265 266 }