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