/*
 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
 * This software is the proprietary information of Sun Microsystems, Inc.
 * Use is subject to license terms.
 * 
 * Copyright 2004 Sun Microsystems, Inc.  Tous droits réservés.
 * Ce logiciel est propriété de Sun Microsystems, Inc.
 * Distribué par des licences qui en restreignent l'utilisation.
 *
 * ident        "@(#)MfC_ConnectorClient.java 1.12     04/05/19 SMI"
 *
 */

package com.sun.mfwk.conn;

import com.sun.rmi2rpc.*;
import com.sun.rmi2rpc.rpc.*;
import javax.management.*;
import java.io.IOException;
import java.net.InetAddress;
import javax.management.MBeanServerConnection;
import java.util.Set;
import javax.management.loading.ClassLoaderRepository;
import java.io.ObjectInputStream;

import java.util.logging.*;
import com.sun.mfwk.util.log.MfLogService;

public class MfC_ConnectorClient
    implements MBeanServerConnection {

    /**
     * Initializes the communication with an RPC server.
     * The port number is given as parameter.
     * If a communication problem occurs this method will throw
     * a <CODE>IOException</CODE>.
     */
    public synchronized String connect(int port) throws IOException {
	logger.entering("MfC_ConnectorClient", "connect", new Integer(port));
	RpcClient serviceClient = null;
	try {
	    // Only connection to the local host is supported
	    InetAddress host = InetAddress.getLocalHost();
	    serviceClient = new TcpRpcClient(host, port);
	} catch(Exception e) {
	    throw new IOException(e.toString());
	}

	RpcStubCalls defaultStubCalls = new DefaultRpcStubCalls();
	service = new ServiceStub(serviceClient, defaultStubCalls);

	return new String(String.valueOf(port));
    }


    /////////////////////////////////////////////////////////////////////////////
    //
    // Implementation of MBeanServerConnection
    //
    /////////////////////////////////////////////////////////////////////////////

    /**
     * Gets the value of a specific attribute of an object name.
     *
     * @param name The object name from which the attribute is to be retrieved.
     * @param attribute A String specifying the name of the attribute to be
     * retrieved.
     *
     * @return  The value of the retrieved attribute. Only the primitive types are supported.
     *
     * @exception AttributeNotFoundException The attribute specified is not accessible in the object.
     * @exception InstanceNotFoundException The object specified is not registered in the server.
     * @exception IOException rmi2rpc exception.
     */
    public synchronized Object getAttribute(ObjectName name, String attribute) throws
    InstanceNotFoundException, AttributeNotFoundException, IOException {

	logger.entering("MfC_ConnectorClient", "getAttribute");
	logger.finer("objectName = " + name.toString() + ", attribute = " + attribute);
	String objName = name.toString();
	Object value = null;
	MfAttValue attValue = null;
	try {
	    attValue = service.getAttribute(objName, attribute);
	    if (attValue.type == MfAttValue.OBJECT_NOT_FOUND) {
		throw new InstanceNotFoundException();
	    }
	    value = getValue(attValue);
	    if (value == null) {
		throw new AttributeNotFoundException();
	    }
	}
	catch (Exception e) {
	    throw new IOException(e.toString());
	}

	logger.finest("Value = " + value);

	return value;
    }

    /**
     * Enables the values of several attributes of a named object.
     *
     * @param name The object name from which the attributes are
     * retrieved.
     * @param attributes A list of the attributes to be retrieved.
     *
     * @return The list of the retrieved attributes. Only the primitive types are supported.
     *
     * @exception InstanceNotFoundException The object specified is not registered in the server.
     * @exception IOException rmi2rpc exception.
     */
    public synchronized AttributeList getAttributes(ObjectName name,
						    String[] attributes) throws
						    InstanceNotFoundException, IOException {

	logger.entering("MfC_ConnectorClient", "getAttributes");
	logger.finer("objectName = " + name.toString());
	logger.finer("attributes = ");
	for (int ii = 0; ii < attributes.length; ii++) {
	    logger.finer(attributes[ii]);

	}
	String objName = name.toString();
	MfAttValue[] attValues = null;
	try {
	    attValues = service.getAttributes(objName, attributes);
	    if (attValues.length == 0) {
		logger.finest("InstanceNotFoundException");
		throw new InstanceNotFoundException();
	    }
	}
	catch (Exception e) {
	    logger.finest("IOException - " + e);
	    throw new IOException(e.toString());
	}

	AttributeList list = new AttributeList();
	for (int ii = 0; ii < attValues.length; ii++) {
	    Object value = getValue(attValues[ii]);
	    if (value != null) {
		Attribute att = new Attribute(attributes[ii], value);
		list.add(att);
		logger.finer("Value " + ii + " = " + value.toString());
	    }
	}

	return list;
    }

    /**
     * Invokes an operation on an object.
     *
     * @param name The object name on which the method is to be invoked.
     * @param operationName The name of the operation to be invoked.
     * @param params An array containing the parameters to be set when the operation is invoked.
     * @param signature An array containing the signature of the operation.
     * Only the primitive types are supported.
     *
     * @return  The value returned by the operation, which represents the result of
     * invoking the operation on the object specified. Only the primitive types are supported.
     *
     * @exception InstanceNotFoundException - The object specified is not registered in the server.
     * @exception MBeanException - Exception thrown if the operation does not exist on the specified object.
     * @exception JMRuntimeException - Exception thrown if there is an error in the operation.
     * @exception IOException rmi2rpc exception.
     */
    public synchronized Object invoke(ObjectName name,
				      String operationName,
				      Object[] params,
				      String[] signature) throws
				      InstanceNotFoundException,
				      MBeanException,
				      JMRuntimeException,
				      IOException {

	logger.entering("MfC_ConnectorClient", "invoke");
	logger.finer("objectName = " + name.toString());
	logger.finer("params = ");
	if (params != null) {
	    for (int ii = 0; ii < params.length; ii++) {
		logger.finer(params[ii].toString());
	    }
	}

	logger.finer("signature = ");
	if (signature != null) {
	    for (int ii = 0; ii < signature.length; ii++) {
		logger.finer(signature[ii]);
	    }
	}

	String objName = name.toString();

	MfAttValue[] paramValues = null;
	if (params != null) {
	    paramValues = new MfAttValue[params.length];
	    for (int ii = 0; ii < params.length; ii++) {
		paramValues[ii] = setValue(params[ii]);
	    }
	}
	else {
	    // RPC doesn't support null object!
	    paramValues = new MfAttValue[1];
	    paramValues[0] = new MfAttValue();
	    paramValues[0].value = new String(" ");
	}

	if (signature == null) {
	    // RPC doesn't support null object!
	    signature = new String[1];
	    signature[0] = new String(" ");
	}

	MfAttValue retValue = null;
	try {
	    retValue = service.invoke(objName, operationName, paramValues, signature);
	}
	catch (Exception e) {
	    logger.finest("IOException - " + e);
	    throw new IOException(e.toString());
	}
	return retValue;
    }

    // Not supported methods

    /**
     * Not supported method, always throw an IOException 
     * with the detail message "Not supported method".
     *
     * @return Integer
     */
    public Integer getMBeanCount()
	throws IOException {
	throw new IOException("Not supported method");
    }

    /**
     * Not supported method, always throw an IOException 
     * with the detail message "Not supported method".
     *
     * @return String
     */
    public String getDefaultDomain()	
	throws IOException {
	throw new IOException("Not supported method");
    }

    /**
     * Not supported method, always throw an IOException 
     * with the detail message "Not supported method".
     *
     * @return String[]
     */
    public String[] getDomains()
	throws IOException {
	throw new IOException("Not supported method");
    }

    /**
     * Not supported method, always throw an IOException 
     * with the detail message "Not supported method".
     *
     * @param objectName ObjectName
     */
    public void unregisterMBean(ObjectName objectName)
	throws IOException {
	throw new IOException("Not supported method");
    }

    /**
     * Not supported method, always throw an IOException 
     * with the detail message "Not supported method".
     *
     * @param objectName ObjectName
     * @return boolean
     */
    public boolean isRegistered(ObjectName objectName)
	throws IOException {
	throw new IOException("Not supported method");
    }

    /**
     * Not supported method, always throw an IOException 
     * with the detail message "Not supported method".
     *
     * @param objectName ObjectName
     * @param string String
     * @return boolean
     */
    public boolean isInstanceOf(ObjectName objectName, String string)
	throws IOException {
	throw new IOException("Not supported method");
    }

    /**
     * Not supported method, always throw an IOException 
     * with the detail message "Not supported method".
     *
     * @param objectName ObjectName
     * @param attribute Attribute
     */
    public void setAttribute(ObjectName objectName, Attribute attribute)
	throws IOException {
	throw new IOException("Not supported method");
    }

    /**
     * Not supported method, always throw an IOException 
     * with the detail message "Not supported method".
     *
     * @param objectName ObjectName
     * @return MBeanInfo
     */
    public MBeanInfo getMBeanInfo(ObjectName objectName)
	throws IOException {
	throw new IOException("Not supported method");
    }

    /**
     * Not supported method, always throw an IOException 
     * with the detail message "Not supported method".
     *
     * @param objectName ObjectName
     * @param notificationListener NotificationListener
     */
    public void removeNotificationListener(ObjectName objectName,
					   NotificationListener
					   notificationListener)
	throws IOException {
	throw new IOException("Not supported method");

    }

    /**
     * Not supported method, always throw an IOException 
     * with the detail message "Not supported method".
     *
     * @param objectName ObjectName
     * @return ObjectInstance
     */
    public ObjectInstance getObjectInstance(ObjectName objectName)
	throws IOException {
	throw new IOException("Not supported method");
    }

    /**
     * Not supported method, always throw an IOException 
     * with the detail message "Not supported method".
     *
     * @param objectName ObjectName
     * @param objectName1 ObjectName
     */
    public void removeNotificationListener(ObjectName objectName,
					   ObjectName objectName1)
	throws IOException {
	throw new IOException("Not supported method");

    }

    /**
     * Not supported method, always throw an IOException 
     * with the detail message "Not supported method".
     *
     * @param objectName ObjectName
     * @param queryExp QueryExp
     * @return Set
     */
    public Set queryMBeans(ObjectName objectName, QueryExp queryExp)
	throws IOException {
	throw new IOException("Not supported method");

    }

    /**
     * Not supported method, always throw an IOException 
     * with the detail message "Not supported method".
     *
     * @param objectName ObjectName
     * @param queryExp QueryExp
     * @return Set
     */
    public Set queryNames(ObjectName objectName, QueryExp queryExp)
	throws IOException {
	throw new IOException("Not supported method");

    }

    /**
     * Not supported method, always throw an IOException 
     * with the detail message "Not supported method".
     *
     * @param objectName ObjectName
     * @param attributeList AttributeList
     * @return AttributeList
     */
    public AttributeList setAttributes(ObjectName objectName,
				       AttributeList attributeList)
	throws IOException {
	throw new IOException("Not supported method");
    }

    /**
     * Not supported method, always throw an IOException 
     * with the detail message "Not supported method".
     *
     * @param objectName ObjectName
     * @param notificationListener NotificationListener
     * @param notificationFilter NotificationFilter
     * @param object Object
     */
    public void addNotificationListener(ObjectName objectName,
					NotificationListener notificationListener,
					NotificationFilter notificationFilter,
					Object object)
	throws IOException {
	throw new IOException("Not supported method");

    }

    /**
     * Not supported method, always throw an IOException 
     * with the detail message "Not supported method".
     *
     * @param objectName ObjectName
     * @param notificationListener NotificationListener
     * @param notificationFilter NotificationFilter
     * @param object Object
     */
    public void removeNotificationListener(ObjectName objectName,
					   NotificationListener
					   notificationListener,
					   NotificationFilter notificationFilter,
					   Object object)
	throws IOException {
	throw new IOException("Not supported method");

    }

    /**
     * Not supported method, always throw an IOException 
     * with the detail message "Not supported method".
     *
     * @param objectName ObjectName
     * @param objectName1 ObjectName
     * @param notificationFilter NotificationFilter
     * @param object Object
     */
    public void addNotificationListener(ObjectName objectName,
					ObjectName objectName1,
					NotificationFilter notificationFilter,
					Object object) 
	throws IOException {
	throw new IOException("Not supported method");

    }

    /**
     * Not supported method, always throw an IOException 
     * with the detail message "Not supported method".
     *
     * @param objectName ObjectName
     * @param objectName1 ObjectName
     * @param notificationFilter NotificationFilter
     * @param object Object
     */
    public void removeNotificationListener(ObjectName objectName,
					   ObjectName objectName1,
					   NotificationFilter notificationFilter,
					   Object object)
	throws IOException {
	throw new IOException("Not supported method");

    }

    /**
     * Not supported method, always throw an IOException 
     * with the detail message "Not supported method".
     *
     * @param className String
     * @param objectName ObjectName
     * @return ObjectInstance
     */
    public ObjectInstance createMBean(String className, ObjectName objectName)
	throws IOException {
	throw new IOException("Not supported method");
    }

    /**
     * Not supported method, always throw an IOException 
     * with the detail message "Not supported method".
     *
     * @param className String
     * @param objectName ObjectName
     * @param objectName2 ObjectName
     * @return ObjectInstance
     */
    public ObjectInstance createMBean(String className, ObjectName objectName,
				      ObjectName objectName2) 	
	throws IOException {
	throw new IOException("Not supported method");
    }

    /**
     * Not supported method, always throw an IOException 
     * with the detail message "Not supported method".
     *
     * @param className String
     * @param objectName ObjectName
     * @param objectArray Object[]
     * @param stringArray String[]
     * @return ObjectInstance
     */
    public ObjectInstance createMBean(String className, ObjectName objectName,
				      Object[] objectArray, String[] stringArray) 	
	throws IOException {
	throw new IOException("Not supported method");

    }

    /**
     * Not supported method, always throw an IOException 
     * with the detail message "Not supported method".
     *
     * @param className String
     * @param objectName ObjectName
     * @param objectName2 ObjectName
     * @param objectArray Object[]
     * @param stringArray String[]
     * @return ObjectInstance
     */
    public ObjectInstance createMBean(String className, ObjectName objectName,
				      ObjectName objectName2,
				      Object[] objectArray, String[] stringArray)
	throws IOException {
	throw new IOException("Not supported method");
    }

    /////////////////////////////////////////////////////////////////////////////
    //
    // Private methods
    //
    /////////////////////////////////////////////////////////////////////////////

    private Object getValue(MfAttValue attValue) {
	Object val = null;
	String value = new String(attValue.value);
	if (attValue.type == attValue.BOOLEAN) {
	    val = new Boolean(value);
	}
	else if (attValue.type == attValue.BYTE) {
	    val = new Byte(value);
	}
	else if (attValue.type == attValue.DOUBLE) {
	    val = new Double(value);
	}
	else if (attValue.type == attValue.FLOAT) {
	    val = new Float(value);
	}
	else if (attValue.type == attValue.INTEGER) {
	    val = new Integer(Integer.parseInt(value, 16));
	}
	else if (attValue.type == attValue.LONG) {
	    val = new Long(Long.parseLong(value, 16));
	}
	else if (attValue.type == attValue.SHORT) {
	    val = new Short(Short.parseShort(value, 16));
	}
	else if (attValue.type == attValue.STRING) {
	    val = value;
	}
	else if (attValue.type == attValue.ERROR) {
	    val = null;
	}
	else {
	    logger.finest("Unsupported type! (type = " + attValue.type + ")");

	}
	return val;
    }

    private MfAttValue setValue(Object obj) {
	MfAttValue val = new MfAttValue();
	if (obj instanceof Boolean) {
	    val.type = val.BOOLEAN;
	    val.value = obj.toString();
	}
	else if (obj instanceof Byte) {
	    val.type = val.BYTE;
	    val.value = obj.toString();
	}
	else if (obj instanceof Double) {
	    val.type = val.DOUBLE;
	    val.value = obj.toString();
	}
	else if (obj instanceof Float) {
	    val.type = val.FLOAT;
	    val.value = obj.toString();
	}
	else if (obj instanceof Integer) {
	    val.type = val.INTEGER;
	    val.value = ( (Integer) obj).toHexString( ( (Integer) obj).intValue());
	}
	else if (obj instanceof Long) {
	    val.type = val.LONG;
	    val.value = ( (Long) obj).toHexString( ( (Long) obj).longValue());
	}
	else if (obj instanceof Short) {
	    val.type = val.SHORT;
	    val.value = java.lang.Integer.toHexString( ( (Short) obj).intValue());
	}
	else if (obj instanceof String) {
	    val.type = val.STRING;
	    val.value = obj.toString();
	}
	else {
	    logger.finest("Unsupported object type! (object = " + obj.toString() +
			       ")");

	}

	return val;
    }

    // Private variables
    private Service service = null;

    private static Logger logger = MfLogService.getLogger("MfC_ConnectorClient");
}
