1 /*
   2  * Copyright (c) 1997, 2003, 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 package com.sun.corba.se.impl.activation;
  26 
  27 /**
  28  *
  29  * @author      Anita Jindal
  30  * @since       1.2
  31  */
  32 
  33 import org.omg.CORBA.CompletionStatus;
  34 
  35 import com.sun.corba.se.spi.activation.Server;
  36 import com.sun.corba.se.spi.activation.EndPointInfo;
  37 import com.sun.corba.se.spi.activation.ORBAlreadyRegistered;
  38 import com.sun.corba.se.spi.activation.ORBPortInfo;
  39 import com.sun.corba.se.spi.activation.InvalidORBid;
  40 import com.sun.corba.se.spi.activation.ServerHeldDown;
  41 import com.sun.corba.se.spi.activation.RepositoryPackage.ServerDef;
  42 import com.sun.corba.se.spi.activation.IIOP_CLEAR_TEXT;
  43 import com.sun.corba.se.spi.orb.ORB ;
  44 
  45 import com.sun.corba.se.impl.orbutil.ORBConstants;
  46 import com.sun.corba.se.impl.logging.ActivationSystemException ;
  47 
  48 import java.io.File;
  49 import java.util.HashMap;
  50 import java.util.Iterator;
  51 import java.util.NoSuchElementException;
  52 
  53 public class ServerTableEntry
  54 {
  55 
  56     private final static int DE_ACTIVATED = 0;
  57     private final static int ACTIVATING   = 1;
  58     private final static int ACTIVATED    = 2;
  59     private final static int RUNNING      = 3;
  60     private final static int HELD_DOWN    = 4;
  61 
  62 
  63     private String printState()
  64     {
  65         String str = "UNKNOWN";
  66 
  67         switch (state) {
  68         case (DE_ACTIVATED) : str = "DE_ACTIVATED"; break;
  69         case (ACTIVATING  ) : str = "ACTIVATING  "; break;
  70         case (ACTIVATED   ) : str = "ACTIVATED   "; break;
  71         case (RUNNING     ) : str = "RUNNING     "; break;
  72         case (HELD_DOWN   ) : str = "HELD_DOWN   "; break;
  73         default: break;
  74         }
  75 
  76         return str;
  77     }
  78 
  79     private final static long waitTime    = 2000;
  80     private static final int ActivationRetryMax = 5;
  81 
  82     // state of each entry
  83     private int state;
  84     private int serverId;
  85     private HashMap orbAndPortInfo;
  86     private Server serverObj;
  87     private ServerDef serverDef;
  88     private Process process;
  89     private int activateRetryCount=0;
  90     private String activationCmd;
  91     private ActivationSystemException wrapper ;
  92     public String toString()
  93     {
  94         return "ServerTableEntry[" + "state=" + printState() +
  95             " serverId=" + serverId +
  96             " activateRetryCount=" + activateRetryCount + "]" ;
  97     }
  98 
  99     // get the string needed to make the activation command
 100     private static String javaHome, classPath, fileSep, pathSep;
 101 
 102     static {
 103         javaHome  = System.getProperty("java.home");
 104         classPath = System.getProperty("java.class.path");
 105         fileSep   = System.getProperty("file.separator");
 106         pathSep   = System.getProperty("path.separator");
 107     }
 108 
 109     ServerTableEntry( ActivationSystemException wrapper,
 110         int serverId, ServerDef serverDef, int initialPort,
 111         String dbDirName, boolean verify, boolean debug )
 112     {
 113         this.wrapper = wrapper ;
 114         this.serverId = serverId;
 115         this.serverDef = serverDef;
 116         this.debug = debug ;
 117         // create a HashMap with capacity 255
 118         // Since all methods are synchronized, we don't need any
 119         // additional synchronization mechanisms
 120         orbAndPortInfo = new HashMap(255);
 121 
 122         activateRetryCount = 0;
 123         state = ACTIVATING;
 124 
 125         // compute the activation command
 126         activationCmd =
 127 
 128             // add path to the java vm
 129             javaHome + fileSep + "bin" + fileSep + "java " +
 130 
 131             // add any arguments to the server Java VM
 132             serverDef.serverVmArgs + " " +
 133 
 134             // add ORB properties
 135             "-Dioser=" + System.getProperty( "ioser" ) + " " +
 136             "-D" + ORBConstants.INITIAL_PORT_PROPERTY   + "=" + initialPort + " " +
 137             "-D" + ORBConstants.DB_DIR_PROPERTY         + "=" + dbDirName + " " +
 138             "-D" + ORBConstants.ACTIVATED_PROPERTY      + "=true " +
 139             "-D" + ORBConstants.SERVER_ID_PROPERTY      + "=" + serverId + " " +
 140             "-D" + ORBConstants.SERVER_NAME_PROPERTY    + "=" + serverDef.serverName + " " +
 141             // we need to pass in the verify flag, so that the server is not
 142             // launched, when we try to validate its definition during registration
 143             // into the RepositoryImpl
 144 
 145             (verify ? "-D" + ORBConstants.SERVER_DEF_VERIFY_PROPERTY + "=true ": "") +
 146 
 147             // add classpath to the server
 148             "-classpath " + classPath +
 149             (serverDef.serverClassPath.equals("") == true ? "" : pathSep) +
 150             serverDef.serverClassPath +
 151 
 152             // add server class name and arguments
 153             " com.sun.corba.se.impl.activation.ServerMain " + serverDef.serverArgs
 154 
 155             // Add the debug flag, if any
 156             + (debug ? " -debug" : "") ;
 157 
 158         if (debug) System.out.println(
 159                                       "ServerTableEntry constructed with activation command " +
 160                                       activationCmd);
 161     }
 162 
 163     /**
 164      * Verify whether the server definition is valid.
 165      */
 166     public int verify()
 167     {
 168         try {
 169 
 170             if (debug)
 171                 System.out.println("Server being verified w/" + activationCmd);
 172 
 173             process = Runtime.getRuntime().exec(activationCmd);
 174             int result = process.waitFor();
 175             if (debug)
 176                 printDebug( "verify", "returns " + ServerMain.printResult( result ) ) ;
 177             return result ;
 178         } catch (Exception e) {
 179             if (debug)
 180                 printDebug( "verify", "returns unknown error because of exception " +
 181                             e ) ;
 182             return ServerMain.UNKNOWN_ERROR;
 183         }
 184     }
 185 
 186     private void printDebug(String method, String msg)
 187     {
 188         System.out.println("ServerTableEntry: method  =" + method);
 189         System.out.println("ServerTableEntry: server  =" + serverId);
 190         System.out.println("ServerTableEntry: state   =" + printState());
 191         System.out.println("ServerTableEntry: message =" + msg);
 192         System.out.println();
 193     }
 194 
 195     synchronized void activate() throws org.omg.CORBA.SystemException
 196     {
 197         state = ACTIVATED;
 198 
 199         try {
 200             if (debug)
 201                 printDebug("activate", "activating server");
 202             process = Runtime.getRuntime().exec(activationCmd);
 203         } catch (Exception e) {
 204             deActivate();
 205             if (debug)
 206                 printDebug("activate", "throwing premature process exit");
 207             throw wrapper.unableToStartProcess() ;
 208         }
 209     }
 210 
 211     synchronized void register(Server server)
 212     {
 213         if (state == ACTIVATED) {
 214 
 215             serverObj = server;
 216 
 217             //state = RUNNING;
 218             //notifyAll();
 219 
 220             if (debug)
 221                 printDebug("register", "process registered back");
 222 
 223         } else {
 224 
 225             if (debug)
 226                 printDebug("register", "throwing premature process exit");
 227             throw wrapper.serverNotExpectedToRegister() ;
 228         }
 229     }
 230 
 231     synchronized void registerPorts( String orbId, EndPointInfo [] endpointList)
 232         throws ORBAlreadyRegistered
 233     {
 234 
 235         // find if the ORB is already registered, then throw an exception
 236         if (orbAndPortInfo.containsKey(orbId)) {
 237             throw new ORBAlreadyRegistered(orbId);
 238         }
 239 
 240         // store all listener ports and their types
 241         int numListenerPorts = endpointList.length;
 242         EndPointInfo [] serverListenerPorts = new EndPointInfo[numListenerPorts];
 243 
 244         for (int i = 0; i < numListenerPorts; i++) {
 245             serverListenerPorts[i] = new EndPointInfo (endpointList[i].endpointType, endpointList[i].port);
 246         if (debug)
 247             System.out.println("registering type: " + serverListenerPorts[i].endpointType  +  "  port  " + serverListenerPorts[i].port);
 248         }
 249 
 250         // put this set of listener ports in the HashMap associated
 251         // with the orbId
 252         orbAndPortInfo.put(orbId, serverListenerPorts);
 253         if (state == ACTIVATED) {
 254             state = RUNNING;
 255             notifyAll();
 256         }
 257         // _REVISIT_, If the state is not equal to ACTIVATED then it is a bug
 258         // need to log that error, once the Logging framework is in place
 259         // for rip-int.
 260         if (debug)
 261             printDebug("registerPorts", "process registered Ports");
 262     }
 263 
 264     void install()
 265     {
 266         Server localServerObj = null;
 267         synchronized ( this ) {
 268             if (state == RUNNING)
 269                 localServerObj = serverObj;
 270             else
 271                 throw wrapper.serverNotRunning() ;
 272         }
 273         if (localServerObj != null) {
 274             localServerObj.install() ;
 275         }
 276 
 277     }
 278 
 279     void uninstall()
 280     {
 281         Server localServerObj = null;
 282         Process localProcess = null;
 283 
 284         synchronized (this) {
 285             localServerObj = serverObj;
 286             localProcess = process;
 287 
 288             if (state == RUNNING) {
 289 
 290                 deActivate();
 291 
 292             } else {
 293                 throw wrapper.serverNotRunning() ;
 294             }
 295         }
 296         try {
 297             if (localServerObj != null) {
 298                 localServerObj.shutdown(); // shutdown the server
 299                 localServerObj.uninstall() ; // call the uninstall
 300             }
 301 
 302             if (localProcess != null) {
 303                 localProcess.destroy();
 304             }
 305         } catch (Exception ex) {
 306             // what kind of exception should be thrown
 307         }
 308     }
 309 
 310     synchronized void holdDown()
 311     {
 312         state = HELD_DOWN;
 313 
 314         if (debug)
 315             printDebug( "holdDown", "server held down" ) ;
 316 
 317         notifyAll();
 318     }
 319 
 320     synchronized void deActivate()
 321     {
 322         state = DE_ACTIVATED;
 323 
 324         if (debug)
 325             printDebug( "deActivate", "server deactivated" ) ;
 326 
 327         notifyAll();
 328     }
 329 
 330     synchronized void checkProcessHealth( ) {
 331         // If the State in the ServerTableEntry is RUNNING and the
 332         // Process was shut down abnormally, The method will change the
 333         // server state as De-Activated.
 334         if( state == RUNNING ) {
 335             try {
 336                 int exitVal = process.exitValue();
 337             } catch (IllegalThreadStateException e1) {
 338                 return;
 339             }
 340             synchronized ( this ) {
 341                 // Clear the PortInformation as it is old
 342                 orbAndPortInfo.clear();
 343                 // Move the state to De-Activated, So that the next
 344                 // call to this server will re-activate.
 345                 deActivate();
 346             }
 347         }
 348     }
 349 
 350     synchronized boolean isValid()
 351     {
 352         if ((state == ACTIVATING) || (state == HELD_DOWN)) {
 353             if (debug)
 354                 printDebug( "isValid", "returns true" ) ;
 355 
 356             return true;
 357         }
 358 
 359         try {
 360             int exitVal = process.exitValue();
 361         } catch (IllegalThreadStateException e1) {
 362             return true;
 363         }
 364 
 365         if (state == ACTIVATED) {
 366             if (activateRetryCount < ActivationRetryMax) {
 367                 if (debug)
 368                     printDebug("isValid", "reactivating server");
 369                 activateRetryCount++;
 370                 activate();
 371                 return true;
 372             }
 373 
 374             if (debug)
 375                 printDebug("isValid", "holding server down");
 376 
 377             holdDown();
 378             return true;
 379         }
 380 
 381         deActivate();
 382         return false;
 383     }
 384 
 385     synchronized ORBPortInfo[] lookup(String endpointType) throws ServerHeldDown
 386     {
 387         while ((state == ACTIVATING) || (state == ACTIVATED)) {
 388             try {
 389                 wait(waitTime);
 390                 if (!isValid()) break;
 391             } catch(Exception e) {}
 392         }
 393         ORBPortInfo[] orbAndPortList = null;
 394 
 395         if (state == RUNNING) {
 396             orbAndPortList = new ORBPortInfo[orbAndPortInfo.size()];
 397             Iterator setORBids = orbAndPortInfo.keySet().iterator();
 398 
 399             try {
 400                 int numElements = 0;
 401                 int i;
 402                 int port;
 403                 while (setORBids.hasNext()) {
 404                     String orbId = (String) setORBids.next();
 405                     // get an entry corresponding to orbId
 406                     EndPointInfo [] serverListenerPorts = (EndPointInfo []) orbAndPortInfo.get(orbId);
 407                     port = -1;
 408                     // return the port corresponding to the endpointType
 409                     for (i = 0; i < serverListenerPorts.length; i++) {
 410                         if (debug)
 411                             System.out.println("lookup num-ports " + serverListenerPorts.length + "   " +
 412                                 serverListenerPorts[i].endpointType + "   " +
 413                                 serverListenerPorts[i].port );
 414                         if ((serverListenerPorts[i].endpointType).equals(endpointType)) {
 415                             port = serverListenerPorts[i].port;
 416                             break;
 417                         }
 418                     }
 419                     orbAndPortList[numElements] = new ORBPortInfo(orbId, port);
 420                     numElements++;
 421                 }
 422             } catch (NoSuchElementException e) {
 423                 // have everything in the table
 424             }
 425             return orbAndPortList;
 426         }
 427 
 428         if (debug)
 429             printDebug("lookup", "throwing server held down error");
 430 
 431         throw new ServerHeldDown( serverId ) ;
 432     }
 433 
 434     synchronized EndPointInfo[] lookupForORB(String orbId)
 435         throws ServerHeldDown, InvalidORBid
 436     {
 437         while ((state == ACTIVATING) || (state == ACTIVATED)) {
 438             try {
 439                 wait(waitTime);
 440                 if (!isValid()) break;
 441             } catch(Exception e) {}
 442         }
 443         EndPointInfo[] portList = null;
 444 
 445         if (state == RUNNING) {
 446 
 447             try {
 448 
 449                 // get an entry corresponding to orbId
 450                 EndPointInfo [] serverListenerPorts = (EndPointInfo []) orbAndPortInfo.get(orbId);
 451 
 452                 portList = new EndPointInfo[serverListenerPorts.length];
 453                 // return the port corresponding to the endpointType
 454                 for (int i = 0; i < serverListenerPorts.length; i++) {
 455                    if (debug)
 456                       System.out.println("lookup num-ports " + serverListenerPorts.length + "   "
 457                              + serverListenerPorts[i].endpointType + "   " +
 458                              serverListenerPorts[i].port );
 459                    portList[i] = new EndPointInfo(serverListenerPorts[i].endpointType, serverListenerPorts[i].port);
 460                 }
 461             } catch (NoSuchElementException e) {
 462                 // no element in HashMap corresponding to ORBid found
 463                 throw new InvalidORBid();
 464             }
 465             return portList;
 466         }
 467 
 468         if (debug)
 469             printDebug("lookup", "throwing server held down error");
 470 
 471         throw new ServerHeldDown( serverId ) ;
 472     }
 473 
 474     synchronized String[] getORBList()
 475     {
 476         String [] orbList = new String[orbAndPortInfo.size()];
 477         Iterator setORBids = orbAndPortInfo.keySet().iterator();
 478 
 479         try {
 480             int numElements = 0;
 481             while (setORBids.hasNext()) {
 482                 String orbId = (String) setORBids.next();
 483                 orbList[numElements++] = orbId ;
 484             }
 485         } catch (NoSuchElementException e) {
 486             // have everything in the table
 487         }
 488         return orbList;
 489     }
 490 
 491     int getServerId()
 492     {
 493         return serverId;
 494     }
 495 
 496     boolean isActive()
 497     {
 498         return (state == RUNNING) || (state == ACTIVATED);
 499     }
 500 
 501     synchronized void destroy()
 502     {
 503 
 504         Server localServerObj = null;
 505         Process localProcess = null;
 506 
 507         synchronized (this) {
 508             localServerObj = serverObj;
 509             localProcess = process;
 510 
 511             deActivate();
 512         }
 513 
 514         try {
 515             if (localServerObj != null)
 516                 localServerObj.shutdown();
 517 
 518             if (debug)
 519                 printDebug( "destroy", "server shutdown successfully" ) ;
 520         } catch (Exception ex) {
 521             if (debug)
 522                 printDebug( "destroy",
 523                             "server shutdown threw exception" + ex ) ;
 524             // ex.printStackTrace();
 525         }
 526 
 527         try {
 528             if (localProcess != null)
 529                 localProcess.destroy();
 530 
 531             if (debug)
 532                 printDebug( "destroy", "process destroyed successfully" ) ;
 533         } catch (Exception ex) {
 534             if (debug)
 535                 printDebug( "destroy",
 536                             "process destroy threw exception" + ex ) ;
 537 
 538             // ex.printStackTrace();
 539         }
 540     }
 541 
 542     private boolean debug = false;
 543 }