/* * Copyright 2001-2004 The Apache Software Foundation. * * 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 samples.attachments; import org.apache.axis.AxisFault; import org.apache.axis.attachments.AttachmentPart; import org.apache.axis.client.Call; import org.apache.axis.client.Service; import org.apache.axis.message.SOAPBodyElement; import org.apache.axis.transport.http.HTTPConstants; import org.apache.axis.utils.Options; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import javax.activation.DataHandler; import javax.activation.FileDataSource; import java.io.ByteArrayInputStream; import java.net.URL; import java.util.Hashtable; import java.util.Vector; /** * * @author Rick Rineholt */ /** * An example of sending an attachment via messages. * The main purpose is to validate the different types of attachment references * by content Id, content location both absolute and relative. * * Creates 5 separate attachments referenced differently by a SOAP document. * Each attachment contains a string that is assembled and tested to see if * if the attachments are correctly sent and referenced. Each attachment also * contains a mime header indicating its position and validated on the server * to see if mime headers are correctly sent with attachments. * * Sends the same message again however the second attachments are placed in the * stream in reverse to see if they are still referenced ok. * * * The return SOAP document references a single attachment which is the a Java * serialized vector holding strings to the individual attachments sent. * * Demos using attachments directly. * */ public class TestRef { Options opts = null; public static final String positionHTTPHeader="Ordinal"; public static final String TheKey= "Now is the time for all good men to come to the aid of their country."; public TestRef( Options opts) { this.opts = opts; } /** * This method sends all the files in a directory. * @param The directory that is the source to send. * @return True if sent and compared. */ public boolean testit() throws Exception { boolean rc = true; String baseLoc= "http://axis.org/attachTest"; Vector refs= new Vector(); //holds a string of references to attachments. Service service = new Service(); //A new axis Service. Call call = (Call) service.createCall(); //Create a call to the service. /*Un comment the below statement to do HTTP/1.1 protocol*/ //call.setScopedProperty(MessageContext.HTTP_TRANSPORT_VERSION,HTTPConstants.HEADER_PROTOCOL_V11); Hashtable myhttp= new Hashtable(); myhttp.put(HTTPConstants.HEADER_CONTENT_LOCATION, baseLoc); //Send extra soap headers /*Un comment the below to do http chunking to avoid the need to calculate content-length. (Needs HTTP/1.1)*/ //myhttp.put(HTTPConstants.HEADER_TRANSFER_ENCODING, HTTPConstants.HEADER_TRANSFER_ENCODING_CHUNKED); /*Un comment the below to force a 100-Continue... This will cause httpsender to wait for * this response on a post. If HTTP 1.1 and this is not set, *SOME* servers *MAY* reply with this anyway. * Currently httpsender won't handle this situation, this will require the resp. which it will handle. */ //myhttp.put(HTTPConstants.HEADER_EXPECT, HTTPConstants.HEADER_EXPECT_100_Continue); call.setProperty(HTTPConstants.REQUEST_HEADERS,myhttp); call.setTargetEndpointAddress( new URL(opts.getURL()) ); //Set the target service host and service location, java.util.Stack rev= new java.util.Stack(); //Create an attachment referenced by a generated contentId. AttachmentPart ap= new AttachmentPart(new javax.activation.DataHandler( "Now is the time", "text/plain" )); refs.add(ap.getContentIdRef()); //reference the attachment by contentId. ap.setMimeHeader(positionHTTPHeader, ""+refs.size() ); //create a MIME header indicating postion. call.addAttachmentPart(ap); rev.push(ap); //Create an attachment referenced by a set contentId. String setContentId="rick_did_this"; ap= new AttachmentPart(new DataHandler(" for all good", "text/plain" )); //new MemoryOnlyDataSource( ap.setContentId(setContentId); refs.add("cid:" + setContentId); //reference the attachment by contentId. ap.setMimeHeader(positionHTTPHeader, ""+refs.size() ); //create a MIME header indicating postion. call.addAttachmentPart(ap); rev.push(ap); //Create an attachment referenced by a absolute contentLocation. ap= new AttachmentPart(new DataHandler( " men to", "text/plain" )); //new MemoryOnlyDataSource( " men to", "text/plain" ))); ap.setContentLocation(baseLoc+ "/firstLoc"); refs.add(baseLoc+ "/firstLoc"); //reference the attachment by contentId. ap.setMimeHeader(positionHTTPHeader, ""+refs.size() ); //create a MIME header indicating postion. call.addAttachmentPart(ap); rev.push(ap); //Create an attachment referenced by relative location to a absolute location. ap= new AttachmentPart(new DataHandler( " come to", "text/plain" )); // new MemoryOnlyDataSource( " come to", "text/plain" ))); ap.setContentLocation(baseLoc+ "/secondLoc"); refs.add("secondLoc"); //reference the attachment by contentId. ap.setMimeHeader(positionHTTPHeader, ""+refs.size() ); //create a MIME header indicating postion. call.addAttachmentPart(ap); rev.push(ap); //Create an attachment referenced by relative location to a relative location. ap= new AttachmentPart(new DataHandler( " the aid of their country.", "text/plain" )); // new MemoryOnlyDataSource( " the aid of their country.", "text/plain" ))); ap.setContentLocation("thirdLoc"); refs.add("thirdLoc"); //reference the attachment by contentId. ap.setMimeHeader(positionHTTPHeader, ""+refs.size() ); //create a MIME header indicating postion. call.addAttachmentPart(ap); rev.push(ap); //Now build the message.... String namespace="urn:attachmentsTestRef"; //needs to match name of service. StringBuffer msg = new StringBuffer("\n<attachments xmlns=\"" +namespace +"\">\n"); for (java.util.Iterator i = refs.iterator(); i.hasNext() ; ) msg.append(" <attachment href=\"" + (String) i.next() + "\"/>\n"); msg.append( "</attachments>"); call.setUsername( opts.getUser()); call.setPassword( opts.getPassword() ); call.setOperationStyle("document"); call.setOperationUse("literal"); //Now do the call.... Object ret = call.invoke(new Object[]{ new SOAPBodyElement(new ByteArrayInputStream(msg.toString().getBytes("UTF-8"))) } ); validate(ret, call, "12345"); //Note: that even though the attachments are sent in reverse they are still // retreived by reference so the ordinal will still match. int revc=1; for( ap= (AttachmentPart)rev.pop(); ap!=null ;ap= rev.empty()? null : (AttachmentPart)rev.pop()){ call.addAttachmentPart(ap); } //Now do the call.... ret = call.invoke(new Object[]{ new SOAPBodyElement(new ByteArrayInputStream(msg.toString().getBytes("UTF-8"))) } ); validate(ret, call, "54321"); return rc; } void validate(Object ret, Call call, final String expOrdPattern) throws Exception{ if (null == ret) { System.out.println("Received null "); throw new AxisFault("", "Received null", null, null); } if (ret instanceof String) { System.out.println("Received problem response from server: " + ret); throw new AxisFault("", (String) ret, null, null); } Vector vret= (Vector) ret; if (!(ret instanceof java.util.Vector )) { //The wrong type of object that what was expected. System.out.println("Received unexpected type :" + ret.getClass().getName()); throw new AxisFault("", "Received unexpected type:" + ret.getClass().getName(), null, null); } org.apache.axis.message.RPCElement retrpc= (org.apache.axis.message.RPCElement ) ((Vector)ret).elementAt(0); Document retDoc= org.apache.axis.utils.XMLUtils.newDocument( new org.xml.sax.InputSource(new java.io.ByteArrayInputStream( retrpc.toString().getBytes()))); //get at the attachments. org.apache.axis.attachments.Attachments attachments= call.getResponseMessage().getAttachmentsImpl(); //Still here, so far so good. Element rootEl= retDoc.getDocumentElement(); Element caEl= getNextFirstChildElement(rootEl); //this should be the only child element with the ref to our attachment // response. String href= caEl.getAttribute("href"); org.apache.axis.Part p= attachments.getAttachmentByReference(href); if(null == p) throw new org.apache.axis.AxisFault("Attachment for ref='"+href+"' not found." ); //Check to see the the attachment were sent in order String ordPattern= caEl.getAttribute("ordinalPattern"); if(!expOrdPattern.equals(ordPattern)) throw new org.apache.axis.AxisFault( "Attachments sent out of order expected:'" +expOrdPattern + "', got:'"+ordPattern+"'." ); //now get at the data... DataHandler dh= ((org.apache.axis.attachments.AttachmentPart)p).getDataHandler(); System.err.println("content-type:" + dh.getContentType()); java.util.Vector rspVector= null; Object rspObject = dh.getContent();//This SHOULD just return the vector but reality strikes... if(rspObject == null) throw new AxisFault("", "Received unexpected object:null", null, null); else if(rspObject instanceof java.util.Vector) rspVector= (java.util.Vector)rspObject; else if(rspObject instanceof java.io.InputStream) rspVector= (java.util.Vector) new java.io.ObjectInputStream((java.io.InputStream)rspObject ).readObject(); else throw new AxisFault("", "Received unexpected object:" + rspObject.getClass().getName(), null, null); StringBuffer fullmsg= new StringBuffer(); for(java.util.Iterator ri= rspVector.iterator(); ri.hasNext();){ String part= (String)ri.next(); fullmsg.append(part); System.out.print(part); } System.out.println(""); if(!(TheKey.equals (fullmsg.toString()))) throw new org.apache.axis.AxisFault("Fullmsg not correct'"+fullmsg +"'." ); } Element getNextFirstChildElement(Node n) { if(n== null) return null; n= n.getFirstChild(); for(; n!= null && !(n instanceof Element); n= n.getNextSibling()); return (Element)n; } Element getNextSiblingElement(Node n) { if(n== null) return null; n= n.getNextSibling(); for(; n!= null && !(n instanceof Element); n= n.getNextSibling()); return (Element)n; } /** * Give a single file to send or name a directory * to send an array of attachments of the files in * that directory. */ public static void main(String args[]) { try { Options opts = new Options(args); TestRef echoattachment = new TestRef(opts); args = opts.getRemainingArgs(); int argpos=0; if (echoattachment.testit()) { System.out.println("Attachments sent and received ok!"); System.exit(0); } } catch ( Exception e ) { System.err.println(e); e.printStackTrace(); } System.exit(18); } /** * Return an array of datahandlers for each file in the dir. * @param the name of the directory * @return return an array of datahandlers. */ protected DataHandler[] getAttachmentsFromDir(String dirName) { java.util.LinkedList retList = new java.util.LinkedList(); DataHandler[] ret = new DataHandler[0];// empty java.io.File sourceDir = new java.io.File(dirName); java.io.File[] files = sourceDir.listFiles(); for ( int i = files.length - 1; i >= 0; --i) { java.io.File cf = files[i]; if (cf.isFile() && cf.canRead()) { String fname = null; try { fname = cf.getAbsoluteFile().getCanonicalPath(); } catch ( java.io.IOException e) { System.err.println("Couldn't get file \"" + fname + "\" skipping..."); continue; } retList.add( new DataHandler( new FileDataSource( fname ))); } } if (!retList.isEmpty()) { ret = new DataHandler[ retList.size()]; ret = (DataHandler[]) retList.toArray(ret); } return ret; } /**This class should store all attachment data in memory */ static class MemoryOnlyDataSource extends org.apache.axis.attachments.ManagedMemoryDataSource{ MemoryOnlyDataSource( byte [] in, String contentType) throws java.io.IOException{ super( new java.io.ByteArrayInputStream( in) , Integer.MAX_VALUE -2, contentType, true); } MemoryOnlyDataSource( String in, String contentType)throws java.io.IOException{ this( in.getBytes() , contentType); } } }