1 /*
2  * Created on Jun 17, 2003
3  *
4  * To change the template for this generated file go to
5  * Window>Preferences>Java>Code Generation>Code and Comments
6  */
7 /*
8  * Copyright (C) 2003  robert rowntree
9 
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 * GNU General Public License for more details.
19
20 * ref. http://www.gnu.org/copyleft/gpl.html
21*/
22//TODO this class should impl interface so that it can be plug-in
23//  impl of behavior that gets event(s) of type "data created"
24//  transportd from client to the PO. PO then inspects contents
25//  of what came up over the wire and reacts by forwarding the 
26//  raw data or by useing the transported event to "PULL" the 
27//  data from the client or maybe even trigger a 3rd party 
28//  P2P session(s) amoung all subscribers and the producer.
29package com.borneo.net.soap;
30
31import java.io.BufferedInputStream;
32import java.io.File;
33import java.io.IOException;
34import java.io.InputStream;
35import java.net.MalformedURLException;
36import java.net.URL;
37import java.rmi.RemoteException;
38import java.util.ArrayList;
39import java.util.Collection;
40import java.util.Iterator;
41import java.util.LinkedList;
42import java.util.Vector;
43
44import javax.activation.DataHandler;
45import javax.activation.FileDataSource;
46
47import javax.xml.namespace.QName;
48import javax.xml.rpc.ParameterMode;
49import javax.xml.rpc.ServiceException;
50import javax.xml.soap.AttachmentPart;
51import javax.xml.soap.Name;
52import javax.xml.soap.SOAPBody;
53import javax.xml.soap.SOAPBodyElement;
54import javax.xml.soap.SOAPConnection;
55import javax.xml.soap.SOAPElement;
56import javax.xml.soap.SOAPException;
57import javax.xml.soap.SOAPMessage;
58
59import org.apache.axis.AxisFault;
60import org.apache.axis.Constants;
61import org.apache.axis.Message;
62import org.apache.axis.MessageContext;
63import org.apache.axis.attachments.OctetStream;
64import org.apache.axis.client.Call;
65import org.apache.axis.client.Service;
66import org.apache.axis.description.ParameterDesc;
67import org.apache.axis.encoding.TypeMapping;
68import org.apache.axis.encoding.TypeMappingRegistry;
69import org.apache.axis.encoding.TypeMappingRegistryImpl;
70import org.apache.axis.encoding.XMLType;
71import org.apache.axis.message.RPCElement;
72import org.apache.axis.message.RPCParam;
73import org.apache.axis.message.SOAPEnvelope;
74import org.apache.axis.soap.MessageFactoryImpl;
75import org.apache.axis.soap.SOAPConnectionFactoryImpl;
76import org.apache.log4j.Logger;
77import org.apache.log4j.PropertyConfigurator;
78
79import com.borneo.util.FileSelector;
80import com.borneo.util.POProperty;
81
82/** 
83 * This implementation uses following API's to PUSH data to Remote Node:
84 *   HTTP, SOAP, Apache AXIS, JAX-RPC, SAAJ or SwA.  
85 * Manager class for API's in above list. This class sits between the client app.
86 * where data is being created and the entire API collection that implements
87 * connectivity for distributing files in a data-interchange or PostOffice.
88 * @author r
89 * <p>CLIENT-SIDE uses SAAJ API for Web Services and "Soap with Attachments"
90 * 4 options for WS connections designated by property file key="ws.invocation.typ"
91 *   - diicall "invoke" supports parm "ArrayOFDataHandler" dynamic req'd
92 *       std msg call won't support the array ... had to patch w/ dii
93 *   - SoapMsg "call" single File supports non-array type DataHandlers in parms
94 *   - SoapMsg "call" FileSet supports array-OF-DataHandlers in parms 
95 * </p><p>
96 * According to SAAJ API rules, the client formats a SOAP msg that will
97 * get to the proper WS endpt and that will meet the signature of the
98 * requested method at that endpt. 
99 * see WSDL "service", "port", "operation" elements.
00 * </p><p>
01 * The Server is according to JAX-RPC so, according to SAAJ, the SOAP message
02 * constructed here in the client needs to conform to the server-side JAX-RPC signature.
03 * 
04 * The properties file has following directives:
05 * - 3 for "wsdl" concat these for the service Endpoint
06 * - 1 for "soap" operation or method called by RPC on server 
07 * - 1 for "ws" "connect" type  (dynamic or static msg call) 
08 *  - for the method called on the service class handling that endpt
09 *    useing these, go chek the method and it's argList... 
10 * The "service" element of the wsdd file, relates the URL from the 
11 * client's endpt. to the actual Service class and list of allowed methods...
12 * Well, what is the link you use to coordinate Client and Server?
13 * * Ans: get the endpt. URL and query the WSDL via browser link belo
14 *  <host><port>/axis/services/urn:EchoAttachmentsService?wsdl 
15 * </p><p>
16 * If you want to extend the signature you have to make correlated changes to:
17 *  - wsdd.   then redeploy to AXIS container
18 *  - Client methods <this> to format the SOAP Envelope's elements
19 *  - server implementation and method's parameters and parm order
20 *  - without the server being up, you can test revision...
21 *     use TCPMON to trap the client message and inspect
22 *    the child element of <soapenv:Body>. Child's name should =
23 *    method name on the server .. follow the rules outlined in the SOAP
24 *    spec under "RPC and SOAP Body"
25 * </p>
26 * To change the template for this generated type comment go to
27 * Window>Preferences>Java>Code Generation>Code and Comments
28 * TODO encryption and other bolt on Services can be added via 
29 * DD Layer and the following Interface. 
30 * see ${sun.JWSDP.dev.pack}/docs/api/javax/xml/rpc/handler/Handler.html
31 * The above also applies to server-side changes.
32 */
33
34public class SAAJCallMgr {
35    
36    SOAPConnection soapConnection;
37//  SOAPMessage message;
38    Message reqMessage;
39    Message resMessage;
40    
41    SOAPEnvelope requestEnvelope; 
42    SOAPElement elementRpcOp;
43    protected static Logger log;
44    private MessageContext     msgContext      = null ;
45
46
47//TODO what is the proper duration of the connection belo??
48//    where is the connection killed    
49    public void setConnection(SOAPConnection conn){
50        log.debug("beg. getconn ");     
51            soapConnection = conn;
52        }
53    public SOAPConnection getConnection(){
54        return soapConnection;
55        }
56//TODO need an interface for the SOAP struct setters
57//    they are always the same ( env, body, method, parmSet )       
58
59// wrong should be addMessageAttachment (impl, File)
60//  
61    public void putFile(File afile, String wsdlURL){
62        AttachmentPart attachment =
63            getReqMessage().createAttachmentPart(
64                new DataHandler(
65                    new FileDataSource(
66                        afile               
67                    )
68                )
69            );
70        getReqMessage().addAttachmentPart(attachment);
71        try{
72            elementRpcOp.addAttribute(
73                requestEnvelope.createName("href")
74                , "cid:" + attachment.getContentId()
75            );
76            log.debug("making SOAP call to " +wsdlURL);
77            javax.xml.soap.SOAPMessage returnedSOAPMessage =
78                getConnection().call(getReqMessage(), wsdlURL);
79        } catch (SOAPException e) {
80        // TODO Auto-generated catch block
81        e.printStackTrace();
82        }   
83    }
84    public void putFile(Collection fileset){
85        for ( 
86            Iterator i = fileset.iterator();i.hasNext();
87        ){
88            putFile( 
89                (File)i.next()
90                ,
91                POProperty.get(
92                    "wsdl.service.addr.host"
93                ) 
94                + "/" 
95                + POProperty.get(
96                    "wsdl.service.addr.axis.webapp"
97                )
98                + "/" 
99                + POProperty.get(
00                    "wsdl.service.addr.port.name"
01                )                               
02            );
03        }   
04    }
05    public void putFile(String name, String wsdlURL){
06    // better signature(s) ( File, Endpt ) ( FileSet, Endpt )
07    // Set above just delegates to singleFile   
08    // not used because the instantiantion of the collection
09    // should be closer to the client making call of the service
10    // if you parm a string then you should also do a boolean parm
11    // for a "use name as regex pattern" to drive collection of files   
12    // fixme wrap the url
13    //"http://localhost:" +opts.getPort() + "/axis/services/urn:EchoAttachmentsService";
14    /*String wsdlURLString =  
15    POProperty.get(             
16        "file.io.output.rpc.attachment"                                 
17    );
18    */
19    System.out.println("beg. put fnm , endptURL : "
20        +name
21        +" "
22        +wsdlURL
23    );
24    try {
25                        
26
27//aset
28        
29      for ( Iterator i = 
30              FileSelector.getFiles(name).iterator() ;
31          i.hasNext();
32      ){
33                AttachmentPart attachment =
34                    getReqMessage().createAttachmentPart(
35                        new DataHandler(
36                            new FileDataSource(
37                                (File)i.next()              
38                            )
39                        )
40                    );                  
41                getReqMessage().addAttachmentPart(attachment);
42                elementRpcOp.addAttribute(
43                    requestEnvelope.createName("href")
44                    , "cid:" + attachment.getContentId()
45                );
46            }   //endFor
47            log.debug("making SOAP call to " +wsdlURL);
48            javax.xml.soap.SOAPMessage returnedSOAPMessage =
49                getConnection().call(getReqMessage(), wsdlURL);
50        } catch (SOAPException e) {
51        // TODO Auto-generated catch block
52        e.printStackTrace();
53    }
54    }
55    public MessageContext getMessageContext(){
56        return msgContext;
57    }
58    
59    public void setMessageContext(MessageContext msgC){
60         msgContext = msgC;
61    }   
62    
63    public Message getReqMessage(){
64        return reqMessage;
65    }
66    
67    /**
68     * Get the "SOAPMessage" portion of the soap message via calls
69     * to the appropriate Obj. Factory. Meant to be used by client 
70     * that is NOT in a container.
71     * @return javax.xml.soap.SOAPMessage
72     */ 
73    public void setReqMessage(Message msg){
74        log.debug("beg. getmsg ");
75    
76            reqMessage = msg;
77        
78    }
79
80    /**
81     * Get the "SOAPEnvelope" portion of the soap message.
82     * @return SOAPEnvelope
83     */ 
84    public SOAPEnvelope getRequestEnvelope(){           
85            return requestEnvelope;
86    }
87
88    public SOAPEnvelope getRequestEnvelope(Message msg){
89        try {
90            return msg.getSOAPEnvelope();
91            
92//          return this.getReqMessage().getSOAPEnvelope();
93//          return this.getMessage().getSOAPPart().getEnvelope();
94
95        } catch (AxisFault e) {
96            // TODO Auto-generated catch block
97            e.printStackTrace();
98            return null;
99        }
00    }
01
02    public void setRequestEnvelope(SOAPEnvelope env){
03
04        requestEnvelope = env;
05    }
06
07/**
08 * Get the "SOAPBody" portion of the soap message.
09 * @return javax.xml.soap.SOAPBody
10 */ 
11    public SOAPBody getBody(){
12        try {           
13            return  getRequestEnvelope(this.getReqMessage()).getBody();
14        } catch (SOAPException e) {
15            // TODO Auto-generated catch block
16            e.printStackTrace();
17            return null;
18        }
19    }
20    /** 
21     * This is the ROOT element of the XML content portion of the
22     * SoapBody obj. The name of this element is also the RPC Operation name
23     * that's called via JAX-RPC on the server.
24     */
25    public SOAPElement getElementRpcOp(){
26        return elementRpcOp;
27    }
28
29/**
30 * This needs to be set as part of the creation of the SOAPMESSAGe and 
31 * its contents. This is the ROOT element of the XML content portion of the
32 * SoapBody obj. The name of this element is also the RPC Operation name
33 * that's called via JAX-RPC on the server.
34 * @param element javax.xml.soap.SOAPElement
35 */ 
36    public void setElementRpcOp(SOAPElement element){
37        elementRpcOp = element;
38    }
39    
40    /**
41     * Use the appropriate Soap entry from the property file to create
42     * the QNAME whose value should be the corresponding WSDL entry for 
43     * "operation name" of the bound web service. The "port" and "service"
44     * sections ofthe WSDL should contain this value. 
45     * @return the QName for the Root Node of the XML content inside 
46     * the SOAPBODY. 
47     */
48    public Name setQName(String name){
49        try {
50            return getRequestEnvelope(this.getReqMessage())
51            .createName(name
52//              POProperty.get(
53//                  "soap.rpc.methodname.attachment"
54//              )
55            );
56        } catch (SOAPException e) {
57            // TODO Auto-generated catch block
58            e.printStackTrace();
59            return null;
60        }
61    }
62    public Name setQName(String name, String prefix, String uri){
63        try {
64            return getRequestEnvelope(this.getReqMessage())
65            .createName(
66                name, prefix, uri
67            );
68        } catch (SOAPException e) {
69            // TODO Auto-generated catch block
70            e.printStackTrace();
71            return null;
72        }
73    }   
74/**
75 * 
76 * @return the XML node that corresponds to the Root in the SOAPBODY.
77 * Also, according to SOAP Protocol, this is the 
78 * WSDL Binding sectn's "operation name".
79 */ 
80    public SOAPElement addMethod(String name){
81        try {
82            return
83             getBody()
84            .addBodyElement(
85                setQName(name)              
86            );
87        } catch (SOAPException e) {
88            // TODO Auto-generated catch block
89            e.printStackTrace();
90            return null;
91        }
92    }
93
94
95/**
96 * The mid-ware symantic is hey "i created some data on this client,
97 * in the clients file system, and it's data that is of interest to remote
98 * subscribers." All the SOAP message stuff is to satisfy the protocol but,
99 * this is where the meat and potatoes are because this is where the file 
00 * or the encoded version of the file will be hooked to the SAAJ envelope
01 * for its trip over-the-wire with the message.
02 * @param afile, part of the Collection from the client's call to 
03 * "FileSelector.getFiles."
04 * @return
05 */
06    public AttachmentPart createFileAttachment(File afile){
07        return
08        getReqMessage().createAttachmentPart(
09            new DataHandler(
10                new FileDataSource(
11                    afile               
12                )
13            )
14        );  
15    }
16    
17    /**
18     * <p>The SOAPBody hasa entity, (property with an attibute whose value
19     * is a reference to the actual "DataHandler" attached to the SOAP msg.
20     * according to the rules of JAX-RPC, SOAP, and SAAJ API). The name of 
21     * the property in the xml message is also a parm name in the signature
22     * of the RPC operation over on the server.</p><p>
23     * In addition to this, the message hasa Attachment part which is the
24     * encoded version of the client's file that will be transported to the
25     * Post Office where a different sub-system meets the needs of 
26     * subscribers on the topic associated with the message.</p><p>
27     * For each file that is new, create the xml node holding the refernce
28     * and also create the attachment. Connect the attachment to the message.
29     * @param fil java.io.File
30     */
31//TODO on anymore than 1 file , the "createName' won't be unique in NS
32// you should parm the element that attach ref will be added? 
33// its now hardcode as "getElementRpcOP' so you can only attach the refids here
34// get rid of hard-coded "dh"   
35    public void addAttachment(File fil){
36        AttachmentPart myAttachment = createFileAttachment(fil);
37        getReqMessage().addAttachmentPart(myAttachment);
38        try {
39            getElementRpcOp()
40            .addChildElement(
41                getRequestEnvelope(this.getReqMessage()).createName("dh")
42            )
43            .addAttribute(
44                getRequestEnvelope(this.getReqMessage()).createName("href")
45                , "cid:" + myAttachment.getContentId()
46            );
47        } catch (SOAPException e) {
48            // TODO Auto-generated catch block
49            e.printStackTrace();
50        }
51    }
52    public void addAttachment(File fil, String parm){
53        AttachmentPart myAttachment = createFileAttachment(fil);
54        getReqMessage().addAttachmentPart(myAttachment);
55        try {
56            getElementRpcOp()
57            .addChildElement(
58                getRequestEnvelope(this.getReqMessage()).createName(parm)
59            )
60            .addAttribute(
61                getRequestEnvelope(this.getReqMessage()).createName("href")
62                , "cid:" + myAttachment.getContentId()
63            );
64        } catch (SOAPException e) {
65            // TODO Auto-generated catch block
66            e.printStackTrace();
67        }
68    }
69    
70// pass in file, parent elem "attachments"
71// file to DH
72    
73    public void addAttachment(File fil, SOAPBodyElement element){
74//      AttachmentPart myAttachment = createFileAttachment(fil);
75        addAttachment(
76            new DataHandler(
77                new FileDataSource( 
78                    fil
79                )
80            )
81            ,
82            element
83        );
84    
85    }   
86/**
87 * According to the rules of SOAP, SAAJ, JAXRPC, create the XML node in the
88 * SOAP body that holds a value reference to the actual SAAJ attachment part.
89 * The xml node and its name will be treated as RPC parm by the server-side
90 * interface of the Operation specified in the Root element. A DataHandler obj.
91 * is being used to get the attachment file over-the-wire. So, for now,
92 * this element name is dh. 
93 * NOTE: only one dh is allowed at this point. 
94 * @param name the parm name used by the server-side operation's 
95 *
96 * @param nameVal the "href" to the actual attachment
97 */ 
98    public void addRPCParm ( String name, String nameVal){
99//      SOAPElement ele = getElementRpcOp()     
00        try {
01            getElementRpcOp()
02            .addChildElement(
03                getRequestEnvelope(this.getReqMessage())
04                .createName(name)
05            )
06            .addTextNode(nameVal);
07        } catch (SOAPException e) {
08            // TODO Auto-generated catch block
09            e.printStackTrace();
10        }
11    }
12
13    
14    /**
15     * Post the request that Wraps the SOAP message.  Explain??
16     * Using the AXIS runtime (client-side impl) that uses HTTP/SOAP to 
17     * connect to the URL endpt. on the Server. Server hosts the interface impl. 
18     * of the RPC method or operation.
19     * See 3 property file properties with name like "wsdl.service.addr."
20     * @param message SOAPMessage
21     * @return
22     */
23    public SOAPMessage call ( SOAPMessage message ){
24        try {
25            return getConnection().call(
26                message                             
27                ,
28                    POProperty.get(
29                        "wsdl.service.addr.host"
30                    ) 
31                    + "/" 
32                    + POProperty.get(
33                        "wsdl.service.addr.axis.webapp"
34                    )
35                    + "/" 
36                    + POProperty.get(
37                        "wsdl.service.addr.port.name"
38                    ) 
39            );
40        } catch (SOAPException e) {
41            // TODO Auto-generated catch block
42            e.printStackTrace();
43            return null;
44        }
45    }
46// get the param, set it's ParmDesc
47//   then load it into Array
48    public Object[] setParam(DataHandler[] dh){
49        RPCParam rpcParam = new RPCParam(
50            ""
51            , "attachments"
52            ,dh
53        );
54        rpcParam.setParamDesc(
55        new ParameterDesc(new QName("attachments"),
56                             ParameterDesc.IN,
57                             XMLType.SOAP_ARRAY)
58        );
59        Vector result = new Vector();
60        result.add(rpcParam);       
61        return ( result.toArray() );
62    }
63
64//  get the params (topicname, DH's) set their  ParmDesc's
65//    then load them into Array
66     public Object[] setParams(String topicname,DataHandler[] dh){
67        RPCParam rpcParam = new RPCParam(
68            ""
69            , "topicname"
70            ,topicname
71        );
72        rpcParam.setParamDesc(
73        new ParameterDesc(new QName("topicname"),
74                             ParameterDesc.IN,
75                             XMLType.XSD_STRING)
76        );
77        Vector result = new Vector();
78        result.add(rpcParam);       
79        
80         RPCParam rpcParam2 = new RPCParam(
81             ""
82             , "attachments"
83             ,dh
84         );
85         rpcParam.setParamDesc(
86         new ParameterDesc(new QName("attachments"),
87                              ParameterDesc.IN,
88                              XMLType.SOAP_ARRAY)
89         );
90         result.add(rpcParam2);     
91         return ( result.toArray() );
92     }
93//  Default apache typemapping for OctetStream looks tobe improvement over
94//    base64Bin. Since the mailGateway interface specifies "attachments" 
95//    as InputStream[], this method is used to do the conversion from
96//    one ArrayType to another. 
97//  TODO verify that the implementation is optimal. Look to get the germans
98//    to drive following 2 interfaces into their client portions of code:
99//          javax.mail.internet.MimeMultipart  <-- totally easy
00//          javax.activation.DataHandler        <-- encapsulates MIME type...
01//  Note: for .NET clients it may have to be Arrayofbase64Binary  
02//    each MIME attachment from email gateWy is conver to Steam then load them into Array
03//  Note: see axis utils for re-injecting to MIME on the other side
04//    ref: <axis_root>\org\apache\axis\attachments\MimeUtils.java
05     public Object[] setParams(String topicname, InputStream[] is){
06        LinkedList osList = new LinkedList();       
07        for (int i = 0; i < is.length; i++) {
08          osList.add(this.setOctet(is[i]));
09        }       
10        OctetStream[] osarray = new OctetStream[0];                 
11        return this.setParams(topicname      
12            , (OctetStream[])new ArrayList(osList).toArray(osarray));                   
13    }
14
15//  Demo  version of the OutboundMailGateway uses this for protocol converter
16//  By the time the rpc element is complete, the original collection of  
17//   Mime Attachments is completed conversion into type= 
18//   org.apache.axis.attachments.OctetStream for default bundling in SAAJ API
19     public Object[] setParams(String topicname, OctetStream[] is){
20        RPCParam rpcParam = new RPCParam(
21            ""
22            , "topicnameo"
23            ,topicname
24        );
25        rpcParam.setParamDesc(
26        new ParameterDesc(new QName("topicnameo"),
27                             ParameterDesc.IN,
28                             XMLType.XSD_STRING)
29        );
30        Vector result = new Vector();
31        result.add(rpcParam);       
32        
33         RPCParam rpcParam2 = new RPCParam(
34             ""
35             , "octetstream"
36             ,is
37         );
38         rpcParam.setParamDesc(
39         new ParameterDesc(new QName("octetstream"),
40                              ParameterDesc.IN,
41                              XMLType.SOAP_ARRAY)
42         );
43         result.add(rpcParam2);     
44         return ( result.toArray() );
45     }
46
47     
48//  get the params (topicname, DH's) set their  ParmDesc's
49//    then load them into Array
50     public Object[] setParams(String topicname){
51        RPCParam rpcParam = new RPCParam(
52            ""
53            , "topicname"
54            ,topicname
55        );
56        rpcParam.setParamDesc(
57        new ParameterDesc(new QName("topicname"),
58                             ParameterDesc.IN,
59                             XMLType.XSD_STRING)
60        );
61        Vector result = new Vector();
62        result.add(rpcParam);       
63                 return ( result.toArray() );
64     }   
65
66     public Object[] setParams(String topicname, String sessionid){
67        RPCParam rpcParam = new RPCParam(
68            ""
69            , "topicname"
70            ,topicname
71        );
72        rpcParam.setParamDesc(
73        new ParameterDesc(new QName("topicname"),
74                             ParameterDesc.IN,
75                             XMLType.XSD_STRING)
76        );
77        Vector result = new Vector();
78        result.add(rpcParam);
79        
80        RPCParam rpcParam2 = new RPCParam(
81                ""
82                , "sessionid"
83                , sessionid
84        );
85        rpcParam.setParamDesc(
86        new ParameterDesc(new QName("sessionid"),
87                             ParameterDesc.IN,
88                             XMLType.XSD_STRING)
89        );
90        result.add(rpcParam2);              
91        return ( result.toArray() );
92     }
93     
94    public DataHandler[] setDH(Collection fileset){
95        LinkedList dhList = new LinkedList();       
96            for ( 
97                Iterator i = fileset.iterator();i.hasNext();
98            ){          
99                dhList.add(
00                    new DataHandler(
01                        new FileDataSource( 
02                            (File)i.next()
03                        )
04                    )
05                );                                      
06            }               
07        DataHandler[] dharray = new DataHandler[0];                 
08        return 
09            (DataHandler[])new ArrayList(dhList).toArray(dharray);      
10    }
11// call this w/     setDHArray(SelectFiles(), attachments    as parms
12// AttachmentPart caution subcls
13//   javax.xml.soap.AttachmentPart
14//      org.apache.axis.attachments | a subcls
15//  addchild "item" to attachments
16//  addattr href cid to item
17//  addattachment dh to message
18
19    public void addAttachment(DataHandler dh, SOAPBodyElement element){
20//      AttachmentPart myAttachment = getMessage()
21//      .createAttachmentPart();
22
23        org.apache.axis.attachments.AttachmentPart 
24        myAttachment = new org.apache.axis.attachments.AttachmentPart(
25            new DataHandler(
26                dh 
27                ,"text/plain"
28            )
29        );
30        getReqMessage().addAttachmentPart(myAttachment);
31        try {
32            element
33            .addChildElement(
34                getRequestEnvelope(this.getReqMessage()).createName("item")
35            )
36            .addAttribute(
37                getRequestEnvelope(this.getReqMessage()).createName("href")
38                , "cid:" + myAttachment.getContentId()
39            );
40        } catch (SOAPException e) {
41        // TODO Auto-generated catch block
42            e.printStackTrace();
43        }   
44        }   
45    /**
46     * what other way is there to handle DataHandler[] as parm??
47     * this seems to work with the attachment sample's "echoDir" operation
48     * where a parm encapsulates ArrayofDataHandlers...
49     * The key was removing the explicit Typ Registration for encoding the
50     * DH array. Just let it default and it seems to work OK on client...
51     * @return
52     */
53    public Call getCall(){
54        try {
55            Call call = (Call)(new Service().createCall());
56            /*Un comment the below statement to do HTTP/1.1 protocol*/
57            //call.setScopedProperty(MessageContext.HTTP_TRANSPORT_VERSION,HTTPConstants.HEADER_PROTOCOL_V11);
58/* rcr removed 5 lines as extraneous
59
60            Hashtable myhttp = new Hashtable();
61            myhttp.put("dddd", "yyy");     //Send extra soap headers
62            myhttp.put("SOAPAction", "dyyy");
63            myhttp.put("SOAPActions", "prova");
64            call.setProperty(HTTPConstants.REQUEST_HEADERS, myhttp);
65            */
66            
67            /*Un comment the below to do http chunking to avoid the need to calculate content-length. (Needs HTTP/1.1)*/
68            //myhttp.put(HTTPConstants.HEADER_TRANSFER_ENCODING, HTTPConstants.HEADER_TRANSFER_ENCODING_CHUNKED);
69
70            /*Un comment the below to force a 100-Continue... This will cause  httpsender to wait for
71             * this response on a post.  If HTTP 1.1 and this is not set, *SOME* servers *MAY* reply with this anyway.
72             *  Currently httpsender won't handle this situation, this will require the resp. which it will handle.
73             */
74            //myhttp.put(HTTPConstants.HEADER_EXPECT, HTTPConstants.HEADER_EXPECT_100_Continue);
75
76            //Set the target service host and service location,
77            call.setTargetEndpointAddress(
78                new URL(                        
79                    POProperty.get(
80                        "wsdl.service.addr.host"
81                    ) 
82                    + "/" 
83                    + POProperty.get(
84                        "wsdl.service.addr.axis.webapp"
85                    )
86                    + "/" 
87                    + POProperty.get(
88                        "wsdl.service.addr.port.name"
89                    )                       
90                )
91            );
92            //This is the target services method to invoke.
93//TODO hardcode removal use wsdl.service.addr.port.name for valueOf
94//     urn:EchoAttach...            
95            call.setOperationName(
96                new QName(
97                    "urn:EchoAttachmentsService"
98                    , 
99                    POProperty.get(
00                        "soap.rpc.methodname.attachment"
01                    )
02                )
03            );
04                        
05//          Add serializer for attachment.
06/* rcr tst byp          call.registerTypeMapping(
07                Class.forName(
08                    "javax.activation.DataHandler"
09                )
10                ,  
11                new QName(
12                    "urn:EchoAttachmentsService"
13                    , "DataHandler"
14                )                                    
15                , JAFDataHandlerSerializerFactory.class
16                , JAFDataHandlerDeserializerFactory.class
17            ); // end registerType
18            */
19            // argname for serverside method is the parm here
20            call.addParameter(
21                "attachments"
22                , XMLType.SOAP_ARRAY // new XMLType(qnameAttachment),
23                ,ParameterMode.IN
24            ); //Add the file.
25            call.setReturnType(XMLType.SOAP_ARRAY); // new XMLType(qnameAttachment));
26/* rcr tst byp          call.setProperty(
27                Call.ATTACHMENT_ENCAPSULATION_FORMAT
28                , Call.ATTACHMENT_ENCAPSULATION_FORMAT_DIME
29            );
30            */
31            return call;                                         
32            
33        } catch (ServiceException e) {
34            // TODO Auto-generated catch block
35            e.printStackTrace();
36        }
37        catch (MalformedURLException e) {
38            // TODO Auto-generated catch block
39            e.printStackTrace();
40        }
41        return null;
42    }
43    /**
44     * <p>Make the call to the WS endpt and operation specified in the props
45     * file directives ( soap.wsdl.url, soap.rpc.methodname )
46     * Note that serverside method "echoDir" expects a DataHandler[] typ parm.
47     * </p><p>Using an intermediate List form , convert collection of file(s)
48     *  returned by an earlier call to "FileSelector.getFiles()" to an Array  
49     * of DataHandlers because this is acceptible struct. for auto-encoding 
50     * by JAX-RPC runtime...
51     * Invoke the Service...
52     * @param fileset Collection of files that will be loaded in Array of DH's
53     * @param argcal The DII "call" that will get invoked
54     * @return the "Response type" of the WS and the return type of the operation
55     *   that's being invoked...
56     */
57    public Object diiCall(Collection fileset, Call argcal){
58                                
59        LinkedList dhList = new java.util.LinkedList();     
60        for ( 
61            Iterator i = fileset.iterator();i.hasNext();
62        ){          
63            dhList.add(
64                new DataHandler(
65                    new FileDataSource( 
66                        (File)i.next()
67                    )
68                )
69            );                                      
70        }
71        try {
72            DataHandler[] dharray = new DataHandler[0]; 
73            return argcal.invoke(
74                new Object[]{
75                   new ArrayList(dhList).toArray(dharray)
76                }
77            );
78        } catch (RemoteException e) {
79            // TODO Auto-generated catch block
80            e.printStackTrace();
81        }
82        return new Object();
83    }
84    
85    public void close(){
86        try {
87            getConnection().close();
88        } catch (SOAPException e) {
89            // TODO Auto-generated catch block
90            e.printStackTrace();
91        }   
92    }
93
94    public void setTypeMappingRegistry() {
95         TypeMappingRegistry tmr = null;
96         TypeMapping tm = null;
97  
98      
99        tmr = new TypeMappingRegistryImpl();
00
01        // Gets / Creates the TypeMapping instance
02        String encodingStyle = Constants.URI_DEFAULT_SOAP_ENC;
03        tm = (TypeMapping) tmr.getTypeMapping(encodingStyle);
04        TypeMapping df = (TypeMapping) tmr.getDefaultTypeMapping();
05        
06        Class[] myclass = df.getAllClasses();
07    
08        for ( int j = 0
09            ;j < myclass.length ;
10            j++
11            ){
12                log.debug(
13                    "mapd : "
14                    + myclass[j].getName()
15                    + " "
16                    +df.getTypeQName(myclass[j]).toString()
17                    + " "
18                    +df.getSerializer(myclass[j])
19                    )
20                ;               
21            }   
22        
23    /*  if (tm == null || tm == df) {
24          tm = (TypeMapping) tmr.createTypeMapping();
25          tm.setSupportedEncodings(new String[] {encodingStyle});
26          tmr.register(encodingStyle, tm);
27        }
28        */
29      
30    }
31    private OctetStream setOctet(InputStream is){
32        BufferedInputStream bis = new BufferedInputStream(is);
33        OctetStream out = new OctetStream();
34
35          byte[] buf = new byte[20 * 1024];  // 20K buffer for .xls in j/1_2/docs
36          int bytesRead;
37          try {
38            while ((bytesRead = bis.read(buf)) != -1) {
39                out.setBytes(buf);
40              }
41        } catch (IOException e) {
42            // TODO Auto-generated catch block
43            e.printStackTrace();
44        }
45        return out;
46    }
47    
48    
49    //TODO need to get the 4 modes of connection split out in seperate
50    // classes , all impls. of the same interface
51    //  soapsingleImpl, diiImpl, soapArrayImpl 
52    //A point-to-point connection SoapConnection - soapconnection
53    //JAXRPC Dynamic Invoation Interface implementation of the Service - diiservice
54    //#ws.invocation.typ=soapconnection
55    //ws.invocation.typ=diiservice  arg0=tm1*
56    // file name and endpt are the args
57    // F:\\axis-1_1RC2\\samples\\attachments\\build.xml
58    //http://localhost:8080/axis/services/urn:EchoAttachmentsService
59    // use diiservice for operation with DataHandler[] as parm
60    public static void main(String[] args) {
61        SAAJCallMgr myMgr= new SAAJCallMgr();
62//      myMgr.setMessageContext(
63//          MessageContext.getCurrentContext()
64//      );
65        myMgr.setMessageContext(
66            new MessageContext(
67                new Service().getEngine()
68                )
69        );
70        
71        if (
72            POProperty.get(
73                "ws.invocation.typ"
74            ).equalsIgnoreCase("soapconnection")
75        ) {
76        try {
77            myMgr.setConnection(
78                SOAPConnectionFactoryImpl.newInstance()
79                .createConnection()
80            );
81            myMgr.setReqMessage(
82
83                (Message)MessageFactoryImpl.newInstance().createMessage()
84            );
85        } catch (UnsupportedOperationException e) {
86            // TODO Auto-generated catch block
87            e.printStackTrace();
88        } catch (SOAPException e) {
89            // TODO Auto-generated catch block
90            e.printStackTrace();
91        }
92
93        myMgr.setElementRpcOp(myMgr.addMethod("echo"));
94        log.debug("RpcOp as element " + myMgr.getElementRpcOp().toString());
95//      myMgr.addRPCParm("topicaction","publish");
96//      myMgr.addRPCParm("topicname","testattachment");     
97        for ( Iterator i = 
98                FileSelector.getFiles(args[0]).iterator() ;
99            i.hasNext();
00        ){
01            myMgr.addAttachment(
02                (File)i.next()
03                , "dh"
04            );              
05        }
06//TODO remove 2nd file name for test of dh2 and 2nd parm
07  for ( Iterator i = 
08          FileSelector.getFiles(args[1]).iterator() ;
09      i.hasNext();
10  ){
11      myMgr.addAttachment(
12          (File)i.next()
13          , "dh2"
14      );                
15  }     
16        myMgr.call(myMgr.getReqMessage());
17        myMgr.close();
18    }else if (
19        POProperty.get(
20            "ws.invocation.typ"
21        ).equalsIgnoreCase("diiservice")
22    )
23    {
24        Object ret = myMgr.diiCall(
25            FileSelector.getFiles(args[0])
26            ,
27            myMgr.getCall()
28        );
29//      myMgr.close();  rcr causing error 6/29
30    }
31    // this option doesn't work due to illegal parm being thrown at
32    // mysoapmessage.createAttachmentPart(dhset[] , cType)
33    else if (
34            POProperty.get(
35                "ws.invocation.typ"
36            ).equalsIgnoreCase("soaparrayofdhattach") 
37        )
38        {
39            // rcr test check typemapping for default serialization
40            myMgr.setTypeMappingRegistry();
41            try {
42                myMgr.setConnection(
43                    SOAPConnectionFactoryImpl.newInstance()
44                    .createConnection()
45                );
46                myMgr.setReqMessage(
47                    (Message)MessageFactoryImpl.newInstance().createMessage()
48                );
49                    
50            
51//              myMgr.setElementRpcOp(myMgr.addMethod("echoDir"));
52                RPCElement myRpcEl =    
53                new RPCElement(
54                    "urn:EchoAttachmentsService"
55                    ,"echoDir"
56                    ,myMgr.setDH(
57                        FileSelector.getFiles(
58                            args[0]
59                        )
60                    )
61                );
62                log.debug("using encd styl : "+
63                myMgr.getMessageContext(                        
64                    ).getSOAPConstants().getEncodingURI());
65                myRpcEl.setEncodingStyle(
66                    myMgr.getMessageContext(                        
67                    ).getSOAPConstants().getEncodingURI()
68                );
69                myRpcEl.setParentElement(myMgr.getBody());
70//              ).setParentElement(myMgr.getElementRpcOp());
71
72            } catch (SOAPException e) {
73                // TODO Auto-generated catch block
74                e.printStackTrace();
75            }                                                                               
76            myMgr.call(myMgr.getReqMessage());
77            myMgr.close();          
78        }
79        
80// in order to replace diiCall with a more static form of:
81// getConnection().call(amessage
82// provide re-impl of the code found in cls=
83//      org.apache.axis.client.Call.invoke(RPCElement) and in
84//      org.apache.axis.client.Call.invoke()
85//Note that the key to re-impl is using the RPCElement 
86//   built from Array of RPCParams
87// Note that this array contains the parameter(s) expected by the operation
88//  that is the target of the Service Call ie the server side method...
89        
90        else if (
91                POProperty.get(
92                    "ws.invocation.typ"
93                ).equalsIgnoreCase("soapconnparms") 
94            )
95// get new  envelope that will hold all attachments
96            myMgr.setRequestEnvelope(
97                new SOAPEnvelope(
98                    myMgr.getMessageContext().getSOAPConstants()
99                    ,myMgr.getMessageContext().getSchemaVersion()
00                )
01            );
02 
03// get new element with FileSet to DataHandler[] to RPCParam[]
04            RPCElement myRpcEl =    
05            new RPCElement(
06                "urn:EchoAttachmentsService"
07                ,"echoDir"
08                ,myMgr.setParam(                
09                    myMgr.setDH(
10                        FileSelector.getFiles(
11                            args[0]
12                        )
13                    )
14                )               
15            );          
16            log.debug("using encd styl : "+
17            myMgr.getMessageContext(                        
18                ).getSOAPConstants().getEncodingURI());
19            try {
20                myRpcEl.setEncodingStyle(
21                    myMgr.getMessageContext(                        
22                    ).getSOAPConstants().getEncodingURI()
23                );
24            } catch (SOAPException e) {
25                // TODO Auto-generated catch block
26                e.printStackTrace();
27            }
28// add attachments to envelope
29            myMgr.getRequestEnvelope().addBodyElement(myRpcEl);
30            myMgr.getRequestEnvelope().setMessageType(Message.REQUEST);         
31            try {
32                myMgr.getMessageContext().setTargetService(
33                    myMgr.getRequestEnvelope()
34                    .getFirstBody()
35                    .getNamespaceURI()
36                );              
37                myMgr.setConnection(
38                    SOAPConnectionFactoryImpl.newInstance()
39                    .createConnection()
40                );              
41            } catch (AxisFault e1) {
42                // TODO Auto-generated catch block
43                e1.printStackTrace();
44            } catch (UnsupportedOperationException e) {
45                // TODO Auto-generated catch block
46                e.printStackTrace();
47            } catch (SOAPException e) {
48                // TODO Auto-generated catch block
49                e.printStackTrace();
50            }
51//  call on the connection with parm of new message
52            myMgr.setReqMessage(
53                new Message(
54                    myMgr.getRequestEnvelope()
55                )
56            );
57            myMgr.getReqMessage().setMessageContext(
58                myMgr.getMessageContext()
59            );
60            myMgr.call(myMgr.getReqMessage());
61            myMgr.close();          
62            }
63        
64    static 
65    {
66        log = Logger.getLogger((SAAJCallMgr.class).getName());  
67        ClassLoader cl = SAAJCallMgr.class.getClassLoader();
68        PropertyConfigurator.configure(cl.getResource(
69            "config/log4j.properties"));
70    }
71    }
72