edu.wisc.hrs.dao.BaseHrsSoapDao.java Source code

Java tutorial

Introduction

Here is the source code for edu.wisc.hrs.dao.BaseHrsSoapDao.java

Source

/**
 * Licensed to Jasig under one or more contributor license
 * agreements. See the NOTICE file distributed with this work
 * for additional information regarding copyright ownership.
 * Jasig 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 edu.wisc.hrs.dao;

import java.util.Iterator;

import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.ws.client.WebServiceFaultException;
import org.springframework.ws.client.core.WebServiceOperations;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.soap.SoapFault;
import org.springframework.ws.soap.SoapFaultDetail;
import org.springframework.ws.soap.SoapFaultDetailElement;
import org.springframework.ws.soap.client.SoapFaultClientException;
import org.w3c.dom.Node;

import edu.wisc.ws.client.support.SetSoapActionCallback;

/**
 * Base class for HRS Web Services. Provides common invocation and error handling logic
 * 
 * @author Eric Dalquist
 * @version $Revision: 1.2 $
 */
public abstract class BaseHrsSoapDao {
    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    private SetSoapActionCallback soapActionCallback;

    @Required
    public void setSoapAction(String soapAction) {
        this.soapActionCallback = new SetSoapActionCallback(soapAction);
    }

    protected abstract WebServiceOperations getWebServiceOperations();

    /**
     * Calls {@link WebServiceTemplate#marshalSendAndReceive(Object)} on the passed
     * in argument, and returns the result.
     * 
     * In the event a SOAP Fault occurs (e.g. {@link SoapFaultClientException}, this method
     * inspects the faultStringOrReason field. 
     * Based on the contents of that field, this method may throw a {@link ClientRuntimeException} or
     * return null.
     * 
     * null return values are used as hints to callers that they should throw either the checked
     * {@link ClassNotFoundException}.
     * 
     * @param request
     * @return the result of {@link WebServiceTemplate#marshalSendAndReceive(Object)}, or null if the caller should throw a {@link ClassNotFoundException}
     * @throws AuthenticationFailedException if the username/password configured on the webServiceTemplate are incorrect
     * @throws AuthorizationFailedException if the user is authenticated but not authorized to call the particular method
     * @throws WebServiceFaultException for other soap faults
     */
    @SuppressWarnings("unchecked")
    protected <T> T internalInvoke(Object request) {
        final WebServiceOperations webServiceOperations = this.getWebServiceOperations();
        try {
            return (T) webServiceOperations.marshalSendAndReceive(request, this.soapActionCallback);
        } catch (SoapFaultClientException e) {
            final StringBuilder errorMessage = new StringBuilder("Failed to call ");
            errorMessage.append(this.soapActionCallback.getSoapAction());
            errorMessage.append(" with ");
            errorMessage.append(request);

            final SoapFault soapFault = e.getSoapFault();
            final SoapFaultDetail faultDetail = soapFault.getFaultDetail();

            for (final Iterator<SoapFaultDetailElement> detailEntryItr = faultDetail
                    .getDetailEntries(); detailEntryItr.hasNext();) {
                final SoapFaultDetailElement detailEntry = detailEntryItr.next();
                final Source source = detailEntry.getSource();

                //              TODO Once PS adds a namespace declaration to the fault document unmarshaller can be used to pull out the error message
                //              final Object result = this.unmarshaller.unmarshal(source);

                final Node node = this.getNode(source);
                if (node == null) {
                    //Couldn't turn the source into a node, no detailed error message for us :(
                    continue;
                }

                final String defaultTitle = evaluateXPath(node, "DefaultTitle");
                final String defaultMessage = evaluateXPath(node, "DefaultMessage");

                errorMessage.append("\n\t").append(defaultTitle).append(" - ").append(defaultMessage);
            }

            final WebServiceFaultException webServiceFaultException = new WebServiceFaultException(
                    errorMessage.toString());
            webServiceFaultException.initCause(e);
            throw webServiceFaultException;
        }
    }

    protected Node getNode(Source source) {
        if (source instanceof DOMSource) {
            return ((DOMSource) source).getNode();
        }

        //Not a DOM source, transform into a DOM node
        try {
            final TransformerFactory transformerFactory = TransformerFactory.newInstance();
            final Transformer transformer = transformerFactory.newTransformer();
            final DOMResult domResult = new DOMResult();
            transformer.transform(source, domResult);
            return domResult.getNode();
        } catch (TransformerConfigurationException tce) {
            //ignore this SoapFaultDetailElement since sadly it could not be converted to a DOM Node
            return null;
        } catch (TransformerException te) {
            //ignore this SoapFaultDetailElement since sadly it could not be converted to a DOM Node
            return null;
        }
    }

    protected String evaluateXPath(Node node, String expression) {
        final XPathFactory xpathFactory = XPathFactory.newInstance();
        final XPath xPath = xpathFactory.newXPath();
        final XPathExpression xpathExpression;
        try {
            xpathExpression = xPath.compile(expression);
        } catch (XPathExpressionException e) {
            return null;
        }

        try {
            return xpathExpression.evaluate(node);
        } catch (XPathExpressionException e) {
            return null;
        }
    }
}