Package org.xmlBlaster.contrib.replication

Source Code of org.xmlBlaster.contrib.replication.OracleByEventsScheduler

/*------------------------------------------------------------------------------
Name:      OracleByEventsScheduler.java
Project:   org.xmlBlasterProject:   xmlBlaster.org
Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
------------------------------------------------------------------------------*/
package org.xmlBlaster.contrib.replication;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.Types;
import java.util.logging.Logger;
import java.util.logging.Level;

import org.xmlBlaster.contrib.I_Info;
import org.xmlBlaster.contrib.db.I_DbPool;
import org.xmlBlaster.contrib.dbwatcher.DbWatcher;
import org.xmlBlaster.contrib.dbwatcher.detector.I_AlertProducer;
import org.xmlBlaster.contrib.dbwatcher.detector.I_ChangeDetector;
import org.xmlBlaster.contrib.replication.impl.SpecificDefault;

/**
* This scheduler wakes up in intervals and triggers a database check.
* <p>
* Supported configuration:
* </p>
* <ul>
*   <li><tt>alertScheduler.pollInterval</tt> The polling interval in milliseconds.
*       Setting it to 0 switches the timer off.
*   </li>
* </ul>
*
*/
public class OracleByEventsScheduler implements I_AlertProducer {
  
   private class SchedulerRunner extends Thread {
      /* The minimum amount of ms to sleep after an exception (to avoid looping). Normally it will be 'alertScheduler.pollInterval' ms */
      private final static long MIN_SLEEP_DELAY = 1000L;
      /* The maximum amount of ms to sleep after an exception (to avoid looping). Normally it will be 'alertScheduler.pollInterval' ms  */
      private final static long MAX_SLEEP_DELAY = 60000L;
      private boolean forceShutdown;
      private long pollIntervall;
      private I_ChangeDetector changeDetector;
      private I_Info info;
      private String event;
     
      private final void sleepToAvoidLooping() throws InterruptedException {
         if (this.pollIntervall < MIN_SLEEP_DELAY)
            Thread.sleep(MIN_SLEEP_DELAY);
         else {
            if (this.pollIntervall > MAX_SLEEP_DELAY)
               Thread.sleep(MAX_SLEEP_DELAY);
            else
               Thread.sleep(this.pollIntervall);
         }
      }
     
      SchedulerRunner(I_Info info, I_ChangeDetector changeDetector) {
         super("OracleByEventsScheduler");
         setDaemon(true);
         this.pollIntervall = info.getLong("alertScheduler.pollInterval", 30000L);
         this.changeDetector = changeDetector;
         this.info = info;
         this.event = SpecificDefault.getReplPrefix(info) + "ITEMS";
         if (this.pollIntervall <= 0L) {
            log.warning("OracleByEventsScheduler is switched off with alertScheduler.pollInterval=" + this.pollIntervall);
         }
         log.info("Starting timer with pollInterval=" + this.pollIntervall + " ...");
      }
     
      public void doShutdown() {
         this.forceShutdown = true;
      }
     
      public void run() {
        
         I_DbPool pool = null;
         long count = 0L;
         try {
            pool = DbWatcher.getDbPool(this.info);
            // OracleByEventsScheduler.registerEvent(pool, this.event);
            while (!this.forceShutdown) {
               Connection conn = null;
               try {
                  conn = pool.reserve();
                  conn.setAutoCommit(true);
                  if (log.isLoggable(Level.FINE))
                     log.fine("Checking now Database again. pollInterval=" + this.pollIntervall + " ...");
                  try {
                     OracleByEventsScheduler.registerEvent(conn, this.event);
                    
                     while (changeDetector.checkAgain(null) > 0) {
                        Thread.sleep(5L);
                     }
                     log.fine("scheduler: before blocking " + count);
                     OracleByEventsScheduler.waitForEvent(conn, this.event, this.pollIntervall);
                     log.fine("scheduler: after blocking " + count);
                  }
                  catch (Throwable e) {
                     log.severe("Don't know how to handle error: " + e.toString());
                     this.sleepToAvoidLooping();
                  }
                  count++;
                  if (count == Long.MAX_VALUE)
                     count = 0L;
               }
               catch (Throwable ex) {
                  log.severe("An exception occured when waiting for oracle scheduler: " + ex.getMessage());
                  ex.printStackTrace();
                  conn = SpecificDefault.removeFromPool(conn, SpecificDefault.ROLLBACK_NO, pool);
                  this.sleepToAvoidLooping();
               }
               finally {
                  conn = SpecificDefault.releaseIntoPool(conn, SpecificDefault.COMMIT_NO, pool);
               }
            }
            // OracleByEventsScheduler.unregisterEvent(pool, this.event);
         }
         catch (Throwable ex) {
            log.severe("An exception occured in the running thread of the scheduler. It will be halter. " + ex.getMessage());
            ex.printStackTrace();
         }
         finally {
            if (pool != null) {
               try {
                  pool.shutdown();
               }
               catch (Exception ex) {
                  log.severe("Exception occured when shutting down the scheduler");
                  ex.printStackTrace();
               }
               pool = null;
            }
         }
      }
   }
  
  
   private static Logger log = Logger.getLogger(OracleByEventsScheduler.class.getName());
   private I_ChangeDetector changeDetector;
   private SchedulerRunner runner;
   private I_Info info;
  
   /**
    * Default constructor, you need to call {@link #init} thereafter. 
    */
   public OracleByEventsScheduler() {
   }

   /**
    * Create a scheduler, calls {@link #init}
    * @param info The configuration environment
    * @param changeDetector The class to be alerted then and again
    */
   public OracleByEventsScheduler(I_Info info, I_ChangeDetector changeDetector) throws Exception {
      init(info, changeDetector);
   }

   /**
    * @see org.xmlBlaster.contrib.dbwatcher.convert.I_DataConverter#init(I_Info)
    */
   public void init(I_Info info, I_ChangeDetector changeDetector) throws Exception {
      if (changeDetector == null)
         throw new IllegalArgumentException("changeDetector is null, can't schedule anything.");
      log.fine("created");
      this.info = info;
      this.changeDetector = changeDetector;
   }
  
   /**
    * @see org.xmlBlaster.contrib.dbwatcher.detector.I_AlertProducer#startProducing
    */
   public synchronized void startProducing() {
      if (this.runner != null) {
         log.warning("A Scheduler is already running");
         return;
      }
      this.runner = new SchedulerRunner(this.info, this.changeDetector);
      this.runner.start();
   }

   /**
    * @see org.xmlBlaster.contrib.dbwatcher.detector.I_AlertProducer#stopProducing
    */
   public void stopProducing() throws Exception {
      log.info("stopProducing");
      shutdown();
   }
  
   /**
    * Stop the scheduler.
    * @see org.xmlBlaster.contrib.dbwatcher.detector.I_AlertProducer#shutdown
    */
   public synchronized void shutdown() throws Exception {
      log.fine("Shutdown");
      if (this.runner != null) {
         this.runner.doShutdown();
         this.runner = null;
      }
   }

  
  
   /**
    * This method does not return exceptions (also catches Throwable).
    * @param conn The database connection to use.
    * @param event the name of the even on which to wait
    * @param timeout the maximum time to wait in ms
    */
   public static void waitForEvent(Connection conn, String event, long timeout) throws Exception {
      CallableStatement st = null;
      try {
         String sql = "{call dbms_alert.waitone(?,?,?,?)}";
         st = conn.prepareCall(sql);
         st.setString(1, event);
         st.setLong(4, timeout / 1000L);
         st.registerOutParameter(2, Types.VARCHAR);
         st.registerOutParameter(3, Types.INTEGER);
         st.executeQuery();
      }
      finally {
         if (st != null)
            st.close();
      }
   }

   public static void registerEvent(Connection conn, String event) throws Exception {
      registerUnregisterForEvents(conn, event, true);
   }
  
   public static void unregisterEvent(Connection conn, String event) throws Exception {
      registerUnregisterForEvents(conn, event, false);
   }

   /**
    * This method does not return exceptions (also catches Throwable).
    * @param conn the database connection to use.
    * @param event the name of the even on which to wait
    * @param doRegister if true it will register, otherwise unregister.
    */
   private static void registerUnregisterForEvents(Connection conn, String event, boolean doRegister) throws Exception {
      CallableStatement st = null;
      String sql = null;
      if (doRegister)
         sql = "{call dbms_alert.register(?)}";
      else
         sql = "{call dbms_alert.remove(?)}";
      try {
         st = conn.prepareCall(sql);
         st.setString(1, event);
         st.executeQuery();
      }
      finally {
         if (st != null)
            st.close();
      }
   }
  
}
TOP

Related Classes of org.xmlBlaster.contrib.replication.OracleByEventsScheduler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.