//
// CIMHTTPIndicationReceiver.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 CIMHTTPIndicationReceiver.java
//
// 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: CIMHTTPIndicationReceiver.java,v 1.1 2003/07/17 18:32:55 kumpf Exp $
//
// The Initial Developer of the Original Code is Adrian Schuur.
//
// Contributor(s):
//
// For HP Release 2.0 2003/03/12 ( Bapu Patil)
// Support Indication and seperate CIMListner part from
// Client API code
//
//

package org.snia.wbem.listener;

import java.util.*;
import java.io.*;
import java.net.*;
import java.lang.*;
import org.snia.wbemcfg.GlobalConfig;
import org.snia.wbem.cim.CIMInstance;
import org.snia.wbem.cim.CIMException;
import org.snia.wbemcmd.xml.*;
import org.snia.wbemcmd.xml.XMLParse;
import org.snia.wbemcmd.xml.XMLNode;
import org.snia.wbemcmd.xml.HTTPReader;
import org.snia.wbemcmd.xml.HTTPException;
import org.snia.wbemcmd.utils.Log;


class ThreadedIndReceiver extends Thread
{
   Socket insocket;
   CIMListener cl;
   XMLParse xml=null;
   XMLNode node=null;
   private HTTPReader reader;
   private InputStream    in;

   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 final String INDICATION_TYPE="TYPE";

   // Bapu - added 
   static final String NAME="NAME";

   static int hNum=0;


   void sendIndResponse(Socket sok, String id, String expIndicationName)
   {
      String hNumStr=null;
      synchronized(this) 
      {
         if (++hNum>99) hNum=1;
           hNumStr=(hNum%10)+""+(hNum/10);
      }

//public static int XML_ELEMENT_SIMPLEEXPREQ=3999;
//public static int XML_ELEMENT_SIMPLEEXPRSP=3998;
//public static int XML_ELEMENT_EXPMETHODCALL=3997;
//public static int XML_ELEMENT_EXPMETHODRESPONSE=3996;
//public static int XML_ELEMENT_EXPPARAMVALUE=3995;

      String body=
         "<?xml version=\"1.0\" ?>\n"+
         "<CIM CIMVERSION=\"2.0\" DTDVERSION=\"2.0\">\n"+
         "<MESSAGE ID=\""+id+"\" PROTOCOLVERSION=\"1.0\">\n"+
         "<SIMPLEEXPRSP><EXPMETHODRESPONSE NAME=\""+expIndicationName+"\">"+
         "<IRETURNVALUE></IRETURNVALUE>"+
         "</EXPMETHODRESPONSE></SIMPLEEXPRSP></MESSAGE></CIM>\n";

      String msg=
         "HTTP/1.1 200 OK\n"+
         "Content-type: application/xml; charset=\"utf-8\"\n"+
         "Content-length: "+body.length()+"\n"+
         "Ext:\n"+
         "Cache-Control: no-cache\n"+
         "Man: http://www.dmtf.org/cim/mapping/http/v1.0;ns="+hNumStr+"\n"+
         hNumStr+"-CIMExport: MethodResponse\n\n"+body;


      try 
      {
         PrintStream out=new PrintStream(sok.getOutputStream());

         if (GlobalConfig.DEBUG_XML)
            Log.printlnTransaction("OUT:"+msg);

         out.print(msg);
         out.print("\r\n");
         out.flush();
      }
      catch (Exception e) 
      {
         if (GlobalConfig.DEBUG_XML)
         {
            Log.println("Unable to send response. ");
            Log.println("CIMHTTPIndicationReceiver -Exception: "+e);
         }
      }
   }


   ThreadedIndReceiver(Socket s, CIMListener  clin)
   {
      insocket=s;
      cl = clin;
   }

   public void run()
   {
      XMLNode node=null;
      //HTTPReader rdr=null;
      String reqURL = null;
      int counter = 0;

      try 
      {
         reader = new HTTPReader(insocket);
      }
      catch (Exception e) 
      {
         if (GlobalConfig.DEBUG_XML)
         {
            Log.println("read Indication request failed. ");
            Log.printlnTransaction("CIMHTTPIndicationReceiver -Exception: "+e);
         }
         return;
      }
      for (;;) 
      {
         if (GlobalConfig.DEBUG_XML)
         {
	    counter++;
            Log.printlnTransaction("CIMHTTPIndicationReceiver Request Counter="+counter);
         }
         try 
	 {
            node=reader.parseRequest(null,false);
         }
         catch (IOException ioe) 
	 {
            if (GlobalConfig.DEBUG_XML)
            {
               Log.printlnTransaction("CIMHTTPIndicationReceiver -Exception: "+ioe);
               Log.printlnTransaction("This may be due to "+
                        "Client did not send the indication request or " +
			"client closed the connection. No action needed. "+
			"CIMListener will close the connection. ");
	       // BAPU - Debug purpose only
	       //ioe.printStackTrace();
            }
            try 
	    {
               reader.close();
            } catch (IOException e1)   { return; }
            return;
         }
         catch (HTTPException httpe) 
	 {
            if (GlobalConfig.DEBUG_XML)
            {
               Log.println("HTTPException occurred.");
               Log.printlnTransaction("CIMHTTPIndicationReceiver -Exception: "+httpe);
            }
            try {
               reader.close();
            } catch (IOException e2)   { return; }
            return;
         }

	 // Request URL for Listeners would be /cimom/listner1
         reqURL = reader.getRequestURL();

         try 
	 {
            node=node.mustFindElement(XMLNode.XML_ELEMENT_CIM);

            String cimattr=node.mustGetAttribute(CIMVERSION);
            if (!cimattr.equals(CIMVERSION_VALUE))
                throw new CIMException(CIMException.CIM_ERR_INVALID_PARAMETER,
                   "Return is for CIMVERSION "+cimattr);

            cimattr=node.mustGetAttribute(DTDVERSION);
            if (!cimattr.equals(DTDVERSION_VALUE))
               throw new CIMException(CIMException.CIM_ERR_INVALID_PARAMETER,
                  "Return is for DTDVERSION "+cimattr);


            node=node.mustChildFindElement(XMLNode.XML_ELEMENT_MESSAGE);
            String id=node.mustGetAttribute(MSG_ID);

            cimattr=node.mustGetAttribute(PROTOCOLVERSION);
            if (!cimattr.equals(PROTOCOLVERSION_VALUE))
                throw new CIMException(CIMException.CIM_ERR_INVALID_PARAMETER,
                   "Return is for PROTOCOLVERSION "+cimattr);


            node=node.mustChildFindElement(XMLNode.XML_ELEMENT_SIMPLEEXPREQ);

            node=node.mustChildFindElement(XMLNode.XML_ELEMENT_EXPMETHODCALL);
            String expIndName =node.mustGetAttribute(NAME);

            node=node.mustChildFindElement(XMLNode.XML_ELEMENT_EXPPARAMVALUE);
            String expParamName=node.mustGetAttribute(NAME);

            node=node.getChild();
            if (node==null)
               throw new CIMException(CIMException.CIM_ERR_INVALID_PARAMETER,
                  "No XML_ELEMENT_IRETURNVALUE (22)");

            sendIndResponse(insocket, id, expIndName);

            CIMInstance ci=new CIMInstance(node);
            CIMIndication ev=new CIMIndication(ci);

            synchronized (ci) 
	    {
               cl.indicationOccured(ev, reqURL);
            }
         }
         catch (Exception e) 
	 {
            if (GlobalConfig.DEBUG_XML)
            {
               Log.println("Invalid Indication document: "+e);
               Log.println("CIMHTTPIndicationReceiver -Exception: "+e);
            }
            try 
	    {
               reader.close();
            } catch (IOException e3)   { return; }
            return;
         }
      }
   }

};


class CIMHTTPIndicationReceiver extends Thread
{
   CIMListener cl=null;
   ServerSocket ss=null;

   public CIMHTTPIndicationReceiver(ServerSocket sock, CIMListener ccl)
   {
      ss=sock;
      cl = ccl;
   }

   public void run() 
   {
      try 
      {

         for (;;) 
	 {
            Socket incoming=ss.accept( );
            new ThreadedIndReceiver(incoming,cl).start();
         }
      }
      catch (Exception e) 
      {
            if (GlobalConfig.DEBUG_XML)
            {
               Log.println("CIMHTTPIndicationReceiver -Exception: "+e);
            }
      }
   }
};
