
/**
 * Title:        JASMI API<p>
 * Description:  Dump all OID to object name mappings of all parsable MIB files
 *               in a directory.<p>
 * Copyright:    Copyright (c) Frank Fock<p>
 * Company:      AGENT++<p>
 * @author Frank Fock
 * @version 1.8
 */
package com.agentpp.smi.examples;

import com.agentpp.smi.*;
import com.agentpp.smi.event.*;
import java.io.*;
import java.util.*;
import com.agentpp.smiparser.SMIParseException;

/**
 * This example shows how MIB information is directly used without persistently
 * storing compiled MIBs in a MIB repository. It also shows how the objects in
 * a MIB module are added to a SMIRepository instance for easy lookup and
 * browsing of MIB information across module boundaries.
 *
 * @author Frank Fock
 * @version 1.8
 */
public class DumpObjectNames implements ImportModuleListener {

  private SMIRepositoryManager repMan;
  private String mibFileDir;
  // Set this to false to use loading on demand instead of caching loaded
  // objects (see importModule() for details).
  private boolean useCache = false;

  // The module hash will hold all MIB modules successfully parsed.
  private Hashtable moduleHash = new Hashtable();

  // The moduleFileNames Hashtable is needed to map module names to file names.
  private Hashtable moduleFileNames = new Hashtable();

  // Used to create unique module IDs
  private static int moduleID = 1;

  public DumpObjectNames(String license, String licenseKey, String mibFileDir,
                         String cache) {
    useCache = Boolean.getBoolean(cache);
    // create repository manager
    repMan = new SMIRepositoryManager(license, licenseKey);
    this.mibFileDir = mibFileDir;
  }

  public void run() {
    // open
    File f = new File(mibFileDir);
    Vector v = getSubtree(f);
    Vector moduleInfos = new Vector();
    Vector files = new Vector();
    for (Enumeration en = v.elements(); en.hasMoreElements();) {
      f = (File)en.nextElement();
      try {
	IModuleInfo[] mi = repMan.getModuleInfo(f);
	for (int i=0; i<mi.length; i++) {
	  moduleInfos.addElement(mi[i]);
	  moduleFileNames.put(mi[i].getModuleName(), f);
	}
	files.addElement(f);
      }
      catch (Exception ex) {
	System.err.println("Error in file "+f.getPath()+": "+ex.toString());
      }
    }
    IModuleInfo[] infoList = new IModuleInfo[moduleInfos.size()];
    moduleInfos.copyInto(infoList);
    IModuleInfoSorter sorter = new IModuleInfoSorter(infoList);
    if (!sorter.sort())
      System.err.println("Could not resolve all imports!");
    infoList = sorter.getSortedList();

    // create a repository to hold the MIB modules and their objects.
    SMIRepository repository = new SMIRepository();

    for (int i=0; i<infoList.length; i++) {
      try {
	f = (File)moduleFileNames.get(infoList[i].getModuleName());
	if (f == null) continue;
	FileInputStream fis = new FileInputStream(f);
	IModule[] modules = repMan.getModules(fis, this);
	fis.close();
	for (int j=0; j<modules.length; j++) {
	  // feed cache if activated
	  if (useCache)
	    moduleHash.put(modules[j].getModuleName(), modules[j]);
          // this adds the module and all its objects to the repository
	  repository.addObject(modules[j]);
          for (Enumeration en = modules[j].objects(); en.hasMoreElements();) {
            repository.addObject((IObject)en.nextElement());
          }
	}
        repository.structureChanged();
      }
      catch (SMIParseException pex) {
        System.out.println(repMan.getErrorText(pex));
      }
      catch (Exception ex) {
        System.out.println(ex.getMessage());
	ex.printStackTrace();
      }
    }
    dumpRepository(repository);
  }

  /**
   * Dumps all objects (that have an OID) in the given MIB repository.
   * @param repository
   */
  private void dumpRepository(IRepository repository) {
    // this shows how the object class OID can be resolved from an OID:
    Vector v = repository.getObjectClassOID("sysDescr.0");
    System.out.println("Resolved OID 'sysDescr.0': class="+v.elementAt(0)+
                       ", instance suffix="+v.elementAt(1));
    // now dump the repository
    for (Enumeration en = repository.objects();
         en.hasMoreElements();) {
      IObject o = (IObject)en.nextElement();
      System.out.println(o.getName()+" = "+o.getPrintableOid());
    }
  }

  /**
   * Creates a new unique module ID.
   * @param moduleName
   * @return
   *    an <code>Integer</code> representing an unique identifier for
   *    MIB modules.
   */
  public Integer createModuleID(String moduleName) {
    // Create a unique module ID
    return new Integer(moduleID++);
  }

  public void freeModuleID(Integer i, String moduleName) {
    // we do not store module IDs persistently so we may ignore this event.
  }

  /**
   * The parser signals with this event that it needs to read an imported
   * MIB module. Depending whether caching is enabled or not, we either
   * fetch the requested module from the cache (if available) or reparse it
   * from the MIB module source.
   *
   * @param e
   *    an <code>ImportModuleEvent</code>.
   */
  public void importModule(ImportModuleEvent e) {
    // Since we sorted to MIB modules to be parsed, we can assume here that
    // we have already successfully parsed all relevant modules.
    if (useCache) {
      // use Cache
      IModule m = (IModule)moduleHash.get(e.getModuleName());
      if (m != null) {
	Vector v = m.getObjectsVector();
	IObject[] objs = new IObject[v.size()];
	v.copyInto(objs);
	e.setObjects(objs);
      }
    }
    else {
      // However we could also (re)parse them on demand as shown be the
      // following code snippet:
      File f = (File)moduleFileNames.get(e.getModuleName());
      if (f != null) {
	try {
	  FileInputStream fis = new FileInputStream(f);
	  IModule[] modules = repMan.getModules(fis, this);
	  fis.close();
	  for (int i=0; i<modules.length; i++) {
	    if (modules[i].getModuleName().equals(e.getModuleName())) {
	      IObject[] objs = new IObject[modules[i].size()];
	      Vector v = modules[i].getObjectsVector();
	      v.copyInto(objs);
	      // Put the imported objects into the event object
	      e.setObjects(objs);
	      return;
	    }
	  }
	}
	catch (Exception ex) {
	  // ignore
	  ex.printStackTrace();
	}
      }
    }
    // Leave the imported objects array of the event object empty in case of
    // any error!
  }

  /**
   * Gets recursively the files in a directory.
   *
   * @param directory
   *    a <code>File</code>.
   * @return
   *    a <code>Vector</code> of <code>File</code>s.
   */
  public static Vector getSubtree(File directory) {
    if (directory.isDirectory()) {
      File[] files = directory.listFiles(new FileFilter() {
        public boolean accept(File f) {
          if (!f.isDirectory()) return true;
          return false;
        }
      });
      File[] dirs = directory.listFiles(new FileFilter() {
        public boolean accept(File f) {
          if (f.isDirectory()) return true;
          return false;
        }
      });
      Vector v = new Vector(files.length, 10);
      for (int i=0; i<files.length; i++) {
        v.addElement(files[i]);
      }
      for (int i=0; i<dirs.length; i++) {
        v.addAll(getSubtree(dirs[i]));
      }
      return v;
    }
    return new Vector();
  }

  public static void main(String[] args) {
    if (args.length < 4) {
      System.out.println("Usage: DumpObjectNames <license> <licenseKey> <mibFileDir> <useCache>");
      System.out.println("where: <useCache>   is \"true\" or \"false\"");
      System.out.println("       <mibFileDir> is a directory containing SMIv1/v2 MIB files.");
      System.exit(1);
    }
    DumpObjectNames dumpObjectNames =
      new DumpObjectNames(args[0], args[1], args[2], args[3]);
    dumpObjectNames.run();
  }

}

