/* JFox, the OpenSource J2EE Application Server
 *
 * Copyright (C) 2002 huihoo.com
 * Distributable under GNU LGPL license
 * See the GNU Lesser General Public License for more details.
 */

package org.huihoo.jfox.xmlet;

import java.util.Set;
import java.util.HashSet;
import java.util.Iterator;
import java.io.File;
import java.io.IOException;
import java.io.FilenameFilter;
import javax.management.ObjectName;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanServerInvocationHandler;
import javax.management.loading.MLetMBean;

import org.huihoo.jfox.service.ServiceSupport;

/**
 * A extention MLet, it can monitor the folder, when add/remove a xmlet config
 * file, it will register/unregister the MBean auto
 * 
 * @author <a href="mailto:young_yy@hotmail.com">Young Yang</a>
 */

public class DirMLet extends ServiceSupport implements DirMLetMBean, Runnable{

  /**
   * the path which the Monitor will monitor
   */
//  private File path = new File("./");

  private ObjectName mletObjectName = null;

  /**
   * loaded pathes
   */
  private Set pathes = new HashSet();

  /**
   * the path want to be load
   */
  private Set queryPathes = new HashSet();

  private long sleepTime = 5000L;

  public DirMLet() {

  }

  public DirMLet(String name) {
    super(name);
  }

  /**
   * get loaded pathes
   */
  public String[] getPathes() {
    return (String[])pathes.toArray(new String[0]);
  }

  public void addPath(String path) {
    if(path.startsWith("./") && mletObjectName != null) { // relative path
      path = getMLetInstance().getLibraryDirectory() + "/" + path;
    }
    File file = new File(path);
    if(!file.isDirectory()) {
      throw new RuntimeException("path must be a directory");
    }
    try {
      synchronized(queryPathes) {
        queryPathes.add(file.getCanonicalFile());
      }
    }
    catch(IOException e){
      e.printStackTrace();
      logger.warn(e.getMessage());
    }
  }

  public void setMLet(ObjectName mletObjectName) {
    this.mletObjectName = mletObjectName;
  }

  public ObjectName getMLet() {
    return mletObjectName;
  }

  public MLetMBean getMLetInstance() {
    if(mletObjectName == null) return null;
    try {
      return (MLetMBean)MBeanServerInvocationHandler.newProxyInstance(server,mletObjectName,MLetMBean.class,false);
    }
    catch(Exception e) {
      logger.warn(e.getMessage(),e);
      return null;
    }
  }

  /**
   * set the sleep time in millisecond
   */
  public void setSleepTime(long milSec){
    sleepTime = milSec;
  }

  public long getSleepTime() {
    return sleepTime;
  }

  protected void doInit() throws Exception {
    if(mletObjectName == null) {
      logger.warn("MLet not set yet, can not initialze DirMLet");
      return;
    }

    try {
      if(!server.isInstanceOf(mletObjectName,MLetMBean.class.getName())) {
        logger.warn("the ObjectName " + mletObjectName + " is not a " + MLetMBean.class.getName());
      }
    }
    catch(InstanceNotFoundException e){
      logger.warn("the ObjectName " + mletObjectName + " is not registered",e);
    }
  }

  protected void doStart() throws Exception {

    new Thread(this).start();
  }

  protected void doStop() throws Exception {

  }

  protected void doDestroy() throws Exception {
    mletObjectName = null;
  }

  public void run() {
    while(isRunning() && (mletObjectName != null)){
      synchronized(queryPathes) {
        // loop the directory
        for(Iterator iter = queryPathes.iterator(); iter.hasNext(); ){
          File dir = (File)iter.next();
          if(!pathes.contains(dir.toString())) {
            getMBeansFromDirectory(dir);
          }
          pathes.add(dir.toString());
        }
        queryPathes.clear();
        try {
          Thread.sleep(sleepTime);
        }
        catch(InterruptedException e){
          e.printStackTrace();
        }
      }
    }
  }


  private void getMBeansFromDirectory(File dir){
    if(dir.isFile()) return;
    logger.info(dir.toString());
    MLetMBean mlet = getMLetInstance();
    File[] files = dir.listFiles(new FilenameFilter(){
                                    public boolean accept(File dir, String name) {
                                      if(name.endsWith(".xml")){
                                        return true;
                                      }
                                      else {
                                        return false;
                                      }
                                    }
    });
    for(int i=0; i<files.length; i++){
//      logger.info(files[i].toString());
      try {
        mlet.getMBeansFromURL(files[i].toURL());
      }
      catch(Exception e){
        e.printStackTrace();
        logger.warn(e.getMessage());
      }
    }
  }

}


