I have a JAX-RS Application (running Jersey 2 on Tomcat) that relies on a heavyweight connection to HBase. I want to initialize and reuse that connection throughout my application for multiple resources. I have set up a Binder that binds the connection as a Singleton, and used the #Inject annotaton to inject that connection into my resource. However, since the injection doesn't occur until the first call of the service, the connection isn't initialized until then.
The application:
public class MyApplication extends ResourceConfig {
public MyApplication() {
super(MyResource.class);
register(new HbaseBinder());
}
}
The Binder:
public class HbaseBinder extends AbstractBinder {
#Override
protected void configure() {
bindAsContract(HbaseConnection.class).in(Singleton.class);
bind(new HbaseConnection()).to(HbaseConnection.class);
}
}
The Injection:
#Path("/myResource")
public class MyResource {
#Inject
private HbaseConnection hbaseConnection;
...
}
The HBase Connection:
#Singleton
public class HbaseConnection {
public Connection getConnection() throws IOException {
...
}
...
}
What I would like to do is initialize the Singleton at application deployment time so that it's ready to go on the first call to the service. What is the proper way to do this?
Thank you for all of the comments and answers. A combination of the above were required.
Part of the issue was that I was using the the #PostConstruct to call the HbaseConnection.getConnection() method had an unchecked exception. Once I got rid of that, and switch to the Immediate scope, the class seems to be loaded appropriately. Here's my final solution:
public class MyApplication extends ResourceConfig {
#Inject
public MyApplication(ServiceLocator locator) {
super(MyResource.class);
register(new HbaseBinder());
ServiceLocatorUtilities.enableImmediateScope(locator);
}
}
#Path("/myResource")
public class MyResource {
#Inject
private HbaseConnection hbaseConnection;
...
}
public class HbaseBinder extends AbstractBinder {
#Override
protected void configure() {
bindAsContract(HbaseConnection.class).in(Immediate.class);
}
}
#Immediate
public class HbaseConnection {
#PostConstruct
public void postConstruct() {
// Call getConnection(), wrapped in try/catch.
}
public Connection getConnection() throws IOException {
// Get the connection.
}
#PreDestroy
public void preDestroy() {
// Call cleanup(), wrapped in try/catch.
}
public void cleanup() throws IOException {
// Close/cleanup the connection
}
}
Now my only problem is that it looks like some Threads/ThreadLocals are being left around on undeployment, but this has to be bugs in the libraries that I'm using as I have no control over their lifecycle.
12-Feb-2016 14:01:45.054 INFO [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.startup.HostConfig.undeploy Undeploying context [/my-resource]
12-Feb-2016 14:01:46.129 WARNING [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [my-resource] appears to have started a thread named [ImmediateThread-1455303641406] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
sun.misc.Unsafe.park(Native Method)
java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
java.util.concurrent.SynchronousQueue$TransferQueue.awaitFulfill(SynchronousQueue.java:764)
java.util.concurrent.SynchronousQueue$TransferQueue.transfer(SynchronousQueue.java:695)
java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:941)
java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1066)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
java.lang.Thread.run(Thread.java:745)
12-Feb-2016 14:01:46.130 WARNING [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [my-resource] appears to have started a thread named [Thread-5] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
sun.net.dns.ResolverConfigurationImpl.notifyAddrChange0(Native Method)
sun.net.dns.ResolverConfigurationImpl$AddressChangeListener.run(ResolverConfigurationImpl.java:144)
12-Feb-2016 14:01:46.134 SEVERE [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks The web application [my-resource] created a ThreadLocal with key of type [org.apache.htrace.core.Tracer.ThreadLocalContext] (value [org.apache.htrace.core.Tracer$ThreadLocalContext#2c25bbe0]) and a value of type [org.apache.htrace.core.Tracer.ThreadContext] (value [org.apache.htrace.core.Tracer$ThreadContext#787153ae]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
12-Feb-2016 14:01:46.135 SEVERE [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks The web application [my-resource] created a ThreadLocal with key of type [org.apache.hadoop.io.Text$1] (value [org.apache.hadoop.io.Text$1#1badb836]) and a value of type [sun.nio.cs.UTF_8.Encoder] (value [sun.nio.cs.UTF_8$Encoder#13652d32]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
12-Feb-2016 14:01:46.136 SEVERE [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks The web application [my-resource] created a ThreadLocal with key of type [org.apache.hadoop.hdfs.DFSUtil$1] (value [org.apache.hadoop.hdfs.DFSUtil$1#6080a3db]) and a value of type [java.util.Random] (value [java.util.Random#169acbf5]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
12-Feb-2016 14:03:02.383 INFO [Thread-7] org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading Illegal access: this web application instance has been stopped already. Could not load [org.apache.hadoop.util.ShutdownHookManager$2]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
java.lang.IllegalStateException: Illegal access: this web application instance has been stopped already. Could not load [org.apache.hadoop.util.ShutdownHookManager$2]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading(WebappClassLoaderBase.java:1353)
at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForClassLoading(WebappClassLoaderBase.java:1341)
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1206)
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1167)
at org.apache.hadoop.util.ShutdownHookManager.getShutdownHooksInOrder(ShutdownHookManager.java:124)
at org.apache.hadoop.util.ShutdownHookManager$1.run(ShutdownHookManager.java:52)
12-Feb-2016 14:03:02.383 INFO [Thread-4] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["http-apr-8080"]
12-Feb-2016 14:03:02.449 INFO [Thread-4] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["ajp-apr-8009"]
12-Feb-2016 14:03:02.500 INFO [Thread-4] org.apache.catalina.core.StandardService.stopInternal Stopping service Catalina
12-Feb-2016 14:03:02.530 INFO [Thread-4] org.apache.coyote.AbstractProtocol.stop Stopping ProtocolHandler ["http-apr-8080"]
12-Feb-2016 14:03:02.581 INFO [Thread-4] org.apache.coyote.AbstractProtocol.stop Stopping ProtocolHandler ["ajp-apr-8009"]
Your HbaseConnection gets initialized twice.
at first, it initializes in your binder (provided your MyApplication class is registered as init-param in your web.xml)
and then, it initializes once again when HK2 detects #Singleton annotation (or when it proceeds the bindAsContract instruction)
As a result, to make your example work, you need to:
remove #Singleton annotation from your HbaseConnection class.
remove line bindAsContract(HbaseConnection.class).in(Singleton.class); from your HBaseBinder class
The initialization of MyApplication happens during the servlet container startup (thus the construction of HbaseConnection) which is what you want, right?
It's you, who's providing the instance (in the binder), not HK2. That's why you don't want to instruct it by using #Singleton to create the instance.
The binder should be:
public class HbaseBinder extends AbstractBinder {
#Override
protected void configure() {
// just bind is ok
bind(new HbaseConnection()).to(HbaseConnection.class);
}
}
And the HBase Connection:
// do not annotate with `#Singleton`!
public class HbaseConnection {
public Connection getConnection() throws IOException {
...
}
...
}
Related
I am using embedded Jetty v9.4.x and have the following issue:
My server registers a ServletContextListener:
final WebAppContext context = new WebAppContext();
// add listener
context.addLifeCycleListener(new AbstractLifeCycle.AbstractLifeCycleListener() {
#Override
public void lifeCycleStarting(LifeCycle event) {
ContextHandler.Context ctx = context.getServletContext();
ctx.setExtendedListenerTypes(true);
ctx.addListener("LISTENER_CLASS_NAME");
}
});
My listener gets called on Servet start. However, my context listener registers a ServletRequestListener inside:
servletContext.addListener(foo.MyServletRequestListener.class);
And this fails with the following exception:
java.lang.UnsupportedOperationException
at org.eclipse.jetty.servlet.ServletContextHandler$Context.addListener(ServletContextHandler.java:1506)
And when I looked it seems that context is not enabled (at least, this flags makes an exception to be thrown).
When I run the same application with the web.xml everything works.
How can I let the contextListener register a ServletRequestListener?
edit
There is explict note in Jetty code:
//toggle state of the dynamic API so that the listener cannot use it
This is enabled only on programatically added listeners - using API and not web-xml.
How I can make this work???
There are many different kinds of listeners in Jetty, each with their own specific set of add/remove/get/set methods.
Your AbstractLifeCycleListener is a Jetty LifeCycle listener, applying specifically for the Jetty internal starting/started/stopping/stopped of the various beans within Jetty.
Your implementation of this listener in your question is incomplete and shows a lack of understanding of the LifeCycleEvent (you are not looking for a specific bean to be started), your implementation will run hundreds of times. (once for each bean being started).
The use of ServletContext.addListener() has rules around it, and those specify that it can only be used during the ServletContext initialization phase (not before, not after). The use of ServletContext.addListener() outside of this phase is supposed to throw an IllegalStateException (the javadoc even says so)
The ServletContext.addListener() also has a limited set of servlet Listeners that are allowed to be used with it, far less then the number of listeners types that are valid with a Web App, or can be declared within a WEB-INF/web.xml, or flagged with the #WebListener annotation.
The only way to use the ServletContext.addListener() is from within the webapp itself, using webapp code, from within the webapp's own classloader.
The places to use ServletContext.addListener() are ...
ServletContainerInitializer.onStartup()
ServletContextListener.contextInitialized()
Filter.init()
Servlet.init()
As you can see, all of these locations are defined from within the webapp itself.
The existence of ServletContextHandler.addEventListener(EventListener) is an embedded-jetty work around, which allows the Listener to be added on construction of the ServletContextHandler, but not called until the actual event occurs.
The use of ServletContextHandler.addEventListener(EventListener) is equivalent to using the WEB-INF/web.xml to declare the Listener you are interested in having be used.
Example:
package jetty.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletContextHandler;
public class ServletContextListenerExample
{
public static void main(String[] args) throws Exception
{
Server server = new Server(8080);
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
MyContextListener contextListener = new MyContextListener();
context.addEventListener(contextListener);
// for context based static file serving and error handling
context.addServlet(DefaultServlet.class, "/");
HandlerList handlers = new HandlerList();
handlers.addHandler(context);
// for non-context error handling
handlers.addHandler(new DefaultHandler());
server.setHandler(handlers);
server.start();
server.join();
}
public static class MyContextListener implements ServletContextListener
{
#Override
public void contextInitialized(ServletContextEvent sce)
{
System.err.printf("MyContextListener.contextInitialized(%s)%n", sce);
sce.getServletContext().addListener(new MyRequestListener());
}
#Override
public void contextDestroyed(ServletContextEvent sce)
{
System.err.printf("MyContextListener.contextDestroyed(%s)%n", sce);
}
}
public static class MyRequestListener implements ServletRequestListener
{
#Override
public void requestDestroyed(ServletRequestEvent sre)
{
System.err.printf("MyRequestListener.requestDestroyed(%s)%n", sre);
}
#Override
public void requestInitialized(ServletRequestEvent sre)
{
System.err.printf("MyRequestListener.requestInitialized(%s)%n", sre);
}
}
}
This will register MyContextListener which implements both javax.servlet.ServletContextListener.
When the ServletContext initialization phase kicks in, the contextInitialized() event is triggered.
The implementation of contextInitalized() then uses the passed in ServletContext to add a new MyRequestListener (which implements javax.servlet.ServletRequestListener) via the ServletContext.addListener() API.
Output of the above, and hitting http://localhost:8080/ from a browser ...
2018-06-28 09:42:06.352:INFO::main: Logging initialized #340ms to org.eclipse.jetty.util.log.StdErrLog
2018-06-28 09:42:06.475:INFO:oejs.Server:main: jetty-9.4.11.v20180605; built: 2018-06-05T18:24:03.829Z; git: d5fc0523cfa96bfebfbda19606cad384d772f04c; jvm 9.0.4+11
MyContextListener.contextInitialized(javax.servlet.ServletContextEvent[source=ServletContext#o.e.j.s.ServletContextHandler#12e61fe6{/,null,STARTING}])
2018-06-28 09:42:06.532:INFO:oejsh.ContextHandler:main: Started o.e.j.s.ServletContextHandler#12e61fe6{/,null,AVAILABLE}
2018-06-28 09:42:06.695:INFO:oejs.AbstractConnector:main: Started ServerConnector#4567f35d{HTTP/1.1,[http/1.1]}{0.0.0.0:8080}
2018-06-28 09:42:06.695:INFO:oejs.Server:main: Started #690ms
MyRequestListener.requestInitialized(javax.servlet.ServletRequestEvent[source=ServletContext#o.e.j.s.ServletContextHandler#12e61fe6{/,null,AVAILABLE}])
MyRequestListener.requestDestroyed(javax.servlet.ServletRequestEvent[source=ServletContext#o.e.j.s.ServletContextHandler#12e61fe6{/,null,AVAILABLE}])
Caution: Be aware that there are many more listener APIs and listener types on Jetty then discussed here, they exist for other features / components with Jetty that are unrelated to your question.
Don't get hung up on them, skip them, ignore them and you'll be fine.
Using Camel-core v2.14.1 and camel-testng v2.14.1
Attempting to Unit Test a basic route.
The RouteBuilder class is named as FileToJmsRB and the Route is configured this way
#Override
public void configure() {
from("file:C:\\camel_folder\\orders")
.when(fileToJmsConditions.camelFileNameEndingWithXml(this))
.to("file:C:\\camel_folder\\recieved")
}
fileToJmsConditions is a variable that I am failing to inject as Spring Bean.
My Test class extends CamelTestSupport and it overrides createRouteBuilder() as follows
#Override
protected RouteBuilder createRouteBuilder() throws Exception{
return new FileToJmsRB();
}
and I configure a method as test.
#Test
public void testTextFileMove() throws Exception{
template.sendBodyAndHeader("file:C:\\camel_folder\\orders"
, "Hello World"
, Exchange.FILE_NAME
, "hello.txt");
Thread.sleep(10000);
File target = new File("C:\\camel_folder\\recieved\\hello.txt");
assertTrue(target.exists(), "File Not Moved");
}
On running
maven install
on the project, I expect a Null Pointer Exception with a StackTrace in Console.
However, observation no hint of type of Exception Thrown and there is not stacktrace printed. It just says that the test failed but does not prints the type of exception or stacktrace.
Tests run: 2, Failures: 1, Errors: 0, Skipped: 1
However, if I wrap my configure method in FileToJmsRB class with
try... Catch...
Only then do I see the NullPointerException thrown and Stack Trace printed.
Is there no other, more elegant way of handling this more elegantly? Because this way I must do try...catch... in every Route Builder class?
I wrote a web service using cxf web service. I want to send different error messages to client. I have a method and this method return an object if everything is ok. Method receives parameters if one of parameters is wrong, method must send different messages. But i can not change method return type so i cant send different objects. How can i do that?
Try to use the exceptions.
Within the java annotations cxf system you can return an exception if it looks like this :
import javax.xml.ws.WebFault;
#WebFault(name = "UsageMyException")
public class MyException extends Exception
{
private static final long serialVersionUID = 1L;
public MyException(final String string)
{
super(string);
}
public MyException(final Exception e)
{
super(e);
}
}
You can use more than one exception that extends each other. The exception corresponds to wsdl/soap FaultMessage.
We are using Jboss 7.1.1 in an application mostly generated by Jboss Forge, however we added a repository layer for all domain related code.
I was trying to create a Startup bean to initialize the database state. I would like to use my existing repositories for that.
My repositories all have an extended PersistenceContext injected into them. I use these from my View beans that are #ConversationScoped #Stateful beans, by using the extended context my entities remain managed during a conversation.
First I tried this:
#Startup
#Singleton
public class ConfigBean {
#Inject
private StatusRepository statusRepository;
#Inject
private ZipCode zipCodeRepository;
#PostConstruct
public void createData() {
statusRepository.add(new Status("NEW"));
zipCodeRepository.add(new ZipCode("82738"));
}
}
Example repository:
#Stateful
public class ZipCodeRepository {
#PersistenceContext(PersistenceContextType.EXTENDED)
private EntityManger em;
public void add(ZipCode zipCode) {
em.persist(zipCode);
}
....
}
This ends up throwing an javax.ejb.EJBTransactionRolledbackException on Application startup with the following message:
JBAS011437: Found extended persistence context in SFSB invocation call stack but that cannot be used because the transaction already has a transactional context associated with it. This can be avoided by changing application code, either eliminate the extended persistence context or the transactional context. See JPA spec 2.0 section 7.6.3.1.
I struggled finding a good explanation for this, and actually figured that since EJB's and their injection are handled by proxies all the PersistenceContext injection and propagation would be handled automatically. I guess I was wrong.
However, while on this trail of thought I tried the following:
#Startup
#Singleton
public class ConfigBean {
#Inject
private SetupBean setupBean;
#PostConstruct
public void createData() {
setupBean.createData();
}
#Stateful
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public static class SetupBean {
#Inject
private StatusRepository statusRepository;
#Inject
private ZipCode zipCodeRepository;
public void createData() {
statusRepository.add(new Status("NEW"));
zipCodeRepository.add(new ZipCode("82738"));
}
}
}
This does the trick. All I did was wrap the code in a Stateful SessionBean that is a static inner class of my Singleton bean.
Does anyone understand this behavior? Because while everything works now I'm still a bit estranged as to why it works this way.
A container-managed extended persistence context can only be initiated
within the scope of a stateful session bean. It exists from the point
at which the stateful session bean that declares a dependency on an
entity manager of type PersistenceContextType.EXTENDED is created, and
is said to be bound to the stateful session bean.
From the posted code, it seems ZipCodeRepository isn't itself stateful bean, but you're calling it from one such bean.
In this case, you are initiating PersistenceContextType.TRANSACTION from ConfigBean & propogates through ZipCodeRepository having PersistenceContextType.EXTENDED & it tries to join the transaction, hence the exception.
Invocation of an entity manager defined with PersistenceContext- Type.EXTENDED will result in the use of the existing extended
persistence context bound to that component.
When a business method of the stateful session bean is invoked, if the stateful session bean uses container managed transaction
demarcation, and the entity manager is not already associated with the
current JTA transaction, the container associates the entity manager
with the current JTA transaction and calls
EntityManager.joinTransaction. If there is a different persistence
context already associated with the JTA transaction, the container
throws the EJBException.
While in later case, you're creating a new transaction in SetupBean for each invocation with TransactionAttributeType.REQUIRES_NEW which is of extended type, as it's a stateful bean.
Therefore, adding SetupBean as stateful session bean initiating new transaction for each invocation & later calling ZipCodeRepository doesn't result in exception. ZipCodeRepository will join the same transaction as initiated by SetupBean.
I'm using Hectors EmbeddedServerHelper to set up embedded Cassandra. It has teardown() and cleanup() methods.
The problem is that cleanup method cannot delete some commit log files created by cassandra. Probably because there are still some cassandra daemons that were not properly shut down by the teardown() method. Here us the setup and teardown code:
#BeforeClass
public static void setUpBeforeClass() throws Exception {
EmbeddedServerHelper sh = new EmbeddedServerHelper();
sh.setup();
}
#AfterClass
public static void tearDownAfterClass() throws Exception {
EmbeddedServerHelper.teardown();
EmbeddedServerHelper.cleanup();
doDelete(new File("tmp"));
}
How can I delete these files?
The data files and commit logs are checked-for and deleted on startup as it was quite difficult to know when the cassandra process was done with cleaning up from the context of JUnit.