ServerMain.java revision 608:7e06bf1dcb09
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
26package com.sun.corba.se.impl.activation;
27
28import java.lang.reflect.Method;
29import java.lang.reflect.Modifier;
30import java.io.*;
31import java.util.Date;
32import java.util.Properties ;
33
34import org.omg.CORBA.ORB ;
35import com.sun.corba.se.spi.activation.Activator ;
36import com.sun.corba.se.spi.activation.ActivatorHelper ;
37import com.sun.corba.se.impl.orbutil.ORBConstants ;
38
39/**
40 * @author      Ken Cavanaugh
41 * @since       JDK1.2
42 */
43public 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
321class 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}
384