Thursday, January 26, 2012

Running Oracle Weblogic Server on Windows: a shutdown class

Overview



Running Oracle Weblogic server on Windows can be done in two ways:

  •  You can start Oracle Weblogic Server from the command line. This is good for test purposes but not very likely to be used in a production environment. 
  • You can install Oracle Weblogic Server to run as a windows service using the java wrapper beasvc.exe (or beasvcX64.exe on windows 64-bit)
The problem with the last option is that, if you stop the service, the Java Virtual Machine (and thus the Oracle Weblogic Server) simply gets killed. This can result in corrupt files, database connections that aren’t closed or even transactions that are started but won’t be stopped. A possible workaround is to stop each Weblogic server in the domain from the admin console. This not only time consuming but also not the preferred way of working.
In order to provide a proper shutdown, the beasvc.exe has an option called “stopclass”. It specifies a java class with a stop method that will be invoked at the moment the windows service gets stopped. Although you can write any kind of java code in the shutdown class, we will focus on writing code for a decent shutdown for both admin servers and managed servers.
The shutdown class works as follows: 
  • It sends a request over HTTP to the Admin server 
  • The Admin server sends the shutdown request to the corresponding server.
This means that the admin server sends a request to itself in case of a shutdown. The shutdown request for a managed server passes first via the admin server back to the managed server.

 

Configuration

First of all the beasvc.exe service wrapper needs to be aware of the shutdown class. This can be done by adding the -stopclass option (for example: -stopclass: be.i8c.systemtools.weblogic.ServerStopper)
Secondly, two options need to be set on each server in the domain:
  • You have to enable tunneling. You do this by ticking “Enable Tunneling” under Domain > Environment > Servers > “Server” > Protocols > General
  • You have to ignore http sessions during shutdown, otherwise the server keeps on waiting for ever until no more http sessions are active. Enable the option “Ignore Sessions During Shutdown” under Domain > Environment > Servers > “Server” > Control > Start/Stop

 

Code

package be.i8c.systemtools.weblogic;

import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Date;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;

import javax.naming.Context;

import weblogic.jndi.Environment;
import weblogic.management.MBeanHome;
import weblogic.management.runtime.ServerRuntimeMBean;
import weblogic.management.runtime.ServerStates;

public class ServerStopper
{
  public static void stop()
  {
    Properties prop = System.getProperties();
    try
    {
      MBeanHome home = null;
      //url of the Admin server
      String url = "";

      if (prop.getProperty("weblogic.management.server") != null)
      {
        // this property will be set automatically on a managed server to indicate the location of the admin server    
        url = prop.getProperty("weblogic.management.server");
      }
      else
      {
        // the admin.url is a property to indicate the location of the admin server on the admin server. It refers to itself, but is necessary to perform a proper shutdown. You can add it manually as a –D property when you install the server as a windows service. The name of the property can be any random name.
   url = prop.getProperty("admin.url");
      }
      // username and password to perform the shutdown operation
      username = "username";
      password = "password";
               
      ServerRuntimeMBean serverRuntime = null;
      Set mbeanSet = null;
      Iterator mbeanIterator = null;
      // Set ContextClassloader to prevent assertions
      URL[] urls = { new File("/").toURL() };
      Thread.currentThread().setContextClassLoader(new URLClassLoader(urls));
      Environment env = new Environment();
      env.setProviderUrl(url);
      env.setSecurityPrincipal(username);
      env.setSecurityCredentials(password);
      Context ctx = env.getInitialContext();
      home = (MBeanHome)ctx.lookup("weblogic.management.adminhome");
      mbeanSet = home.getMBeansByType("ServerRuntime");
      mbeanIterator = mbeanSet.iterator();
             
      while(mbeanIterator.hasNext())
      {
        serverRuntime = (ServerRuntimeMBean)mbeanIterator.next();
        try
        {
          // we have to add this check, since the iterator will list all the servers, both admin and managed. If we don’t add this check a shutdown of all the servers will be performed in case we only stop one server
          if (serverRuntime.getName().equalsIgnoreCase(prop.getProperty("weblogic.Name")))
       {
         if(serverRuntime.getState().equals(ServerStates.RUNNING))
         {
           // we perform a normal shut down in case the server is in the RUNNING state
           serverRuntime.shutdown();
         }
         else
         {
           //This is the same as a forced shutdown, but not the same as killing the JVM. We don’t do a normal shutdown in case the server is not in the RUNNING state.
 System.exit(10);
         }
       }
        }
        catch (Exception e)
        {
          // You can do nothing over here. In case the shutdown call will fail, windows will wait for the service to end, but that won’t happen. It will kill the service anyway after a while.
        }
      }
    }
    catch (Exception e)
    {
      // We get here in case the admin server couldn’t be reached
      System.exit(10);
    }
  }
}

Author: Dimitri Van Kerckhoven

3 comments:

  1. Hello,
    Thanks for sharing this information. I did have a question.
    I am not clear why “enable tunneling” is required for all servers? In my deployment the “stopclass” class seems to be working fine with only the Admin server having tunneling enabled?

    ReplyDelete
  2. Hi Agianni,

    I think we had to do this because our admin server is in the intranet while our managed servers are running in the perimeter network. These are other network segments, separated by a firewall, and thus http tunneling was the only way to allow the communication between admin and managed servers.
    In our case it didn't work without enabling the tunneling option.
    Your admin and managed servers are probably in the same network segment? In that case native T3 communication would be possible.

    ReplyDelete
  3. Indeed my managed servers are on the same network. In fact they are on the same server  Thanks for the explanation.

    ReplyDelete