View Javadoc

1    /****************************************************************************
2    * Copyright (c) 2005, 2006, 2007, 2008, 2009 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   package it.imolinfo.jbi4corba.webservice.runtime;
9   
10  import it.imolinfo.jbi4corba.Logger;
11  import it.imolinfo.jbi4corba.LoggerFactory;
12  import it.imolinfo.jbi4corba.exception.Jbi4CorbaException;
13  import it.imolinfo.jbi4corba.jbi.Messages;
14  import it.imolinfo.jbi4corba.webservice.descriptor.ProviderServiceDescriptor;
15  import it.imolinfo.jbi4corba.webservice.generator.MethodSignature;
16  import java.lang.reflect.Array;
17  import java.lang.reflect.InvocationTargetException;
18  import java.lang.reflect.Method;
19  import java.util.Arrays;
20  import java.util.List;
21  import net.java.hulp.measure.Probe;
22  
23  import org.apache.cxf.frontend.MethodDispatcher;
24  import org.apache.cxf.helpers.CastUtils;
25  import org.apache.cxf.interceptor.Fault;
26  import org.apache.cxf.message.Exchange;
27  import org.apache.cxf.message.FaultMode;
28  import org.apache.cxf.message.MessageContentsList;
29  import org.apache.cxf.service.Service;
30  import org.apache.cxf.service.invoker.AbstractInvoker;
31  import org.apache.cxf.service.model.BindingOperationInfo;
32  import org.apache.cxf.service.model.MessageInfo;
33  import org.apache.cxf.service.model.MessagePartInfo;
34  import org.omg.CORBA.SystemException;
35  
36  /**
37   * This class handle invokation of web services and forward in to a legacy
38   * service invokation.
39   */
40  public final class ProviderServiceInvoker extends AbstractInvoker {
41  
42      /**
43       * Logger.
44       */
45      private static final Logger LOG = LoggerFactory.getLogger(ProviderServiceInvoker.class);
46      /**
47       * The responsible to translate localized messages.
48       */
49      private static final Messages MESSAGES = Messages.getMessages(ProviderServiceInvoker.class);
50      
51      /**
52       * The object proxed by the invoker
53       */
54      Object obj = null;
55      
56      private Probe mMeasurement;
57      /**
58       * The service descriptor.
59       */
60      private ProviderServiceDescriptor serviceDescriptor;
61      /**
62       * The Servant is a Corba Object.
63       */
64      boolean isCorbaServant = true;
65      
66  
67      /**
68       * Constructor.
69       *
70       * @param serviceDescriptor  The service descriptor
71       */
72      public ProviderServiceInvoker(
73              final ProviderServiceDescriptor serviceDescriptor) {
74          this.serviceDescriptor = serviceDescriptor;
75          if (serviceDescriptor != null) {
76              obj = serviceDescriptor.getCorbaObjectReference();
77          }
78      }
79  
80      /**
81       * Constructor.
82       *
83       * @param serviceDescriptor  The service descriptor
84       */
85      public ProviderServiceInvoker(
86              final ProviderServiceDescriptor serviceDescriptor, boolean isCorbaServant) {
87          this.serviceDescriptor = serviceDescriptor;
88          if (serviceDescriptor != null) {
89              obj = serviceDescriptor.getCorbaObjectReference();
90          }
91          this.isCorbaServant = isCorbaServant;
92      }
93  
94      /**
95       * Creates and returns a service object depending on the scope.
96       */
97      public Object getServiceObject(final Exchange context) {
98          LOG.debug("Returning object for exchange: " + context.getInMessage());
99          return obj;
100     }
101 
102     /**
103      * Set the service object for testing pourpose
104      */
105     public void setServiceObject(Object obj) {
106         this.obj = obj;
107     }
108 
109     /**
110      * Sets ths classloader to find the corba classes and invokes the superclass.
111      */
112     @Override
113     public Object invoke(Exchange exchange, Object o) {
114         
115         Object dynamicObject=null;
116         //Is used to use the correct Object for invokatio
117         //It's the dynamic is dynamic is != null else is the obj. 
118         Object currentObj=null;
119         
120         //If this request is dynamic the object used for the invocation is generated from the IOR
121         
122         if (exchange.get("EPR_IOR") != null) {
123            try {
124         	 
125         	String ior=exchange.get("EPR_IOR").toString();
126         	dynamicObject = serviceDescriptor.getEndpoint().getCorbaObjectReference(ior);
127 		  
128            } catch (Jbi4CorbaException e) {
129    			String msg = MESSAGES.getString("CRB000766_Unable_to_get_corba_object_from_IOR");
130 			LOG.error(msg, e.getMessage());
131                exchange.getOutMessage().put(FaultMode.class, FaultMode.UNCHECKED_APPLICATION_FAULT);
132                exchange.getOutFaultMessage().setContent(Exception.class, new Fault(e));                
133                // e.printStackTrace();
134                throw new Fault(e);
135            }
136             
137         }
138 
139         LOG.debug("Invoking exchange: " + exchange + " with object: " + o.getClass().getName() + "[" + o + "] using CXF");
140 
141         // Stop chrono for measure of Denormalization      
142         mMeasurement = (Probe) exchange.get("Measure-deN");
143         mMeasurement.end();
144 
145         ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
146         Thread.currentThread().setContextClassLoader(
147                 serviceDescriptor.getOriginalClassLoader());
148               
149         // information needed for service to corba and corba to service object transformation
150         RuntimeInformation runtimeInfo = new RuntimeInformation(serviceDescriptor.getUrlClassLoader(),
151                 serviceDescriptor.getOriginalClassLoader(), serviceDescriptor.getAllCorbaTypes(), serviceDescriptor.getEndpoint(),
152                 serviceDescriptor.getEndpoint().getOrb(), serviceDescriptor.getAllIDLTypes(), serviceDescriptor.getCorbaEnumMap(),
153                 serviceDescriptor.getIdToClassNameMap(), serviceDescriptor.getTypeDefs());
154         
155 
156         try {
157             // TODO: add i18 messages on exceptions
158             BindingOperationInfo bop = exchange.get(BindingOperationInfo.class);
159             MethodDispatcher md = (MethodDispatcher) exchange.get(Service.class).get(MethodDispatcher.class.getName());
160             Method m = md.getMethod(bop);
161 
162             bop.getInput().getMessageInfo().getMessageParts();
163 
164             // Extract the Params. With CXF 2.1.x, the Object param is changed and contains
165             // a wrapper of the 
166             List<Object> params = extractParams(o, bop.getInput().getMessageInfo());
167 
168             Object[] paramArray = new Object[]{};
169             if (params != null) {
170                 paramArray = params.toArray();
171             }
172             
173             
174             if (LOG.isDebugEnabled()) {
175         	 
176                 LOG.debug("Parameters:");
177                 for (int i = 0; i < paramArray.length; i++) {
178                     if (paramArray[i] != null) {
179                         LOG.debug("Parameter #" + i + " of class:" + paramArray[i].getClass().getName());
180 
181                     } else {
182                         LOG.debug("Parameter #" + i + " is null");
183                     }
184 
185                 }
186             }
187             try {
188 
189                 LOG.debug(">>>> OBJ: " + obj);
190                 if (obj == null) {
191                     if(serviceDescriptor.getLocalizationType()!=null){
192                         if (serviceDescriptor.getCorbaObjectReference() == null) {
193                             LOG.debug(">>>> Reconnect begin...");
194                             serviceDescriptor.getEndpoint().locateCorbaService();
195                             LOG.debug(">>>> Reconnect end...");
196                         }
197                         
198                     }                        
199                     //get corbaObjectReference
200                     obj = serviceDescriptor.getCorbaObjectReference();
201                    
202                     
203                 }
204                 //Change the Invokation Object if there is a valid dynamic Object
205                 if(dynamicObject!=null){
206                     currentObj=dynamicObject;    
207                 }else{
208                     currentObj=obj;
209                 }
210                 
211                 //**********************************************************************
212                 // INOUT Gets the Object array with the correct Holder and gets the method from the stub 
213                 MethodSignature methodSignature = getMetodSignatureFromMethod(m);
214                 
215                 //**** Added for management of Array of length 0****************
216                 //**** Workaroud added to manage array of length 0
217                 for(int i=0;i<paramArray.length;i++){
218                     if(methodSignature.getParameters().get(i).isArray()){
219                         if(paramArray[i]==null){
220                             LOG.debug("********************************************Instance new Array of size 0");
221                             paramArray[i]=Array.newInstance(methodSignature.getParameters().get(i).getType(), 0);
222 
223                         }
224                     }
225                 }
226                 //**************************************************************
227                 
228                 if (methodSignature.isContainsHolder()) {
229                     // manage holders.             
230                     paramArray = CorbaTransformationUtils.changeHoldersFromServiceToCorbaObjects(methodSignature, params, runtimeInfo);
231                     m = getMethodFromStub(currentObj.getClass(), methodSignature);
232                     LOG.debug("methodSignature:" + methodSignature.getMethod().toGenericString());
233                     LOG.debug("M:" + m.toGenericString());
234 
235                 }
236                 //**********************************************************************  
237                 //Runtime Generic Types
238                 //**********************************************************************
239                 // Get parameters about Corba Types Interface,Any or Union
240                 //if (methodSignature.hasCorbaTypes()) {
241                     // TODO not completed or tested 
242                     LOG.debug("***Retrieved  Union or Any or Interfaces ***");
243                     LOG.debug("Param Array LENGTH " + paramArray.length);
244                     
245                   //  LOG.debug("Param  class" + paramArray[0].getClass());
246 
247                     paramArray = CorbaTransformationUtils.changeFromServiceToCorbaObjects(paramArray, runtimeInfo, methodSignature);
248                     LOG.debug("Param  " + methodSignature);
249                     LOG.debug("Param  " + currentObj.getClass());
250 
251                     m = getMethodFromStub(currentObj.getClass(), methodSignature);
252                 //}
253                 LOG.debug("Param  " + methodSignature);
254                 //**********************************************************************  
255 
256                 try {
257                     if (this.isCorbaServant && ((org.omg.CORBA.Object) currentObj)._non_existent()) {
258                         LOG.debug(">>>> Reconnect begin...");
259                         serviceDescriptor.getEndpoint().locateCorbaService();
260                         LOG.debug(">>>> Reconnect end...");
261                         //get corbaObjectReference
262                         currentObj = serviceDescriptor.getCorbaObjectReference();
263                     }
264                 } catch (SystemException se) {
265                     LOG.debug(">>>> Reconnect begin...");
266                     serviceDescriptor.getEndpoint().locateCorbaService();
267                     LOG.debug(">>>> Reconnect end...");
268                     //get corbaObjectReference
269                     currentObj = serviceDescriptor.getCorbaObjectReference();
270                 }
271 
272                 // Invocation
273                 // Invoke the stub method and pass the correct params
274                 //ADDED FOR Array OCTET TEST
275                 
276                 //LOG.debug("Param  " + paramArray[0]);
277                 //LOG.debug("Param  " + paramArray[0].getClass().getName());
278                 //byte[] par = ((byte[]) paramArray[0]);
279                 //LOG.info("PARAM ARRAY:" + par);
280                 //for (int i = 0; i < par.length; i++) {
281                 //LOG.info("PARAM ARRAY:" + i + ":" + par[i]);    
282                 //}
283                 
284                 
285                // LOG.debug("Param  class" + paramArray[0].getClass());
286                 if(LOG.isDebugEnabled()){
287                 LOG.debug("ParamArray  ===================> " + Arrays.toString(paramArray) + " \n **********************************************************");
288                 LOG.debug("Exchange ======================>  " + exchange + "\n ************************************************************");
289                 LOG.debug("OBJ ===========================>  " + currentObj + "\n******************************************************************");
290                 LOG.debug("OBJ CLASSLOADER ===============>  " + currentObj.getClass().getClassLoader() + "\n******************************************************************");
291           //      LOG.debug("PARAM CLASSLOADER ===============>  " + paramArray[0].getClass().getClassLoader() + "\n******************************************************************");
292                 
293                 LOG.debug("METHOD SIGNATURE ==============>  " + m + "\n********************************************************************");
294 
295                 LOG.debug("**********************INVOCATION*****************************************************************************");
296                 if (paramArray != null) {
297                 	LOG.debug("ParamArray  ====>" + paramArray.length);
298                 }
299                
300 //                LOG.debug("Param       ====>"+paramArray[0].getClass().getField("fieldEcho2").toString());
301 //                LOG.debug("Field Number " + paramArray[0].getClass().getFields().length);
302 //                for (Field f : paramArray[0].getClass().getFields()) {
303 //                    LOG.debug("field ===>" + f.getName() + " -- value: " + f.get(paramArray[0]));
304 //                    LOG.debug("field ===>" + f.toGenericString());
305 //                    LOG.debug("field ===>" + f.getType());
306 //                    LOG.debug("field ===>" + f.toString());
307 //                    LOG.debug("field ===>" + f.getClass().getClassLoader());
308 //                }
309                
310                 LOG.debug("*************************************************************************************************************");
311                 }
312                 org.omg.CORBA_2_3.ORB orb=(org.omg.CORBA_2_3.ORB)serviceDescriptor.getEndpoint().getOrb();
313                 //LOG.debug("RAAAF: lookup value factory per MySequence: "+orb.lookup_value_factory("IDL:3hh4.123/it/imolinfo/jbi4corba/test/testprovidercomplex/MySequence:1.0"));
314                 //LOG.debug("CL stub: "+currentObj.getClass().getClassLoader());
315                 //LOG.debug("RAAAF: classloader value factory per MySequence: "+orb.lookup_value_factory("IDL:3hh4.123/it/imolinfo/jbi4corba/test/testprovidercomplex/MySequence:1.0").getClass().getClassLoader());
316                 Object res = performInvocation(exchange, currentObj, m, paramArray);
317                 
318            
319                 LOG.debug("!!!! invokation successful with return:" + res);
320                 
321                    //**********************************************************************
322                 // INOUT Change holder parameters
323                 if (methodSignature.isContainsHolder()) {
324                     LOG.debug("The method contains holders: the parameters must be changed");
325                     CorbaTransformationUtils.changeHoldersFromCorbaToServiceObjects(methodSignature, params, paramArray, runtimeInfo);
326                 }
327 
328                 if (res != null) {
329                     LOG.debug("TYPE"+m.getReturnType().getName());
330                     res = CorbaTransformationUtils.changeFromCorbaToServiceObject(res, runtimeInfo, m.getReturnType());
331                     LOG.debug("RESULT CLASS"+res.getClass().toString());
332                     LOG.debug("RESULT CLASSLOADER"+res.getClass().getClassLoader());
333                 }
334                 LOG.debug("!!!! transformation successful");
335 
336                 //Normalization timer starts
337                 String topic = new String("Normalization");
338                 String endpointName = (String) exchange.get("EndpointName");
339                 mMeasurement = Probe.fine(getClass(), endpointName, topic);
340                 //Add timer object to context, so it can be stopped in the other class
341                 exchange.put("Measure-N", mMeasurement);
342 
343                 if (exchange.isOneWay()) {
344                     return null;
345                 }
346 
347                 return new MessageContentsList(res);
348             } catch (InvocationTargetException e) {
349                 Throwable t = e.getCause();
350 
351                 if (t == null) {
352                     t = e;
353                 }
354 
355 
356                 LOG.debug(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>    FAULT ");
357                 for (Class classException : m.getExceptionTypes()) {
358                     LOG.debug("Exception Application : " + classException.getName());
359                     if (classException.isInstance(t)) {
360                         // Checked
361                         LOG.debug(">>>>>>>>>> CHECKED_APPLICATION_FAULT");
362                         try
363                         {
364                         t = (Throwable)CorbaTransformationUtils.changeFromCorbaToServiceObject(t, runtimeInfo, classException);
365                         } catch (Exception ex) {              
366                         exchange.getOutMessage().put(FaultMode.class, FaultMode.UNCHECKED_APPLICATION_FAULT);
367                         exchange.getOutFaultMessage().setContent(Exception.class, new Fault(ex));
368                         ex.printStackTrace();
369                         throw new Fault(ex);
370                         } 
371                      
372                         exchange.getOutMessage().put(FaultMode.class, FaultMode.CHECKED_APPLICATION_FAULT);
373                         exchange.getOutFaultMessage().setContent(Exception.class, new Fault(t));
374                         throw new Fault(t);
375                     }
376                 }
377                 // Unchecked 
378                 LOG.debug(">>>>>>>>>> UNCHECKED_APPLICATION_FAULT");
379                 exchange.getOutMessage().put(FaultMode.class, FaultMode.UNCHECKED_APPLICATION_FAULT);
380                 exchange.getOutFaultMessage().setContent(Exception.class, new Fault(t));
381                 LOG.warn("error invokating stub: ", t);
382                 throw new Fault(t);
383             // VERIFICARE SE I SEGUENTI CATCH SONO NECESSARI                                 
384             } catch (Fault f) {
385                 exchange.getOutMessage().put(FaultMode.class, FaultMode.CHECKED_APPLICATION_FAULT);
386                 exchange.getOutFaultMessage().setContent(Exception.class, f);
387                 throw f;
388             } catch (Exception e) {
389                 LOG.warn("error invokating stub: ", e);
390                 exchange.getOutMessage().put(FaultMode.class, FaultMode.UNCHECKED_APPLICATION_FAULT);
391                 exchange.getOutFaultMessage().setContent(Exception.class, new Fault(e));                
392                 // e.printStackTrace();
393                 throw new Fault(e);
394             }
395 
396         } finally {
397             Thread.currentThread().setContextClassLoader(oldClassLoader);
398         }
399     }
400     
401 
402     /**
403      * Creates the parameter arry from the parameter object (that contains a wrapper object for each part).
404      * @param o
405      * @param info
406      * @return
407      */
408     private List<Object> extractParams(Object o, MessageInfo info) {
409 
410         List<MessagePartInfo> messageParts = info.getMessageParts();
411         for (int i = 0; i < messageParts.size(); i++) {
412             MessagePartInfo partInfo = messageParts.get(i);
413         }
414         List<Object> params = null;
415         if (o instanceof List) {
416             params = CastUtils.cast((List<?>) o);
417         } else if (o != null) {
418             params = new MessageContentsList(o);
419         }
420         return params;
421     }
422 
423     /**
424      * Get the provider service Descriptor object.
425      * @return The provider service descriptor
426      */
427     public ProviderServiceDescriptor getServiceDescriptor() {
428         return serviceDescriptor;
429     }
430 
431     /**
432      * Set the provider service Descriptor object.
433      * @param serviceDescriptor The ProviderServiceDescriptor
434      */
435     public void setServiceDescriptor(ProviderServiceDescriptor serviceDescriptor) {
436         this.serviceDescriptor = serviceDescriptor;
437     }
438 
439     /**
440      * Gets the <code>MethodSignature</code> object from the <code>Method</code> class.
441      * The correspondace between the MethodSignature and the method can be saved for further optimization.
442      * @param method
443      * @return 
444      */
445     private MethodSignature getMetodSignatureFromMethod(Method method) {
446         List<MethodSignature> methodSignatures = serviceDescriptor.getMethodSignatures();
447         MethodSignature methodSignature = null;
448         boolean found = false;
449         for (int i = 0; i < methodSignatures.size() && (!found); i++) {
450             methodSignature = (MethodSignature) methodSignatures.get(i);
451             LOG.debug("METHOD SIGNATURE ===>"+methodSignature);
452            
453            // if(methodSignature.getChangedMethod()!=null){
454                 if (compareMethodsWithNameAndParameters(method, methodSignature.getChangedMethod())) {
455                     found = true;
456                     break;
457                 }      
458            //}
459         }
460         if (methodSignature == null) {
461 			String msg = MESSAGES.getString(
462 					"CRB000767_No_method_signature_found_for_method",
463 					new java.lang.Object[] { method.toGenericString() });
464 			LOG.warn(msg);
465 		}
466         return methodSignature;
467     }
468 
469     
470 
471     /**
472      * The method saved in the <code>MethodSignature</code> is of the corba interface. The object
473      * used to invoke the method is the Stub reference. This method found the Stub method, comparing
474      * the method name and the parameter types.
475      * TODO: This operation is expensive, the correspondance between methods can be saved.
476      * @param stub
477      * @param signature
478      * @return
479      */
480     public Method getMethodFromStub(Class stub, MethodSignature signature) {
481         Method interfaceMethod = signature.getMethod();
482 
483         Method matchedMethod = null;
484         // Get the stub methods
485         Method[] methods = stub.getMethods();
486         LOG.debug("********INTERFACE Method   ->" + signature.getMethod());
487         LOG.debug("********INTERFACE STUB  ->" + stub);
488         LOG.debug("********ClassLoader STUB  ->" + stub.getClassLoader());
489         LOG.debug("********METHODS LENGTH  ->" + methods.length);
490 
491         for (int i = 0; i < methods.length; i++) {
492             LOG.debug("********INTERFACE METHOD  ->" + methods[i].getName());
493             boolean found = compareMethodsWithNameAndParameters(methods[i], interfaceMethod);
494             if (found) {
495                 matchedMethod = methods[i];
496                 break;
497             }
498         }
499         LOG.debug("********MATHCED METHOD  _->" + matchedMethod);
500         return matchedMethod;
501 
502     }
503 
504     /**
505      * Compares two method looking for the name and the parameters (not the original class).
506      * @param methodA
507      * @param methodB
508      * @return
509      */
510     private boolean compareMethodsWithNameAndParameters(Method methodA, Method methodB) {
511         boolean ret = false;
512         LOG.debug("**************Method A" + methodA.toGenericString());
513         LOG.debug("**************Method B" + methodB.toGenericString());
514         boolean paramEquals = compareParameterTypes(methodA.getParameterTypes(), methodB.getParameterTypes());
515         LOG.debug("**************Method A" + methodA.toGenericString());
516         LOG.debug("**************Method B" + methodB.toGenericString());
517         LOG.debug("**************PARAM EQUALS" + paramEquals);
518         if ((paramEquals) &&
519                 (methodA.getName().equals(methodB.getName()))) {
520             ret = true;
521         }
522         return ret;
523     }
524 
525     /**
526      * True if two <code>Class</code> array are of <code>Class</code> of the same type. 
527      * @param typesA
528      * @param typesB
529      * @return
530      */
531     private boolean compareParameterTypes(Class[] typesA, Class[] typesB) {
532         boolean ret = true;
533         LOG.debug("***************TYpe A" + typesA.length);
534         LOG.debug("***************Type B" + typesB.length);
535         if (typesA.length != typesB.length) {
536             ret = false;
537         } else {
538             for (int i = 0; i < typesA.length; i++) {
539                 if (!(typesA[i].getName().equals(typesB[i].getName()))) {
540                     LOG.debug("***************Type A" + typesA[i].getName());
541                     LOG.debug("***************Type B" + typesB[i].getName());
542                     ret = false;
543                     break;
544                 }
545             }
546         }
547         return ret;
548     }
549     
550    
551     
552 }