/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.apache.axis2.jaxws.handler;

import junit.framework.TestCase;
import org.apache.axis2.jaxws.core.MessageContext;
import org.apache.axis2.jaxws.handler.factory.HandlerPostInvokerFactory;
import org.apache.axis2.jaxws.handler.factory.HandlerPreInvokerFactory;
import org.apache.axis2.jaxws.message.Block;
import org.apache.axis2.jaxws.message.Message;
import org.apache.axis2.jaxws.message.Protocol;
import org.apache.axis2.jaxws.message.factory.MessageFactory;
import org.apache.axis2.jaxws.message.factory.XMLStringBlockFactory;
import org.apache.axis2.jaxws.registry.FactoryRegistry;

import javax.xml.ws.handler.Handler;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import java.util.ArrayList;
import java.util.Set;

/**
 * HandlerPrePostInvokerTests verifies that the mechanisms for finding the implementation classes to 
 * call before and after handler.handleMessage work, and that the calls are actually made.  Simple as that.
 */
public class HandlerPrePostInvokerTests extends TestCase {

	private MessageContext mc = null;
	private boolean preInvokerCalled = false;
	private boolean postInvokerCalled = false;
	
	private static final String soap11env = "http://schemas.xmlsoap.org/soap/envelope/";
	
    public static final String SOAP11_ENVELOPE = 
        "<?xml version='1.0' encoding='utf-8'?>" + 
        "<soapenv:Envelope xmlns:soapenv=\"" + soap11env + "\">" +
        "<soapenv:Header />" + 
        "<soapenv:Body>" +
        "</soapenv:Body>" + 
        "</soapenv:Envelope>";

	@Override
	protected void setUp() throws Exception {

        // Create a SOAP 1.1 Message and MessageContext
		// I just grabbed this code from the JAXWS MessageTests
        MessageFactory mf = (MessageFactory) FactoryRegistry.getFactory(MessageFactory.class);
        Message m = mf.create(Protocol.soap11);
        XMLStringBlockFactory f =
                (XMLStringBlockFactory) FactoryRegistry.getFactory(XMLStringBlockFactory.class);
        Block block = f.createFrom(SOAP11_ENVELOPE, null, null);
        m.setBodyBlock(block);

        mc = new MessageContext();
        mc.setMessage(m);
        mc.setMEPContext(new MEPContext(mc));
	}

	/**
	 * make sure the defaults are as expected
	 *
	 */
	public void testFactoryRegistry() {
		HandlerPreInvokerFactory preFact = (HandlerPreInvokerFactory)FactoryRegistry.getFactory(HandlerPreInvokerFactory.class);
		HandlerPostInvokerFactory postFact = (HandlerPostInvokerFactory)FactoryRegistry.getFactory(HandlerPostInvokerFactory.class);
		HandlerPreInvoker preInvoker = preFact.createHandlerPreInvoker();
		HandlerPostInvoker postInvoker = postFact.createHandlerPostInvoker();
		assertTrue("preInvoker should be instanceof " + org.apache.axis2.jaxws.handler.impl.HandlerPreInvokerImpl.class.getCanonicalName(), preInvoker instanceof org.apache.axis2.jaxws.handler.impl.HandlerPreInvokerImpl);
		assertTrue("postInvoker should be instanceof " + org.apache.axis2.jaxws.handler.impl.HandlerPostInvokerImpl.class.getCanonicalName(), postInvoker instanceof org.apache.axis2.jaxws.handler.impl.HandlerPostInvokerImpl);
	}
	
	/**
	 * make sure the registered factories are used, and the calls are made in the places we expect
	 *
	 */
	public void testFactoryPrePost() {
		
		FactoryRegistry.setFactory(HandlerPreInvokerFactory.class, new HandlerPreInvokerFactoryImpl());
		FactoryRegistry.setFactory(HandlerPostInvokerFactory.class, new HandlerPostInvokerFactoryImpl());
		
		ArrayList<Handler> handlers = new ArrayList<Handler>();
		handlers.add(new SOAPHandler1());
        HandlerChainProcessor processor =
                new HandlerChainProcessor(handlers, Protocol.soap11);
        boolean success = true;
        try {
            // server-side incoming request
            success = processor.processChain(mc.getMEPContext(),
                                    HandlerChainProcessor.Direction.IN,
                                    HandlerChainProcessor.MEP.REQUEST,
                                    true);
        } catch (Exception e) {
            assertNull(e);  // should not get exception
        }
        
        assertTrue("processChain should have succeeded", success);
        assertTrue("preInvoker should have been called", preInvokerCalled);
        assertTrue("postInvoker should have been called", postInvokerCalled);

	}
	
	/*****************************************
	 * Classes needed for junit testcase     *
	 *****************************************/
	
    private class SOAPHandler1 implements SOAPHandler<SOAPMessageContext> {

        public Set getHeaders() {
            return null;
        }

        public void close(javax.xml.ws.handler.MessageContext messagecontext) {
        }

        public boolean handleFault(SOAPMessageContext messagecontext) {
            return true;
        }

        public boolean handleMessage(SOAPMessageContext messagecontext) {
        	return true;
        }

    }
    
    private class HandlerPreInvokerFactoryImpl implements HandlerPreInvokerFactory {
		public HandlerPreInvoker createHandlerPreInvoker() {
			return new HandlerPreInvokerImpl();
		}
    }
    
    private class HandlerPostInvokerFactoryImpl implements HandlerPostInvokerFactory {
    	public HandlerPostInvoker createHandlerPostInvoker() {
    		return new HandlerPostInvokerImpl();
    	}
    }
    
    private class HandlerPreInvokerImpl implements HandlerPreInvoker {
		public void preInvoke(javax.xml.ws.handler.MessageContext mc) {
			preInvokerCalled = true;
		}
    }
    
    private class HandlerPostInvokerImpl implements HandlerPostInvoker {
		public void postInvoke(javax.xml.ws.handler.MessageContext mc) {
			postInvokerCalled = true;
		}
    }
}
