//
// XMLOperationGeneric.java
//
// The contents of this file are subject to the SNIA Public License Version 1.0
// (the "License"); you may not use this file except in compliance with the
// License. You may obtain a copy of the License at
//
//    http://www.snia.org/resources/openSource.html
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the 
// License for the specific language governing rights and limitations
// under the License.
//
// The Original Code is XMLOperationGeneric.java
// 
// The Initial Developer of the Original Code is David Simons.
//
// Contributor(s):
//
//
// This source uses the Solaris WBEM APIs version 2.2. 
// Synchronization will be maintained with the Solaris WBEM APIS,
// which are being standardized through the Java Community Process.
//
//
// $Id: XMLOperationGeneric.java,v 1.1 2003/07/17 18:32:55 kumpf Exp $
//
// $Log: XMLOperationGeneric.java,v $
// Revision 1.1  2003/07/17 18:32:55  kumpf
// HP-BAPU: PEP-64 CIM Client and CIM Listener Java Interface
//
// Revision 1.1.1.1  2001/10/31 18:17:54  karl
// import of SNIA 0_7
//
// Revision 1.9  2001/03/19 17:41:45  davidsi
// - Fixed casing on attribute names.
// - Return values made optional as per spec.
//
// Revision 1.8  2000/11/06 19:19:46  davidsi
// - Reconciled error ids.
//
// Revision 1.7  2000/08/16 05:59:59  shawn
// merge P_TOMCAT31 branch
//
// Revision 1.6.6.1  2000/08/10 00:03:36  shawn
// head merge
//
// Revision 1.6  2000/07/10 18:20:08  davidsi
// - All references to HTTPWriter are now to HTTPOutput.
//
// Revision 1.5  2000/05/11 10:11:25  davidsi
// - Fixed tabs.
//
// Revision 1.4  2000/05/06 17:20:04  davidsi
// - Brought in line with SUN WBEM APIs 2.2
//
// Revision 1.3  2000/04/09 14:45:28  davidsi
// - Removed CIMObjectPath param from extrinsicMethod
// - Fixed header tracking so that it no longer assumes that the message
//   id is an integer.
// - Removed '\n' from XML strings
//
// Revision 1.2  2000/02/13 15:10:07  davidsi
// - Added text to cover re-use of Solaris WBEM APIs.
//
// Revision 1.1.1.1  2000/02/06 16:41:02  davidsi
// Initial version.
//
//
//
package org.snia.wbemcmd.xml;

import java.util.Enumeration;
import java.util.Vector;
import java.net.MalformedURLException;
import org.snia.wbem.cim.CIMException;
import org.snia.wbem.cim.CIMObjectPath;
import org.snia.wbem.cim.CIMDataType;
import org.snia.wbem.client.CIMOMHandle;


public abstract class XMLOperationGeneric 
    extends XMLParameters implements XMLOperation 
{
    static final String CIMVERSION="CIMVERSION";
    static final String DTDVERSION="DTDVERSION";
    static final String MSG_ID="ID";
    static final String PROTOCOLVERSION="PROTOCOLVERSION";
    static final String CIMVERSION_VALUE="2.0";
    static final String DTDVERSION_VALUE="2.0";
    static final String PROTOCOLVERSION_VALUE="1.0";
    static int messageid=0;
    
    private static String paramErrorCode="CODE";
    private static String paramErrorDescription="DESCRIPTION";
    
    public void extrinsicMethod(HTTPWriter pw,XMLNode node,String method,CIMOMHandle hdl) 
        throws CIMException,MalformedURLException 
    {
        throw new CIMException(CIMException.CIM_ERR_NOT_SUPPORTED);
    }
    
    
    
    private static String doMessage(HTTPOutput pw) throws CIMException 
    {
        String messageStr;
        int msgID=messageid++;
        if (messageid>65535)
            messageid=0;
        messageStr=new Integer(msgID).toString();
        pw.makeHeader(messageStr);
        return(messageStr);
    }
    
    //
    // On return a pointer to the relevant XML_ELEMENT_IMETHODRESPONSE 
    // node is passed back
    //
    protected static XMLNode intrinsicMethod(
        HTTPOutput output, CIMObjectPath path,String operation,String vals)
        throws CIMException 
    { 
        int i;
    
        String msgid=doMessage(output);
    
        output.setObjectPath(path.getNameSpace());
    
        try 
        {
            output.println("<SIMPLEREQ><IMETHODCALL NAME=\""+operation+"\">"+
                path.getFullNameSpace().toXml(true));
        } 
        catch (MalformedURLException e) 
        {
            throw new CIMException(CIMException.CIM_ERR_FAILED,e);
        }
        if (vals!=null)
            output.println(vals);
    
        output.println("</IMETHODCALL></SIMPLEREQ>");

        XMLNode reply=output.sendRequest(null);
        if (reply==null)
            return(null);
        return(processReturnStream(reply,false, operation,msgid));
    }
    
    
        
    //
    // On return a pointer to the relevant XML_ELEMENT_IMETHODRESPONSE 
    // node is passed back
    //
    protected static XMLNode intrinsicMethod(HTTPOutput output,CIMObjectPath path,
        String operation,Vector params,String extra) 
        throws CIMException 
    {
        int i;

        String msgid=doMessage(output);
    
        output.setObjectPath(path.getNameSpace());
    
        try 
        {
            output.println("<SIMPLEREQ><IMETHODCALL NAME=\""+operation+"\">"+
                path.getFullNameSpace().toXml(true));
        } 
        catch (MalformedURLException e) 
        {
            throw new CIMException(CIMException.CIM_ERR_FAILED,e);
        }

        for(i=0;i<params.size();i++) 
        {
            Param p=(Param)(params.elementAt(i));
            output.println("<IPARAMVALUE NAME=\""+
                p.getArgName()+"\">"+
                p.getArgValue()+"</IPARAMVALUE>");
        }
        if (extra!=null)
            output.println(extra);
    
        output.println("</IMETHODCALL></SIMPLEREQ>");
        XMLNode reply=output.sendRequest(null);
        if (reply==null)
            return(null);
        return(processReturnStream(reply,false, operation,msgid));
    }
    
    
    protected static XMLNode intrinsicMethod(HTTPOutput output,CIMObjectPath path,
             String operation,Vector params) throws CIMException
    {
        return(intrinsicMethod(output,path,operation,params,null));
    }

    
    protected static String intrinsicMethodHeader(HTTPOutput output,
        CIMObjectPath path, String operation) throws CIMException 
    {
        String msgid=doMessage(output);
        output.setObjectPath(path.getNameSpace());
    
        output.println("<SIMPLEREQ><IMETHODCALL NAME=\""+operation+"\">");
        try 
        {
            output.println(path.getFullNameSpace().toXml(true));
        } 
        catch (MalformedURLException e) 
        {
            throw new CIMException(CIMException.CIM_ERR_FAILED,e);
        }
        return(msgid);
    }
    
    protected static XMLNode intrinsicMethodTail(
        HTTPOutput output,String operation,String msgid) throws CIMException 
    {        
        output.println("</IMETHODCALL></SIMPLEREQ>");
    
        if (output!=null) 
        {
            XMLNode reply=output.sendRequest(null);

            if (reply==null)
                return(null);

            return(processReturnStream(reply,false, operation,msgid));
        }
        return(null);
    }
    
    //
    // On return a pointer to the relevant XML_ELEMENT_METHODRESPONSE 
    // node is passed back
    //
    protected static XMLNode extrinsicMethod(HTTPOutput output,
        CIMObjectPath path, String operation,String extra) throws CIMException 
    {
        int i;
        String text;


        //
        // Fix to make it work with Pegasus CIMOM as well!.
        //
        //output.setObjectPath(path.toString());
        output.setObjectPath(path.getNameSpace() + ":" + path.toString());

        String msgid=doMessage(output);
        text="<SIMPLEREQ><METHODCALL NAME=\""+operation+"\">";
    
        if (extra!=null)
            text=text.concat(extra);
    
        text=text.concat("</METHODCALL></SIMPLEREQ>");

        if (output!=null) 
        {
            XMLNode reply=output.sendRequest(text);

            if (reply==null)
                return(null);

            return(processReturnStream(reply,true,
                            operation,msgid));
        }
        return(null);
    }
    
    
    //
    // token should be either XMLNode.XML_ELEMENT_METHODRESPONSE or
    // XMLNode.XML_ELEMENT_IMETHODRESPONSE
    private static XMLNode processReturnStream(XMLNode reply, 
        boolean extrinsic, String operation, String origMsgID) throws CIMException
    {
        int tokenMsgType;
        int tokenRetType;
    
        if (extrinsic) {
            tokenMsgType=XMLNode.XML_ELEMENT_METHODRESPONSE;
            tokenRetType=XMLNode.XML_ELEMENT_RETURNVALUE;
        } else {
            tokenMsgType=XMLNode.XML_ELEMENT_IMETHODRESPONSE;
            tokenRetType=XMLNode.XML_ELEMENT_IRETURNVALUE;
        }
        //
        // Find <CIM> element
        //
        reply=reply.mustFindElement(XMLNode.XML_ELEMENT_CIM);
        String cimattr=reply.mustGetAttribute(CIMVERSION);
        if (!cimattr.equals(CIMVERSION_VALUE))
            throw new CIMException(CIMException.CIM_ERR_INVALID_PARAMETER,
                "Return is for CIMVERSION "+cimattr);
        
        cimattr=reply.mustGetAttribute(DTDVERSION);
        if (!cimattr.equals(DTDVERSION_VALUE)) 
            throw new CIMException(CIMException.CIM_ERR_INVALID_PARAMETER,
                "Return is for DTDVERSION "+cimattr);

        //
        // Find <MESSAGE>
        //  
        reply=reply.mustChildFindElement(XMLNode.XML_ELEMENT_MESSAGE);
        cimattr=reply.mustGetAttribute(MSG_ID);
        if (!cimattr.equals(origMsgID)) 
            throw new CIMException(CIMException.CIM_ERR_INVALID_PARAMETER,
                "Return messageid="+cimattr+", expected="+origMsgID);

        cimattr=reply.mustGetAttribute(PROTOCOLVERSION);
        if (!cimattr.equals(PROTOCOLVERSION_VALUE))
            throw new CIMException(CIMException.CIM_ERR_INVALID_PARAMETER,
                "Return is for PROTOCOLVERSION "+cimattr);
    
        reply=reply.getChild();
        if (reply==null)
            throw new CIMException(CIMException.CIM_ERR_INVALID_PARAMETER,
                "No XML_ELEMENT_IRETURNVALUE (22)");
    
        //
        // Find <SIMPLERSP>
        //
        reply=reply.findElementChild(XMLNode.XML_ELEMENT_SIMPLERSP);
        //
        // TODO-NICE: need to look for complex RSPs!!
        //
        if (reply==null)
            throw new CIMException(CIMException.CIM_ERR_INVALID_PARAMETER,
                "No XML_ELEMENT_SIMPLERSP");

        //
        // <METHODRESPONSE> or <IMETHODRESPONSE>
        //
        reply=reply.mustFindElement(tokenMsgType);
        String nameOfMethod=reply.getAttribute("NAME");
        if (nameOfMethod==null) 
            throw new CIMException(CIMException.CIM_ERR_INVALID_PARAMETER,
                "Response had no method name");

        if (!nameOfMethod.equalsIgnoreCase(operation))
            throw new CIMException(CIMException.CIM_ERR_INVALID_PARAMETER,
                "Called "+operation+" but response was for "+nameOfMethod);
        
        reply=reply.getChild();
        if (reply==null)
            return(null);

        //
        // See if there was an error, and if there was throw an equivalent
        // exception on the client
        //
        XMLNode errorNode=reply.findElement(XMLNode.XML_ELEMENT_ERROR);
        if (errorNode!=null) {
            CIMException ce=new CIMException();
            String errCode=errorNode.mustGetAttribute(paramErrorCode);
            String description=errorNode.mustGetAttribute(paramErrorDescription);
            throw new CIMException(ce.getXmlCode(new Integer(errCode).intValue()),
                    description);
        }
        
        // Attn: 09/16/02 - (Jenny) Return method response for extrinsic methods
        //
        if (extrinsic) 
        {
            //
            // return the METHOD RESPONSE
            //
            return(reply);
        }
        else
        {
            //
            // Find returnvalue
            //
            return(reply.mustFindElementChild(tokenRetType));
        }
    }

    
    static public XMLNode XMLGetCIMElement(XMLNode node) throws CIMException 
    {
        if (node.getToken()!=XMLNode.XML_ELEMENT_CIM)
            throw new CIMException(CIMException.CIM_ERR_FAILED,
                       "Could not find <CIM> element");
        String str=node.mustGetAttribute(CIMVERSION);
        if (!str.equals(CIMVERSION_VALUE))
            throw new CIMException(CIMException.CIM_ERR_NOT_SUPPORTED,
                "Unsupported version of CIMVERSION");
        
    
        str=node.mustGetAttribute(DTDVERSION);
        if (!str.equals(DTDVERSION_VALUE))
            throw new CIMException(CIMException.CIM_ERR_NOT_SUPPORTED,
                "Unsupported version of DTDVERSION");
    
        node=node.getChild();
        if (node==null)
            throw new CIMException(CIMException.CIM_ERR_FAILED,
                       "No child for <CIM> element");
        return(node);
    }

}
