com.ibm.xsp.webdav.DavXMLResponse.java Source code

Java tutorial

Introduction

Here is the source code for com.ibm.xsp.webdav.DavXMLResponse.java

Source

/** ========================================================================= *
 * Copyright (C) 2012 IBM Corporation                                         *
 *           based on work of                                                 *
 * Copyright (C) 2006, 2007 TAO Consulting Pte <http://www.taoconsulting.sg/> *
 *                            All rights reserved.                            *
 * ========================================================================== *
 *                                                                            *
 * 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.ibm.xsp.webdav;

//import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Locale;
import java.util.Stack;
import java.util.TimeZone;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

import com.ibm.xsp.webdav.interfaces.IDAVXMLResponse;

/**
 * The DavXMLResponse renders XML that is returned from PROPFIND or LOCK into
 * the respective XML structure into the DAV: namespace. Not really relevant for
 * web access but critical when accessing the stuff through a webDAV client like
 * webfolders in Windows Explorer
 * 
 * @author Stephan H. Wissel
 * 
 */
public class DavXMLResponse implements IDAVXMLResponse {

    /**
     * the prefix for every element (needs to be checked if that works)
     */
    private static final String DAV_PREFIX = "D:";
    private Locale DAV_LOCALE = Locale.getDefault();

    /**
     * The namespace definition
     */
    private static final String DAV_NAMESPACE = "DAV:";

    /**
     * The namespace definition for auxiliary elements "DaveXTensions"
     */
    private static final String AUX_NAMESPACE = "DXT:";

    /**
     * the prefix for every element (needs to be checked if that works)
     */
    private static final String AUX_PREFIX = "dxt:";

    /**
     * Logger for Errors
     */
    private static final Log LOGGER = LogFactory.getLog(DavXMLResponse.class);

    /**
     * The root element needs the namespace, so we track it here
     */
    private boolean rootElementWritten = false;

    /**
     * Will we write back more than DAV:
     */
    private boolean extendedResult = false;

    /**
     * What stylesheet to use as processing instruction
     */
    private String xmlStyleSheet = null;

    /**
     * The writer we write out to
     */
    // private ByteArrayOutputStream out = null;
    private StringWriter out = null;

    /**
     * The stream result for the XML document
     */
    private StreamResult streamResult = null;

    /**
     * Keeping track of all open / closed XML tags
     */
    private Stack<String> xmlTagStack = new Stack<String>();

    /**
     * We can't write comments before we have the first element
     */
    private ArrayList<String> deferedComments;

    /**
     * Where we write out all the XML content
     */
    TransformerHandler body = null;

    /**
     * creates as new XML reply that gets written out to the response writer
     * 
     * @param curResp
     */
    public DavXMLResponse() {
    }

    /**
     * creates as new XML reply that gets written out to the response writer
     * adds an XML stylesheet processing instruction at the top to ensure nice
     * display in browsers
     * 
     * @param curResp
     * @param stylesheet
     */
    public DavXMLResponse(String stylesheet, boolean extendedResult) {
        this.extendedResult = extendedResult;
        this.xmlStyleSheet = stylesheet;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.ibm.xsp.webdav.IDAVXMLResponse#addComment(java.lang.String)
     */
    public void addComment(String comment) {
        // Comment only gets written on extended results
        if (!this.extendedResult) {
            return;
        }
        if (!this.rootElementWritten) {
            if (this.deferedComments == null) {
                this.deferedComments = new ArrayList<String>();
            }
            this.deferedComments.add(comment);
        } else {
            try {
                body.comment(comment.toCharArray(), 0, comment.length());
            } catch (SAXException e) {
                LOGGER.error(e);
            }
        }

    }

    /*
     * (non-Javadoc)
     * 
     * @see com.ibm.xsp.webdav.IDAVXMLResponse#auxTag(java.lang.String,
     * java.lang.String)
     */
    public void auxTag(String tagName, String tagValue) {
        // Auxliliary Tag can be the first and only gets written on extended
        // results
        if (!this.rootElementWritten || !this.extendedResult) {
            return;
        }
        try {
            body.startElement("", tagName, AUX_PREFIX + tagName, null);
            body.characters(tagValue.toCharArray(), 0, tagValue.length());
            body.endElement("", tagName, AUX_PREFIX + tagName);
        } catch (SAXException e) {
            LOGGER.error(e);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.ibm.xsp.webdav.IDAVXMLResponse#cdataTag(java.lang.String,
     * java.lang.String)
     */
    public void cdataTag(String tagName, String tagValue) {
        this.openTag(tagName);
        try {
            body.startCDATA();
            body.characters(tagValue.toCharArray(), 0, tagValue.length());
            body.endCDATA();
        } catch (SAXException e) {
            LOGGER.error(e);
        }
        this.closeTag(1);
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.ibm.xsp.webdav.IDAVXMLResponse#closeDocument()
     */
    public void closeDocument() {
        this.closeTag(-1); // Make sure all tages are closes
        try {
            this.body.endDocument();
            this.out.flush();
            this.out.close();
        } catch (SAXException e) {
            LOGGER.error(e);
        } catch (IOException e) {
            LOGGER.error(e);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.ibm.xsp.webdav.IDAVXMLResponse#closeTag(int)
     */
    public void closeTag(int howMany) {

        if (howMany < 0) {
            while (!this.xmlTagStack.empty()) {
                try {
                    String closeTag = this.xmlTagStack.pop();
                    body.endElement("", closeTag, DAV_PREFIX + closeTag);
                } catch (SAXException e) {
                    LOGGER.error(e);
                    break;
                }
            }
        } else {
            for (int i = 0; i < howMany; i++) {
                if (!this.xmlTagStack.empty()) {
                    try {
                        String closeTag = this.xmlTagStack.pop();
                        body.endElement("", closeTag, DAV_PREFIX + closeTag);
                    } catch (SAXException e) {
                        LOGGER.error(e);
                        break;
                    }
                } else {
                    break; // No point looping
                }
            }
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.ibm.xsp.webdav.IDAVXMLResponse#closeTag(java.lang.String)
     */
    public boolean closeTag(String lastTagToClose) {

        boolean result = false;

        while (!this.xmlTagStack.empty()) {
            try {
                String closeTag = this.xmlTagStack.pop();
                body.endElement("", closeTag, DAV_PREFIX + closeTag);
                if (closeTag.equals(lastTagToClose)) {
                    result = true;
                    break;
                }
            } catch (SAXException e) {
                LOGGER.error(e);
                break;
            }
        }

        return result;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.ibm.xsp.webdav.IDAVXMLResponse#emptyTag(java.lang.String)
     */
    public void emptyTag(String tagName) {
        this.openTag(tagName);
        this.closeTag(1);
    }

    /**
     * Gets the transformer handler object where we write everything to
     * 
     * @param streamResult
     *            the place where we write the result to
     * @return the body object to append XML tags to
     */
    private TransformerHandler getSAXOutputObject(StreamResult streamResult) {

        // Factory pattern at work
        SAXTransformerFactory tf = (SAXTransformerFactory) TransformerFactory.newInstance();
        // SAX2.0 ContentHandler that provides the append point and access to
        // serializing options
        TransformerHandler hd;
        try {
            hd = tf.newTransformerHandler();
            Transformer serializer = hd.getTransformer();
            serializer.setOutputProperty(OutputKeys.ENCODING, "utf-8");// Suitable
            // for
            // all
            // languages
            serializer.setOutputProperty(OutputKeys.METHOD, "xml");
            if (this.extendedResult || true) {
                serializer.setOutputProperty(OutputKeys.INDENT, "yes");
            }
            hd.setResult(streamResult);

            return hd;

        } catch (TransformerConfigurationException e) {
            LOGGER.error(e);
        }

        return null;

    }

    /**
     * Returns the XML for the current document. Nice to be written into the
     * response
     * 
     * @return
     */
    // public byte[] getXMLBytes() {
    // return this.out.toByteArray();
    // }

    /*
     * (non-Javadoc)
     * 
     * @see com.ibm.xsp.webdav.IDAVXMLResponse#openTag(java.lang.String)
     */
    public void openTag(String tagName) {

        if (this.rootElementWritten) {

            try {
                body.startElement("", tagName, DAV_PREFIX + tagName, null);
                this.xmlTagStack.push(tagName);
            } catch (SAXException e) {
                LOGGER.error(e);
            }
        } else {
            this.startNewResponseBody(tagName);
        }

    }

    /*
     * (non-Javadoc)
     * 
     * @see com.ibm.xsp.webdav.IDAVXMLResponse#simpleTag(java.lang.String,
     * java.lang.String)
     */
    public void simpleTag(String tagName, String tagValue) {
        this.openTag(tagName);
        try {
            body.characters(tagValue.toCharArray(), 0, tagValue.length());
        } catch (SAXException e) {
            LOGGER.error(e);
        } catch (NullPointerException e) {
            LOGGER.error(e);
        }
        this.closeTag(1);
    }

    /**
     * Starts a new XML document and inserts the correct starting tag with name
     * spaces
     * 
     * @param tagName
     */
    private void startNewResponseBody(String tagName) {

        // this.out = new ByteArrayOutputStream();
        this.out = new StringWriter();

        if (this.out != null) {
            this.streamResult = new StreamResult(out);
            this.body = this.getSAXOutputObject(streamResult);

            try {
                // Start the document
                this.body.startDocument();

                // Stylesheet if we have one and we are on extended results
                if (this.xmlStyleSheet != null && this.extendedResult) {
                    this.body.processingInstruction("xml-stylesheet",
                            "type=\"text/xsl\" href=\"" + this.xmlStyleSheet + "\"");
                }

                // First tag with correct namespaces
                AttributesImpl attr = new AttributesImpl();
                String nsShort = DAV_PREFIX.substring(0, (DAV_PREFIX.length() - 1));
                String auxShort = AUX_PREFIX.substring(0, (AUX_PREFIX.length() - 1));
                attr.addAttribute("", nsShort, "xmlns:" + nsShort, "String", DAV_NAMESPACE);
                if (this.extendedResult) {
                    attr.addAttribute("", auxShort, "xmlns:" + auxShort, "String", AUX_NAMESPACE);
                }
                this.body.startElement("", tagName, DAV_PREFIX + tagName, attr);
                this.xmlTagStack.push(tagName);
                this.rootElementWritten = true; // We memorize that

                // If there are defered commends process them
                if (this.deferedComments != null) {
                    for (String curComment : this.deferedComments) {
                        this.addComment(curComment);
                    }
                }

            } catch (SAXException e) {
                LOGGER.error(e);
            }

        } else {
            LOGGER.error("Can't start an XML body for the response");
        }

    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.ibm.xsp.webdav.IDAVXMLResponse#dateTagForCreateDate(java.lang.String,
     * java.util.Date)
     */
    public void dateTagForCreateDate(String TagName, Date date) {
        if (date == null) {
            // return;
            date = new Date();

        }

        // "2005-08-10T10:19:24Z";
        String creatFormat = "yyyy'-'MM'-'d'T0'H':'m':'s'Z'";
        SimpleDateFormat fmt = new SimpleDateFormat(creatFormat, DAV_LOCALE);
        fmt.setTimeZone(TimeZone.getTimeZone("GMT"));
        String datestring = fmt.format(date);
        this.simpleTag(TagName, datestring);
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.ibm.xsp.webdav.IDAVXMLResponse#dateTag(java.lang.String,
     * java.util.Date)
     */
    public void dateTag(String TagName, Date date) {
        if (date == null) {
            date = new Date();
            // return;
        }
        // "Sat, 26 Mar 2005 11:22:20 GMT";
        String lastmodFormat = "EE', 'd' 'MMM' 'yyyy' 'H':'m':'s' 'z";
        SimpleDateFormat fmt = new SimpleDateFormat(lastmodFormat, DAV_LOCALE);
        fmt.setTimeZone(TimeZone.getTimeZone("GMT"));
        String datestring = fmt.format(date);
        this.simpleTag(TagName, datestring);
    }

    @Override
    public String toString() {
        if (this.out != null) {
            return this.out.toString();
        }
        return super.toString();
    }

    public void setLocale(Locale l) {
        this.DAV_LOCALE = l;
    }
}