1 /*
   2  * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.corba.se.impl.activation;
  27 
  28 import java.lang.reflect.Method;
  29 import java.lang.reflect.Modifier;
  30 import java.io.*;
  31 import java.util.Date;
  32 import java.util.Properties ;
  33 
  34 import org.omg.CORBA.ORB ;
  35 import com.sun.corba.se.spi.activation.Activator ;
  36 import com.sun.corba.se.spi.activation.ActivatorHelper ;
  37 import com.sun.corba.se.impl.orbutil.ORBConstants ;
  38 
  39 /**
  40  * @author      Ken Cavanaugh
  41  * @since       JDK1.2
  42  */
  43 public class ServerMain
  44 {
  45     /* TODO:
  46     * 1.  Rewrite all uses of ORB properties to use constants from someplace.
  47     *     The strings are scattered between here, the ORB classes, and
  48     *     ServerTableEntry.
  49     * 2.  Consider a more general log facility.
  50     * 3.  Remove ServerCallback from POAORB.
  51     * 4.  Needs to be merged with Harold's changes to support SSL.
  52     * 5.  Logs need to be internationalized.
  53     */
  54 
  55     public final static int OK = 0;
  56     public final static int MAIN_CLASS_NOT_FOUND = 1;
  57     public final static int NO_MAIN_METHOD = 2;
  58     public final static int APPLICATION_ERROR = 3;
  59     public final static int UNKNOWN_ERROR = 4;
  60     public final static int NO_SERVER_ID = 5 ;
  61     public final static int REGISTRATION_FAILED = 6;
  62 
  63     public static String printResult( int result )
  64     {
  65         switch (result) {
  66             case OK :                   return "Server terminated normally" ;
  67             case MAIN_CLASS_NOT_FOUND : return "main class not found" ;
  68             case NO_MAIN_METHOD :       return "no main method" ;
  69             case APPLICATION_ERROR :    return "application error" ;
  70             case NO_SERVER_ID :         return "server ID not defined" ;
  71             case REGISTRATION_FAILED:   return "server registration failed" ;
  72             default :                   return "unknown error" ;
  73         }
  74     }
  75 
  76     private void redirectIOStreams()
  77     {
  78         // redirect out and err streams
  79         try {
  80             String logDirName =
  81                 System.getProperty( ORBConstants.DB_DIR_PROPERTY ) +
  82                 System.getProperty("file.separator") +
  83                 ORBConstants.SERVER_LOG_DIR +
  84                 System.getProperty("file.separator");
  85 
  86             File logDir = new File(logDirName);
  87             String server = System.getProperty(
  88                 ORBConstants.SERVER_ID_PROPERTY ) ;
  89 
  90             FileOutputStream foutStream =
  91                 new FileOutputStream(logDirName + server+".out", true);
  92             FileOutputStream ferrStream =
  93                 new FileOutputStream(logDirName + server+".err", true);
  94 
  95             PrintStream pSout = new PrintStream(foutStream, true);
  96             PrintStream pSerr = new PrintStream(ferrStream, true);
  97 
  98             System.setOut(pSout);
  99             System.setErr(pSerr);
 100 
 101             logInformation( "Server started" ) ;
 102 
 103         } catch (Exception ex) {}
 104     }
 105 
 106     /** Write a time-stamped message to the indicated PrintStream.
 107     */
 108     private static void writeLogMessage( PrintStream pstream, String msg )
 109     {
 110         Date date = new Date();
 111         pstream.print( "[" + date.toString() + "] " + msg + "\n");
 112     }
 113 
 114     /** Write information to standard out only.
 115     */
 116     public static void logInformation( String msg )
 117     {
 118         writeLogMessage( System.out, "        " + msg ) ;
 119     }
 120 
 121     /** Write error message to standard out and standard err.
 122     */
 123     public static void logError( String msg )
 124     {
 125         writeLogMessage( System.out, "ERROR:  " + msg ) ;
 126         writeLogMessage( System.err, "ERROR:  " + msg ) ;
 127     }
 128 
 129     /** Write final message to log(s) and then terminate by calling
 130     * System.exit( code ).  If code == OK, write a normal termination
 131     * message to standard out, otherwise write an abnormal termination
 132     * message to standard out and standard error.
 133     */
 134     public static void logTerminal( String msg, int code )
 135     {
 136         if (code == 0) {
 137             writeLogMessage( System.out, "        " + msg ) ;
 138         } else {
 139             writeLogMessage( System.out, "FATAL:  " +
 140                 printResult( code ) + ": " + msg ) ;
 141 
 142             writeLogMessage( System.err, "FATAL:  " +
 143                 printResult( code ) + ": " + msg ) ;
 144         }
 145 
 146         System.exit( code ) ;
 147     }
 148 
 149     private Method getMainMethod( Class serverClass )
 150     {
 151         Class argTypes[] = new Class[] { String[].class } ;
 152         Method method = null ;
 153 
 154         try {
 155             method = serverClass.getDeclaredMethod( "main", argTypes ) ;
 156         } catch (Exception exc) {
 157             logTerminal( exc.getMessage(), NO_MAIN_METHOD ) ;
 158         }
 159 
 160         if (!isPublicStaticVoid( method ))
 161             logTerminal( "", NO_MAIN_METHOD ) ;
 162 
 163         return method ;
 164     }
 165 
 166     private boolean isPublicStaticVoid( Method method )
 167     {
 168         // check modifiers: public static
 169         int modifiers =  method.getModifiers ();
 170         if (!Modifier.isPublic (modifiers) || !Modifier.isStatic (modifiers)) {
 171             logError( method.getName() + " is not public static" ) ;
 172             return false ;
 173         }
 174 
 175         // check return type and exceptions
 176         if (method.getExceptionTypes ().length != 0) {
 177             logError( method.getName() + " declares exceptions" ) ;
 178             return false ;
 179         }
 180 
 181         if (!method.getReturnType().equals (Void.TYPE)) {
 182             logError( method.getName() + " does not have a void return type" ) ;
 183             return false ;
 184         }
 185 
 186         return true ;
 187     }
 188 
 189     private Method getNamedMethod( Class serverClass, String methodName )
 190     {
 191         Class argTypes[] = new Class[] { org.omg.CORBA.ORB.class } ;
 192         Method method = null ;
 193 
 194         try {
 195             method = serverClass.getDeclaredMethod( methodName, argTypes ) ;
 196         } catch (Exception exc) {
 197             return null ;
 198         }
 199 
 200         if (!isPublicStaticVoid( method ))
 201             return null ;
 202 
 203         return method ;
 204     }
 205 
 206     private void run(String[] args)
 207     {
 208         try {
 209             redirectIOStreams() ;
 210 
 211             String serverClassName = System.getProperty(
 212                 ORBConstants.SERVER_NAME_PROPERTY ) ;
 213 
 214             // determine the class loader to be used for loading the class
 215             // since ServerMain is going to be in JDK and we need to have this
 216             // class to load application classes, this is required here.
 217             ClassLoader cl = Thread.currentThread().getContextClassLoader();
 218 
 219             if (cl == null)
 220                 cl = ClassLoader.getSystemClassLoader();
 221 
 222             // determine the main class
 223             Class serverClass = null;
 224 
 225             try {
 226                 // determine the main class, try loading with current class loader
 227                 serverClass = Class.forName( serverClassName ) ;
 228             } catch (ClassNotFoundException ex) {
 229                 // eat the exception and try to load using SystemClassLoader
 230                 serverClass = Class.forName( serverClassName, true, cl);
 231             }
 232 
 233             if (debug)
 234                 System.out.println("class " + serverClassName + " found");
 235 
 236             // get the main method
 237             Method mainMethod = getMainMethod( serverClass ) ;
 238 
 239             // This piece of code is required, to verify the server definition
 240             // without launching it.
 241 
 242             // verify the server
 243 
 244             boolean serverVerifyFlag = Boolean.getBoolean(
 245                 ORBConstants.SERVER_DEF_VERIFY_PROPERTY) ;
 246             if (serverVerifyFlag) {
 247                 if (mainMethod == null)
 248                     logTerminal("", NO_MAIN_METHOD);
 249                 else {
 250                     if (debug)
 251                         System.out.println("Valid Server");
 252                     logTerminal("", OK);
 253                 }
 254             }
 255 
 256 
 257             registerCallback( serverClass ) ;
 258 
 259             // build args to the main and call it
 260             Object params [] = new Object [1];
 261             params[0] = args;
 262             mainMethod.invoke(null, params);
 263 
 264         } catch (ClassNotFoundException e) {
 265             logTerminal("ClassNotFound exception: " + e.getMessage(),
 266                 MAIN_CLASS_NOT_FOUND);
 267         } catch (Exception e) {
 268             logTerminal("Exception: " + e.getMessage(),
 269                 APPLICATION_ERROR);
 270         }
 271     }
 272 
 273     public static void main(String[] args) {
 274         ServerMain server = new ServerMain();
 275         server.run(args);
 276     }
 277 
 278     private static final boolean debug = false;
 279 
 280     private int getServerId()
 281     {
 282         Integer serverId = Integer.getInteger( ORBConstants.SERVER_ID_PROPERTY ) ;
 283 
 284         if (serverId == null)
 285             logTerminal( "", NO_SERVER_ID ) ;
 286 
 287         return serverId.intValue() ;
 288     }
 289 
 290     private void registerCallback( Class serverClass )
 291     {
 292         Method installMethod = getNamedMethod( serverClass, "install" ) ;
 293         Method uninstallMethod = getNamedMethod( serverClass, "uninstall" ) ;
 294         Method shutdownMethod = getNamedMethod( serverClass, "shutdown" ) ;
 295 
 296         Properties props = new Properties() ;
 297         props.put( "org.omg.CORBA.ORBClass",
 298             "com.sun.corba.se.impl.orb.ORBImpl" ) ;
 299         // NOTE: Very important to pass this property, otherwise the
 300         // Persistent Server registration will be unsucessfull.
 301         props.put( ORBConstants.ACTIVATED_PROPERTY, "false" );
 302         String args[] = null ;
 303         ORB orb = ORB.init( args, props ) ;
 304 
 305         ServerCallback serverObj = new ServerCallback( orb,
 306             installMethod, uninstallMethod, shutdownMethod ) ;
 307 
 308         int serverId = getServerId() ;
 309 
 310         try {
 311             Activator activator = ActivatorHelper.narrow(
 312                 orb.resolve_initial_references( ORBConstants.SERVER_ACTIVATOR_NAME ));
 313             activator.active(serverId, serverObj);
 314         } catch (Exception ex) {
 315             logTerminal( "exception " + ex.getMessage(),
 316                 REGISTRATION_FAILED ) ;
 317         }
 318     }
 319 }
 320 
 321 class ServerCallback extends
 322     com.sun.corba.se.spi.activation._ServerImplBase
 323 {
 324     private ORB orb;
 325     private transient Method installMethod ;
 326     private transient Method uninstallMethod ;
 327     private transient Method shutdownMethod ;
 328     private Object methodArgs[] ;
 329 
 330     ServerCallback(ORB orb, Method installMethod, Method uninstallMethod,
 331         Method shutdownMethod )
 332     {
 333         this.orb = orb;
 334         this.installMethod = installMethod ;
 335         this.uninstallMethod = uninstallMethod ;
 336         this.shutdownMethod = shutdownMethod ;
 337 
 338         orb.connect( this ) ;
 339 
 340         methodArgs = new Object[] { orb } ;
 341     }
 342 
 343     private void invokeMethod( Method method )
 344     {
 345         if (method != null)
 346             try {
 347                 method.invoke( null, methodArgs ) ;
 348             } catch (Exception exc) {
 349                 ServerMain.logError( "could not invoke " + method.getName() +
 350                     " method: " + exc.getMessage() ) ;
 351             }
 352     }
 353 
 354     // shutdown the ORB and wait for completion
 355     public void shutdown()
 356     {
 357         ServerMain.logInformation( "Shutdown starting" ) ;
 358 
 359         invokeMethod( shutdownMethod ) ;
 360 
 361         orb.shutdown(true);
 362 
 363         ServerMain.logTerminal( "Shutdown completed", ServerMain.OK ) ;
 364     }
 365 
 366     public void install()
 367     {
 368         ServerMain.logInformation( "Install starting" ) ;
 369 
 370         invokeMethod( installMethod ) ;
 371 
 372         ServerMain.logInformation( "Install completed" ) ;
 373     }
 374 
 375     public void uninstall()
 376     {
 377         ServerMain.logInformation( "uninstall starting" ) ;
 378 
 379         invokeMethod( uninstallMethod ) ;
 380 
 381         ServerMain.logInformation( "uninstall completed" ) ;
 382     }
 383 }