I have a class
class ObjFactory {
MyObject getObject() {...}
void returnObject() {...}
}
How can we configure Tomcat so that it would provide this factory through JNDI and manages
this factory?
Say, one web app should get access to this factory and it must exist only 1 factory in Tomcat, every copy of a web app references the same object.
What are specific rules to design this factory class? Maybe it should implement some interface to work with Tomcat, JNDI in the way I described?
How to glue this class, tomcat and webapp (what should be written in what file, web.xml, context.xml, etc)?
If you are using Tomcat 5.5, this is a good place to start: JNDI Resources HOW-TO.
Scroll down to the 'Adding Custom Resource Factories' section for a step-by-step explanation.
Related
I recently started learning java EE (jsp, servlets and some patterns for working with database like a DAO) and I dont understand where I should initialize my bussines logic? I think that create instances of it in body of do*** servlet methods is a bad practice. P.S. my app use DataSource and ConnectionPool for connection with db.
You need to specify your requirement somehow, what initialization you are looking for. Is it a EJB solution? Pure Servlet/JSP solution? etc.
Normally when deploying your application, after an invocation the application will load the required logic.
Of course you can do initialize to speed up the load, to make required code run before users enter the application etc.
In EJB we are talking about #Singleton and #Startup annotations.
For servlet you can use the annotation #WebServlet(name="startup", loadOnStartup="0"). Or put it in your web.xml. Depends how you code.
A more recommended way is to create you own listener, and override the contextInitialized and contextDestoryed methods. E.g. create db connection etc in initialized method and deregister the driver in contextdestory method. Use annotation #WebServletContextListener or add the listener to your web.xml
Also Java web server specific solutions exists, you need to check your vendor.
In my project I have 2 modules, a ejb and a war module. In the war module i have a properties file that is processed when I start the web application (by a listener). For each property in this properties file, i add it to the servlet context.
So, my question is: is it possible to access this properties, in the servlet context, from a enterprise java bean in the ejb module? I want to do something like this, but in a ejb:
ServletContext sc = myservlet.getServletContext();
String xpto = sc.getAttribute("my-attr");
If this is not possible, what is the alternative?
Thanks!
P.S I'm using netbeans and glassfish.
ServletContext is always loaded ahead in the Servlet lifecycle loading. Ref to this link. As you see the Listeners are loaded after the ServletContext is loaded when application starts. You can have your code in the listener class that extends ServletContextListener. Ensure you are extending correct Listener as given in the link.
In your situation, One of the alternative is to have a Singleton class load all the properties from the properties file. for ex: ApplicationPropertiesLoader class can have a Properties map attribute to store the key value pairs of that property file. This class can have a getProperty method that always refer to its internal Properties.
In your servlet class refer to this singleton class to load the properties as required.
Speaking of alternatives, it might be worth a thought to use configuration stored in database, at least if you already have a database connection in your application and have control over the database schema.
We use this technique in all our web applications, mainly for two reasons:
Changes to a property can be done during runtime without monitoring file changes, they can be done by the application itself and one does not need to know a path outside of the deployed application.
Properties can have additional information, such as a type (e.g. number, date, string), a default value, a comment or a user who changed it.
For implementing it, you'll create an application-scoped component which accesses the database properties for the rest of the application.
I'm going through the EJB 3.1 spec and am trying to grasp the different possible ways a JNDI call can be made.
You can do it using a SessionContext and an InitialContext (or a self-created context based on the Initial- or SessionContext).
Based on which you use the syntax differs, but I can't seem to find the logic behind it.
So my question is: when can I use what syntax to use JNDI calls within an EJB container environment?
The rest of this question just serves as illustration of my point.
For example, I believe this is always possible for a correctly injected sessioncontext or created initialcontext:
ctx.lookup(java:global[/<app-name>]/<module-name>/<bean-name>[!<fully-qualified-interface-name>])
ctx.lookup(java:comp/env ...)
// special ones like these
ctx.lookup("java:comp/UserTransaction");
ctx.lookup("java:comp/ORB");
Sometimes (only for session context?) this shorter version is possible:
ctx.lookup(<bean-name>);
What about in an embedded environment, can only global references be used?
I usually inject EJBs inside EJB container with #EJB annotation. So the JDNI look ups are done by the server at deploy time.
For example JBOSS deployment:
INFO [org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor] (MSC service thread 1-2) JNDI bindings for session bean named TestBean in deployment unit subdeployment "MyEJB.jar" of deployment "MyProject.ear" are as follows:
java:global/MyProject/MyEJB/TestBean!my.project.TestBean
java:app/MyEJB/TestEJB!my.project.TestBean
java:module/TestEJB!my.project.TestBean
java:global/MyProject/MyEJB/TestEJB
java:app/MyEJB/TestBean
java:module/TestBean
Some are per EJB specification some are application server dependent.
If you have to make look ups from context I think the best way is to use java:global.
You can also find some additional info at: http://glassfish.java.net/javaee5/ejb/EJB_FAQ.html#POJOLocalEJB
jndi is a bit like a file system. You can refer to things using a relative path based on where you are in the tree (where you "cd"-ed to).
The injected session context is by default "positioned" on java:comp, so there you reference things that are available in java:comp, without the need to provide the "full path".
Note that java:comp itself is relative to a single EJB bean, or because of historical reasons to the entire Web module.
I'm not 100% sure what you mean with embedded environment, but if the code from which you are doing the JNDI lookup is not part of any of the predefined scopes (like java:module, java:app, etc) only java:global can be portably used.
I have a service where I want to maintain data persistence in a mysql db using jdbc. While i have experience building jdbc apps and jax-rs apps in isolation, I've never combined the two. The question is, where does the build up and tear down required for the jdbc-type stuff go? Ordinarily i'd put the build up in a static block, or in a constructor, and id have have a cleanup method that gets called in a finally. this doesnt seem to work in the jax-rs framework- the constructor gets called at every invocation, and there is no place to my knowledge to put any clean up methods. unfortunately, there are sparse examples for combining the two technologies online, something i find surprising. Can you guys help me out?
As a general rule, to do things at the startup and shutdown of your web application, you should create custom ServletContextListeners and list them in your web.xml.
With JDBC resources in a WAR, often times you have your container (e.g. Tomcat, Websphere, etc.) create and manage a connection pool which can be shared with a number of web applications. You would define a resource-ref for a javax.sql.DataSource in your web.xml. Then there is a container specific method for defining and binding the JDBC DataSource to the resource-ref of your application.
I'm not familiar with Memchached and what is needed on startup/shutdown so this is only a guess. If you need to register/unregister with a Memcache server you might try having one or more env-entry tags defined in your web.xml which could be used by a custom ServletContextListener to do your bidding.
I have a .properties file in my application which contains dataSource properties.
I set up a JNDI reference to this dataSource using the following code :
// first I create MyDataSource from the properties found in the .properties file
//then :
Context initContext = new InitialContext();
initContext.createSubcontext("jdbc");
initContext.createSubcontext("jdbc/oracle");
initContext.rebind(jdbc/oracle/myDataSource, MyDataSource);
If I use a lookup in this application, the dataSource is found :
Context initContext = new InitialContext();
BasicDataSource dataSource =
(BasicDataSource) initContext.lookup("jdbc/oracle/myDataSource")
//everything works fine and I can use my dataSource to getConnection,
//requests, etc...
Now I would like to use this dataSource in another application. But if I do the same lookup than previously, I don't find myDataSource (whereas there is still the previous application in tomcat and the jndi binding is done on start-up with the help of a listener).
How can I get myDataSource in this second application, given that I can't use a Tomcat's resource in server.xml or a context.xml file (for different reasons I have to use this .properties file)?
Thanks
"local" JDNI directories are read-only in Tomcat. Nevertheless, you can bind "global" JNDI resources in a LifecycleListener, and then "link" them to your context(s)(*):
You need to implement org.apache.catalina.LifecycleListener http://tomcat.apache.org/tomcat-6.0-doc/api/org/apache/catalina/LifecycleListener.html
Then register it in your server.xml like this (along with the other listeners):
<Listener className="yourlistener.YourLifecycleListener"/>
Your listener should await for 2 events:
public void lifecycleEvent(final LifecycleEvent event) {
if (Lifecycle.START_EVENT.equals(event.getType())) {
// Create your datasource instance...
Context initContext = new InitialContext();
initContext.createSubcontext("jdbc");
initContext.createSubcontext("jdbc/oracle");
initContext.rebind("jdbc/oracle/myDataSource", myDataSource);
} else if (Lifecycle.STOP_EVENT.equals(event.getType())) {
// unbind...
}
}
Then you'll have to propagate resource accesses by "linking" them from "global" JNDI directory to "local" JNDI directory using ResourceLink element in your META-INF/context.xml:
<ResourceLink name="jdbc/oracle/myDataSource" global="jdbc/oracle/myDataSource"
type="javax.sql.DataSource" />
That worked for me so far.
(*) Some notes:
There's an advantage on using lifecycle listeners. Since the order of context creation is not guaranteed. The advantage is that all of your contexts will see this object created.
If you need to create and configure datasource creation more dynamically that on lifecycle listener creation, note that you can bind a custom class implementing the Factory pattern.
To avoid classloading incompatibility problems, consider putting your listener, datasource, etc. classes in a jar file in the Tomcat lib directory, so they're included y the common classloader.
Regards.
What you are trying to do is not going to work. J2EE applications are not allowed to modify the JNDI environment provided by the application server (J2EE spec, section 5.2.2) and the Tomcat JNDI documentation also states, that each web applications gets each own read-only JNDI environment. I'm not sure why binding/rebinding your datasource is not failing immediately and why it's working within the same web application, but even such application-internal usage of the JNDI environment is undocumented behaviour, which I would not rely on.
A couple people have already commented on this, but I think the answer to your question is: Tomcat has a file called server.xml that you need to use. A good reference I have used before is below:
http://tomcat.apache.org/tomcat-5.5-doc/jndi-resources-howto.html
Resources defined here will be visible to all apps deployed (if set up correctly). If you set up a JNDI resource in your apps context or web xml file, it should only be available to your app.
JNDI context are private to each webapp. Context created in one app can't be accessed by others.
Try to create an entry in GlobalNamingResources and links in both webapps using <ResourceLink> to see if it works.
I used this setup before to read from both apps but never tried to write from one. So not sure if it will work.
Actually, it is possible to access others JNDI resources, if the servlet implements org.apache.catalina.ContainerServlet. This interface has a org.apache.catalina.Wrapper attribute, that is "populated" by the container itself.
through that, I created a simple application to monitor resources.
BUT, I would like to do that in a listener, so my resource monitor could start when the container starts. Anyone knows a way?