001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019: package org.apache.axis2.jaxws.message.attachments;
020:
021: import org.apache.axiom.attachments.Attachments;
022: import org.apache.axiom.attachments.CachedFileDataSource;
023: import org.apache.axiom.om.OMElement;
024: import org.apache.axiom.om.OMFactory;
025: import org.apache.axiom.om.OMNode;
026: import org.apache.axiom.om.OMText;
027: import org.apache.axiom.om.impl.llom.OMNavigator;
028: import org.apache.axiom.soap.SOAPEnvelope;
029: import org.apache.commons.logging.Log;
030: import org.apache.commons.logging.LogFactory;
031:
032: import javax.activation.DataHandler;
033: import javax.activation.DataSource;
034: import javax.xml.namespace.QName;
035:
036: import java.io.File;
037: import java.util.ArrayList;
038:
039: /** A suite of utilities used for handling MTOM attachment data. */
040: public class AttachmentUtils {
041:
042: private static final Log log = LogFactory
043: .getLog(AttachmentUtils.class);
044: private static final QName XOP_INCLUDE = new QName(
045: "http://www.w3.org/2004/08/xop/include", "Include");
046:
047: /**
048: * Can be used to find all instances of the <pre><xop:include></pre> element
049: * within a given OM SOAPEnvelope.
050: *
051: * @param env
052: * @return
053: */
054: public static ArrayList<OMElement> findXopElements(OMElement env) {
055: ArrayList<OMElement> xops = new ArrayList<OMElement>();
056: findXopElements(env, xops);
057: return xops;
058: }
059:
060: /*
061: * A recursive search for all of the <xop:include> elements in the tree.
062: */
063: private static void findXopElements(OMElement root,
064: ArrayList<OMElement> xops) {
065:
066: // Forces a parse. This seems to be necessary due to bugs in OMNavigator
067: root.getNextOMSibling();
068:
069: // Navigator does a traversal that mimics the structure of an xml document.
070: // Each non-element object is processed once.
071: // Each element object is visited prior to its children and after its children.
072: //
073: // Suppose you have the following tree (caps are elements, lowers are text)
074: //
075: // A
076: // / \
077: // B C
078: // /\ /\
079: // D e F g
080: //
081: // The traversal is
082: // is A B D D' e B' C F F' g C' A'
083: // The ' indicates that this is the second time the node is visited (i.e. nav.visited()
084: // returns true)
085:
086: OMNavigator nav = new OMNavigator(root);
087:
088: while (nav.isNavigable()) {
089: OMNode curr = nav.next();
090:
091: // Inspect elements that have been visited.
092: // It is probably safer to inspect the node when it is visited, because
093: // this guarantees that its children have been processed/expanded.
094: if (nav.visited() && curr instanceof OMElement) {
095: OMElement element = (OMElement) curr;
096: if (element.getQName().equals(XOP_INCLUDE)) {
097: if (log.isDebugEnabled()) {
098: log.debug("[XOP_INCLUDE] "
099: + element.getLocalName());
100: }
101: xops.add(element);
102: }
103: }
104: }
105: }
106:
107: /**
108: * Can be used to find all of the nodes in a tree that contain binary content that is targetted
109: * for optimization via MTOM.
110: *
111: * @param env
112: * @return
113: */
114: public static ArrayList<OMText> findBinaryNodes(SOAPEnvelope env) {
115: ArrayList<OMText> nodes = new ArrayList<OMText>();
116: findBinaryElements(env, nodes);
117: return nodes;
118: }
119:
120: /*
121: * A recursive search for all of the binary, optimized nodes in a tree.
122: */
123: private static void findBinaryElements(OMNode node,
124: ArrayList<OMText> attachments) {
125:
126: // Forces a parse. This seems to be necessary due to bugs in OMNavigator
127: node.getNextOMSibling();
128:
129: // Navigator does a traversal that mimics the structure of an xml document.
130: // Each non-element object is processed once.
131: // Each element object is visited prior to its children and after its children.
132: //
133: // Suppose you have the following tree (caps are elements, lowers are text)
134: //
135: // A
136: // / \
137: // B C
138: // /\ /\
139: // D e F g
140: //
141: // The traversal is
142: // The traversal is
143: // is A B D D' e B' C F F' g C' A'
144: // The ' indicates that this is the second time the node is visited
145: // (i.e. nav.isVisited() returns true)
146: OMNavigator nav = new OMNavigator(node);
147:
148: while (nav.isNavigable()) {
149: OMNode curr = nav.next();
150: if (curr instanceof OMText) {
151: // If it's an OMText, see if its optimized and add it to the list
152: if (log.isDebugEnabled())
153: log.debug("text node found");
154:
155: OMText textNode = (OMText) curr;
156: if (textNode.isOptimized()) {
157: if (log.isDebugEnabled())
158: log.debug("optimized text node found");
159:
160: attachments.add(textNode);
161: }
162: }
163: }
164: }
165:
166: /**
167: * Given an <pre><xop:include></pre> element, create an OMText element
168: * with the appropriate attachment data.
169: *
170: * @param xop
171: * @param data
172: * @return
173: */
174: public static OMText makeBinaryOMNode(OMElement xop, DataHandler dh) {
175: OMFactory factory = xop.getOMFactory();
176: OMText binaryNode = factory.createOMText(dh, true);
177: return binaryNode;
178: }
179:
180: /**
181: * Given an OMText node, create it's corresponding <pre><xop:include></pre>
182: * element.
183: */
184: public static OMElement makeXopElement(OMText data) {
185: OMFactory factory = data.getOMFactory();
186: OMElement xop = factory.createOMElement(XOP_INCLUDE, null);
187: xop.addAttribute("href", data.getContentID(), null);
188: return xop;
189: }
190:
191: /**
192: * Process attachment's dataHandlers for CachedFileDataSource.
193: * If exist, execute file.deleteOnExit() request on the cached
194: * attachment file referenced by each CachedFileDataSource.
195: * This will delete the cached attachment file on JVM exit.
196: *
197: * @param attachments
198: */
199: public static void findCachedAttachment(Attachments attachments) {
200: if (attachments == null) {
201: return;
202: }
203:
204: String[] contentIds = attachments.getAllContentIDs();
205: if (contentIds.length > 0) {
206: if (log.isDebugEnabled()) {
207: log.debug("Attachments exist....");
208: }
209: for (int i = 0; i < contentIds.length; i++) {
210: DataHandler dh = attachments
211: .getDataHandler(contentIds[i]);
212: if (dh != null) {
213: DataSource dataSource = dh.getDataSource();
214: if (dh != null
215: && dataSource instanceof CachedFileDataSource) {
216: if (log.isDebugEnabled()) {
217: log
218: .debug("Attachment's DataHandler uses CachedFileDataSource...");
219: }
220: File file = ((CachedFileDataSource) dataSource)
221: .getFile();
222: if (log.isDebugEnabled()) {
223: log
224: .debug(" Making file.deleteOnExit() request on "
225: + file.getAbsolutePath());
226: }
227: file.deleteOnExit();
228: }
229: }
230: }
231: }
232: }
233:
234: }
|