admin@glassfish.java.net

code review: ApplicationServer/OnDemandServer

From: Lloyd Chambers <lloyd.chambers_at_mac.com>
Date: Thu, 8 Feb 2007 12:23:29 -0800

https://glassfish.dev.java.net/issues/show_bug.cgi?id=2365

This change accomplishes several things:

1. Makes the ServerContext available when instantiating
ServerLifecycle objects. This allows a ServerLifecycle to optimize
its code by (potentially) performing initialization work when
instantiated (perhaps in a separate thread). It potentially also
allows better use of 'final' variables to minimize threading issues.

2. adds generic types for the List of ServerLifecycle, making the
code type-safe at compile time, and eliminating casts.

3. factors out the instantiation of ServerLifecycle, make the code
more amenable to both PE and EE startup sharing (instead of
duplicating) the instantiation code as was done before.

4. Threads the ServerLifecycle instantiation loop for a small
speedup of about 0.7% in EE. This is mainly for the benefit of a
pending change for AdminService; a subsequent checkin will offer
additional speedups.

5. Isolate these changes from subsequent ones that are more
"interesting".


Lloyd


Index: src/java/com/sun/enterprise/server/ApplicationServer.java
===================================================================
RCS file: /cvs/glassfish/appserv-core/src/java/com/sun/enterprise/
server/ApplicationServer.java,v
retrieving revision 1.8
diff -w -u -1 -0 -r1.8 ApplicationServer.java
--- src/java/com/sun/enterprise/server/ApplicationServer.java 16
Nov 2006 19:47:49 -0000 1.8
+++ src/java/com/sun/enterprise/server/ApplicationServer.java 8 Feb
2007 20:20:47 -0000
@@ -16,23 +16,26 @@
   * If applicable, add the following below the CDDL Header,
   * with the fields enclosed by brackets [] replaced by
   * you own identifying information:
   * "Portions Copyrighted [year] [name of copyright owner]"
   *
   * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
   */
package com.sun.enterprise.server;
import java.io.File;
+import java.util.List;
import java.util.ArrayList;
import java.io.IOException;
+import java.lang.reflect.Constructor;
+
import com.sun.enterprise.Switch;
import com.sun.enterprise.server.J2EEServer;
import com.sun.enterprise.security.audit.AuditModuleEventListenerImpl;
import
com.sun.enterprise.security.audit.SecurityServiceEventListenerImpl;
import
com.sun.enterprise.security.auth.realm.AuthRealmEventListenerImpl;
import com.sun.enterprise.security.auth.realm.UserMgmtEventListenerImpl;
import
com.sun.enterprise.security.jmac.config.MessageSecurityConfigEventListen
erImpl;
import com.sun.enterprise.config.serverbeans.ServerBeansFactory;
import com.sun.enterprise.config.serverbeans.TransactionService;
@@ -67,52 +70,48 @@
//IASRI 4717059 BEGIN
//import com.sun.ejb.containers.ReadOnlyBeanNotifierImpl;
//IASRI 4717059 END
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sun.logging.LogDomains;
import com.sun.enterprise.server.logging.ServerLogManager;
+
+import com.sun.appserv.management.util.misc.TimingDelta;
+import com.sun.appserv.management.util.misc.RunnableBase;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
/**
   * ApplicationServer is the main entry point for iAS 7.0 J2EE
server instance.
   * This code implements the server lifecycle state transitions and
it relies on
   * various iAS 7.0 subsystems such as Web/EJB containers throught
its lifecycle.
   * com.sun.enterprise.J2EEServer is the RI counerpart of this code;
the evolving
   * iAS server implementation replaces functionality of RI J2EEServer.
- */
-public class ApplicationServer {
-
- /** server logger */
- static Logger _logger = LogDomains.getLogger
(LogDomains.CORE_LOGGER);
-
- public static java.io.PrintStream ostream = System.out;
- public static java.io.PrintStream estream = System.err;
-
- private static final String USER_TX = "java:comp/UserTransaction";
- private static final String CODEBASE_PROP =
"java.rmi.server.codebase";
-
- /**
- * Default services implementing lifecycle interface for orderly
startup/
+ *
+ * NOTES on services by name:
+ * Default services implementing lifecycle interface for orderly
startup
       * shutdown and hot deployment.
       * Each service entry is of the form {name, className}.
       * Note: Make sure LifecycleModuleService is the last subsystem
in this list.
       */
- static String[][]servicesByName;
-
+public class ApplicationServer {
+ /** server logger */
+ protected static final Logger _logger = LogDomains.getLogger
(LogDomains.CORE_LOGGER);
      /** ServerContext -- server-wide runtime environment context **/
      private static ServerContext context = null;
      /** services -- standard runtime service objects **/
- private ArrayList services = new ArrayList();
+ private final List<ServerLifecycle> services = new
ArrayList<ServerLifecycle>();
      /** common class loader for the server */
      private ClassLoader commonClassLoader;
      /** share class loader for the server */
      private ClassLoader connectorClassLoader;
      /**
       * Default constructor.
       */
@@ -124,21 +123,21 @@
       * subsystem. This method is called before any of the public
methods of
       * this subsystem are utilized.
       *
       * @param context ServerContext the server runtime context.
       *
       * @exception IllegalStateException if this subsystem has
already been
       * started
       * @exception ServerLifecycleException if this subsystem
detects a fatal
       * error that prevents this subsystem from being used
       */
- public void onInitialization(ServerContext context)
+ public void onInitialization( final ServerContext context)
                  throws ServerLifecycleException
      {
          // sets the server context
          this.context = context;
          // initialize all server loggers that were not initialized
          // Note: reInitializeServerLoggers should be called after
          // setting the server context and before performing any
          // other server startup activities that needs a logger
@@ -148,26 +147,25 @@
          printStartupInfo();
          // system class loader
          ClassLoader parentOfCommonCL = this.getClass
().getClassLoader();
          //Shared CL
          //In the new CL hierarchy the parent of common classloader
          //is the shared chain.
          if(Boolean.getBoolean
(com.sun.enterprise.server.PELaunch.USE_NEW_CLASSLOADER_PROPERTY))
              parentOfCommonCL = PELaunch.getSharedChain();
- InstanceEnvironment env = this.context.getInstanceEnvironment
();
+ final InstanceEnvironment env =
this.context.getInstanceEnvironment();
          try {
-
- String dir = env.getLibClassesPath();
- String jarDir = env.getLibPath();
+ final String dir = env.getLibClassesPath();
+ final String jarDir = env.getLibPath();
              // constructs the common class loader. System class loader
              // is the parent of common class loader. Common class
loader
              // includes <instance>/lib/classes dir, <instance>/lib/
*.jar
              // and <instance>/lib/*.zip
              commonClassLoader =
                  ClassLoaderUtils.getClassLoader(new File[] {new File
(dir)},
                                                  new File[] {new File
(jarDir)},
                                                  parentOfCommonCL
                                                  );
@@ -185,21 +183,21 @@
          }
          // Create the connector class loader. This will be the
parent class
          // loader for all j2ee components!! Common class loader is the
          // parent of connector class loader.
          connectorClassLoader =
              ConnectorClassLoader.getInstance(commonClassLoader);

          // sets the class loaders in the server context
          if (this.context instanceof ServerContextImpl) {
- ServerContextImpl contextImpl = (ServerContextImpl)
this.context;
+ final ServerContextImpl contextImpl =
(ServerContextImpl) this.context;
              // set the common classloader in the server context
              contextImpl.setCommonClassLoader(commonClassLoader);
              // sets the shared class loader
              contextImpl.setSharedClassLoader(connectorClassLoader);
              // sets the life cycle parent class loader
              contextImpl.setLifecycleParentClassLoader
(connectorClassLoader);
          }
@@ -211,62 +209,59 @@
              java.security.AccessController.doPrivileged(
                      new java.security.PrivilegedAction() {
                  public Object run() {
                      Thread.currentThread().setContextClassLoader
(commonCL);
                      return null;
                  }
              }
              );
         //added the pluggable interface way of getting the list of
services
- InternalServicesList servicesList =
+ final InternalServicesList servicesList =
                 context.getPluggableFeatureFactory
().getInternalServicesList();
- servicesByName = servicesList.getServicesByName();
+ final String[][] servicesByName =
servicesList.getServicesByName();
         if (servicesByName == null) {
               _logger.log(Level.SEVERE, "services.null");
               throw new ServerLifecycleException();
         }
          // security manager is set inside SecurityLifecycle
         // Instantiate the built-in runtime services
- services = instantiateRuntimeServices();
+ final List<ServerLifecycle> temp = instantiateRuntimeServices
( context, servicesByName );
+ services.addAll( temp );

          // Initialize the built-in runtime services
- for (int i = 0; i < services.size(); i++) {
- Object service = services.get(i);
- if (service instanceof ServerLifecycle) {
+ for ( final ServerLifecycle service : services) {
                 try {
- ((ServerLifecycle) service).onInitialization
(context);
+ service.onInitialization(context);
                 } catch (ServerLifecycleException e) {
                     _logger.log(Level.SEVERE, "service.notinit",
                                 new Object[] {service, e.toString()});
                     throw e;
                 }
              }
- }
          //add listeners for security dynamic reconfiguration
          AdminEventListenerRegistry.addAuditModuleEventListener(
                  new AuditModuleEventListenerImpl());
          AdminEventListenerRegistry.addAuthRealmEventListener(
                  new AuthRealmEventListenerImpl());
          AdminEventListenerRegistry.addSecurityServiceEventListener(
                  new SecurityServiceEventListenerImpl());
          AdminEventListenerRegistry.addUserMgmtEventListener(
                  new UserMgmtEventListenerImpl());
          AdminEventListenerRegistry.addEventListener(
                  MessageSecurityConfigEvent.eventType,
                  new MessageSecurityConfigEventListenerImpl());
-
          // Call RI J2EEServer initialization code. Note that all
resources
          // specified in server.xml will be loaded by the common
class loader.
         try {
             J2EEServer.main(context);
         } catch (Exception e) {
             throw new ServerLifecycleException(e);
         }
          // final connector class loader for the anonymous inner class
          final ClassLoader connCL = connectorClassLoader;
@@ -274,76 +269,140 @@
          // set the connector class loader as the thread context
class loader
          java.security.AccessController.doPrivileged(
              new java.security.PrivilegedAction() {
                  public Object run() {
                      Thread.currentThread().
                          setContextClassLoader(connCL);
                          return null;
                      }
                  }
          );
+ }
+
+ static protected final ServerLifecycle
+ instantiateOneServerLifecycle(
+ final ServerContext serverContext,
+ final String classname )
+ throws ClassNotFoundException, InstantiationException,
IllegalAccessException {
+ final TimingDelta delta = new TimingDelta();
+
+ final Class c = Class.forName( classname );
+
+ ServerLifecycle item = null;
+
+ // call a constructor that takes a ServerContext if it
exists, since
+ // some services might make efficient use of it during
construction.
+ // otherwise use a no-argument constructor
+ try {
+ final Constructor constructor = c.getConstructor
( ServerContext.class );
+ item = (ServerLifecycle)constructor.newInstance
( serverContext );
+ }
+ catch( Exception e ) {
+ item = (ServerLifecycle)c.newInstance();
+ }
+
+ //System.out.println( "Instantiate " + classname + ": " +
delta.elapsedMillis() );
+ return item;
+ }
+
+
+ protected List<ServerLifecycle>
+ instantiateRuntimeServices(
+ final ServerContext serverContext,
+ final String[][] servicesByName ) throws
ServerLifecycleException {
+ final List<String> classnames = new ArrayList<String>();
+
+ for (int i=0; i < servicesByName.length; i++) {
+ final String[] def = servicesByName[i];
+ classnames.add( def[1] );
+ }
+
+ return instantiateRuntimeServices( serverContext, classnames );
+ }
+
+ private static final class Instantiator extends RunnableBase {
+ private final String mClassname;
+ private final ServerContext mServerContext;
+ private volatile ServerLifecycle mService;
+
+ public Instantiator(
+ final ServerContext serverContext,
+ final String classname ) {
+ mServerContext = serverContext;
+ mClassname = classname;
+ mService = null;
+ }
+
+ protected void doRun()
+ throws ClassNotFoundException, InstantiationException,
IllegalAccessException
+ {
+ mService = instantiateOneServerLifecycle
( mServerContext, mClassname );
+ }
+ public ServerLifecycle getService() {
+ waitDoneThrow();
+ return mService;
+ }
      }
      /**
       * Go through the list of built-in runtime services and
instantiate them.
       */
- protected ArrayList instantiateRuntimeServices() throws
ServerLifecycleException{
-
- ArrayList serviceList = new ArrayList();
+ protected List<ServerLifecycle>
+ instantiateRuntimeServices(
+ final ServerContext serverContext,
+ final List<String> classnames )
+ throws ServerLifecycleException {
+ final Instantiator[] instantiators = new Instantiator
[ classnames.size() ];
          // Instantiate service objects
- for (int i=0; i < servicesByName.length; i++) {
- try {
- String[] def = servicesByName[i];
- Class c = Class.forName(def[1]);
- Object o = c.newInstance();
-
- serviceList.add(o);
- } catch (Exception ex) {
- _logger.log(Level.SEVERE, "server.exception", ex);
- throw new ServerLifecycleException(ex.getMessage());
+ int idx = 0;
+ for ( final String classname : classnames ) {
+ instantiators[idx] = new Instantiator( serverContext,
classname );
+ instantiators[idx].submit();
+ ++idx;
             }
+ // collect the resulting ServerLifecycle
+ final List<ServerLifecycle> serviceList = new
ArrayList<ServerLifecycle>();
+ for ( int i = 0; i < instantiators.length; ++i ) {
+ serviceList.add( instantiators[i].getService() );
          }
+
          return serviceList;
      }
      /**
       * Server is starting up applications
       *
       * @param context ServerContext the server runtime context.
       *
       * @exception ServerLifecycleException if this subsystem
detects a fatal
       * error that prevents this subsystem from being used
       *
       * Note: Currently, with the J2EEServer code handles
initialization and
       * applications startup in one place <code> J2EEServer.run() </
code>.
       *
       * XXX: This separation needs to be worked on to make it cleaner.
       */
      public void onStartup() throws ServerLifecycleException
      {
          // startup the built-in runtime services
- for (int i = 0; i < services.size(); i++) {
- Object service = services.get(i);
-
- if (service instanceof ServerLifecycle) {
+ for ( final ServerLifecycle service : services) {
                 try {
- ((ServerLifecycle) service).onStartup(context);
+ service.onStartup(context);
                 } catch (ServerLifecycleException e) {
                     _logger.log(Level.SEVERE, "service.notstarted",
                                 new Object[] {service, e.toString()});
                     throw e;
                 }
              }
- }
          // _REVISIT_: Mover AlertConfigurator to configure after
onReady()
          AlertConfigurator.getAlertConfigurator( ).configure( );
      }
      /**
       * Server has complted loading the applications and is ready to
       * serve requests.
       *
       * @exception ServerLifecycleException if this subsystem
detects a fatal
       * error that prevents this subsystem from being used
@@ -405,53 +464,46 @@
                      }
                  }
              }
          } catch (Exception ee) {
              throw new ServerLifecycleException(ee);
          }
          // notify the built-in runtime services that we are ready
- for (int i = 0; i < services.size(); i++) {
- Object service = services.get(i);
-
- if (service instanceof ServerLifecycle) {
+ for ( final ServerLifecycle service : services) {
                 try {
- ((ServerLifecycle) service).onReady(context);
+ service.onReady(context);
                 } catch (ServerLifecycleException e) {
                   _logger.log(Level.SEVERE, "service.notready",
                               new Object[] {service, e.toString()});
                 }
              }
          }
- }
      /**
       * Server is shutting down applications
       *
       * @exception ServerLifecycleException if this subsystem
detects a fatal
       * error that prevents this subsystem from being used
       */
      public void onShutdown() throws ServerLifecycleException
      {
          // shutdown the built-in runtime services (in the reverse
order).
          for (int i = services.size(); i > 0; i--) {
- Object service = services.get(i-1);
+ final ServerLifecycle service = services.get(i-1);
- _logger.log(Level.FINE,"service.shutdown",
- services.get(i-1));
+ _logger.log(Level.FINE,"service.shutdown", services.get
(i-1));
             try {
- if (service instanceof ServerLifecycle) {
- ((ServerLifecycle) service).onShutdown();
- }
+ service.onShutdown();
             } catch (Exception e) {
                 //do nothing since we want to continue shutting down
other LFC
                 //modules
                  _logger.log(Level.WARNING, "server.exception", e);
             }
          }
      }
      /**
       * Server is terminating the subsystems and the runtime
environment.
@@ -470,36 +522,34 @@
         }
         try {
             Switch.getSwitch().getPoolManager().killAllPools();
         } catch( Throwable t ) {
             if (_logger.isLoggable( Level.FINE ) ) {
                 _logger.log(Level.FINE, "exception : " +t);
             }
         }
   // terminate the built-in runtime services (in the reverse order)
          for (int i = services.size(); i > 0; i--) {
- Object service = services.get(i-1);
+ final ServerLifecycle service = services.get(i-1);
             _logger.log(Level.FINE,"service.shutdown",
                                         services.get(i-1));
             try {
- if (service instanceof ServerLifecycle) {
- ((ServerLifecycle) service).onTermination();
- }
+ service.onTermination();
             } catch (Exception e) {
                 //do nothing since we want to continue shutting down
other LFC
                 //modules
                  _logger.log(Level.WARNING, "server.exception", e);
             }
          }
- services = null;
+ services.clear();
      }
      /**
       * Get the server runtime context; returns a valid context only
       * after initialization; a null otherwise.
       *
       * @return a server runtime context or null if not initialized
       */
      public static ServerContext getServerContext() {
          return context;
cvs server: Diffing src/java/com/sun/enterprise/server/event
cvs server: Diffing src/java/com/sun/enterprise/server/logging
cvs server: Diffing src/java/com/sun/enterprise/server/logging/
diagnostics
cvs server: Diffing src/java/com/sun/enterprise/server/logging/logviewer
cvs server: Diffing src/java/com/sun/enterprise/server/logging/
logviewer/backend
cvs server: Diffing src/java/com/sun/enterprise/server/logging/stats
cvs server: Diffing src/java/com/sun/enterprise/server/ondemand
Index: src/java/com/sun/enterprise/server/ondemand/OnDemandServer.java
===================================================================
RCS file: /cvs/glassfish/appserv-core/src/java/com/sun/enterprise/
server/ondemand/OnDemandServer.java,v
retrieving revision 1.4
diff -w -u -1 -0 -r1.4 OnDemandServer.java
--- src/java/com/sun/enterprise/server/ondemand/
OnDemandServer.java 8 Mar 2006 12:58:03 -0000 1.4
+++ src/java/com/sun/enterprise/server/ondemand/
OnDemandServer.java 8 Feb 2007 20:20:47 -0000
@@ -30,37 +30,29 @@
import com.sun.enterprise.server.ss.*;
import com.sun.enterprise.server.ondemand.entry.*;
import com.sun.appserv.server.ServerLifecycle;
import com.sun.appserv.server.LifecycleEvent;
import com.sun.appserv.server.ServerLifecycleException;
import com.sun.enterprise.server.pluggable.PluggableFeatureFactory;
import com.sun.enterprise.server.pluggable.PluggableFeatureFactoryImpl;
import com.sun.enterprise.server.pluggable.InternalServicesList;
-
-
/**
   * Represents on-demand server. This is the main class that ties
ondemand logic
   * with rest of the application server.
   */
public class OnDemandServer extends ApplicationServer implements
EntryPoint{
-
      private static boolean onDemandStartup = true;
-
- private static ServerEntryListener listener = null;
- private static SystemAppLoader systemAppLoader = null;
- private ServiceGroup sg = null;
-
- /** server logger */
- static Logger _logger = LogDomains.getLogger
(LogDomains.CORE_LOGGER);
-
+ private static volatile ServerEntryListener listener = null;
+ private static volatile SystemAppLoader systemAppLoader = null;
+ private volatile ServiceGroup sg = null;
      /**
       * Server is initializing subsystems and setting up the runtime
environment.
       * Prepare for the beginning of active use of the public
methods of this
       * subsystem. This method is called before any of the public
methods of
       * this subsystem are utilized.
       *
       * @param sc ServerContext the server runtime context.
       *
       * @exception IllegalStateException if this subsystem has
already been
@@ -125,54 +117,57 @@
              sg.stop(null);
          } catch (Exception e) {
              throw new ServerLifecycleException(e);
          }
      }
      public void generateEntryContext(Object event) {
          ServerEntryHelper.generateStartUpEntryContext((Boolean)
event);
      }
- protected ArrayList instantiateRuntimeServices() throws
ServerLifecycleException {
+ protected List<ServerLifecycle>
+ instantiateRuntimeServices(
+ final ServerContext serverContext,
+ final String[][] defaultServices )
+ throws ServerLifecycleException {
          if (onDemandStartup) {
- InternalServicesList services = new TomcatServices();
- InternalServicesList ondemandservices = new
OnDemandServices();
- String[][] servicesByName = services.getServicesByName();
- String[][] odsByName = ondemandservices.getServicesByName
();
+ final InternalServicesList services = new TomcatServices();
+ final InternalServicesList ondemandservices = new
OnDemandServices();
+ final String[][] servicesByName =
services.getServicesByName();
+ final String[][] odsByName =
ondemandservices.getServicesByName();
              if (servicesByName == null) {
                 _logger.log(Level.SEVERE, "services.null");
                 throw new ServerLifecycleException();
              }
- ArrayList serviceList = new ArrayList();
+ final List<ServerLifecycle> serviceList = new
ArrayList<ServerLifecycle>();
              // Instantiate service objects
              allServices :
- for (String[] service : servicesByName) {
- for (String[] ods : odsByName) {
+ for (final String[] service : servicesByName) {
+ for (final String[] ods : odsByName) {
                      if (service[0].equals(ods[0])) {
                          continue allServices;
                      }
                 }
                 try {
- //String[] def = servicesByName[i];
- Class c = java.lang.Class.forName(service[1]);
- Object o = c.newInstance();
- serviceList.add(o);
+ final ServerLifecycle serverLifecycle =
+ super.instantiateOneServerLifecycle
( serverContext, service[1] );
+ serviceList.add( serverLifecycle );
                 } catch (Exception ex) {
                     _logger.log(Level.SEVERE, "server.exception", ex);
                     throw new ServerLifecycleException(ex.getMessage
());
                 }
              }
              return serviceList;
          } else {
- return super.instantiateRuntimeServices();
+ return super.instantiateRuntimeServices( serverContext,
defaultServices);
          }
      }
      // Return the server entry listener.
      public static ServerEntryListener getServerEntryListener() {
          return listener;
      }
      // Return the system apploader.
      public static SystemAppLoader getSystemAppLoader() {
cvs server: Diffing src/java/com/sun/enterprise/server/ondemand