/*
 * JBoss, Home of Professional Open Source
 * Copyright 2005, JBoss Inc., and individual contributors as indicated
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.jboss.system;

import java.util.Set;
import java.util.Iterator;
import java.util.HashSet;
import java.util.ArrayList;
import java.util.jar.Manifest;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.net.URL;
import java.net.URLConnection;
import java.net.JarURLConnection;
import javax.management.MBeanServer;
import javax.management.ObjectName;

import org.jboss.mx.loading.ClassLoaderUtils;
import org.jboss.net.protocol.file.FileURLConnection;

/** A version service pojo which can be used to view the jar version info
 of jars visible through the mbean class loaders.

 <mbean code="org.jboss.system.PackageVersionService"
    name="jboss.system:service=PackageVersionService"
    xmbean-dd="">
    <xmbean>
       <operation>
          <description>Get the package version info</description>
          <name>getVersionInfo</name>
          <return-type>java.lang.String</return-type>
       </operation>
    </xmbean>
 </mbean>
 @author Scott.Stark@jboss.org
 @version $Revison:$
 */
public class PackageVersionService
{
   private MBeanServer server;

   public void setMBeanServer(MBeanServer server)
   {
      this.server = server;
   }

   public String getVersionInfo()
   {
      return getVersionInfo("text/html");
   }

   public String getVersionInfo(String contentType)
   {
      Object[] urls = createVersionInfo();
      StringBuffer tmp = new StringBuffer("<pre>\n");
      for (int n = 0; n < urls.length; n++)
      {
         tmp.append(urls[n].toString());
         tmp.append('\n');
      }
      tmp.append("</pre>\n");
      return tmp.toString();
   }

   protected Object[] createVersionInfo()
   {
      // Query for all class loaders
      Set names = server.queryNames(null, null);
      Iterator namesIter = names.iterator();
      HashSet classLoaders = new HashSet();
      HashSet classpathURLs = new HashSet();
      try
      {
         while (namesIter.hasNext())
         {
            ObjectName name = (ObjectName) namesIter.next();
            ClassLoader cl = server.getClassLoaderFor(name);
            if (classLoaders.contains(cl) == false)
            {
               while (cl != null && classLoaders.contains(cl) == false)
               {
                  classLoaders.add(cl);
                  URL[] urls = ClassLoaderUtils.getClassLoaderURLs(cl);
                  int length = urls != null ? urls.length : 0;
                  for (int n = 0; n < length; n++)
                  {
                     URL u = urls[n];
                     classpathURLs.add(u);
                  }
                  cl = cl.getParent();
               }
            }
         }
      } catch (Exception e)
      {

      }

      // Go through the URLs
      classLoaders.clear();
      Iterator cpIter = classpathURLs.iterator();
      ArrayList jars = new ArrayList();
      while (cpIter.hasNext())
      {
         URL u = (URL) cpIter.next();
         try
         {
            URLConnection conn = u.openConnection();
            if (conn instanceof FileURLConnection)
            {
               FileURLConnection fconn = (FileURLConnection) conn;
               JarFile jf = new JarFile(fconn.getFile());
               Manifest mf = jf.getManifest();
               Attributes mfAttrs = mf.getMainAttributes();
               String jar = u.getFile();
               int slash = jar.lastIndexOf('/');
               if (slash > 0)
                  jar = jar.substring(slash + 1);
               JarInfo info = new JarInfo(jar, mfAttrs);
               jars.add(info);
               jf.close();
            }
            if (conn instanceof JarURLConnection)
            {
               JarURLConnection jconn = (JarURLConnection) conn;
               Manifest mf = jconn.getManifest();
               Attributes mfAttrs = mf.getMainAttributes();
               String value = mfAttrs.getValue(Attributes.Name.SPECIFICATION_VERSION);
               System.out.println(Attributes.Name.SPECIFICATION_VERSION + "=" + value);
               JarFile jf = jconn.getJarFile();
               jf.close();
            }
         } catch (Exception e)
         {
         }
      }
      classpathURLs.clear();

      return jars.toArray();
   }

   static class JarInfo
   {
      String jar;
      String version;
      String vendor;
      String title;
      String sealed;
      String implTitle;
      String implVersion;
      String implVendor;
      String implVendorID;
      String implURL;

      JarInfo(String jar, Attributes mfAttrs)
      {
         this.jar = jar;
         version = mfAttrs.getValue(Attributes.Name.SPECIFICATION_VERSION);
         vendor = mfAttrs.getValue(Attributes.Name.SPECIFICATION_VENDOR);
         title = mfAttrs.getValue(Attributes.Name.SPECIFICATION_TITLE);
         sealed = mfAttrs.getValue(Attributes.Name.SEALED);
         implTitle = mfAttrs.getValue(Attributes.Name.IMPLEMENTATION_TITLE);
         implVersion = mfAttrs.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
         implVendor = mfAttrs.getValue(Attributes.Name.IMPLEMENTATION_VENDOR);
         implVendorID = mfAttrs.getValue(Attributes.Name.IMPLEMENTATION_VENDOR_ID);
         implURL = mfAttrs.getValue(Attributes.Name.IMPLEMENTATION_URL);
         implURL = mfAttrs.getValue(Attributes.Name.EXTENSION_NAME);
      }

      public String toString()
      {
         StringBuffer tmp = new StringBuffer(jar);
         tmp.append("[SPECIFICATION_VERSION=");
         tmp.append(version);
         tmp.append(",SPECIFICATION_VENDOR=");
         tmp.append(vendor);
         tmp.append(",SPECIFICATION_TITLE=");
         tmp.append(title);
         tmp.append(",IMPLEMENTATION_VERSION=");
         tmp.append(implVersion);
         tmp.append(",IMPLEMENTATION_VENDOR=");
         tmp.append(implVendor);
         tmp.append(",IMPLEMENTATION_TITLE=");
         tmp.append(implTitle);
         tmp.append(",IMPLEMENTATION_VENDOR_ID=");
         tmp.append(implVendorID);
         tmp.append(",IMPLEMENTATION_URL=");
         tmp.append(implURL);
         tmp.append(",SEALED=");
         tmp.append(sealed);
         tmp.append("]");
         return tmp.toString();
      }
   }
}
