org.nimbustools.messaging.query.AxisBodyWriter.java Source code

Java tutorial

Introduction

Here is the source code for org.nimbustools.messaging.query.AxisBodyWriter.java

Source

/*
 * Copyright 1999-2009 University of Chicago
 *
 * 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 org.nimbustools.messaging.query;

import org.apache.axis.description.TypeDesc;
import org.apache.axis.message.MessageElement;
import org.apache.axis.encoding.SerializationContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.cxf.jaxrs.ext.MessageContext;
import org.xml.sax.Attributes;

import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.*;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.List;

@Provider
@Produces({ "text/xml" })
public class AxisBodyWriter implements MessageBodyWriter<Object> {

    private static final Log logger = LogFactory.getLog(AxisBodyWriter.class.getName());

    private static final String GET_TYPE_DESC = "getTypeDesc";
    private static final String TYPE_SUFFIX = "Type";

    @Context
    MessageContext messageContext;

    // this is a travesty

    public boolean isWriteable(Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType) {

        return getTypeDescVerySlowly(aClass) != null;
    }

    public long getSize(Object o, Class aClass, Type type, Annotation[] annotations, MediaType mediaType) {
        return -1;
    }

    public void writeTo(Object o, Class aClass, Type type, Annotation[] annotations, MediaType mediaType,
            MultivaluedMap multivaluedMap, OutputStream outputStream) throws IOException, WebApplicationException {
        final TypeDesc typeDesc = getTypeDescVerySlowly(aClass);

        final QName qName = typeDesc.getXmlType();

        if (qName == null) {
            throw new WebApplicationException(500);
        }

        String name = qName.getLocalPart();
        // responses should not have 'Type' on end of element name. ugly.
        if (name.endsWith(TYPE_SUFFIX)) {
            name = name.substring(0, name.length() - TYPE_SUFFIX.length());
        }

        String namespace = getNamespaceUriFromContext();
        if (namespace == null) {
            namespace = qName.getNamespaceURI();
        }

        final OutputStreamWriter writer = new OutputStreamWriter(outputStream);

        //manually write the xml header deal
        writer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");

        MessageElement element = new MessageElement(name, "", namespace);
        try {
            element.setObjectValue(o);

            final SerializationContext context = new CleanSerializationContext(writer, namespace);
            context.setDoMultiRefs(false);
            context.setPretty(true);
            element.output(context);

        } catch (SOAPException e) {
            throw new WebApplicationException(e);
        } catch (Exception e) {
            throw new WebApplicationException(e);
        }
        writer.close();
    }

    private String getNamespaceUriFromContext() {
        if (this.messageContext != null) {

            final HttpHeaders headers = this.messageContext.getHttpHeaders();
            if (headers != null) {
                final List<String> versionHeaders = headers.getRequestHeader(ElasticQuery.API_VERSION_HEADER);

                if (versionHeaders != null && !versionHeaders.isEmpty()) {
                    final String version = versionHeaders.get(0);
                    if (version.length() > 0) {
                        return "http://ec2.amazonaws.com/doc/" + version + "/";
                    }
                }
            }
        }
        return null;
    }

    private static TypeDesc getTypeDescVerySlowly(Class aClass) {
        try {

            final Method method = aClass.getMethod(GET_TYPE_DESC);
            return (TypeDesc) method.invoke(null);
        } catch (IllegalAccessException e) {
            return null;
        } catch (NoSuchMethodException e) {
            return null;
        } catch (InvocationTargetException e) {
            return null;
        } catch (ClassCastException e) {
            return null;
        }
    }

}

class CleanSerializationContext extends SerializationContext {
    private final String defaultNamespace;

    public CleanSerializationContext(Writer writer, String defaultNamespace) {
        super(writer);
        this.defaultNamespace = defaultNamespace;
    }

    @Override
    public boolean shouldSendXSIType() {
        return false;
    }

    @Override
    public void startElement(QName qName, Attributes attributes) throws IOException {
        // for some reason many of the EC2 types are coming through with an empty namespace
        // override it with the one provided at constructor time
        if ("".equals(qName.getNamespaceURI())) {
            qName = new QName(defaultNamespace, qName.getLocalPart());
        }
        super.startElement(qName, attributes);
    }

    // override these to ensure that by default nil elements are left out of
    // serialized XML. Only the first one is apparently called by MessageElement, but
    // overriding both for completeness.

    @Override
    public void serialize(QName elemQName, Attributes attributes, Object value) throws IOException {
        serialize(elemQName, attributes, value, null, Boolean.FALSE, null);
    }

    @Override
    public void serialize(QName elemQName, Attributes attributes, Object value, QName xmlType) throws IOException {
        serialize(elemQName, attributes, value, xmlType, Boolean.FALSE, null);
    }
}