com.jkoolcloud.tnt4j.streams.inputs.WsStream.java Source code

Java tutorial

Introduction

Here is the source code for com.jkoolcloud.tnt4j.streams.inputs.WsStream.java

Source

/*
 * Copyright 2014-2017 JKOOL, LLC.
 *
 * Licensed 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 com.jkoolcloud.tnt4j.streams.inputs;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.soap.*;

import org.apache.commons.lang3.StringUtils;
import org.quartz.*;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;

import com.jkoolcloud.tnt4j.core.OpLevel;
import com.jkoolcloud.tnt4j.sink.DefaultEventSinkFactory;
import com.jkoolcloud.tnt4j.sink.EventSink;
import com.jkoolcloud.tnt4j.streams.parsers.ActivityParser;
import com.jkoolcloud.tnt4j.streams.scenario.WsScenario;
import com.jkoolcloud.tnt4j.streams.scenario.WsScenarioStep;
import com.jkoolcloud.tnt4j.streams.utils.StreamsResources;
import com.jkoolcloud.tnt4j.streams.utils.Utils;
import com.jkoolcloud.tnt4j.streams.utils.WsStreamConstants;

/**
 * Implements a scheduled JAX-WS service call activity stream, where each call response is assumed to represent a single
 * activity or event which should be recorded.
 * <p>
 * Service call is performed by invoking {@link SOAPConnection#call(SOAPMessage, Object)}. Provided request XML data is
 * set as {@link SOAPMessage} body data.
 * <p>
 * This activity stream requires parsers that can support {@link String} data.
 * <p>
 * This activity stream supports properties from {@link AbstractWsStream} (and higher hierarchy streams).
 *
 * @version $Revision: 1 $
 *
 * @see ActivityParser#isDataClassSupported(Object)
 * @see SOAPConnection#call(SOAPMessage, Object)
 */
public class WsStream extends AbstractWsStream {
    private static final EventSink LOGGER = DefaultEventSinkFactory.defaultEventSink(WsStream.class);

    /**
     * Constructs an empty WsStream. Requires configuration settings to set input stream source.
     */
    public WsStream() {
        super();
    }

    @Override
    protected EventSink logger() {
        return LOGGER;
    }

    @Override
    protected JobDetail buildJob(WsScenario scenario, WsScenarioStep step, JobDataMap jobAttrs) {
        jobAttrs.put(JOB_PROP_URL_KEY, step.getUrlStr());
        jobAttrs.put(JOB_PROP_REQ_KEY, step.getRequest());

        return JobBuilder.newJob(WsCallJob.class).withIdentity(scenario.getName() + ':' + step.getName()) // NON-NLS
                .usingJobData(jobAttrs).build();
    }

    /**
     * Performs JAX-WS service call using SOAP API.
     *
     * @param url
     *            JAX-WS service URL
     * @param soapRequestData
     *            JAX-WS service request data: headers and body XML string
     * @return service response string
     * @throws Exception
     *             if exception occurs while performing JAX-WS service call
     */
    protected static String callWebService(String url, String soapRequestData) throws Exception {
        if (StringUtils.isEmpty(url)) {
            LOGGER.log(OpLevel.DEBUG, StreamsResources.getString(WsStreamConstants.RESOURCE_BUNDLE_NAME,
                    "WsStream.cant.execute.request"), url);
            return null;
        }

        LOGGER.log(OpLevel.DEBUG,
                StreamsResources.getString(WsStreamConstants.RESOURCE_BUNDLE_NAME, "WsStream.invoking.request"),
                url, soapRequestData);

        Map<String, String> headers = new HashMap<>();
        // separate SOAP message header values from request body XML
        BufferedReader br = new BufferedReader(new StringReader(soapRequestData));
        StringBuilder sb = new StringBuilder();
        try {
            String line;
            while ((line = br.readLine()) != null) {
                if (line.trim().startsWith("<")) { // NON-NLS
                    sb.append(line).append(Utils.NEW_LINE);
                } else {
                    int bi = line.indexOf(':'); // NON-NLS
                    if (bi >= 0) {
                        String hKey = line.substring(0, bi).trim();
                        String hValue = line.substring(bi + 1).trim();
                        headers.put(hKey, hValue);
                    } else {
                        sb.append(line).append(Utils.NEW_LINE);
                    }
                }
            }
        } finally {
            Utils.close(br);
        }

        soapRequestData = sb.toString();

        LOGGER.log(OpLevel.DEBUG,
                StreamsResources.getString(WsStreamConstants.RESOURCE_BUNDLE_NAME, "WsStream.invoking.request"),
                url, soapRequestData);

        // Create Request body XML document
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document doc = builder.parse(new InputSource(new StringReader(soapRequestData)));

        // Create SOAP Connection
        SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance();
        SOAPConnection soapConnection = soapConnectionFactory.createConnection();

        // Create SOAP message and set request XML as body
        SOAPMessage soapRequest = MessageFactory.newInstance().createMessage();

        // SOAPPart part = soapRequest.getSOAPPart();
        // SOAPEnvelope envelope = part.getEnvelope();
        // envelope.addNamespaceDeclaration();

        if (!headers.isEmpty()) {
            MimeHeaders mimeHeaders = soapRequest.getMimeHeaders();

            for (Map.Entry<String, String> e : headers.entrySet()) {
                mimeHeaders.addHeader(e.getKey(), e.getValue());
            }
        }

        SOAPBody body = soapRequest.getSOAPBody();
        body.addDocument(doc);
        soapRequest.saveChanges();

        // Send SOAP Message to SOAP Server
        SOAPMessage soapResponse = soapConnection.call(soapRequest, url);

        ByteArrayOutputStream soapResponseBaos = new ByteArrayOutputStream();
        soapResponse.writeTo(soapResponseBaos);
        String soapResponseXml = soapResponseBaos.toString();

        return soapResponseXml;
    }

    /**
     * Scheduler job to execute JAX-WS call.
     */
    public static class WsCallJob implements Job {

        /**
         * Constructs a new WsCallJob.
         */
        public WsCallJob() {
        }

        @Override
        public void execute(JobExecutionContext context) throws JobExecutionException {
            String respStr = null;

            JobDataMap dataMap = context.getJobDetail().getJobDataMap();

            AbstractWsStream stream = (AbstractWsStream) dataMap.get(JOB_PROP_STREAM_KEY);
            String urlStr = dataMap.getString(JOB_PROP_URL_KEY);
            String reqData = dataMap.getString(JOB_PROP_REQ_KEY);

            try {
                respStr = callWebService(urlStr, reqData);
            } catch (Exception exc) {
                LOGGER.log(OpLevel.WARNING, StreamsResources.getString(WsStreamConstants.RESOURCE_BUNDLE_NAME,
                        "WsStream.execute.exception"), exc);
            }

            if (StringUtils.isNotEmpty(respStr)) {
                stream.addInputToBuffer(respStr);
            }
        }
    }
}