KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > petals > engine > forward > Forward


1 /**
2  * PETALS - PETALS Services Platform.
3  * Copyright (c) 2005 EBM Websourcing, http://www.ebmwebsourcing.com/
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * -------------------------------------------------------------------------
19  * $Id: Csv.java 1216 2006-11-14 18:27:09Z dutoo $
20  * -------------------------------------------------------------------------
21  */

22 package org.objectweb.petals.engine.forward;
23
24 import java.net.URI JavaDoc;
25 import java.util.HashMap JavaDoc;
26 import java.util.Iterator JavaDoc;
27 import java.util.Map JavaDoc;
28 import java.util.Properties JavaDoc;
29 import java.util.Set JavaDoc;
30 import java.util.logging.Level JavaDoc;
31 import java.util.logging.Logger JavaDoc;
32
33 import javax.activation.DataHandler JavaDoc;
34 import javax.jbi.JBIException;
35 import javax.jbi.management.DeploymentException;
36 import javax.jbi.messaging.DeliveryChannel;
37 import javax.jbi.messaging.ExchangeStatus;
38 import javax.jbi.messaging.Fault;
39 import javax.jbi.messaging.InOnly;
40 import javax.jbi.messaging.InOptionalOut;
41 import javax.jbi.messaging.InOut;
42 import javax.jbi.messaging.MessageExchange;
43 import javax.jbi.messaging.MessageExchangeFactory;
44 import javax.jbi.messaging.MessagingException;
45 import javax.jbi.messaging.NormalizedMessage;
46 import javax.jbi.messaging.RobustInOnly;
47 import javax.jbi.servicedesc.ServiceEndpoint;
48 import javax.xml.namespace.QName JavaDoc;
49 import javax.xml.transform.Source JavaDoc;
50 import javax.xml.transform.TransformerException JavaDoc;
51
52 import org.objectweb.petals.component.common.basic.AbstractComponent;
53 import org.objectweb.petals.component.common.basic.AbstractServiceUnitManager;
54 import org.objectweb.petals.component.common.util.SourceHelper;
55 import org.objectweb.petals.component.common.util.XMLHelper;
56 import org.w3c.dom.DOMException JavaDoc;
57 import org.w3c.dom.Node JavaDoc;
58 import org.w3c.dom.NodeList JavaDoc;
59 import org.w3c.dom.Text JavaDoc;
60
61
62 /**
63  * This is the Forward Component.
64  *
65  * It provides a single operation (that may be anything according
66  * to its corresponding WSDL definition) that chains calls to other
67  * services, which must be InOut save for the last one. Chaining calls
68  * here means sending to the next service the content and attachments
69  * that were returned by the last service to be called previously.
70  *
71  * The services and operations to be called are defined in "extension
72  * properties" (meaning component-commons 1.0.1 extension properties)
73  * provided in the service unit's META-INF/jbi.xml , as the text content
74  * of the "service_<i>" and "operation_<i>" extension properties, i
75  * being the order of the call within the chain (starting with 0).
76  *
77  * Here is a sample extension properties configuration :
78  * <petals-extensions:service_0>{http://petals.objectweb.org/}HelloworldService</petals-extensions:service_0>
79  * <petals-extensions:operation_0>sayHello</petals-extensions:operation_0>
80  *
81  * Note : in order to work, every target service must have available
82  * endpoints on the network, according to their exact qualified name
83  * as provided in the extension properties. That means that targeting
84  * {http://petals.objectweb.org/}HelloworldService won't work if the
85  * only available service is {http://petals.objectweb.org}HelloworldService
86  * (missing a slash).
87  *
88  * @version $Rev: 250 $Date: {date}
89  * @since Petals 1.0
90  * @author Marc Dutoo - Open Wide
91  *
92  */

93 public class Forward extends AbstractComponent {
94     
95     public static final String JavaDoc INONLY_METHOD = "InOnly";
96     public static final String JavaDoc INOUT_METHOD = "InOut";
97     public static final String JavaDoc INOPTIONALOUT_METHOD = "InOptionalOut";
98     public static final String JavaDoc ROBUSTINONLY_METHOD = "RobustInOnly";
99     
100
101     private Map JavaDoc<QName JavaDoc, Properties JavaDoc> serviceToPropertiesMap = new HashMap JavaDoc<QName JavaDoc, Properties JavaDoc>();
102
103     
104     /**
105      * Creates a new Forward.
106      *
107      */

108     public Forward() {
109         super();
110     }
111
112     /**
113      * Creates a new Forward.
114      *
115      */

116     public Forward(DeliveryChannel channel, Logger JavaDoc log) {
117         super(channel, log);
118     }
119     
120
121     @Override JavaDoc
122     protected boolean handleMessage(QName JavaDoc service, QName JavaDoc operation,
123         NormalizedMessage in, NormalizedMessage out, URI JavaDoc messageExhangePattern)
124         throws Exception JavaDoc {
125         // Loading configuration for service
126
Properties JavaDoc props = getServiceProperties(service);
127         
128         NormalizedMessage currentIn = in;
129         NormalizedMessage currentOut = null;
130         for (int i = 0; ; i++) {
131             // identifying the next service and operation to call
132
String JavaDoc targetServiceNameProp = "service_" + i;
133             String JavaDoc targetServiceOperationProp = "operation_" + i;
134             String JavaDoc targetServiceMethodProp = "method_" + i;
135             String JavaDoc targetServiceName = props.getProperty(targetServiceNameProp);
136             String JavaDoc targetServiceOperation = props.getProperty(targetServiceOperationProp, "");
137             String JavaDoc targetServiceMethod = props.getProperty(targetServiceMethodProp, INOUT_METHOD);
138             if (targetServiceName == null || targetServiceName.length() == 0) {
139                 // no other target service : this is the end of the forward chain
140
break;
141             }
142
143             // getting available endpoints
144
QName JavaDoc targetService = QName.valueOf(targetServiceName);
145             ServiceEndpoint[] targetEndpoints = this.getComponentContext()
146                 .getEndpointsForService(targetService);
147             if (targetEndpoints == null || targetEndpoints.length == 0) {
148                 throw new Exception JavaDoc("No endpoint found for service "
149                     + targetServiceName);
150             }
151             
152             if (currentIn == null) {
153                 throw new Exception JavaDoc("Previous forward had no OUT message "
154                     + "so there can't be another forward afterwards to "
155                     + targetServiceName + "." + targetServiceOperation);
156             }
157             
158             try {
159                currentOut = forwardCopy(currentIn,
160                    targetService, targetServiceOperation, targetServiceMethod);
161             } catch (Exception JavaDoc e) {
162                 throw new Exception JavaDoc("Error when forwarding to service and operation "
163                     + targetServiceName + "." + targetServiceOperation, e);
164             }
165             if (currentOut == null) {
166                 // the out message was already treated
167
// NB. we'll check that there will be no more forward
168
// and return "<success/>"
169
continue;
170                 
171             } else if (currentOut instanceof Fault) {
172                 String JavaDoc faultString = SourceHelper.createString(currentOut.getContent());
173                 throw new Exception JavaDoc("Service fault received from call "
174                     + "to service and operation " + targetServiceName
175                     + "." + targetServiceOperation + " : " + faultString);
176             }
177             
178             // preparing next forward
179
currentIn = currentOut;
180         }
181
182         if (out != null) {
183             if (currentOut == null) {
184                 // last forward was InOnly, so let's return "<success/>"
185
out.setContent(SourceHelper.createSource("<success/>"));
186             } else {
187                 // let's return the result of the last forward
188
copy(currentOut, out);
189             }
190         } // else called by in InOnly mode : nothing to do
191
return true;
192     }
193     
194     
195     /**
196      * Copies a message's content and attachments in another.
197      * @param originalNm
198      * @param copyNm
199      * @throws Exception
200      */

201     protected final static void copy(NormalizedMessage originalNm,
202         NormalizedMessage copyNm) throws Exception JavaDoc {
203         // setting content, with hardcopy (because if semantic routing...)
204
String JavaDoc contentString = SourceHelper.createString(originalNm.getContent());
205         copyNm.setContent(SourceHelper.createSource(contentString));
206
207         // setting attachments if any
208
Set JavaDoc inAttachmentNameSet = originalNm.getAttachmentNames();
209         if (inAttachmentNameSet != null) {
210             for (Iterator JavaDoc nameIt = inAttachmentNameSet.iterator(); nameIt.hasNext();) {
211                 String JavaDoc attachmentName = (String JavaDoc) nameIt.next();
212                 DataHandler JavaDoc attDh = originalNm.getAttachment(attachmentName);
213                 try {
214                     copyNm.addAttachment(attachmentName, attDh);
215                 } catch (MessagingException e) {
216                     throw new Exception JavaDoc("Error when attaching file "
217                         + attachmentName, e);
218                 }
219             }
220         }
221     }
222     
223     
224     /**
225      * Forwards a copy of the given message to the given service
226      * using the given operation and method (i.e. InOut etc.)
227      * @param originalIn
228      * @param service
229      * @param operation
230      * @param method
231      * @return
232      * @throws Exception
233      */

234     protected NormalizedMessage forwardCopy(NormalizedMessage originalIn,
235         QName JavaDoc service, String JavaDoc operation, String JavaDoc method) throws Exception JavaDoc {
236         // creating message exchange
237
MessageExchangeFactory mef = this.getDeliveryChannel().createExchangeFactory();
238         MessageExchange msg;
239         if (INONLY_METHOD.equals(method)) {
240             msg = mef.createInOnlyExchange();
241         } else if (INOUT_METHOD.equals(method)) {
242             msg = mef.createInOutExchange();
243         } else if (INOPTIONALOUT_METHOD.equals(method)) {
244             msg = mef.createInOptionalOutExchange();
245         } else if (ROBUSTINONLY_METHOD.equals(method)) {
246             msg = mef.createRobustInOnlyExchange();
247         } else {
248             throw new Exception JavaDoc("Unknown method " + method);
249         }
250         
251         // setting target
252
msg.setService(service);
253         msg.setOperation(QName.valueOf(operation));
254         
255         // copying IN message
256
NormalizedMessage copyIn = msg.createMessage();
257         copy(originalIn, copyIn);
258         if (INONLY_METHOD.equals(method)) {
259             ((InOnly) msg).setInMessage(copyIn);
260         } else if (INOUT_METHOD.equals(method)) {
261             ((InOut) msg).setInMessage(copyIn);
262         } else if (INOPTIONALOUT_METHOD.equals(method)) {
263             ((InOptionalOut) msg).setInMessage(copyIn);
264         } else if (ROBUSTINONLY_METHOD.equals(method)) {
265             ((RobustInOnly) msg).setInMessage(copyIn);
266         } else {
267             throw new Exception JavaDoc("Unknown method " + method);
268         }
269
270         // doing the actual message send
271
boolean ok = this.getDeliveryChannel().sendSync(msg, 0);
272         if(ok) {
273             if (ExchangeStatus.DONE.equals(msg.getStatus())) {
274                 return null; // means DONE status received
275

276             } else if (ExchangeStatus.ERROR.equals(msg.getStatus())) {
277                 String JavaDoc err = "ERROR status ! ";
278                 log.log(Level.SEVERE, err, msg.getError());
279                 throw new Exception JavaDoc(err, msg.getError()); // timeout
280

281             } else {
282                 try {
283                     NormalizedMessage out = null;
284                     // NB. maybe necessary to do again full copy with new NormalizedMessageImpl()
285
if (msg.getMessage("OUT") != null) {
286                         out = msg.getMessage("OUT");
287                     } else if (msg.getFault() != null) {
288                         out = msg.getFault();
289                     } else {
290                         // will be the same as DONE status received
291
}
292                     NormalizedMessage copyOut = msg.createMessage();
293                     copy(out, copyOut);
294
295                     msg.setStatus(ExchangeStatus.DONE);
296                     this.getDeliveryChannel().send(msg);
297                     return out;
298                     
299                 } catch (Exception JavaDoc e) {
300                     String JavaDoc err = "Error while getting response message";
301                     log.log(Level.SEVERE, err, e);
302                     throw new Exception JavaDoc(err, e); // timeout
303
}
304             }
305         } else {
306             String JavaDoc err = "Timeout !";
307             log.log(Level.SEVERE, err);
308             throw new Exception JavaDoc(err); // timeout
309
}
310     }
311
312
313
314     /**
315      * TODO MAY GO IN COMMONS
316      * Returns the given content as a String.
317      * Helper method to get everything there is under the top tag
318      * as a String. XML nodes will be formatted and included within.
319      * NB. For XQuare BC, the point is to allow users to write results
320      * formatting in XQuery code without having to XML-encode the tags.
321      * @param contentSource the content of an incoming JBI message
322      * @return a String. NB. For XQuare BC, an XQuery.
323      * @throws ContentException if XML transformation error
324      */

325     protected String JavaDoc transformToContentString(Source JavaDoc contentSource) throws ContentException {
326         try {
327             Node JavaDoc contentDocumentNode = XMLHelper.createDOMNodeFromSource(contentSource);
328             Node JavaDoc contentNode = XMLHelper.getFirstChild(contentDocumentNode);
329             // Now reading the XQuery code in the most "nice" way
330
NodeList JavaDoc queryNodes = contentNode.getChildNodes();
331             int queryNodeNb = queryNodes.getLength();
332             if (queryNodeNb == 1) {
333                 Node JavaDoc singleQueryNode = queryNodes.item(0);
334                 if (singleQueryNode instanceof Text JavaDoc) {
335                     return ((Text JavaDoc) singleQueryNode).getTextContent();
336                 }
337             }
338             StringBuffer JavaDoc contentBuf = new StringBuffer JavaDoc();
339             for (int i = 0; i < queryNodeNb ; i++) {
340                 Node JavaDoc queryNode = queryNodes.item(i);
341                 // getting the full XML of the node in order to help the user pass
342
// along Results XML formatting
343
contentBuf.append(XMLHelper.createStringFromDOMNode(queryNode));
344                 contentBuf.append("\n");
345             }
346             return contentBuf.toString();
347             
348         } catch (DOMException JavaDoc e) {
349             String JavaDoc msg = "Error while reading content string from XML Source "
350                 + tryToCreateStringForError(contentSource);
351             log.log(Level.SEVERE, msg, e);
352             throw new ContentException(msg, e);
353         } catch (TransformerException JavaDoc e) {
354             String JavaDoc msg = "Error while reading content string from XML Source "
355                 + tryToCreateStringForError(contentSource);
356             log.log(Level.SEVERE, msg, e);
357             throw new ContentException(msg, e);
358         }
359     }
360
361     /**
362      * TODO MAY GO IN COMMONS
363      * Returns the given content as a String that must be wrapped under
364      * a given top tag (checked).
365      * Helper method to get everything there is under a given top tag
366      * as a String. XML nodes will be formatted and included within.
367      * NB. For XQuare BC, the point is to allow users to write results
368      * formatting in XQuery code without having to XML-encode the tags.
369      * @param contentSource the content of an incoming JBI message
370      * @param contentTag the top tag of the contentSource
371      * @return a String. NB. For XQuare BC, an XQuery.
372      * @throws ContentException if XML transformation error or bad top tag
373      */

374     protected String JavaDoc transformToContentStringWithRootTag(
375         Source JavaDoc contentSource, String JavaDoc contentTag) throws ContentException {
376         try {
377             Node JavaDoc contentDocumentNode = XMLHelper.createDOMNodeFromSource(contentSource);
378             Node JavaDoc contentNode = XMLHelper.getFirstChild(contentDocumentNode);
379             // Checking that node element tag is the required one
380
if (!contentTag.equals(contentNode.getLocalName())) {
381                 throw new ContentException("Such messages should be "
382                     + "encapsulated in a top <\"" + contentTag + "\"> tag !");
383             }
384             // Now reading the XQuery code in the most "nice" way
385
NodeList JavaDoc queryNodes = contentNode.getChildNodes();
386             int queryNodeNb = queryNodes.getLength();
387             if (queryNodeNb == 1) {
388                 Node JavaDoc singleQueryNode = queryNodes.item(0);
389                 if (singleQueryNode instanceof Text JavaDoc) {
390                     return ((Text JavaDoc) singleQueryNode).getTextContent();
391                 }
392             }
393             StringBuffer JavaDoc contentBuf = new StringBuffer JavaDoc();
394             for (int i = 0; i < queryNodeNb ; i++) {
395                 Node JavaDoc queryNode = queryNodes.item(i);
396                 // getting the full XML of the node in order to help the user pass
397
// along Results XML formatting
398
contentBuf.append(XMLHelper.createStringFromDOMNode(queryNode));
399                 contentBuf.append("\n");
400             }
401             return contentBuf.toString();
402             
403         } catch (DOMException JavaDoc e) {
404             String JavaDoc msg = "Error while reading content string from XML Source "
405                 + tryToCreateStringForError(contentSource);
406             log.log(Level.SEVERE, msg, e);
407             throw new ContentException(msg, e);
408         } catch (TransformerException JavaDoc e) {
409             String JavaDoc msg = "Error while reading content string from XML Source "
410                 + tryToCreateStringForError(contentSource);
411             log.log(Level.SEVERE, msg, e);
412             throw new ContentException(msg, e);
413         }
414     }
415
416
417     /**
418      * TODO MAY GO IN COMMONS
419      * Returns the given content as a DOM node.
420      * @param contentSource the content of an incoming JBI message
421      * @return the corresponding DOM node tree
422      * @throws ContentException if XML transformation error
423      */

424     protected Node JavaDoc transformToContentNode(Source JavaDoc contentSource) throws ContentException {
425          try {
426              Node JavaDoc contentDocumentNode = XMLHelper.createDOMNodeFromSource(contentSource);
427              Node JavaDoc contentNode = XMLHelper.getFirstChild(contentDocumentNode);
428              return contentNode;
429         } catch (TransformerException JavaDoc e) {
430             String JavaDoc msg = "Error while reading content node from XML Source "
431                 + tryToCreateStringForError(contentSource);
432             log.log(Level.SEVERE, msg, e);
433             throw new ContentException(msg, e);
434         }
435     }
436
437     /**
438      * TODO MAY GO IN COMMONS
439      * Returns the given content as a DOM node that must be wrapped under
440      * a given top tag (checked).
441      * @param contentSource the content of an incoming JBI message
442      * @param contentTag the top tag of the contentSource
443      * @return the corresponding DOM node tree
444      * @throws ContentException if XML transformation error or bad top tag
445      */

446     protected Node JavaDoc transformToContentNodeWithRootTag(
447         Source JavaDoc contentSource, String JavaDoc contentTag) throws ContentException {
448         try {
449             Node JavaDoc contentDocumentNode = XMLHelper.createDOMNodeFromSource(contentSource);
450             Node JavaDoc contentNode = XMLHelper.getFirstChild(contentDocumentNode);
451             // Checking that node element tag is the required one
452
if (!contentTag.equals(contentNode.getLocalName())) {
453                 throw new ContentException("Such messages should be "
454                     + "encapsulated in a top <\"" + contentTag + "\"> tag !");
455             }
456             return contentNode;
457         } catch (TransformerException JavaDoc e) {
458             String JavaDoc msg = "Error while reading content node from XML Source "
459                 + tryToCreateStringForError(contentSource);
460             log.log(Level.SEVERE, msg, e);
461             throw new ContentException(msg, e);
462         }
463     }
464     
465     
466     public static final String JavaDoc tryToCreateStringForError(Source JavaDoc contentSource) {
467         String JavaDoc contentString;
468         try {
469             // NB. SourceHelper.createString() does a reset on Stream sources
470
contentString = SourceHelper.createString(contentSource);
471         } catch (Exception JavaDoc e) {
472             // do nothing
473
contentString = "[[error in transforming Source to String]]";
474         }
475         return contentString;
476     }
477
478
479     /**
480      * Returns the targeted service unit's properties.
481      * @param service the targeted service
482      * @return its configuration
483      * @throws XQuareBCException
484      */

485     protected Properties JavaDoc getServiceProperties(QName JavaDoc service) throws Exception JavaDoc {
486         Properties JavaDoc csvProperties = this.serviceToPropertiesMap.get(service);
487         if (csvProperties != null) {
488             return csvProperties;
489         } else {
490             throw new Exception JavaDoc("Service properties not found for service "
491                 + service);
492         }
493     }
494
495
496     @Override JavaDoc
497     protected AbstractServiceUnitManager createServiceUnitManager() throws DeploymentException {
498         // NB. the super impl returns a new SimpleServiceUnitManager with no extension handling
499
PropertiesServiceUnitManager suMgr;
500         try {
501             suMgr = new PropertiesServiceUnitManager(this.getComponentContext(),
502                 log, serviceToPropertiesMap);
503         } catch (JBIException e) {
504             throw new DeploymentException("Unable to get component context", e);
505         }
506         return suMgr;
507     }
508
509 }
510
Popular Tags