| /* |
| * 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(); |
| } |
| } |
| } |
| } |
| } |
| |
| } |