All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.cxf.jaxrs.provider.JAXRSDataBinding Maven / Gradle / Ivy

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF 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 org.apache.cxf.jaxrs.provider;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.validation.Schema;

import org.apache.cxf.databinding.AbstractDataBinding;
import org.apache.cxf.databinding.DataReader;
import org.apache.cxf.databinding.DataWriter;
import org.apache.cxf.jaxrs.impl.MetadataMap;
import org.apache.cxf.message.Attachment;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.PhaseInterceptorChain;
import org.apache.cxf.service.Service;
import org.apache.cxf.service.invoker.MethodDispatcher;
import org.apache.cxf.service.model.BindingOperationInfo;
import org.apache.cxf.service.model.MessagePartInfo;

/**
 * CXF DataBinding implementation wrapping JAX-RS providers
 */
public class JAXRSDataBinding extends AbstractDataBinding {

    private static final Class SUPPORTED_READER_FORMATS[] = new Class[] {XMLStreamReader.class};
    private static final Class SUPPORTED_WRITER_FORMATS[] = new Class[] {XMLStreamWriter.class};
    
    private MessageBodyReader xmlReader;
    private MessageBodyWriter xmlWriter;
    
    @SuppressWarnings("unchecked")
    public void setProvider(Object provider) {
        if (!(provider instanceof MessageBodyWriter)) {
            throw new IllegalArgumentException(
                "The provider must implement javax.ws.rs.ext.MessageBodyWriter");
        }
        xmlWriter = (MessageBodyWriter)provider;
        
        if (provider instanceof MessageBodyReader) {
            xmlReader = (MessageBodyReader)provider;
        }
    }
    
    @SuppressWarnings("unchecked")
    public  DataReader createReader(final Class cls) {
        if (xmlReader == null) {
            throw new IllegalStateException(
                "javax.ws.rs.ext.MessageBodyReader reference is uninitialized");
        }
        return (DataReader)new MessageBodyDataReader();
    }

    @SuppressWarnings("unchecked")
    public  DataWriter createWriter(final Class cls) {
        return (DataWriter)new MessageBodyDataWriter();
    }

    public Class[] getSupportedReaderFormats() {
        return SUPPORTED_READER_FORMATS;
    }

    public Class[] getSupportedWriterFormats() {
        return SUPPORTED_WRITER_FORMATS;
    }

    public void initialize(Service service) {
        // Check how to deal with individual parts if needed, build a single JAXBContext, etc
    }


    // TODO: The method containing the actual annotations have to retrieved 
    protected Method getTargetMethod(Message m) {
        BindingOperationInfo bop = m.getExchange().getBindingOperationInfo();
        MethodDispatcher md = (MethodDispatcher) 
            m.getExchange().getService().get(MethodDispatcher.class.getName());
        return md.getMethod(bop);
    }
    
    @SuppressWarnings("unchecked")
    private MultivaluedMap getHeaders(Message message) {
        return new MetadataMap(
            (Map>)message.get(Message.PROTOCOL_HEADERS), true, true);
    }
    @SuppressWarnings("unchecked")
    private MultivaluedMap getWriteHeaders(Message message) {
        return new MetadataMap(
            (Map>)message.get(Message.PROTOCOL_HEADERS), true, true);
    }
    
    private class MessageBodyDataWriter implements DataWriter {
        
        public void write(Object obj, XMLStreamWriter output) {
            write(obj, null, output);
        }
        
        public void write(Object obj, MessagePartInfo part, XMLStreamWriter output) {
            try {
                Message message = PhaseInterceptorChain.getCurrentMessage();
                Method method = getTargetMethod(message);
                MultivaluedMap headers = getWriteHeaders(message);
                xmlWriter.writeTo(obj, 
                                 method.getReturnType(), 
                                 method.getGenericReturnType(), 
                                 method.getAnnotations(), 
                                 MediaType.APPLICATION_XML_TYPE, 
                                 headers, 
                                 null);
                message.put(Message.PROTOCOL_HEADERS, headers);
            } catch (Exception ex) {
                // ignore
            }
        }

        public void setAttachments(Collection attachments) {
            // complete
        }

        public void setProperty(String key, Object value) {
            // complete
        }

        public void setSchema(Schema s) {
            // complete
        }
    }
    
    private class MessageBodyDataReader implements DataReader {

        public Object read(XMLStreamReader input) {
            throw new UnsupportedOperationException();
        }

        public Object read(MessagePartInfo part, XMLStreamReader input) {
            return doRead(part.getTypeClass(), input);
        }

        public Object read(QName elementQName, XMLStreamReader input, Class type) {
            return doRead(type, input);
        }

        
        @SuppressWarnings("unchecked")
        private  T read(Class cls) throws WebApplicationException, IOException {
            Message message = PhaseInterceptorChain.getCurrentMessage();
            Method method = getTargetMethod(message);
            MessageBodyReader reader = (MessageBodyReader)xmlReader;

            return reader.readFrom(cls, 
                                      method.getGenericParameterTypes()[0], 
                                      method.getParameterTypes()[0].getAnnotations(), 
                                      MediaType.APPLICATION_ATOM_XML_TYPE,
                                      getHeaders(message),             
                                      null);
        }
        private Object doRead(Class cls, XMLStreamReader input) {
            try {
                return read(cls);
            } catch (Exception ex) {
                return null;
            }
        }
        
        public void setAttachments(Collection attachments) {
            // complete
        }

        public void setProperty(String prop, Object value) {
            // complete
        }

        public void setSchema(Schema s) {
            // complete
        }
        
    };
}