Example #1
0
  protected void initialize(String basename) {

    Messages messagesForBasename = messageProvider.getMessages(basename);
    for (Locale locale : messagesForBasename.getLocales()) {
      Map<String, String> codeToMessage = messagesForBasename.getMessages(locale);
      for (String code : codeToMessage.keySet()) {
        addMessage(basename, locale, code, createMessageFormat(codeToMessage.get(code), locale));
      }
    }
  }
Example #2
0
/**
 * Server class called by our Axis hooks to handle all ODE lifecycle management.
 *
 * @author Matthieu Riou <mriou at apache dot org>
 */
public class ODEServer {

  protected final Log __log = LogFactory.getLog(getClass());
  protected final Log __logTx = LogFactory.getLog("org.apache.ode.tx");

  private static final Messages __msgs = Messages.getMessages(Messages.class);

  protected File _appRoot;

  protected File _workRoot;

  protected File _configRoot;

  protected BpelServerImpl _bpelServer;

  protected ProcessStoreImpl _store;

  protected ODEConfigProperties _odeConfig;

  protected ConfigurationContext _configContext;

  protected TransactionManager _txMgr;

  protected BpelDAOConnectionFactory _daoCF;

  protected ExecutorService _executorService;

  protected Scheduler _scheduler;

  protected CronScheduler _cronScheduler;

  protected Database _db;

  private DeploymentPoller _poller;

  private BpelServerConnector _connector;

  private ManagementService _mgtService;

  protected ClusterUrlTransformer _clusterUrlTransformer;

  protected MultiThreadedHttpConnectionManager httpConnectionManager;
  protected IdleConnectionTimeoutThread idleConnectionTimeoutThread;

  public Runnable txMgrCreatedCallback;

  public void init(ServletConfig config, ConfigurationContext configContext)
      throws ServletException {
    init(config.getServletContext().getRealPath("/WEB-INF"), configContext);
  }

  public void init(String contextPath, ConfigurationContext configContext) throws ServletException {
    init(contextPath, configContext, null);
  }

  public void init(
      String contextPath, ConfigurationContext configContext, ODEConfigProperties config)
      throws ServletException {
    _configContext = configContext;
    String rootDir = System.getProperty("org.apache.ode.rootDir");
    if (rootDir != null) _appRoot = new File(rootDir);
    else _appRoot = new File(contextPath);

    if (!_appRoot.isDirectory())
      throw new IllegalArgumentException(_appRoot + " does not exist or is not a directory");
    TempFileManager.setWorkingDirectory(_appRoot);

    __log.debug("Loading properties");
    String confDir = System.getProperty("org.apache.ode.configDir");
    _configRoot = confDir == null ? new File(_appRoot, "conf") : new File(confDir);
    if (!_configRoot.isDirectory())
      throw new IllegalArgumentException(_configRoot + " does not exist or is not a directory");

    try {
      if (config == null) {
        _odeConfig = new ODEConfigProperties(_configRoot);
        _odeConfig.load();
      } else {
        _odeConfig = config;
      }
    } catch (FileNotFoundException fnf) {
      String errmsg = __msgs.msgOdeInstallErrorCfgNotFound(_odeConfig.getFile());
      __log.warn(errmsg);
    } catch (Exception ex) {
      String errmsg = __msgs.msgOdeInstallErrorCfgReadError(_odeConfig.getFile());
      __log.error(errmsg, ex);
      throw new ServletException(errmsg, ex);
    }

    String wdir = _odeConfig.getWorkingDir();
    if (wdir == null) _workRoot = _appRoot;
    else _workRoot = new File(wdir.trim());
    if (!_workRoot.isDirectory())
      throw new IllegalArgumentException(_workRoot + " does not exist or is not a directory");

    __log.debug("Initializing transaction manager");
    initTxMgr();
    if (txMgrCreatedCallback != null) {
      txMgrCreatedCallback.run();
    }
    __log.debug("Creating data source.");
    initDataSource();
    __log.debug("Starting DAO.");
    initDAO();
    EndpointReferenceContextImpl eprContext = new EndpointReferenceContextImpl(this);
    __log.debug("Initializing BPEL process store.");
    initProcessStore(eprContext);
    __log.debug("Initializing BPEL server.");
    initBpelServer(eprContext);
    __log.debug("Initializing HTTP connection manager");
    initHttpConnectionManager();

    // Register BPEL event listeners configured in axis2.properties file.
    registerEventListeners();
    registerMexInterceptors();
    registerExternalVariableModules();

    _store.loadAll();

    try {
      _bpelServer.start();
    } catch (Exception ex) {
      String errmsg = __msgs.msgOdeBpelServerStartFailure();
      __log.error(errmsg, ex);
      throw new ServletException(errmsg, ex);
    }

    _poller = getDeploymentPollerExt();
    if (_poller == null) {
      _poller = new DeploymentPoller(_store.getDeployDir(), this);
    }

    _mgtService = new ManagementService();
    _mgtService.enableService(
        _configContext.getAxisConfiguration(), _bpelServer, _store, _appRoot.getAbsolutePath());

    try {
      __log.debug("Initializing Deployment Web Service");
      new DeploymentWebService()
          .enableService(
              _configContext.getAxisConfiguration(),
              _store,
              _poller,
              _appRoot.getAbsolutePath(),
              _workRoot.getAbsolutePath());
    } catch (Exception e) {
      throw new ServletException(e);
    }

    __log.debug("Starting scheduler");
    _scheduler.start();

    __log.debug("Initializing JCA adapter.");
    initConnector();

    _poller.start();
    __log.info(__msgs.msgPollingStarted(_store.getDeployDir().getAbsolutePath()));
    __log.info(__msgs.msgOdeStarted());
  }

  @SuppressWarnings("unchecked")
  private DeploymentPoller getDeploymentPollerExt() {
    DeploymentPoller poller = null;

    InputStream is = null;
    try {
      is = ODEServer.class.getResourceAsStream("/deploy-ext.properties");
      if (is != null) {
        __log.info("A deploy-ext.properties found; will use the provided class if applicable.");
        try {
          Properties props = new Properties();
          props.load(is);
          String deploymentPollerClass = props.getProperty("deploymentPoller.class");
          if (deploymentPollerClass == null) {
            __log.warn(
                "deploy-ext.properties found in the class path; however, the file does not have 'deploymentPoller.class' as one of the properties!!");
          } else {
            Class pollerClass = Class.forName(deploymentPollerClass);
            poller =
                (DeploymentPoller)
                    pollerClass
                        .getConstructor(File.class, ODEServer.class)
                        .newInstance(_store.getDeployDir(), this);
            __log.info(
                "A custom deployment poller: " + deploymentPollerClass + " has been plugged in.");
          }
        } catch (Exception e) {
          __log.warn(
              "Deployment poller extension class is not loadable, falling back to the default DeploymentPoller.",
              e);
        }
      } else if (__log.isDebugEnabled()) __log.debug("No deploy-ext.properties found.");
    } finally {
      try {
        if (is != null) is.close();
      } catch (IOException ie) {
        // ignore
      }
    }

    return poller;
  }

  private void initDataSource() throws ServletException {
    _db = Database.create(_odeConfig);
    _db.setTransactionManager(_txMgr);
    _db.setWorkRoot(_workRoot);

    try {
      _db.start();
    } catch (Exception ex) {
      String errmsg = __msgs.msgOdeDbConfigError();
      __log.error(errmsg, ex);
      throw new ServletException(errmsg, ex);
    }
  }

  public TransactionManager getTransactionManager() {
    return _txMgr;
  }

  /**
   * Shutdown the service engine. This performs cleanup before the BPE is terminated. Once this
   * method has been called, init() must be called before the transformation engine can be started
   * again with a call to start().
   *
   * @throws AxisFault if the engine is unable to shut down.
   */
  public void shutDown() throws AxisFault {

    ClassLoader old = Thread.currentThread().getContextClassLoader();
    Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
    try {
      if (_poller != null)
        try {
          __log.debug("shutting down poller");
          _poller.stop();
          _poller = null;
        } catch (Throwable t) {
          __log.debug("Error stopping poller.", t);
        }

      if (_bpelServer != null)
        try {
          __log.debug("shutting down ODE server.");
          _bpelServer.shutdown();
          _bpelServer = null;
        } catch (Throwable ex) {
          __log.debug("Error stopping services.", ex);
        }

      if (_cronScheduler != null) {
        try {
          __log.debug("shutting down cron scheduler.");
          _cronScheduler.shutdown();
          _cronScheduler = null;
        } catch (Exception ex) {
          __log.debug("Cron scheduler couldn't be shutdown.", ex);
        }
      }

      if (_scheduler != null)
        try {
          __log.debug("shutting down scheduler.");
          _scheduler.shutdown();
          _scheduler = null;
        } catch (Exception ex) {
          __log.debug("Scheduler couldn't be shutdown.", ex);
        }

      if (_store != null)
        try {
          _store.shutdown();
          _store = null;
        } catch (Throwable t) {
          __log.debug("Store could not be shutdown.", t);
        }

      if (_daoCF != null)
        try {
          _daoCF.shutdown();
        } catch (Throwable ex) {
          __log.debug("DOA shutdown failed.", ex);
        } finally {
          _daoCF = null;
        }

      if (_db != null)
        try {
          _db.shutdown();

        } catch (Throwable ex) {
          __log.debug("DB shutdown failed.", ex);
        } finally {
          _db = null;
        }

      if (_txMgr != null) {
        __log.debug("shutting down transaction manager.");
        _txMgr = null;
      }

      if (_connector != null) {
        try {
          __log.debug("shutdown BpelConnector");
          _connector.shutdown();
          _connector = null;
        } catch (Throwable t) {
          __log.error("Unable to cleanup temp files.", t);
        }
      }
      if (httpConnectionManager != null) {
        __log.debug("shutting down HTTP connection manager.");
        try {
          httpConnectionManager.shutdown();
          httpConnectionManager = null;
        } catch (Throwable t) {
          __log.error("Unable to shut down HTTP connection manager.", t);
        }
      }
      if (idleConnectionTimeoutThread != null) {
        __log.debug("shutting down Idle Connection Timeout Thread.");
        try {
          idleConnectionTimeoutThread.shutdown();
          idleConnectionTimeoutThread = null;
        } catch (Throwable t) {
          __log.error("Unable to shut down Idle Connection Timeout Thread.", t);
        }
      }
      try {
        __log.debug("cleaning up temporary files.");
        TempFileManager.cleanup();
      } catch (Throwable t) {
        __log.error("Unable to cleanup temp files.", t);
      }

      if (_executorService != null) {
        _executorService.shutdownNow();
        _executorService = null;
      }

      __log.info(__msgs.msgOdeShutdownCompleted());
    } finally {
      Thread.currentThread().setContextClassLoader(old);
    }
  }

  @SuppressWarnings("unchecked")
  private void initTxMgr() throws ServletException {
    if (_odeConfig.getDbMode().equals(OdeConfigProperties.DatabaseMode.EXTERNAL)
        && _odeConfig
            .getTxFactoryClass()
            .equals(OdeConfigProperties.DEFAULT_TX_FACTORY_CLASS_NAME)) {
      throw new ServletException(
          "No external transaction manager factory configured. Please use the INTERNAL mode or configure an external transaction manager that is associated with external datasource.");
    }

    String txFactoryName = _odeConfig.getTxFactoryClass();
    __log.debug("Initializing transaction manager using " + txFactoryName);
    try {
      Class txFactClass = this.getClass().getClassLoader().loadClass(txFactoryName);
      Object txFact = txFactClass.newInstance();
      _txMgr =
          (TransactionManager)
              txFactClass.getMethod("getTransactionManager", (Class[]) null).invoke(txFact);
      if (__logTx.isDebugEnabled() && System.getProperty("ode.debug.tx") != null)
        _txMgr = new DebugTxMgr(_txMgr);
    } catch (Exception e) {
      __log.fatal("Couldn't initialize a transaction manager with factory: " + txFactoryName, e);
      throw new ServletException(
          "Couldn't initialize a transaction manager with factory: " + txFactoryName, e);
    }
  }

  private void initConnector() throws ServletException {
    int port = _odeConfig.getConnectorPort();
    if (port == 0) {
      __log.info("Skipping connector initialization.");
    } else {
      _connector = new BpelServerConnector();
      _connector.setBpelServer(_bpelServer);
      _connector.setProcessStore(_store);
      _connector.setPort(_odeConfig.getConnectorPort());
      _connector.setId("jcaServer");
      try {
        _connector.start();
      } catch (Exception e) {
        __log.error("Failed to initialize JCA connector.", e);
      }
    }
  }

  /**
   * Initialize the DAO.
   *
   * @throws ServletException
   */
  protected void initDAO() throws ServletException {
    __log.info(__msgs.msgOdeUsingDAOImpl(_odeConfig.getDAOConnectionFactory()));
    try {
      _daoCF = _db.createDaoCF();
    } catch (Exception ex) {
      String errmsg = __msgs.msgDAOInstantiationFailed(_odeConfig.getDAOConnectionFactory());
      __log.error(errmsg, ex);
      throw new ServletException(errmsg, ex);
    }
  }

  protected void initProcessStore(EndpointReferenceContext eprContext) {
    _store = createProcessStore(eprContext, _db.getDataSource());
    _store.registerListener(new ProcessStoreListenerImpl());
    _store.setDeployDir(
        _odeConfig.getDeployDir() != null
            ? new File(_odeConfig.getDeployDir())
            : new File(_workRoot, "processes"));
    _store.setConfigDir(_configRoot);
  }

  protected ProcessStoreImpl createProcessStore(
      EndpointReferenceContext eprContext, DataSource ds) {
    return new ProcessStoreImpl(
        eprContext, ds, _odeConfig.getDAOConnectionFactory(), _odeConfig, false);
  }

  protected Scheduler createScheduler() {
    SimpleScheduler scheduler =
        new SimpleScheduler(
            new GUID().toString(),
            new JdbcDelegate(_db.getDataSource()),
            _odeConfig.getProperties());
    scheduler.setExecutorService(_executorService);
    scheduler.setTransactionManager(_txMgr);
    return scheduler;
  }

  private void initBpelServer(EndpointReferenceContextImpl eprContext) {
    if (__log.isDebugEnabled()) {
      __log.debug("ODE initializing");
    }
    ThreadFactory threadFactory =
        new ThreadFactory() {
          int threadNumber = 0;

          public Thread newThread(Runnable r) {
            threadNumber += 1;
            Thread t = new Thread(r, "ODEServer-" + threadNumber);
            t.setDaemon(true);
            return t;
          }
        };

    if (_odeConfig.getThreadPoolMaxSize() == 0)
      _executorService = Executors.newCachedThreadPool(threadFactory);
    else
      _executorService =
          Executors.newFixedThreadPool(_odeConfig.getThreadPoolMaxSize(), threadFactory);

    {
      List<String> targets = new ArrayList<String>();
      Collections.addAll(
          targets, _odeConfig.getProperty("cluster.localRoute.targets", "").split(","));
      _clusterUrlTransformer =
          new ClusterUrlTransformer(
              targets,
              _odeConfig.getProperty(
                  "cluster.localRoute.base", "http://localhost:8080/ode/processes/"));
    }
    _bpelServer = new BpelServerImpl();
    _scheduler = createScheduler();
    _scheduler.setJobProcessor(_bpelServer);

    BpelServerImpl.PolledRunnableProcessor polledRunnableProcessor =
        new BpelServerImpl.PolledRunnableProcessor();
    polledRunnableProcessor.setPolledRunnableExecutorService(_executorService);
    polledRunnableProcessor.setContexts(_bpelServer.getContexts());
    _scheduler.setPolledRunnableProcesser(polledRunnableProcessor);

    _cronScheduler = new CronScheduler();
    _cronScheduler.setScheduledTaskExec(_executorService);
    _cronScheduler.setContexts(_bpelServer.getContexts());
    _bpelServer.setCronScheduler(_cronScheduler);

    _bpelServer.setDaoConnectionFactory(_daoCF);
    _bpelServer.setInMemDaoConnectionFactory(
        new BpelDAOConnectionFactoryImpl(_scheduler, _odeConfig.getInMemMexTtl()));
    _bpelServer.setEndpointReferenceContext(eprContext);
    _bpelServer.setMessageExchangeContext(new MessageExchangeContextImpl(this));
    _bpelServer.setBindingContext(new BindingContextImpl(this));
    _bpelServer.setScheduler(_scheduler);
    if (_odeConfig.isDehydrationEnabled()) {
      CountLRUDehydrationPolicy dehy = new CountLRUDehydrationPolicy();
      dehy.setProcessMaxAge(_odeConfig.getDehydrationMaximumAge());
      dehy.setProcessMaxCount(_odeConfig.getDehydrationMaximumCount());
      _bpelServer.setDehydrationPolicy(dehy);
    }
    _bpelServer.setMigrationTransactionTimeout(_odeConfig.getMigrationTransactionTimeout());
    _bpelServer.setConfigProperties(_odeConfig.getProperties());
    _bpelServer.init();
    _bpelServer.setInstanceThrottledMaximumCount(_odeConfig.getInstanceThrottledMaximumCount());
    _bpelServer.setProcessThrottledMaximumCount(_odeConfig.getProcessThrottledMaximumCount());
    _bpelServer.setProcessThrottledMaximumSize(_odeConfig.getProcessThrottledMaximumSize());
    _bpelServer.setHydrationLazy(_odeConfig.isHydrationLazy());
    _bpelServer.setHydrationLazyMinimumSize(_odeConfig.getHydrationLazyMinimumSize());
  }

  private void initHttpConnectionManager() throws ServletException {
    httpConnectionManager = new MultiThreadedHttpConnectionManager();
    // settings may be overridden from ode-axis2.properties using the same properties as HttpClient
    // /!\ If the size of the conn pool is smaller than the size of the thread pool, the thread pool
    // might get starved.
    int max_per_host =
        Integer.parseInt(
            _odeConfig.getProperty(
                HttpConnectionManagerParams.MAX_HOST_CONNECTIONS,
                "" + _odeConfig.getPoolMaxSize()));
    int max_total =
        Integer.parseInt(
            _odeConfig.getProperty(
                HttpConnectionManagerParams.MAX_TOTAL_CONNECTIONS,
                "" + _odeConfig.getPoolMaxSize()));
    if (__log.isDebugEnabled()) {
      __log.debug(HttpConnectionManagerParams.MAX_HOST_CONNECTIONS + "=" + max_per_host);
      __log.debug(HttpConnectionManagerParams.MAX_TOTAL_CONNECTIONS + "=" + max_total);
    }
    if (max_per_host < 1 || max_total < 1) {
      String errmsg =
          HttpConnectionManagerParams.MAX_HOST_CONNECTIONS
              + " and "
              + HttpConnectionManagerParams.MAX_TOTAL_CONNECTIONS
              + " must be positive integers!";
      __log.error(errmsg);
      throw new ServletException(errmsg);
    }
    httpConnectionManager.getParams().setDefaultMaxConnectionsPerHost(max_per_host);
    httpConnectionManager.getParams().setMaxTotalConnections(max_total);

    // Register the connection manager to a idle check thread
    idleConnectionTimeoutThread = new IdleConnectionTimeoutThread();
    idleConnectionTimeoutThread.setName("Http_Idle_Connection_Timeout_Thread");
    long idleConnectionTimeout =
        Long.parseLong(_odeConfig.getProperty("http.idle.connection.timeout", "30000"));
    long idleConnectionCheckInterval =
        Long.parseLong(_odeConfig.getProperty("http.idle.connection.check.interval", "30000"));

    if (__log.isDebugEnabled()) {
      __log.debug("http.idle.connection.timeout=" + idleConnectionTimeout);
      __log.debug("http.idle.connection.check.interval=" + idleConnectionCheckInterval);
    }
    idleConnectionTimeoutThread.setConnectionTimeout(idleConnectionTimeout);
    idleConnectionTimeoutThread.setTimeoutInterval(idleConnectionCheckInterval);

    idleConnectionTimeoutThread.addConnectionManager(httpConnectionManager);
    idleConnectionTimeoutThread.start();
  }

  public ProcessStoreImpl getProcessStore() {
    return _store;
  }

  public BpelServerImpl getBpelServer() {
    return _bpelServer;
  }

  public InstanceManagement getInstanceManagement() {
    return _mgtService.getInstanceMgmt();
  }

  public ProcessManagement getProcessManagement() {
    return _mgtService.getProcessMgmt();
  }

  public File getAppRoot() {
    return _appRoot;
  }

  public File getConfigRoot() {
    return _configRoot;
  }

  private void registerEventListeners() {
    String listenersStr = _odeConfig.getEventListeners();
    if (listenersStr != null) {
      for (StringTokenizer tokenizer = new StringTokenizer(listenersStr, ",;");
          tokenizer.hasMoreTokens(); ) {
        String listenerCN = tokenizer.nextToken();
        try {
          _bpelServer.registerBpelEventListener(
              (BpelEventListener) Class.forName(listenerCN).newInstance());
          __log.info(__msgs.msgBpelEventListenerRegistered(listenerCN));
        } catch (Exception e) {
          __log.warn(
              "Couldn't register the event listener "
                  + listenerCN
                  + ", the class couldn't be "
                  + "loaded properly: "
                  + e);
        }
      }
    }
  }

  private void registerMexInterceptors() {
    String listenersStr = _odeConfig.getMessageExchangeInterceptors();
    if (listenersStr != null) {
      for (StringTokenizer tokenizer = new StringTokenizer(listenersStr, ",;");
          tokenizer.hasMoreTokens(); ) {
        String interceptorCN = tokenizer.nextToken();
        try {
          _bpelServer.registerMessageExchangeInterceptor(
              (MessageExchangeInterceptor) Class.forName(interceptorCN).newInstance());
          __log.info(__msgs.msgMessageExchangeInterceptorRegistered(interceptorCN));
        } catch (Exception e) {
          __log.warn(
              "Couldn't register the event listener "
                  + interceptorCN
                  + ", the class couldn't be "
                  + "loaded properly: "
                  + e);
        }
      }
    }
  }

  private void registerExternalVariableModules() {
    JdbcExternalVariableModule jdbcext;
    jdbcext = new JdbcExternalVariableModule();
    jdbcext.registerDataSource("ode", _db.getDataSource());
    _bpelServer.registerExternalVariableEngine(jdbcext);
  }

  private class ProcessStoreListenerImpl implements ProcessStoreListener {

    public void onProcessStoreEvent(ProcessStoreEvent event) {
      handleEvent(event);
    }
  }

  private void handleEvent(ProcessStoreEvent pse) {
    if (__log.isDebugEnabled()) {
      __log.debug("Process store event: " + pse);
    }
    ProcessConf pconf = _store.getProcessConfiguration(pse.pid);
    switch (pse.type) {
      case DEPLOYED:
        if (pconf != null) {
          /*
           * If and only if an old process exists with the same pid, the old process is cleaned up.
           * The following line is IMPORTANT and used for the case when the deployment and store
           * do not have the process while the process itself exists in the BPEL_PROCESS table.
           * Notice that the new process is actually created on the 'ACTIVATED' event.
           */
          _bpelServer.cleanupProcess(pconf);
        }
        break;
      case ACTVIATED:
        // bounce the process
        _bpelServer.unregister(pse.pid);
        if (pconf != null) {
          _bpelServer.register(pconf);
        } else {
          __log.debug("slighly odd: recevied event " + pse + " for process not in store!");
        }
        break;
      case RETIRED:
        // are there are instances of this process running?
        boolean instantiated = _bpelServer.hasActiveInstances(pse.pid);
        // remove the process
        _bpelServer.unregister(pse.pid);
        // bounce the process if necessary
        if (instantiated) {
          if (pconf != null) {
            _bpelServer.register(pconf);
          } else {
            __log.debug("slighly odd: recevied event " + pse + " for process not in store!");
          }
        } else {
          // we may have potentially created a lot of garbage, so,
          // let's hope the garbage collector is configured properly.
          if (pconf != null) {
            _bpelServer.cleanupProcess(pconf);
          }
        }
        break;
      case DISABLED:
      case UNDEPLOYED:
        _bpelServer.unregister(pse.pid);
        if (pconf != null) {
          _bpelServer.cleanupProcess(pconf);
        }
        break;
      default:
        __log.debug("Ignoring store event: " + pse);
    }

    if (pconf != null) {
      if (pse.type == ProcessStoreEvent.Type.UNDEPLOYED) {
        __log.debug("Cancelling all cron scheduled jobs on store event: " + pse);
        _bpelServer.getContexts().cronScheduler.cancelProcessCronJobs(pse.pid, true);
      }

      // Except for undeploy event, we need to re-schedule process dependent jobs
      __log.debug("(Re)scheduling cron scheduled jobs on store event: " + pse);
      if (pse.type != ProcessStoreEvent.Type.UNDEPLOYED) {
        _bpelServer.getContexts().cronScheduler.scheduleProcessCronJobs(pse.pid, pconf);
      }
    }
  }

  // Transactional debugging stuff, to track down all these little annoying bugs.
  private class DebugTxMgr implements TransactionManager {
    private TransactionManager _tm;

    public DebugTxMgr(TransactionManager tm) {
      _tm = tm;
    }

    public void begin() throws NotSupportedException, SystemException {
      __logTx.debug("Txm begin");
      _tm.begin();
    }

    public void commit()
        throws HeuristicMixedException, HeuristicRollbackException, IllegalStateException,
            RollbackException, SecurityException, SystemException {
      if (__log.isDebugEnabled()) {
        __logTx.debug("Txm commit");
        for (StackTraceElement traceElement : Thread.currentThread().getStackTrace()) {
          __logTx.debug(traceElement.toString());
        }
      }
      _tm.commit();
    }

    public int getStatus() throws SystemException {
      __logTx.debug("Txm status");
      return _tm.getStatus();
    }

    public Transaction getTransaction() throws SystemException {
      Transaction tx = _tm.getTransaction();
      if (__log.isDebugEnabled()) {
        __logTx.debug("Txm get tx " + tx);
      }
      return tx == null ? null : new DebugTx(tx);
    }

    public void resume(Transaction transaction)
        throws IllegalStateException, InvalidTransactionException, SystemException {
      __logTx.debug("Txm resume");
      _tm.resume(transaction);
    }

    public void rollback() throws IllegalStateException, SecurityException, SystemException {
      __logTx.debug("Txm rollback");
      _tm.rollback();
    }

    public void setRollbackOnly() throws IllegalStateException, SystemException {
      __logTx.debug("Txm set rollback");
      _tm.setRollbackOnly();
    }

    public void setTransactionTimeout(int i) throws SystemException {
      if (__log.isDebugEnabled()) {
        __logTx.debug("Txm set tiemout " + i);
      }
      _tm.setTransactionTimeout(i);
    }

    public Transaction suspend() throws SystemException {
      __logTx.debug("Txm suspend");
      return _tm.suspend();
    }
  }

  private class DebugTx implements Transaction {
    private Transaction _tx;

    public DebugTx(Transaction tx) {
      _tx = tx;
    }

    public void commit()
        throws HeuristicMixedException, HeuristicRollbackException, RollbackException,
            SecurityException, SystemException {
      __logTx.debug("Tx commit");
      _tx.commit();
    }

    public boolean delistResource(XAResource xaResource, int i)
        throws IllegalStateException, SystemException {
      return _tx.delistResource(xaResource, i);
    }

    public boolean enlistResource(XAResource xaResource)
        throws IllegalStateException, RollbackException, SystemException {
      return _tx.enlistResource(xaResource);
    }

    public int getStatus() throws SystemException {
      return _tx.getStatus();
    }

    public void registerSynchronization(Synchronization synchronization)
        throws IllegalStateException, RollbackException, SystemException {
      if (__log.isDebugEnabled()) {
        __logTx.debug("Synchronization registration on " + synchronization.getClass().getName());
      }
      _tx.registerSynchronization(synchronization);
    }

    public void rollback() throws IllegalStateException, SystemException {
      __logTx.debug("Tx rollback");
      _tx.rollback();
    }

    public void setRollbackOnly() throws IllegalStateException, SystemException {
      __logTx.debug("Tx set rollback");
      _tx.setRollbackOnly();
    }
  }
}