alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Apache CXF example source code file (AbstractXOPType.java)

This example Apache CXF source code file (AbstractXOPType.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Apache CXF tags/keywords

attachment, context, databindingexception, databindingexception, dom, io, messagereader, messagewriter, node, object, object, override, qname, qname, string, string, util

The Apache CXF AbstractXOPType.java source code

/**
 * 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.aegis.type.mtom;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamReader;

import org.w3c.dom.Attr;
import org.w3c.dom.Node;

import org.apache.cxf.aegis.Context;
import org.apache.cxf.aegis.DatabindingException;
import org.apache.cxf.aegis.type.AegisType;
import org.apache.cxf.aegis.type.basic.Base64Type;
import org.apache.cxf.aegis.xml.MessageReader;
import org.apache.cxf.aegis.xml.MessageWriter;
import org.apache.cxf.common.xmlschema.XmlSchemaConstants;
import org.apache.cxf.helpers.DOMUtils;
import org.apache.cxf.message.Attachment;
import org.apache.ws.commons.schema.XmlSchemaElement;
import org.apache.ws.commons.schema.constants.Constants;

/**
 * Base class for MtoM types.
 */
public abstract class AbstractXOPType extends AegisType {
    public static final String XOP_NS = "http://www.w3.org/2004/08/xop/include";
    public static final String XML_MIME_NS = "http://www.w3.org/2005/05/xmlmime";
    public static final String XML_MIME_ATTR_LOCAL_NAME = "expectedContentTypes";
    public static final QName XOP_INCLUDE = new QName(XOP_NS, "Include");
    public static final QName XML_MIME_CONTENT_TYPE = new QName(XML_MIME_NS, "contentType");
    public static final QName XOP_HREF = new QName("href");
    public static final QName XML_MIME_BASE64 = new QName(XML_MIME_NS, "base64Binary", "xmime");
    
    private String expectedContentTypes;
    // the base64 type knows how to deal with just plain base64 here, which is essentially always 
    // what we get in the absence of the optimization. So we need something of a coroutine.
    private Base64Type fallbackDelegate;
    private boolean useXmimeBinaryType;
    
    /**
     * Create an XOP type. This type will use xmime to publish and receive the content type
     * via xmime:base64Binary if useXmimeBinaryType is true. If expectedContentTypes != null, then
     * it will use xmime to advertise expected content types.
     * @param useXmimeBinaryType whether to use xmime:base64Binary.
     * @param expectedContentTypes whether to public xmime:expectedContentTypes.
     */
    public AbstractXOPType(boolean useXmimeBinaryType, String expectedContentTypes) {
        this.expectedContentTypes = expectedContentTypes;
        this.useXmimeBinaryType = useXmimeBinaryType;
        fallbackDelegate = new Base64Type(this);
        if (useXmimeBinaryType) {
        //      we use the XMIME type instead of the XSD type to allow for our content type attribute.
            setSchemaType(XML_MIME_BASE64);
        } else {
            setSchemaType(XmlSchemaConstants.BASE64BINARY_QNAME);
        }
    }
    
    /**
     * This is called from base64Type when it recognizes an XOP attachment.
     * @param reader
     * @param context
     * @return
     * @throws DatabindingException
     */
    public Object readMtoM(MessageReader reader, Context context) throws DatabindingException {
        Object o = null;
        while (reader.hasMoreElementReaders()) {
            MessageReader child = reader.getNextElementReader();
            if (child.getName().equals(XOP_INCLUDE)) {
                MessageReader mimeReader = child.getAttributeReader(XOP_HREF);
                String type = mimeReader.getValue().trim();
                o = readInclude(type, child, context);
            }
            child.readToEnd();
        }

        return o;
    }

    /**
     * This defers to the plain base64 type, which calls back into here above for XOP.
     * {@inheritDoc}
     */
    @Override
    public Object readObject(MessageReader reader, Context context) throws DatabindingException {
        XMLStreamReader xreader = reader.getXMLStreamReader();
        String contentType = 
            xreader.getAttributeValue(AbstractXOPType.XML_MIME_NS,
                                      AbstractXOPType.XML_MIME_CONTENT_TYPE.getLocalPart());

        Object thingRead = fallbackDelegate.readObject(reader, context);
        // If there was actually an attachment, the delegate will have called back to us and gotten
        // the appropriate data type. If there wasn't an attachment, it just returned the bytes. 
        // Our subclass have to package them.
        if (thingRead.getClass() == (new byte[0]).getClass()) {
            return wrapBytes((byte[])thingRead, contentType);
        }

        return thingRead;
    }
    
    private Object readInclude(String type, MessageReader reader,
                              Context context) throws DatabindingException {
        String href = reader.getAttributeReader(XOP_HREF).getValue().trim();

        Attachment att = AttachmentUtil.getAttachment(href, context.getAttachments());

        if (att == null) {
            throw new DatabindingException("Could not find the attachment " + href);
        }

        try {
            return readAttachment(att, context);
        } catch (IOException e) {
            throw new DatabindingException("Could not read attachment", e);
        }
    }

    protected abstract Object readAttachment(Attachment att, Context context) throws IOException;

    @Override
    public void writeObject(Object object, MessageWriter writer,
                            Context context) throws DatabindingException {
        // add the content type attribute even if we are going to fall back.
        String contentType = getContentType(object, context);
        if (contentType != null && useXmimeBinaryType) {
            MessageWriter ctWriter = writer.getAttributeWriter(XML_MIME_CONTENT_TYPE);
            ctWriter.writeValue(contentType);
        }

        if (!context.isMtomEnabled()) {
            fallbackDelegate.writeObject(getBytes(object), writer, context);
            return;
        }
        
        Collection<Attachment> attachments = context.getAttachments();
        if (attachments == null) {
            attachments = new ArrayList<Attachment>();
            context.setAttachments(attachments);
        }

        String id = AttachmentUtil.createContentID(getSchemaType().getNamespaceURI());

        Attachment att = createAttachment(object, id);

        attachments.add(att);
        
        MessageWriter include = writer.getElementWriter(XOP_INCLUDE);
        MessageWriter href = include.getAttributeWriter(XOP_HREF);
        href.writeValue("cid:" + id);

        include.close();
    }

    protected abstract Attachment createAttachment(Object object, String id);

    protected abstract String getContentType(Object object, Context context);
    
    /**
     * If one of these types arrives unoptimized, we need to convert it to the 
     * desired return type.
     * @param bareBytes the bytes pulled out of the base64.
     * @param contentType when we support xmime:contentType, this will be passed along.
     * @return
     */
    protected abstract Object wrapBytes(byte[] bareBytes, String contentType);

    /**
     * if MtoM is not enabled, we need bytes to turn into base64.
     * @return
     */
    protected abstract byte[] getBytes(Object object);

    @Override
    public void addToSchemaElement(XmlSchemaElement schemaElement) {
        if (expectedContentTypes != null) {
            Map<String, Node> extAttrMap = new HashMap();
            Attr theAttr = DOMUtils.createDocument().createAttributeNS(XML_MIME_NS, "xmime");
            theAttr.setNodeValue(expectedContentTypes);
            extAttrMap.put("xmime", theAttr);
            schemaElement.addMetaInfo(Constants.MetaDataConstants.EXTERNAL_ATTRIBUTES, extAttrMap);
        }
    }
    
    @Override
    public boolean usesXmime() {
        return useXmimeBinaryType || expectedContentTypes != null;
    }
}

Other Apache CXF examples (source code examples)

Here is a short list of links related to this Apache CXF AbstractXOPType.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.