blob: 0f7b367880fd55a38f959e83fffbcc03c52bb0b4 [file] [log] [blame]
/*
* 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.axis2.jaxws.message.attachments;
import org.apache.axiom.attachments.Attachments;
import org.apache.axiom.attachments.CachedFileDataSource;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNode;
import org.apache.axiom.om.OMText;
import org.apache.axiom.om.impl.llom.OMNavigator;
import org.apache.axiom.soap.SOAPEnvelope;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.xml.namespace.QName;
import java.io.File;
import java.util.ArrayList;
/** A suite of utilities used for handling MTOM attachment data. */
public class AttachmentUtils {
private static final Log log = LogFactory.getLog(AttachmentUtils.class);
private static final QName XOP_INCLUDE =
new QName("http://www.w3.org/2004/08/xop/include", "Include");
/**
* Can be used to find all instances of the <pre><xop:include></pre> element
* within a given OM SOAPEnvelope.
*
* @param env
* @return
*/
public static ArrayList<OMElement> findXopElements(OMElement env) {
ArrayList<OMElement> xops = new ArrayList<OMElement>();
findXopElements(env, xops);
return xops;
}
/*
* A recursive search for all of the <xop:include> elements in the tree.
*/
private static void findXopElements(OMElement root, ArrayList<OMElement> xops) {
// Forces a parse. This seems to be necessary due to bugs in OMNavigator
root.getNextOMSibling();
// Navigator does a traversal that mimics the structure of an xml document.
// Each non-element object is processed once.
// Each element object is visited prior to its children and after its children.
//
// Suppose you have the following tree (caps are elements, lowers are text)
//
// A
// / \
// B C
// /\ /\
// D e F g
//
// The traversal is
// is A B D D' e B' C F F' g C' A'
// The ' indicates that this is the second time the node is visited (i.e. nav.visited()
// returns true)
OMNavigator nav = new OMNavigator(root);
while (nav.isNavigable()) {
OMNode curr = nav.next();
// Inspect elements that have been visited.
// It is probably safer to inspect the node when it is visited, because
// this guarantees that its children have been processed/expanded.
if (nav.visited() && curr instanceof OMElement) {
OMElement element = (OMElement)curr;
if (element.getQName().equals(XOP_INCLUDE)) {
if (log.isDebugEnabled()) {
log.debug("[XOP_INCLUDE] " + element.getLocalName());
}
xops.add(element);
}
}
}
}
/**
* Can be used to find all of the nodes in a tree that contain binary content that is targetted
* for optimization via MTOM.
*
* @param env
* @return
*/
public static ArrayList<OMText> findBinaryNodes(SOAPEnvelope env) {
ArrayList<OMText> nodes = new ArrayList<OMText>();
findBinaryElements(env, nodes);
return nodes;
}
/*
* A recursive search for all of the binary, optimized nodes in a tree.
*/
private static void findBinaryElements(OMNode node, ArrayList<OMText> attachments) {
// Forces a parse. This seems to be necessary due to bugs in OMNavigator
node.getNextOMSibling();
// Navigator does a traversal that mimics the structure of an xml document.
// Each non-element object is processed once.
// Each element object is visited prior to its children and after its children.
//
// Suppose you have the following tree (caps are elements, lowers are text)
//
// A
// / \
// B C
// /\ /\
// D e F g
//
// The traversal is
// The traversal is
// is A B D D' e B' C F F' g C' A'
// The ' indicates that this is the second time the node is visited
// (i.e. nav.isVisited() returns true)
OMNavigator nav = new OMNavigator(node);
while (nav.isNavigable()) {
OMNode curr = nav.next();
if (curr instanceof OMText) {
// If it's an OMText, see if its optimized and add it to the list
if (log.isDebugEnabled())
log.debug("text node found");
OMText textNode = (OMText)curr;
if (textNode.isOptimized()) {
if (log.isDebugEnabled())
log.debug("optimized text node found");
attachments.add(textNode);
}
}
}
}
/**
* Given an <pre><xop:include></pre> element, create an OMText element
* with the appropriate attachment data.
*
* @param xop
* @param data
* @return
*/
public static OMText makeBinaryOMNode(OMElement xop, DataHandler dh) {
OMFactory factory = xop.getOMFactory();
OMText binaryNode = factory.createOMText(dh, true);
return binaryNode;
}
/**
* Given an OMText node, create it's corresponding <pre><xop:include></pre>
* element.
*/
public static OMElement makeXopElement(OMText data) {
OMFactory factory = data.getOMFactory();
OMElement xop = factory.createOMElement(XOP_INCLUDE, null);
xop.addAttribute("href", data.getContentID(), null);
return xop;
}
/**
* Process attachment's dataHandlers for CachedFileDataSource.
* If exist, execute file.deleteOnExit() request on the cached
* attachment file referenced by each CachedFileDataSource.
* This will delete the cached attachment file on JVM exit.
*
* @param attachments
*/
public static void findCachedAttachment(Attachments attachments){
if(attachments == null){
return;
}
String[] contentIds = attachments.getAllContentIDs();
if(contentIds.length > 0){
if (log.isDebugEnabled()) {
log.debug("Attachments exist....");
}
for(int i=0; i < contentIds.length; i++){
DataHandler dh = attachments.getDataHandler(contentIds[i]);
if(dh != null){
DataSource dataSource = dh.getDataSource();
if(dh != null && dataSource instanceof CachedFileDataSource){
if (log.isDebugEnabled()) {
log.debug("Attachment's DataHandler uses CachedFileDataSource...");
}
File file = ((CachedFileDataSource)dataSource).getFile();
if (log.isDebugEnabled()) {
log.debug(" Making file.deleteOnExit() request on "+file.getAbsolutePath());
}
file.deleteOnExit();
}
}
}
}
}
}