Solved

Return instance of load-on-startup servlet

Posted on 2006-07-18
11
271 Views
Last Modified: 2013-11-24
The overall goal is to create a DataSource in a startup servlet rather than doing it in every servlet.  The problem I'm having is that I can't figure out how to call the method that returns the datasource.  I've tried making the method and the DataSource variable static but I get a variety of "static reference to non-static variable, etc." message depending on how I try and implement it.  I was following a guide on performance optimization and unfortunately the person who wrote it gave no indication of how one makes a call to the getDataSource() method of the startup servlet.  I've tried modifying a dynamic configuration startup servlet example I found elsewhere to use JNDI to reference the startup servlet and all I get are naming context errors.  Here's my latest (lame) attempt so please don't just critique the code since I know there are probably a lot of things I could do better but I've been trying a bunch of different things to get it to work so it's mutated into the ugliness below.  I just want to learn how to do this.  The precise question I have is at the bottom and may make all this code pointless so you may want to start there.  I'm probably going about this all wrong.  Anyway, here goes:

******* StartupServlet.java ********
public class StartupServlet extends HttpServlet {

    private static DataSource ds = null;
   
    public final static String ENV_CONTEXT = "java:comp/env";
    public final static String JNDI_NAME = "startup/StartupServlet";
   
    public static StartupServlet getInstance() throws NamingException {
        Context initialContext = new InitialContext();
        Context envContext = (Context) initialContext.lookup(ENV_CONTEXT);
        StartupServlet r = (StartupServlet) envContext.lookup(JNDI_NAME);
        if (r == null) {
            throw new NamingException("Naming exception: No JNDI object named `" +
                    JNDI_NAME + "' in context '" + ENV_CONTEXT + "'");            
        }
      return r;
    }
   
    public void init(ServletConfig config) throws ServletException {
        System.out.println("******** StartupServlet init() called. ********");
        super.init(config);

//this code works...was tested outside of startup servlet
        try {            
              Context myContext = new InitialContext();
              Context envContext = (Context)myContext.lookup("java:comp/env");
              ds = (DataSource)envContext.lookup("jdbc/db2");
          } catch (NameNotFoundException ne) {
              System.err.println("Error getting context: " + ne.toString());
              ne.printStackTrace();
          } catch (Exception e){
              System.err.print("Error getting datasource: " + e.toString());
              e.printStackTrace();
          }
    }
   
    public DataSource getDS() {
        System.out.println("******** StartupServlet getDS() called. ********");
        return ds;
    }
   
    public void destroy() {
        System.out.println("******** StartupServlet destroy() called. ********");
    }
}

******** web.xml *********
This is not complete only the relevant sections.  This is what was in the tutorial (with the names changed, of course)
<resource>
      <name>startup/StartupServlet</name>
          <type>com.signet.lcdm.StartupServlet</type>
</resource>

I get an error that <resource> is not a valid tag, so in keeping with other resource references (I'm using WebSphere Application Server Express and WebSphere Development Studio Client, BTW) I did this:

<resource-ref id="ResourceRef_1153257505430"><---- this was automatically created by WSDC
<res-ref-name>startup/StartupServlet</res-ref-name>
<res-type>com.signet.lcdm.StartupServlet</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>

Also, the "startup/" part of the name was "config/" everywhere...I changed in because the error was always on "config" and I wanted to see if the error would be on startup, which it is.  I'm a neophyte with JNDI so I don't fully understand how it works yet.  Here's the error I keep getting, not that I think it matters because I'm probably doing this all wrong anyway, but for the sake of completeness...

[7/18/06 14:31:54:712 PDT] 00000024 SystemErr     R com.ibm.websphere.naming.CannotInstantiateObjectException: Exception occurred while the JNDI NamingManager was processing a javax.naming.Reference object.  Root exception is javax.naming.NameNotFoundException: Context: PC-ISIT-8801Node01Cell/nodes/PC-ISIT-8801Node01/servers/server1, name: startup/StartupServlet: First component in name startup/StartupServlet not found.  Root exception is org.omg.CosNaming.NamingContextPackage.NotFound: IDL:omg.org/CosNaming/NamingContext/NotFound:1.0
      at com.ibm.ws.naming.ipcos.WsnOptimizedNamingImpl.handleNameNotFound(WsnOptimizedNamingImpl.java:2252)
      at com.ibm.ws.naming.ipcos.WsnOptimizedNamingImpl.getNextWsnOptimizedNamingContext(WsnOptimizedNamingImpl.java:1448)
      at com.ibm.ws.naming.cosbase.WsnOptimizedNamingImplBase.getTargetContext(WsnOptimizedNamingImplBase.java:4396)
      at com.ibm.ws.naming.cosbase.WsnOptimizedNamingImplBase$LeafOperationData.<init>(WsnOptimizedNamingImplBase.java:5012)
      at com.ibm.ws.naming.cosbase.WsnOptimizedNamingImplBase.resolve_complete_info(WsnOptimizedNamingImplBase.java:2205)
      at com.ibm.WsnOptimizedNaming._NamingContextStub.resolve_complete_info(Unknown Source)
      at com.ibm.ws.naming.jndicos.CNContextImpl.cosResolve(CNContextImpl.java:4043)
      at com.ibm.ws.naming.jndicos.CNContextImpl.doLookup(CNContextImpl.java:1746)
      at com.ibm.ws.naming.jndicos.CNContextImpl.doLookup(CNContextImpl.java:1707)
      at com.ibm.ws.naming.jndicos.CNContextImpl.lookupExt(CNContextImpl.java:1412)
      at com.ibm.ws.naming.util.IndirectJndiLookupObjectFactory$1.run(IndirectJndiLookupObjectFactory.java:372)
      at com.ibm.ws.security.util.AccessController.doPrivileged(AccessController.java(Compiled Code))
      at com.ibm.ws.naming.util.IndirectJndiLookupObjectFactory.getObjectInstanceExt(IndirectJndiLookupObjectFactory.java:221)
      at com.ibm.ws.naming.util.IndirectJndiLookupObjectFactory.getObjectInstance(IndirectJndiLookupObjectFactory.java:149)
      at com.ibm.ws.util.ResRefJndiLookupObjectFactory.getObjectInstance(ResRefJndiLookupObjectFactory.java:138)
      at javax.naming.spi.NamingManager.getObjectInstance(NamingManager.java:314)
      at com.ibm.ws.naming.util.Helpers.processSerializedObjectForLookupExt(Helpers.java:894)
      at com.ibm.ws.naming.urlbase.UrlContextHelper.processBoundObjectForLookup(UrlContextHelper.java:191)
      at com.ibm.ws.naming.urlbase.UrlContextImpl.processBoundObjectForLookup(UrlContextImpl.java:1775)
      at com.ibm.ws.naming.urlbase.UrlContextImpl.lookup(UrlContextImpl.java:1280)
      at com.ibm.ws.naming.urlbase.UrlContextImpl.lookup(UrlContextImpl.java:1307)
      at com.signet.lcdm.StartupServlet.getInstance(StartupServlet.java:42)
      at com.signet.lcdm.GetRepDataAction.execute(GetRepDataAction.java:83)
      at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:484)
      at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:274)
      at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1482)
      at org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:507)
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:743)
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:856)
      at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1282)
      at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:673)
      at com.ibm.ws.webcontainer.webapp.WebApp.handleRequest(WebApp.java:2965)
      at com.ibm.ws.webcontainer.webapp.WebGroup.handleRequest(WebGroup.java:221)
      at com.ibm.ws.webcontainer.VirtualHost.handleRequest(VirtualHost.java:210)
      at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:1931)
      at com.ibm.ws.webcontainer.channel.WCChannelLink.ready(WCChannelLink.java:84)
      at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:472)
      at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleNewInformation(HttpInboundLink.java:411)
      at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.ready(HttpInboundLink.java:288)
      at com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.sendToDiscriminaters(NewConnectionInitialReadCallback.java:207)
      at com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.complete(NewConnectionInitialReadCallback.java:109)
      at com.ibm.ws.tcp.channel.impl.WorkQueueManager.requestComplete(WorkQueueManager.java:566)
      at com.ibm.ws.tcp.channel.impl.WorkQueueManager.attemptIO(WorkQueueManager.java:619)
      at com.ibm.ws.tcp.channel.impl.WorkQueueManager.workerRun(WorkQueueManager.java:952)
      at com.ibm.ws.tcp.channel.impl.WorkQueueManager$Worker.run(WorkQueueManager.java:1039)
      at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java(Compiled Code))
More stack errors but probably not needed at this point.

The pointed question is how do I return a reference to the StartupServlet class that the container started so I can call the getDataSource() method?

Thanks.  Sorry for the length but I've been criticized before for not posting enough.  Probably went overboard this time.
0
Comment
Question by:SimmerDown
  • 5
  • 5
11 Comments
 
LVL 35

Expert Comment

by:girionis
Comment Utility
Hi SimmerDown

why do you want to create a datasource in the startup servlet? The application server should be able to create the named datasource once and you should be able to accss uit from any servlet/jsp/ejb etc. There is no reason to do it in a Servlet and then get this datasource via a reference to this start up servlet (tbh I am not even sure if you can get a reference to a servlet like you do with a normal java class).

Cheers
0
 

Author Comment

by:SimmerDown
Comment Utility
Hi Girionis,

The purpose is to only do the JNDI lookup once instead of in several places.  This is based on information I got out of a performance improvement article for servlets with reference to datasources.  I found other articles similarly recommending the same thing but with no example code.  My application is already working retrieving the JNDI datasource object in each servlet but I thought this tip sounding like it would be worth checking out.  As I said above, the information was probably intended for someone beyond intermediate in skill because a lot was left to work out on your own, like calling the non-static class.  I also made an assumption based on the example classes name (ControllerServlet) that it was a load-on-startup servlet.  However, even if that assumption is incorrect it's still pretty clear that only one instance of that class would exist and in order to use it's methods one would have to retrieve the instance of the class rather than creating a new instance.

In any case I have found out that the other example I was trying to meld with this one was specifically for resin which explains why I'm getting the naming context error since WebSphere isn't set up to use a config container.  Most of the singleton examples I've referred to which are able to return an instance of themselves also create their own instance to pass back to the calling method.  The question I was asking was how one would have an already instantiated class return itself.

It may not be possible but since I can't contact the author of the original article I thought I'd test the waters here at E-E.  Thanks for the feedback.  I think I'll leave this up for awhile to see if anyone has other ideas.  If I figure something out in the meantime I'll post it here for posterity and close the question.

Cheers

0
 
LVL 35

Accepted Solution

by:
girionis earned 350 total points
Comment Utility
> The question I was asking was how one would have an already instantiated class return itself.

This can only be done if other objects register themselves with the class in question, so the class notifies them when it is loaded.

What I suggest is to write a standard java class that starts up when the application server starts up. In this class you do the jndi look up you need and obtain the datasource. Then have a static method that returns this instance to the callers something like

public class MyJNDIReturner
{
   private static Datasource ds = null;
   private static MyJNDIReturner myObject = null;

   private MyJNDIReturner()
   {
      // Do the lookup and assign the datasource
   }

   public static MyJNDIReturner getInstance() {
        if (myObject == null)
        {
            myObject = new MyJNDIReturner();
        }

       return myObject;
    }

    public Datasource getDatasource()
   {
      return ds;
   }
}


and from your servlets you can do

MyJNDIReturner r = MyJNDIReturner.getInstance();
Datasource ds = r.getDatasource();

Of course the doce might need some modifications and/or optimizations. It is only here to give you an idea of how you should go on. For more info you might want to sdo a google search for "Service locator pattern"
0
 
LVL 35

Expert Comment

by:girionis
Comment Utility
> doce

I mean

code :)
0
 

Author Comment

by:SimmerDown
Comment Utility
I just wanted to say I haven't abandoned this question.  I've had a another project take priority so I haven't been able to try the proposed solution.
0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 

Author Comment

by:SimmerDown
Comment Utility
girionis,

Sorry...I can post here every couple of days until I have a chance to test the solution.  I haven't had a chance to test the solution and before I award 350 points it seems I should have the opportunity to do so.

How fequently do I need to update this question to prevent it being closed?  This is not an abandoned issue...it's a reprioritized project and unfortunately I simply haven't had a chance to work on this project let alone try the proposed solution.  I want to award the points fairly and if the solution hasn't been tested I don't feel it's fair to arbitrarily assign just because someone has offered an unproven solution.  Since you aren't losing anything by leaving the question open, providing I keep updating it, I don't see how this is a problem.

I will update as frequently as necessary to keep the question from being closed, just let me know how frequently that needs to be.  I don't think I've ever abandoned a question here other than ones that never received any expert's response and I've been a member for awhile.  Check my history.

Also, since the only person to have proposed any solution is yourself there would appear to be a bit of a conflict of interest if you decided to close the question and award the points to yourself. :o)

Thank you.
0
 
LVL 35

Expert Comment

by:girionis
Comment Utility
Ok, no problem. Normally you should post at least one comment every 21 days, after that the question is considered abandoned. But I am the only one that is doing clean up in the Java area at the moment, so I can just ignore your question when I see it again even if there is no comment within a three weeks period :)
0
 

Author Comment

by:SimmerDown
Comment Utility
Thank you very much for being understanding.  I appreciate it.  I expect to be put back on this project within the next two weeks.
0
 
LVL 35

Expert Comment

by:girionis
Comment Utility
Hello SimmerDown, do you still need help on this because I am gonna do some cleanup and I am going to post recommendation for this question.
0
 

Author Comment

by:SimmerDown
Comment Utility
Hi,

Sorry again.  I've been so busy on other development projects I still haven't revisited this specific issue but I have had some more experience with singleton classes and based on what I've learned I understand your suggestion better and I'm confident it will work.

Thanks again for being so patient.

Paul
0

Featured Post

What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Are you developing a Java application and want to create Excel Spreadsheets? You have come to the right place, this article will describe how you can create Excel Spreadsheets from a Java Application. For the purposes of this article, I will be u…
Java Flight Recorder and Java Mission Control together create a complete tool chain to continuously collect low level and detailed runtime information enabling after-the-fact incident analysis. Java Flight Recorder is a profiling and event collectio…
This video teaches viewers about errors in exception handling.
This tutorial explains how to use the VisualVM tool for the Java platform application. This video goes into detail on the Threads, Sampler, and Profiler tabs.

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now