// ========================================================================
// $Id: AbstractStore.java,v 1.5 2004/06/22 16:23:44 jules_gosnell Exp $
// Copyright 2002-2004 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at 
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ========================================================================

package org.mortbay.j2ee.session;

//----------------------------------------

import java.util.Timer;
import java.util.TimerTask;

import javax.servlet.http.HttpServletRequest;

import org.jboss.logging.Logger;

//----------------------------------------

public abstract class
  AbstractStore
  implements Store
{
  protected final static Logger _log=Logger.getLogger(AbstractStore.class);

  // distributed scavenging

  /**
   * The period between scavenges
   */
  protected int _scavengerPeriod=60*30;	// 1/2 an hour
  public int getScavengerPeriod() {return _scavengerPeriod;}
  public void setScavengerPeriod(int secs) {_scavengerPeriod=secs;}
  /**
   * The extra time we wait before tidying up a CMPState to ensure
   * that if it loaded locally it will be scavenged locally first...
   */
  protected int _scavengerExtraTime=60*30; // 1/2 an hour
  public int getScavengerExtraTime() {return _scavengerExtraTime;}
  public void setScavengerExtraTime(int secs) {_scavengerExtraTime=secs;}
  /**
   * A maxInactiveInterval of -1 means never scavenge. The DB would
   * fill up very quickly - so we can override -1 with a real value
   * here.
   */
  protected int _actualMaxInactiveInterval=60*60*24*28;	// 28 days
  public int getActualMaxInactiveInterval() {return _actualMaxInactiveInterval;}
  public void setActualMaxInactiveInterval(int secs) {_actualMaxInactiveInterval=secs;}

  public Object
    clone()
    {
      try
      {
	AbstractStore as=(AbstractStore)(getClass().newInstance());
	as.setScavengerPeriod(_scavengerPeriod);
	as.setScavengerExtraTime(_scavengerExtraTime);
	as.setActualMaxInactiveInterval(_actualMaxInactiveInterval);
	return as;
      }
      catch (Exception e)
      {
	_log.warn("could not clone Store", e);
	return null;
      }
    }

  protected Manager _manager;
  public Manager getManager(){return _manager;}
  public void setManager(Manager manager){_manager=manager;}


  protected Timer _scavenger;

  // Store LifeCycle
  public void
    start()
    throws Exception
    {
      _log.trace("starting...");
      boolean isDaemon=true;
      _scavenger=new Timer(isDaemon);
      long delay=_scavengerPeriod+Math.round(Math.random()*_scavengerPeriod);
      if (_log.isDebugEnabled()) _log.debug("starting distributed scavenger thread...(period: "+delay+" secs)");
      _scavenger.scheduleAtFixedRate(new Scavenger(), delay*1000, _scavengerPeriod*1000);
      _log.debug("...distributed scavenger thread started");
      _log.trace("...started");
    }

  public void
    stop()
    {
      _log.trace("stopping...");
      _log.debug("stopping distributed scavenger thread...");
      _scavenger.cancel();
      _scavenger=null;
      _log.debug("...distributed scavenger thread stopped");

      try
      {
	scavenge();
      }
      catch (Exception e)
      {
	_log.warn("error scavenging distributed sessions", e);
      }

      _log.trace("...stopped");
    }

  public void
    destroy()
    {
      _log.trace("destroying...");
      _log.trace("...destroyed");
    }

  class Scavenger
    extends TimerTask
  {
    public void
      run()
    {
      try
      {
	scavenge();
      }
      catch (Throwable e)
      {
	_log.warn("could not scavenge distributed sessions", e);
      }
    }
  }

  // ID allocation

  public String
    allocateId(HttpServletRequest request)
    {
      return getManager().getIdGenerator().nextId(request);
    }

  public void
    deallocateId(String id)
    {
      // these ids are disposable
    }

  // still abstract...

  //   // Store LifeCycle
  //   void destroy();	// corresponds to ctor
  //
  //   boolean isDistributed();
  //
  //   // State LifeCycle
  //   State newState(String id, int maxInactiveInterval) throws Exception;
  //   State loadState(String id) throws Exception;
  //   void  storeState(State state) throws Exception;
  //   void  removeState(State state) throws Exception;
  //
  //   // Store misc
  //   void scavenge() throws Exception;
  //   void passivateSession(StateAdaptor sa);
}
