airbai / sipservlets

Automatically exported from code.google.com/p/sipservlets
0 stars 0 forks source link

@SipApplicationKey fails on Tomcat if not defined on the servlet class #139

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
What steps will reproduce the problem?
1. Annotate a method in a class *other than* an application's Servlet class 
with @SipApplicationKey. This could be either the servlet's superclass, or 
another class in the application.
2. In the method, include logic that retrieves the value of a static variable 
that was set in the servlet's init(...) method.
3. Deploy on tomcat.

What is the expected output? What do you see instead?

The @SipApplicationKey method is being invoked on a class loaded from a 
different classloader than the class on which init(...) and subsequent requests 
are invoked. This is essentially a variation on issue 700:

    http://code.google.com/p/mobicents/issues/detail?id=700

What version of the product are you using? On what operating system?

    1.7.0.FINAL on OSX and Linux.

Please provide any additional information below.

sip-servlets-impl/src/main/java/org/mobicents/servlet/sip/core/dispatchers/Messa
geDispatcher.java includes this logic for locating the correct classloader in 
which to invoke the @SipApplicationKey-annotated method:

173             Class methodDeclaringClass = appKeyMethod.getDeclaringClass();
174             MobicentsSipServlet sipServletImpl = 
sipContext.findSipServletByClassName(methodDeclaringClass.getCanonicalName());
175             if(sipServletImpl != null) {
176                 try {
177                     servlet = sipServletImpl.allocate();
178                     // 
http://code.google.com/p/mobicents/issues/detail?id=700 :
179                     // we get the method from servlet class anew because 
the original method might have been loaded by a different class loader
180                     Method newMethod = 
servlet.getClass().getMethod(appKeyMethod.getName(), 
appKeyMethod.getParameterTypes());
181                     appKeyMethod = newMethod;
182
183                     if(logger.isDebugEnabled()) {
184                         logger.debug("Invoking the application key method " 
 + appKeyMethod.getName() +
185                                 ", on the following servlet " + 
methodDeclaringClass.getCanonicalName());
186                     }
187                 } catch (ServletException e) {
...
197             try {
198                 appGeneratedKey = (String) appKeyMethod.invoke(servlet, new 
Object[] {sipServletRequestImpl});
199             } catch (IllegalArgumentException e) {
...

However, if the annotated method is declared in a class other than the sip 
servlet class, the call to sipContext.findSipServletByClassName(...) at line 
174 will return null. This means that 'servlet' remains null. 

This isn't a problem on JBoss, since the call to Method.invoke(...) at line 198 
doesn't require an instance (as the @SipApplicationKey method must be static). 
More importantly, JBoss does not have issues with a servlet's init() method and 
@SipApplicationKey methods being invoked in the context of different 
classloaders.

On Tomcat, however, the fix for issue 700 (lines 175 to 196) doesn't execute, 
so the invocation of appKeyMethod occurs in a different classloader. This can 
be solved by adding a check that reverts to the context's mainServlet if 
necessary:

173             Class methodDeclaringClass = appKeyMethod.getDeclaringClass();
174             MobicentsSipServlet sipServletImpl = 
sipContext.findSipServletByClassName(methodDeclaringClass.getCanonicalName());
175             if (sipServletImpl == null) {
176                 sipServletImpl = 
sipContext.findSipServletByName(sipContext.getMainServlet());
177             }

Note that it might be safe to simply skip the 
sipContext.findSipServletByClassName(methodDeclaringClass.getCanonicalName()) 
call, and always use sipContext.getMainServlet().

Inside the fix for issue 700, line 180 assumes that the method is defined in 
the servlet class. This can be solved by using the servlet's classloader to get 
a reference to appKeyMethod's declaring class, and then (re-)retrieving the 
method from there:

183                     Class appKeyClass = 
servlet.getClass().getClassLoader().loadClass(methodDeclaringClass.getCanonicalN
ame());
184                     Method newMethod = 
appKeyClass.getMethod(appKeyMethod.getName(), appKeyMethod.getParameterTypes());
185                     appKeyMethod = newMethod;

A patch with these changes is attached.

Original issue reported on code.google.com by philip.i...@gmail.com on 30 Jul 2012 at 12:34

Attachments:

GoogleCodeExporter commented 8 years ago
Hi, 

Can you sign the Contributor License Agreement at the bottom of 
http://telestax.com/open-source/ ?
Also to acknowledge your contribution to 
http://www.mobicents.org/acknowledgements.html, do you agree to publish your 
company name (if you contribute on behalf of a company) there ?

Thanks
Jean

Original comment by jean.deruelle on 10 Aug 2012 at 8:24

GoogleCodeExporter commented 8 years ago

Original comment by jean.deruelle on 16 Aug 2012 at 8:10

GoogleCodeExporter commented 8 years ago

Original comment by jean.deruelle on 16 Aug 2012 at 8:24

GoogleCodeExporter commented 8 years ago

Original comment by jean.deruelle on 5 Jul 2013 at 7:44

GoogleCodeExporter commented 8 years ago
Postponing until the contributor agreement is signed

Original comment by jean.deruelle on 25 Apr 2014 at 3:51

GoogleCodeExporter commented 8 years ago

Original comment by jean.deruelle on 25 Apr 2014 at 6:18

GoogleCodeExporter commented 8 years ago
Issue was moved to GitHub:

https://github.com/Mobicents/sip-servlets/issues/28

Original comment by desi.pep...@telestax.com on 18 Dec 2014 at 6:41

GoogleCodeExporter commented 8 years ago

Original comment by jean.deruelle on 18 Dec 2014 at 9:27