/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2008, Red Hat Middleware LLC, and individual contributors
 * as indicated by the @author tags. See the copyright.txt file 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.console.twiddle.command;

import java.io.PrintWriter;
import java.util.Date;

import javax.management.MBeanAttributeInfo;
import javax.management.MBeanConstructorInfo;
import javax.management.MBeanInfo;
import javax.management.MBeanNotificationInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.ObjectName;

/** 
 * Command to print out mbean metadata as an xmbean descriptor.
 * 
 * The idea is to redirect and use the output as the skeleton
 * for writing an xmbean descriptor for an existing mbean,
 * since this can be very tedious to write by hand.
 *
 * @author <a href="dimitris@jboss.org">Dimitris Andreadis</a>
 * @version $Revision: 81010 $
 */
public class XMBeanCommand  extends MBeanServerCommand
{
   /**
    * Default CTOR
    */
   public XMBeanCommand()
   {
      super("xmbean", "Print out mbean metadata as an xmbean descriptor");
   }

   public void displayHelp()
   {
      PrintWriter out = context.getWriter();

      out.println(desc);
      out.println();      
      out.println("Redirect the output and use it as a skeleton for");
      out.println("writing an xmbean descriptor for an existing mbean.");
      out.println();
      out.println("Usage: " + name + " <object-name>");
      out.println();

      out.flush();
   }

   public void execute(String[] args) throws Exception
   {
      if (args.length != 1)
      {
         throw new CommandException("Missing object name");
      }
      ObjectName target = super.createObjectName(args[0]);

      MBeanInfo mbeanInfo = getMBeanServer().getMBeanInfo(target);
      MBeanConstructorInfo[] ctors = mbeanInfo.getConstructors();
      MBeanAttributeInfo[] attrs = mbeanInfo.getAttributes();
      MBeanOperationInfo[] ops = mbeanInfo.getOperations();
      MBeanNotificationInfo[] notifs = mbeanInfo.getNotifications();
      
      PrintWriter out = context.getWriter();

      // header
      out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
      out.println("<!DOCTYPE mbean PUBLIC");
      out.println("   \"-//JBoss//DTD JBOSS XMBEAN 1.2//EN\"");
      out.println("   \"http://www.jboss.org/j2ee/dtd/jboss_xmbean_1_2.dtd\">");
      out.println("<!--");
      out.println("   xmbean descriptor generated by 'twiddle'");
      out.println("   on " +  new Date());
      out.println("   for '" + target + "'");
      out.println("-->");
      
      out.println("<mbean>");
      
      // mbean
      out.println("   <description>" + mbeanInfo.getDescription() + "</description>");
      out.println("   <class>" + mbeanInfo.getClassName() + "</class>");
      out.println();
      
      // constructors
      if (ctors.length > 0)
      {
         for (int i = 0; i < ctors.length; i++)
         {
            MBeanConstructorInfo ctorInfo = ctors[i];
            out.println("   <constructor>");
            out.println("      <description>" + ctorInfo.getDescription() + "</description>");
            out.println("      <name>" + ctorInfo.getName() + "</name>");
            outputParameters(out, ctorInfo.getSignature());
            out.println("   </constructor>");
         }
         out.println();
      }
      
      // attributes
      if (attrs.length > 0)
      {
         for (int i = 0; i < attrs.length; i++)
         {
            MBeanAttributeInfo attrInfo = attrs[i];
            
            // determine access, rw by default
            String access = "read-write";
            access = attrInfo.isReadable() ? access : "write-only";
            access = attrInfo.isWritable() ? access : "read-only";
            String accessString = " access='" + access + "'";

            // determine get method, if any
            String getMethodString = "";
            if (attrInfo.isReadable())
            {
               getMethodString = " getMethod='" +
                  (attrInfo.isIs() ? "is" : "get") + attrInfo.getName() + "'";  
            }
            
            // determine set method, if any
            String setMethodString = "";
            if (attrInfo.isWritable())
            {
               setMethodString = " setMethod='set" + attrInfo.getName() + "'";
               
            }
            
            out.println("   <attribute" + accessString + getMethodString + setMethodString + ">");
            out.println("      <description>" + attrInfo.getDescription() + "</description>");
            out.println("      <name>" + attrInfo.getName() + "</name>");
            out.println("      <type>" + attrInfo.getType() + "</type>");
            out.println("   </attribute>");
         }
         out.println();
      }
      
      // operations
      if (ops.length > 0)
      {
         for (int i = 0; i < ops.length; i++)
         {
            MBeanOperationInfo opInfo = ops[i];
            // nobody uses opInfo.getImpact()
            out.println("   <operation>");
            out.println("      <description>" + opInfo.getDescription() + "</description>");
            out.println("      <name>" + opInfo.getName() + "</name>");
            outputParameters(out, opInfo.getSignature());            
            out.println("      <return-type>" + opInfo.getReturnType() + "</return-type>");
            out.println("   </operation>");
         }
         out.println();
      }
      
      // notifications
      if (notifs.length > 0)
      {
         for (int i = 0; i < notifs.length; i++)
         {
            MBeanNotificationInfo notifInfo = notifs[i];
            String[] types = notifInfo.getNotifTypes();
            out.println("   <notification>");
            out.println("      <description>" + notifInfo.getDescription() + "</description>");
            out.println("      <name>" + notifInfo.getName() + "</name>");
            for (int j = 0; j < types.length; j++)
            {
               out.println("      <notification-type>" + types[j] + "</notification-type>");
            }
            out.println("   </notification>");
         }
         out.println();
      }
      
      out.println("</mbean>");
      
      out.flush();
   }
   
   private void outputParameters(PrintWriter out, MBeanParameterInfo[] params)
   {
      for (int i = 0; i < params.length; i++)
      {
         MBeanParameterInfo paramInfo = params[i];
         out.println("      <parameter>");
         out.println("         <description>" + paramInfo.getDescription() + "</description>");
         out.println("         <name>" + paramInfo.getName() + "</name>");
         out.println("         <type>" + paramInfo.getType() + "</type>");
         out.println("      </parameter>");
      }
   }
}
