View Javadoc

1   /*
2    *  Copyright (c) 2005, 2006 Imola Informatica.
3    *  All rights reserved. This program and the accompanying materials
4    *  are made available under the terms of the LGPL License v2.1
5    *  which accompanies this distribution, and is available at
6    *  http://www.gnu.org/licenses/lgpl.html
7    */
8   
9   
10  package it.imolinfo.jbi4cics.jbi;
11  
12  import it.imolinfo.jbi4cics.Logger;
13  import it.imolinfo.jbi4cics.LoggerFactory;
14  import it.imolinfo.jbi4cics.commareaparser.CommareaLexer;
15  import it.imolinfo.jbi4cics.commareaparser.CommareaParser;
16  import it.imolinfo.jbi4cics.exception.FormatException;
17  import it.imolinfo.jbi4cics.exception.Jbi4cicsException;
18  import it.imolinfo.jbi4cics.exception.ParseException;
19  import it.imolinfo.jbi4cics.messageformat.commarea.CommareaBeanMappingDescriptor;
20  import it.imolinfo.jbi4cics.webservices.descriptor.ServiceDescriptor;
21  import it.imolinfo.jbi4cics.webservices.runtime.ServiceCreator;
22  import it.imolinfo.jbi4cics.webservices.utils.generators.ServiceBeanGenerator;
23  import it.imolinfo.jbi4cics.webservices.utils.generators.ServiceInterfaceGenerator;
24  import java.io.ByteArrayInputStream;
25  import java.io.ByteArrayOutputStream;
26  import java.io.FileWriter;
27  import java.io.IOException;
28  import java.io.StringReader;
29  import java.util.Collection;
30  import javax.wsdl.Definition;
31  import javax.wsdl.Port;
32  import javax.wsdl.WSDLException;
33  import javax.wsdl.factory.WSDLFactory;
34  import javax.xml.namespace.QName;
35  import javax.xml.parsers.DocumentBuilderFactory;
36  import javax.xml.parsers.ParserConfigurationException;
37  import javax.xml.transform.Transformer;
38  import javax.xml.transform.TransformerException;
39  import javax.xml.transform.TransformerFactory;
40  import javax.xml.transform.dom.DOMSource;
41  import javax.xml.transform.stream.StreamResult;
42  import org.apache.servicemix.common.ExchangeProcessor;
43  import org.apache.servicemix.common.endpoints.ProviderEndpoint;
44  import org.codehaus.xfire.XFire;
45  import org.codehaus.xfire.service.Service;
46  import org.w3c.dom.Document;
47  import org.xml.sax.SAXException;
48  import antlr.ANTLRException;
49  
50  public final class Jbi4cicsEndpoint extends ProviderEndpoint {
51  
52      /**
53       * The logger for this class and its instances.
54       */
55      private static final Logger LOG
56              = LoggerFactory.getLogger(Jbi4cicsEndpoint.class);
57  
58      /**
59       * The responsible to translate localized messages.
60       */
61      private static final Messages MESSAGES
62              = Messages.getMessages(Jbi4cicsEndpoint.class);
63  
64      /**
65       * The code page.
66       */
67      private String codePage;
68  
69      /**
70       * The input copy Cobol file name.
71       */
72      private String copyCobolFileName;
73  
74      /**
75       * The output copy Cobol file name.
76       */
77      private String outputCopyCobolFileName;
78  
79      /**
80       * The input copy Cobol, used also for output if {@link #outputCopyCobol} is
81       * <code>null</code> or empty.
82       */
83      private String copyCobol;
84  
85      /**
86       * The output copy Cobol.
87       */
88      private String outputCopyCobol;
89  
90      /**
91       * The service descriptor.
92       */
93      private ServiceDescriptor serviceDescriptor;
94  
95      /**
96       * The XFire service.
97       */
98      private Service xfireService;
99  
100     private ExchangeProcessor processor = new Jbi4cicsExchangeProcessor(this);
101 
102     /**
103      * Initializes a new instance of this class.
104      */
105     public Jbi4cicsEndpoint() {
106     }
107 
108     /**
109      * Returns the xfire <code>Service</code>.
110      *
111      * @return the xfire <code>Service</code>.
112      */
113     public Service getXFireService() {
114         return xfireService;
115     }
116 
117     /**
118      * Starts the <code>ExchangeProcessor</code>.
119      *
120      * @throws  Exception  if caused by the call to <code>super.start()</code>
121      *                     or the exchange processor startup.
122      */
123     @Override
124     public void start() throws Exception {                      // Overridden
125         super.start();
126         processor.start();
127     }
128 
129     /**
130      * Stops the <code>ExchangeProcessor</code>.
131      *
132      * @throws  Exception  if caused by the call to <code>super.stop()</code>
133      *                     or the exchange processor stop.
134      */
135     @Override
136     public void stop() throws Exception {                       // Overridden
137         super.stop();
138         processor.stop();
139     }
140 
141     /**
142      * Registers the service.
143      */
144     void registerService() throws Jbi4cicsException, IOException,
145             ANTLRException, SAXException, ParserConfigurationException,
146             WSDLException, TransformerException {
147         XFire xfire = getXFire();
148 
149         createServiceBeansAndInterface();
150         if (definition != null) {
151             Port port;
152 
153             // Gets service/endpoint from the WSDL definition
154             LOG.debug("Using WSDL definition to load endpoint data");
155 
156             // Gets the endpoint
157             service = new QName(serviceDescriptor.getServiceNameSpace(),
158                                 serviceDescriptor.getServiceName());
159             port = initEndpointIfIsNull(definition.getService(service));
160             checkEndpointIsNotNull();
161 
162             // XXX What if 'port' is null? Look at initEndpointIfIsNull()...
163             interfaceName = port.getBinding().getPortType().getQName();
164 
165             if (LOG.isDebugEnabled()) {
166                 LOG.debug("Loaded endpoint data, service: " + service
167                           + ", endpoint: " + endpoint + ", interface:"
168                           + interfaceName);
169             }
170         }
171 
172         // Create and register the xfire service
173         xfireService = new ServiceCreator().createJbiService(
174                 serviceDescriptor, xfire, interfaceName);
175         xfire.getServiceRegistry().register(xfireService);
176 
177         if (definition == null) {
178             QName serviceQName;
179             QName interfaceQName;
180             Definition def;
181             javax.wsdl.Service wsdlService;
182 
183             // Check service name, endpoint name ad description from xfire
184             description = generateWsdl();
185             serviceQName = xfireService.getName();
186             interfaceQName = xfireService.getServiceInfo().getPortType();
187             if (service == null) {
188                 service = serviceQName;
189             } else if (!service.equals(serviceQName)) {
190                 LOG.warn("CIC001018_Service_name_not_matched", serviceQName,
191                          service);
192             }
193             if (interfaceName == null) {
194                 interfaceName = interfaceQName;
195             } else if (!interfaceName.equals(interfaceQName)) {
196                 LOG.warn("CIC001019_Interface_name_not_matched", interfaceQName,
197                          interfaceName);
198             }
199             def = WSDLFactory.newInstance().newWSDLReader().readWSDL(
200                     null, description);
201             wsdlService = def.getService(serviceQName);
202             if (wsdlService != null) {
203                 initEndpointIfIsNull(wsdlService);
204             }
205             checkEndpointIsNotNull();
206         }
207 
208         writeWsdlToFile();              // Writes out the description on file
209     }
210 
211     /**
212      * Verifies and updates {@link #serviceDescriptor} creating the input bean,
213      * the output bean and the service interface.
214      *
215      * @throws  Jbi4cicsException  if the service name stored in the service
216      *                             descriptor is <code>null</code>.
217      * @throws  ANTLRException     if an error occurs while parsing the
218      *                             copy/copies Cobol.
219      */
220     private void createServiceBeansAndInterface()
221             throws Jbi4cicsException, ANTLRException {
222         CommareaBeanMappingDescriptor descriptor;
223         BCELClassLoader classLoader = ((Jbi4cicsLifeCycle)
224                 serviceUnit.getComponent().getLifeCycle()).getBCELClassLoader();
225         ServiceBeanGenerator beanGenerator;
226         ServiceInterfaceGenerator interfGenerator;
227 
228         // Set the defaults
229         if (serviceDescriptor.getServiceName() == null) {
230             throw new Jbi4cicsException(
231                     "CIC001013_Service_name_not_initialized");
232         }
233         serviceDescriptor.setDefaultValuesIfNecessary();
234 
235         // Generate the mapping descriptor from copy/copies Cobol. If only
236         // 'copyCobol' is found, the same CommareaBeanMappingDescriptor is used
237         // for both the input and the output step
238         descriptor = parseCommarea(copyCobol);
239         serviceDescriptor.setInputMappingDescriptor(descriptor);
240         if ((outputCopyCobol != null) && (outputCopyCobol.length() > 0)
241                 && !outputCopyCobol.equals(copyCobol)) {
242             descriptor = parseCommarea(outputCopyCobol);
243         }
244         serviceDescriptor.setOutputMappingDescriptor(descriptor);
245 
246         // Creates the service inputBean
247         beanGenerator = new ServiceBeanGenerator(serviceDescriptor, true);
248         beanGenerator.generateBeanClass(classLoader);
249 
250         // Creates the service outputBean
251         beanGenerator = new ServiceBeanGenerator(serviceDescriptor, false);
252         beanGenerator.generateBeanClass(classLoader);
253 
254         // Creates the service interface
255         interfGenerator = new ServiceInterfaceGenerator(serviceDescriptor);
256         interfGenerator.generateServiceInterface(classLoader);
257 
258         // FIXME questa gestione del codepage non e' elegante
259         serviceDescriptor.setCodePage(codePage);
260     }
261 
262     /**
263      * Parses the specified commarea.
264      *
265      * @param   cpyCobol         the copy Cobol describing the commarea to
266      *                           parse. Must be not <code>null</code>.
267      * @return  the descriptor related to the received commarea.
268      * @throws  ANTLRException   if thrown by the ANTLR lexer or parser.
269      * @throws  FormatException  if a field contained in the commarea has a
270      *                           wrong format.
271      * @throws  ParseException   if a field type is not supported or contains
272      *                           erroneous value(s).
273      */
274     CommareaBeanMappingDescriptor parseCommarea(final String cpyCobol)
275             throws ANTLRException, FormatException, ParseException {
276         CommareaLexer lexer = new CommareaLexer(new StringReader(copyCobol));
277         CommareaParser parser = new CommareaParser(lexer);
278         CommareaBeanMappingDescriptor desc = parser.commarea_definition();
279 
280         LOG.info("CIC001014_Commarea_parsed", getEndpoint(), desc);
281         return desc;
282     }
283 
284     /**
285      * Tries to set the <code>enpoint</code> field value if is currently
286      * <code>null</code>, getting its value from the specified WSDL service.
287      *
288      * @param   wsdlService  the WSDL service to get the endpoint name. Must be
289      *                       not <code>null</code>.
290      * @return  the port used to obtain the endpoint name, even if the endpoint
291      *          was also initialized and has not been modified. May be
292      *          <code>null</code>, in which case the <code>endpoint</code> field
293      *          has been left unchanged.
294      */
295     private Port initEndpointIfIsNull(javax.wsdl.Service wsdlService) {
296         Collection ports = wsdlService.getPorts().values();
297         Port port = null;
298 
299         if (ports.size() == 1) {
300 
301             // Check if this is the same as defined in endpoint spec
302             port = (Port) ports.iterator().next();
303             if (endpoint == null) {
304                 endpoint = port.getName();
305             } else if (!endpoint.equals(port.getName())) {
306                 LOG.warn("CIC001016_Endpoint_name_not_matched", port.getName(),
307                          endpoint);
308             }
309         }
310         return port;
311     }
312 
313     /**
314      * Verifies that the current endpoint value is not <code>null</code>.
315      *
316      * @throws  IllegalArgumentException  if the stored endpoint is
317      *                                    <code>null</code>.
318      */
319     private void checkEndpointIsNotNull() {
320         if (endpoint == null) {
321             throw new IllegalArgumentException(MESSAGES.getString(
322                     "CIC001017_Endpoint_name_not_provided"));
323         }
324     }
325 
326     private Document generateWsdl() throws SAXException, IOException,
327             ParserConfigurationException {
328         ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
329         DocumentBuilderFactory factory =
330             DocumentBuilderFactory.newInstance();
331 
332         getXFire().generateWSDL(xfireService.getSimpleName(), baos);
333         if (LOG.isDebugEnabled()) {
334             LOG.debug(baos.toString());
335         }
336         factory.setNamespaceAware(true);
337         return factory.newDocumentBuilder().parse(
338                 new ByteArrayInputStream(baos.toByteArray()));
339     }
340 
341     /**
342      * Write the generated WSDL to a file.
343      *
344      * @throws  IOException                   if the named file exists but is a
345      *                                        directory rather than a regular
346      *                                        file, does not exist but cannot be
347      *                                        created, or cannot be opened for
348      *                                        any other reason.
349      * @throws  TransformerException          if an unrecoverable error occurs
350      *                                        during the course of the XML
351      *                                        transformation.
352      * @throws  SAXException                  if any parse errors occur.
353      * @throws  ParserConfigurationException  if a <code>javax.xml.parsers.DocumentBuilder</code>
354      *                                        cannot be created which satisfies
355      *                                        the configuration requested.
356      */
357     private void writeWsdlToFile() throws IOException, TransformerException,
358             SAXException, ParserConfigurationException {
359         String wsdlFileName = getServiceUnit().getRootPath() + "/"
360                               + xfireService.getSimpleName() + ".wsdl";
361         FileWriter file;
362 
363         LOG.info("CIC001020_Producing_wsdl", wsdlFileName);
364         file = new FileWriter(wsdlFileName);
365         try {
366             TransformerFactory factory = TransformerFactory.newInstance();
367             Transformer transormer = factory.newTransformer();
368 
369             transormer.transform(new DOMSource(generateWsdl()),
370                                  new StreamResult(file));
371         } finally {
372             file.close();
373         }
374     }
375 
376     XFire getXFire() {
377         Jbi4cicsLifeCycle lifeCycle
378                 = (Jbi4cicsLifeCycle) serviceUnit.getComponent().getLifeCycle();
379 
380         return lifeCycle.getXFire();
381     }
382 
383     /**
384      * Returns the exchange processor.
385      *
386      * @return  the exchange processor.
387      */
388     @Override
389     public ExchangeProcessor getProcessor() {                   // Overridden
390         return processor;
391     }
392 
393     /**
394      * Returns the input copy Cobol.
395      *
396      * @return  the input copy Cobol.
397      */
398     public String getCopyCobol() {
399         return copyCobol;
400     }
401 
402     /**
403      * Sets the input copy Cobol.
404      *
405      * @param copyCobol  the input copy Cobol to set.
406      */
407     public void setCopyCobol(final String copyCobol) {
408         this.copyCobol = copyCobol;
409     }
410 
411     /**
412      * Returns the output copy Cobol.
413      *
414      * @return  the output copy Cobol.
415      */
416     public String getOutputCopyCobol() {
417         return outputCopyCobol;
418     }
419 
420     /**
421      * Sets the output copy Cobol.
422      *
423      * @param  outputCopyCobol  the output copy Cobol to set.
424      */
425     public void setOutputCopyCobol(final String outputCopyCobol) {
426         this.outputCopyCobol = outputCopyCobol;
427     }
428 
429     /**
430      * Returns the service descriptor.
431      *
432      * @return the service descriptor.
433      */
434     public ServiceDescriptor getServiceDescriptor() {
435         return serviceDescriptor;
436     }
437 
438     /**
439      * Sets the service descriptor.
440      *
441      * @param  serviceDescriptor  the service descriptor to set.
442      */
443     public void setServiceDescriptor(final ServiceDescriptor serviceDescriptor) {
444         this.serviceDescriptor = serviceDescriptor;
445     }
446 
447     /**
448      * Returns the input copy Cobol file name.
449      *
450      * @return  the input copy Cobol file name.
451      */
452     public String getCopyCobolFileName() {
453         return copyCobolFileName;
454     }
455 
456     /**
457      * Sets the input copy Cobol file name.
458      *
459      * @param  copyCobolFileName  the input copy Cobol file name to set.
460      */
461     public void setCopyCobolFileName(final String copyCobolFileName) {
462         this.copyCobolFileName = copyCobolFileName;
463     }
464 
465     /**
466      * Returns the output copy Cobol file name.
467      *
468      * @return  the output copy Cobol file name.
469      */
470     public String getOutputCopyCobolFileName() {
471         return outputCopyCobolFileName;
472     }
473 
474     /**
475      * Sets the output copy Cobol file name.
476      *
477      * @param  outputCopyCobolFileName  the output copy Cobol file name to set.
478      */
479     public void setOutputCopyCobolFileName(
480             final String outputCopyCobolFileName) {
481         this.outputCopyCobolFileName = outputCopyCobolFileName;
482     }
483 
484     /**
485      * Returns the code page.
486      *
487      * @return the code page.
488      */
489     public String getCodePage() {
490         return codePage;
491     }
492 
493     /**
494      * Sets the code page.
495      *
496      * @param  codePage  the code page to set.
497      */
498     public void setCodePage(final String codePage) {
499         this.codePage = codePage;
500     }
501 }