org.github.alexwibowo.opentext.client.AxiomVRDClient.java Source code

Java tutorial

Introduction

Here is the source code for org.github.alexwibowo.opentext.client.AxiomVRDClient.java

Source

package org.github.alexwibowo.opentext.client;

import com.google.common.base.Function;
import com.vignette._2014._04._14.vignettequery.*;
import com.vignette.rd.webservices.record.Execute;
import org.apache.axiom.attachments.Attachments;
import org.apache.axiom.om.*;
import org.apache.axiom.om.impl.MTOMXMLStreamWriter;
import org.apache.axiom.soap.SOAPEnvelope;
import org.apache.axiom.soap.SOAPFactory;
import org.apache.axiom.util.UIDGenerator;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.github.alexwibowo.activation.MultipartHttpResponseDataSource;
import org.github.alexwibowo.opentext.domain.DocumentMetadata;
import org.github.alexwibowo.opentext.domain.VRDOperationQName;
import org.github.alexwibowo.opentext.VRDXmlUtil;
import org.github.alexwibowo.opentext.client.cfg.VRDConfiguration;
import org.github.alexwibowo.opentext.domain.VRDDocumentVersion;
import org.github.alexwibowo.xml.soap.AxiomSOAP11MessageBuilder;
import org.github.alexwibowo.xml.soap.SOAPMessageBuilder;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.BodyPart;
import javax.mail.internet.WibMimeMultipart;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.namespace.QName;
import java.io.*;
import java.util.List;
import java.util.Map;

import static com.google.common.collect.Lists.transform;
import static org.apache.commons.io.IOUtils.copy;
import static org.github.alexwibowo.opentext.domain.VRDOperationQName.GetRendition;

/**
 * User: alexwibowo
 */
public class AxiomVRDClient implements VRDClient {

    private final JAXBContext jaxbContext;

    private final VRDConfiguration configuration;

    private static final OMFactory factory;

    static {
        factory = OMAbstractFactory.getOMFactory();
    }

    private final SOAPFactory soap11Factory;

    public AxiomVRDClient(JAXBContext jaxbContext, VRDConfiguration configuration, SOAPFactory soap11Factory) {
        this.jaxbContext = jaxbContext;
        this.configuration = configuration;
        this.soap11Factory = soap11Factory;
    }

    @Override
    public void getDocument(String recordID, String section, String renditionType, VRDDocumentVersion version,
            OutputStream outputStream) throws Exception {
        // create vrd namespace without prefix. This is important, as crazy VRD doesnt like prefix.
        OMNamespace vrdNamespace = factory.createOMNamespace("http://record.webservices.rd.vignette.com/", "");

        OMElement getRenditionElement = factory.createOMElement("getRendition", vrdNamespace);

        OMElement recordIdElement = factory.createOMElement("recordID", vrdNamespace);
        recordIdElement.setText(recordID);
        getRenditionElement.addChild(recordIdElement);

        OMElement sectionElement = factory.createOMElement("section", vrdNamespace);
        sectionElement.setText(section);
        getRenditionElement.addChild(sectionElement);

        OMElement subSectionElement = factory.createOMElement("subSection", vrdNamespace);
        subSectionElement.setText("0");
        getRenditionElement.addChild(subSectionElement);

        OMElement renditionTypeElement = factory.createOMElement("renditionType", vrdNamespace);
        renditionTypeElement.setText(StringUtils.isBlank(renditionType) ? "ORIGINAL" : renditionType);
        getRenditionElement.addChild(renditionTypeElement);

        OMElement versionElement = factory.createOMElement("version", vrdNamespace);
        versionElement.setText(version.name());
        getRenditionElement.addChild(versionElement);

        SOAPMessageBuilder soap11MessageBuilder = new AxiomSOAP11MessageBuilder(jaxbContext, soap11Factory)
                .withPayload(getRenditionElement)
                .withUsernameToken(configuration.getUsername(), configuration.getPassword());

        SOAPEnvelope envelope = (SOAPEnvelope) soap11MessageBuilder.build();
        HttpResponse httpResponse = postAsMultipart(envelope, GetRendition.getQName());

        if (httpResponse.getStatusLine() != null && httpResponse.getStatusLine().getStatusCode() == 200) {
            if (httpResponse.getEntity() != null && httpResponse.getEntity().getContent() != null) {
                String contentType = httpResponse.getFirstHeader("Content-Type").getValue();
                InputStream responseAsStream = httpResponse.getEntity().getContent();

                MultipartHttpResponseDataSource dataSource = new MultipartHttpResponseDataSource(responseAsStream,
                        contentType);
                WibMimeMultipart mp = new WibMimeMultipart(dataSource);
                BodyPart bodyPart = mp.getBodyPart(1);

                ByteArrayInputStream content = (ByteArrayInputStream) bodyPart.getContent();
                copy(content, outputStream);
            } else {
                throw new GeneralVRDException("No valid response for getting document from VRD.", null); // need a better structure here..
            }
        } else {
            InputStream in = httpResponse.getEntity().getContent();
            SOAPEnvelope response = OMXMLBuilderFactory.createSOAPModelBuilder(in, "UTF-8").getSOAPEnvelope();
            OMElement fault = response.getBody()
                    .getFirstChildWithName(new QName("http://schemas.xmlsoap.org/soap/envelope/", "Fault"));
            OMElement detail = fault.getFirstChildWithName(new QName("detail")).getFirstElement();
            String vrdResponseXML = detail.toString();
            throw new GeneralVRDException(vrdResponseXML, null); // need a better structure here..
        }
    }

    @Override
    public String storeDocument(String documentSource, Map<String, Object> sourceAttributes, String mimeType,
            File file) throws Exception {
        OMNamespace ns1 = factory.createOMNamespace("http://record.webservices.rd.vignette.com/", "");

        OMElement addRecordMappedElement = factory.createOMElement("addRecordMapped", ns1);

        OMElement licenseElement = factory.createOMElement("license", ns1);
        addRecordMappedElement.addChild(licenseElement);

        OMElement docSourceNameElement = factory.createOMElement("docSourceName", ns1);
        docSourceNameElement.setText(documentSource);
        addRecordMappedElement.addChild(docSourceNameElement);

        OMElement sourceVREFElement = factory.createOMElement("sourceVREF", ns1);
        sourceVREFElement.setText("");
        addRecordMappedElement.addChild(sourceVREFElement);

        for (Map.Entry<String, Object> attributeEntry : sourceAttributes.entrySet()) {
            addRecordMappedElement.addChild(createAttributeElement(factory, ns1, attributeEntry));
        }

        OMElement contentElement = factory.createOMElement("content", ns1);
        OMElement sectionIDElement = factory.createOMElement("sectionID", ns1);
        sectionIDElement.setText("1");
        contentElement.addChild(sectionIDElement);
        OMElement sectionDataElement = factory.createOMElement("sectionData", ns1);
        DataHandler dataHandler = new DataHandler(new FileDataSource(file));
        sectionDataElement.addChild(factory.createOMText(dataHandler, true));
        contentElement.addChild(sectionDataElement);
        OMElement renditionTypeElement = factory.createOMElement("renditionType", ns1);
        renditionTypeElement.setText(mimeType);
        contentElement.addChild(renditionTypeElement);

        addRecordMappedElement.addChild(contentElement);
        addRecordMappedElement.addChild(getOptionElement(factory, ns1));

        SOAPMessageBuilder soap11MessageBuilder = new AxiomSOAP11MessageBuilder(jaxbContext, soap11Factory)
                .withPayload(addRecordMappedElement)
                .withUsernameToken(configuration.getUsername(), configuration.getPassword());

        SOAPEnvelope envelope = (SOAPEnvelope) soap11MessageBuilder.build();
        HttpResponse httpResponse = postAsMultipart(envelope, VRDOperationQName.AddRecordMapped.getQName());

        dataHandler.getInputStream().close();

        if (httpResponse.getEntity() != null && httpResponse.getEntity().getContent() != null) {
            InputStream in = httpResponse.getEntity().getContent();
            Attachments attachments = new Attachments(in, httpResponse.getEntity().getContentType().getValue());
            SOAPEnvelope response = OMXMLBuilderFactory.createSOAPModelBuilder(attachments).getSOAPEnvelope();

            // retrieveContentResponse is addRecordMappedResponse
            OMElement addRecordMappedResponseElement = response.getBody().getFirstElement();

            // Unfortunately, our beautiful VRD responds with 'recDesc' in a null namespace. Hence if we use JAXB to unmarshall the response, we will get
            // null recDesc inside AddRecordMappedResponse object. such is life..
            OMElement recordDescElement = addRecordMappedResponseElement.getFirstElement();

            String recordID = recordDescElement.getFirstChildWithName(new QName("recordID")).getText();
            IOUtils.closeQuietly(in);
            return recordID;
        }
        return null;
    }

    @Override
    public List<DocumentMetadata> getMetadata(List<String> recordAttributesToBeRetrieved,
            List<String> attributesToBeRetrieved, List<ConditionType> conditions, Long maximumRecordsToRetrieve)
            throws Exception {
        DataSource dataSource = new DataSource();
        QueryType queryType = new QueryType();
        queryType.setAction(ActionType.SELECT);
        queryType.setSource("#DEFAULT_FILEPLAN#");
        if (!recordAttributesToBeRetrieved.isEmpty() || !attributesToBeRetrieved.isEmpty()) {
            queryType.setAttrs(new QueryType.Attrs());
            for (String recordAttribute : recordAttributesToBeRetrieved) {
                queryType.getAttrs().getRecordAttr().add(recordAttribute);
            }
            for (String attribute : attributesToBeRetrieved) {
                queryType.getAttrs().getAttr().add(attribute);
            }
        }
        if (!conditions.isEmpty()) {
            queryType.setConditions(new QueryType.Conditions());
            for (ConditionType condition : conditions) {
                queryType.getConditions().getCondition().add(condition);
            }
        }
        dataSource.getQuery().add(queryType);

        StringWriter sw = new StringWriter();
        Marshaller marshaller = jaxbContext.createMarshaller();
        marshaller.marshal(dataSource, sw);

        Execute execute = new Execute();
        execute.setLicense("");
        execute.setXmlRequest(sw.toString());

        SOAPMessageBuilder soap11MessageBuilder = new AxiomSOAP11MessageBuilder(jaxbContext, soap11Factory)
                .withPayload(execute).withUsernameToken(configuration.getUsername(), configuration.getPassword());

        SOAPEnvelope envelope = (SOAPEnvelope) soap11MessageBuilder.build();
        HttpResponse httpResponse = simplePost(envelope, VRDOperationQName.Execute.getQName());

        if (httpResponse.getEntity() != null && httpResponse.getEntity().getContent() != null) {
            InputStream in = httpResponse.getEntity().getContent();
            SOAPEnvelope response = OMXMLBuilderFactory.createSOAPModelBuilder(in, "UTF-8").getSOAPEnvelope();
            OMElement retrieveContentResponse = response.getBody().getFirstElement();
            OMElement content = retrieveContentResponse.getFirstElement();
            DataSource dataSourceResult = new VRDXmlUtil(jaxbContext).parseResponse(content.getText());
            return convertToVRDMetadata(dataSourceResult.getQueryResult());
        }

        return null;
    }

    private List<DocumentMetadata> convertToVRDMetadata(List<QueryResultType> searchResults) {
        QueryResultType queryResultType = searchResults.get(0);
        List<DocumentMetadata> result = transform(queryResultType.getDataItem(),
                new Function<DataItemType, DocumentMetadata>() {
                    public DocumentMetadata apply(DataItemType vrdRecord) {
                        return new DocumentMetadata(vrdRecord.getValue());
                    }
                });
        return result;
    }

    private OMNode createAttributeElement(OMFactory factory, OMNamespace ns1,
            Map.Entry<String, Object> attributeEntry) {
        OMElement attributesElement = factory.createOMElement("attributes", ns1);

        if (attributeEntry.getValue() instanceof Iterable) {
            Iterable iterableValues = (Iterable) attributeEntry.getValue();
            for (Object iterableValue : iterableValues) {
                OMElement nameElement = factory.createOMElement("name", ns1);
                nameElement.setText(attributeEntry.getKey());
                OMElement valueElement = factory.createOMElement("value", ns1);
                valueElement.setText((String) iterableValue);
                attributesElement.addChild(nameElement);
                attributesElement.addChild(valueElement);
            }
        } else {
            OMElement nameElement = factory.createOMElement("name", ns1);
            nameElement.setText(attributeEntry.getKey());
            OMElement valueElement = factory.createOMElement("value", ns1);
            valueElement.setText((String) attributeEntry.getValue());
            attributesElement.addChild(nameElement);
            attributesElement.addChild(valueElement);
        }
        return attributesElement;
    }

    private OMElement getOptionElement(OMFactory factory, OMNamespace ns1) {
        OMElement optionElement = factory.createOMElement("option", ns1);

        OMElement nameElement = factory.createOMElement("name", ns1);
        nameElement.setText("finalize");
        OMElement valueElement = factory.createOMElement("value", ns1);
        valueElement.setText("false");

        optionElement.addChild(nameElement);
        optionElement.addChild(valueElement);
        return optionElement;

    }

    private HttpResponse postAsMultipart(SOAPEnvelope envelope, String soapAction) throws Exception {
        DefaultHttpClient client = new DefaultHttpClient();

        HttpPost request = new HttpPost(configuration.getEndpoint());
        request.addHeader("SOAPAction", soapAction);
        request.addHeader("Pragma", "no-cache");
        request.addHeader("Cache-Control", "no-cache");
        request.addHeader("Accept", "application/soap+xml, application/dime, multipart/related, text/*");

        String boundary = UIDGenerator.generateMimeBoundary();
        String rootContentId = "0." + UIDGenerator.generateContentId();

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        OMOutputFormat format = new OMOutputFormat();
        format.setCharSetEncoding("UTF-8");
        format.setMimeBoundary(boundary);
        format.setRootContentId(rootContentId);
        format.setDoOptimize(true);
        String contentTypeForMTOM = format.getContentTypeForMTOM("text/xml");
        request.addHeader("Content-Type", contentTypeForMTOM);

        MTOMXMLStreamWriter mtomxmlStreamWriter = new MTOMXMLStreamWriter(baos, format);
        mtomxmlStreamWriter.setDoOptimize(true);
        envelope.serialize(mtomxmlStreamWriter);

        request.setEntity(new ByteArrayEntity(baos.toByteArray()));
        HttpResponse response = client.execute(request);
        return response;
    }

    private HttpResponse simplePost(SOAPEnvelope envelope, String soapAction) throws Exception {
        DefaultHttpClient client = new DefaultHttpClient();

        HttpPost request = new HttpPost(configuration.getEndpoint());
        request.addHeader("SOAPAction", soapAction);
        request.addHeader("Pragma", "no-cache");
        request.addHeader("Cache-Control", "no-cache");
        request.addHeader("Accept", "application/soap+xml");

        StringWriter sw = new StringWriter();
        envelope.serialize(sw);
        String string = sw.toString();
        request.setEntity(new StringEntity(string));
        HttpResponse response = client.execute(request);
        return response;
    }

}