/*
 * Created on Apr 3, 2006
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
package com.fujitsu.nextgrid.byteio.faults;

import org.apache.axis2.AxisFault;
import org.apache.ws.commons.om.OMElement;
import org.apache.ws.commons.om.OMNamespace;
import org.apache.ws.commons.soap.SOAPEnvelope;
import org.apache.ws.commons.soap.SOAPFactory;
import org.apache.ws.commons.soap.SOAPFault;
import org.apache.xmlbeans.XmlException;

import com.fujitsu.nextgrid.byteio.SOAP11Constants;


/**
 * Abstract base class for all kinds of Web Services Faults
 * 
 * @author Michel Drescher, Fujitsu Laboratories of Europe, Ltd.
 *
 */
public abstract class SOAPFaultException 
extends Exception {

    /** ------------------------------------------------------------------------------------------- STATIC VARIABLES **/
    
    public enum FaultCode {
        Client ("Client"),
        Server ("Server");

        private String name;

        FaultCode(String name) {
            this.name = name;
        }
        
        String toString( OMNamespace ns ) {
            StringBuffer buf = new StringBuffer();
            buf.append( ns.getPrefix() );
            buf.append( ":" );
            buf.append( name );
            return buf.toString();
        }
        FaultCode createFromXML( String xml ) {
            if ( xml.indexOf( FaultCode.Client.name ) > -1 ) {
                return FaultCode.Client;
            }
            return FaultCode.Server;
        }
    }



    /** --------------------------------------------------------------------------------------------- STATIC METHODS **/
    
    public static SOAPFaultException createFromXML( SOAPEnvelope envelope ) throws AxisFault {
        if ( !envelope.getBody().hasFault() ) return null;
        SOAPFault faultXML = envelope.getBody().getFault();
        // first create create an appropriate subclass
        String faultName = faultXML.getDetail().getFirstElement().getLocalName();
        SOAPFaultException fault = null;
        try {
            Class faultClass = Class.forName( "com.fujitsu.nextgrid.byteio.faults."+faultName );
            fault = (SOAPFaultException) faultClass.newInstance();
        }
        catch ( ClassNotFoundException cnfe ) {
            throw new RuntimeException( "Could not find the appropriate class for fault " + faultName );
        }
        catch ( InstantiationException ie ) {
            throw new RuntimeException( "Could not instantiate class " + faultName );
        }
        catch ( IllegalAccessException iae ) {
            throw new RuntimeException( "Could not illegal access exception for class " + faultName + ": " + iae.getMessage() );
        }
        // now extract the fault detail and let the instance populate itself with it
        OMElement firstDetail = faultXML.getDetail().getFirstElement();
        try {
            fault.populateFromXML( firstDetail );
        } catch ( XmlException xe ) { throw new AxisFault( xe ); }
        // complete the residual information for SOAP faults
        fault.setFaultCode( FaultCode.Client.createFromXML( faultXML.getCode().getValue().getText() ) );
        fault.setReason( faultXML.getReason().getSOAPText().getText() );
        fault.setActor( faultXML.getRole().getRoleValue() );
        
        return fault;
    }
    
    /** ----------------------------------------------------------------------------------------- INSTANCE VARIABLES **/
    
    private FaultCode faultCode = FaultCode.Client;
    private String reason; 
    private String faultActorURI;
    
    /** ----------------------------------------------------------------------------------------------- CONSTRUCTORS **/
    
    public SOAPFaultException() {
    }
    
    public SOAPFaultException( String message, String faultActorURI ) {
        this( FaultCode.Client, message, faultActorURI );
    }

    public SOAPFaultException( FaultCode faultCode, String message, String faultActorURI ) {
        reason = message;
        this.faultCode = faultCode;
        this.faultActorURI = faultActorURI;
    }

    /** --------------------------------------------------------------------------------------------- PUBLIC METHODS **/

    public SOAPEnvelope getEnvelope( SOAPFactory factory ) {
        SOAPEnvelope envelope = factory.getDefaultFaultEnvelope();
        // SOAP 1.1 namespace
        OMNamespace s11 = envelope.findNamespaceURI( SOAP11Constants.NS_SOAP11 );
        // fault code
        if ( s11 == null ) {
            s11 = factory.createOMNamespace( SOAP11Constants.NS_SOAP11, "s11" );
            envelope.getBody().getFault().getCode().declareNamespace( s11 );
        }
        envelope.getBody().getFault().getCode().getValue().setText( faultCode.toString( s11 ) );
        // fault reason
        envelope.getBody().getFault().getReason().getSOAPText().setText( reason );
        // fault actor (SOAP 1.1) or fault role (SOAP 1.2)
        envelope.getBody().getFault().getRole().setRoleValue( faultActorURI );
        // fault detail
        envelope.getBody().getFault().getDetail().addChild( getFaultDetail() );
        // return the envelope
        return envelope;
    }
    
    public String getReason() {
        return reason;
    }
    
    public FaultCode getFaultCode() {
        return faultCode;
    }
    
    public String getFaultActor() {
        return faultActorURI;
    }

    /** ------------------------------------------------------------------------------------------ PROTECTED METHODS **/

    protected abstract OMElement getFaultDetail();

    protected abstract void populateFromXML( OMElement element ) throws XmlException;

    /** -------------------------------------------------------------------------------------------- PRIVATE METHODS **/
    
    private void setReason( String reason ) {
        this.reason = reason;
    }
    
    private void setFaultCode( FaultCode code ) {
        faultCode = code;
    }
    
    private void setActor( String actor ) {
        faultActorURI = actor;
    }
    
}


//
// Copyright (c) Fujitsu Ltd 2000 - 2006
//
// Use and distribution is subject a License.
// A copy was supplied with the distribution (see documentation or the jar file).
//
// This product includes software developed by Fujitsu Limited (http://www.fujitsu.com).
