/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2010, 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.test.ws.jaxws.jbws3027;

import java.net.URL;
import java.text.MessageFormat;
import java.util.UUID;

import javax.xml.namespace.QName;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.Dispatch;
import javax.xml.ws.soap.AddressingFeature;
import javax.xml.ws.soap.SOAPFaultException;

import junit.framework.Test;

import org.jboss.test.ws.jaxws.common.JAXWS_Util;
import org.jboss.test.ws.jaxws.common.WsaSOAPUtils;
import org.jboss.test.ws.jaxws.jbws3027.generated.AddNumbersPortType;
import org.jboss.test.ws.jaxws.jbws3027.generated.AddNumbersService;
import org.jboss.wsf.test.JBossWSTest;
import org.jboss.wsf.test.JBossWSTestSetup;

/**
 * [JBWS-3022] Throw RuntimeExceptions not Protocol exceptions in Addressing Handler.
 *
 * @author <a href="mailto:ropalka@redhat.com">Richard Opalka</a>
 */
public class JBWS3027TestCase extends JBossWSTest
{

   private static final String actionMismatch = "<?xml version=\"1.0\" ?><S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\"><S:Header><To xmlns=\"http://www.w3.org/2005/08/addressing\">{0}</To><Action xmlns=\"http://www.w3.org/2005/08/addressing\">inputAction</Action><MessageID xmlns=\"http://www.w3.org/2005/08/addressing\">uuid:{1}</MessageID><ReplyTo xmlns=\"http://www.w3.org/2005/08/addressing\"><Address>{2}</Address></ReplyTo></S:Header><S:Body><ns1:addNumbers2 xmlns:ns1=\"http://example.com\"><number1>10</number1><number2>10</number2><testName>actionMismatch</testName></ns1:addNumbers2></S:Body></S:Envelope>";

   private static final String actionNotSupported = "<?xml version=\"1.0\" ?><S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\"><S:Header><To xmlns=\"http://www.w3.org/2005/08/addressing\">{0}</To><Action xmlns=\"http://www.w3.org/2005/08/addressing\">ActionNotSupported</Action><MessageID xmlns=\"http://www.w3.org/2005/08/addressing\">uuid:{1}</MessageID><ReplyTo xmlns=\"http://www.w3.org/2005/08/addressing\"><Address>{2}</Address></ReplyTo></S:Header><S:Body><ns1:addNumbers2 xmlns:ns1=\"http://example.com\"><number1>10</number1><number2>10</number2><testName>actionNotSupported</testName></ns1:addNumbers2></S:Body></S:Envelope>";

   private static final String missingActionHeader = "<?xml version=\"1.0\" ?><S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\"><S:Header><To xmlns=\"http://www.w3.org/2005/08/addressing\">{0}</To><MessageID xmlns=\"http://www.w3.org/2005/08/addressing\">uuid:{1}</MessageID><ReplyTo xmlns=\"http://www.w3.org/2005/08/addressing\"><Address>{2}</Address></ReplyTo></S:Header><S:Body><ns1:addNumbers2 xmlns:ns1=\"http://example.com\"><number1>10</number1><number2>10</number2><testName>missingActionHeader</testName></ns1:addNumbers2></S:Body></S:Envelope>";

   private static AddressingFeature DISABLED_ADDRESSING_FEATURE = new AddressingFeature(false);

   private QName PORT_QNAME = new QName("http://example.com", "AddNumbersPort");

   private String endpointURL;

   private URL wsdlURL;

   private AddNumbersPortType port;

   private AddNumbersService service;

   private Dispatch<SOAPMessage> createDispatchSOAPMessage(QName port) throws Exception
   {
      return service.createDispatch(port, SOAPMessage.class, javax.xml.ws.Service.Mode.MESSAGE,
            DISABLED_ADDRESSING_FEATURE);
   }

   public static Test suite()
   {
      return new JBossWSTestSetup(JBWS3027TestCase.class, "jaxws-jbws3027.war");
   }

   protected void setUp() throws Exception
   {
      endpointURL = "http://" + getServerHost() + ":8080/jaxws-jbws3027/Endpoint";
      wsdlURL = new URL(endpointURL + "?wsdl");
      service = new AddNumbersService(wsdlURL);
      port = (AddNumbersPortType) service.getPort(PORT_QNAME, AddNumbersPortType.class);
   }

   public void testDefaultRequestResponseAction() throws Exception
   {
      int number = port.addNumbers2(10, 10, "testDefaultRequestResponseAction");
      log.debug("number=" + number);
   }

   public void testExplicitRequestResponseAction() throws Exception
   {
      int number = port.addNumbers2(10, 10, "testExplicitRequestResponseAction");
      log.debug("number=" + number);
   }

   public void testMessageAddressingHeaderRequiredFault() throws Exception
   {
      try
      {
         String soapMsg = MessageFormat.format(missingActionHeader, endpointURL, UUID.randomUUID(), WsaSOAPUtils
               .getAddrVerAnonUri());
         Dispatch<SOAPMessage> dispatchSM = createDispatchSOAPMessage(PORT_QNAME);
         SOAPMessage request = JAXWS_Util.makeSOAPMessage(soapMsg);
         dispatchSM.invoke(request);
         fail();
      }
      catch (SOAPFaultException e)
      {
         this.assertMessageAddressingHeaderRequiredFaultCode(e);
         this.assertProblemHeaderQName(e);
      }
   }

   public void testActionMismatchOrActionNotSupportedFaultCase1() throws Exception
   {
      try
      {
         String soapMsg = MessageFormat.format(actionMismatch, endpointURL, UUID.randomUUID(), WsaSOAPUtils
               .getAddrVerAnonUri());
         Dispatch<SOAPMessage> dispatchSM = createDispatchSOAPMessage(PORT_QNAME);
         JAXWS_Util.setSOAPACTIONURI(dispatchSM, "ActionMismatch");
         SOAPMessage request = JAXWS_Util.makeSOAPMessage(soapMsg);
         dispatchSM.invoke(request);
         fail();
      }
      catch (SOAPFaultException e)
      {
         this.assertActionMismatchOrActionNotSupportedFaultCode(e);
         this.assertProblemAction(e);
      }
   }

   public void testActionMismatchOrActionNotSupportedFaultCase2() throws Exception
   {
      try
      {
         String soapMsg = MessageFormat.format(actionNotSupported, endpointURL, UUID.randomUUID(), WsaSOAPUtils
               .getAddrVerAnonUri());
         Dispatch<SOAPMessage> dispatchSM = createDispatchSOAPMessage(PORT_QNAME);
         JAXWS_Util.setSOAPACTIONURI(dispatchSM, "ActionNotSupported1");
         SOAPMessage request = JAXWS_Util.makeSOAPMessage(soapMsg);
         dispatchSM.invoke(request);
         fail();
      }
      catch (SOAPFaultException e)
      {
         this.assertActionMismatchOrActionNotSupportedFaultCode(e);
         this.assertProblemAction(e);
      }
   }

   public void testActionMismatchOrActionNotSupportedFaultCase3() throws Exception
   {
      try
      {
         JAXWS_Util.setSOAPACTIONURI(port, "ActionNotSupported2");
         port.addNumbers2(10, 10, "ActionNotSupported2");
         fail();
      }
      catch (SOAPFaultException e)
      {
         this.assertActionMismatchOrActionNotSupportedFaultCode(e);
         this.assertProblemAction(e);
      }
   }

   private void assertActionMismatchOrActionNotSupportedFaultCode(final SOAPFaultException e) throws SOAPException
   {
      final String faultCode = WsaSOAPUtils.getFaultCode(e);
      final boolean expectedFaultCode = WsaSOAPUtils.isActionMismatchFaultCode(e)
            || WsaSOAPUtils.isActionNotSupportedFaultCode(e);
      final String msg = "SOAPFault contains unexpected faultcode got: " + faultCode
            + ", expected: ActionMismatch or ActionNotSupported";

      assertTrue(msg, expectedFaultCode);
   }

   private void assertMessageAddressingHeaderRequiredFaultCode(final SOAPFaultException e) throws SOAPException
   {
      final String faultcode = WsaSOAPUtils.getFaultCode(e);
      final String msg = "SOAPFault contains unexpected faultcode got: " + faultcode
            + ", expected: MessageAddressingHeaderRequired";

      assertTrue(msg, WsaSOAPUtils.isMessageAddressingHeaderRequiredFaultCode(e));
   }

   private void assertProblemHeaderQName(final SOAPFaultException e) throws SOAPException
   {
      final String faultdetail[] = WsaSOAPUtils.getFaultDetail(e);

      if (faultdetail != null)
      {
         final String msg = "FaultDetail contains unexpected value got: " + faultdetail[0]
               + ", expected: ProblemHeaderQName";
         assertTrue(msg, WsaSOAPUtils.isProblemHeaderQNameFaultDetail(faultdetail[0]));
      }
   }

   private void assertProblemAction(final SOAPFaultException e) throws SOAPException
   {
      final String faultdetail[] = WsaSOAPUtils.getFaultDetail(e);

      if (faultdetail != null)
      {
         final String msg = "FaultDetail contains unexpected value got: " + faultdetail[0]
               + ", expected: ProblemAction";

         assertTrue(msg, WsaSOAPUtils.isProblemActionFaultDetail(faultdetail[0]));
      }
   }
}
