I am using EJB3.0, Weblogic 11g
I am trying to do simple lookup from servlet to Statelessbean and run there a method. both under the same EAR.
I managed to do it with Jboss. but I know that in Weblogic it's little bit diffrent so I channged my code and this is what I am doing and still no success:
The interface I have declared:
#Local
public interface OperatorBlockBeanLocal
{
public void testme();
}
This is the class which implements the Interface:
#Stateless
#Local{ OperatorBlockBeanLocal.class })
#JNDIName(value = "OperatorBlockBean")
public class OperatorBlockBean implements OperatorBlockBeanLocal
{
public void testme()
{
System.out.println("OperatorBlockBean");
}
}
And this is the servlet which trying to lookup the bean I decalred before:
try
{
context = new InitialContext();
operatorBlockBean = (OperatorBlockBeanLocal) context
.lookup("java:comp/env/OperatorBlockBean");
operatorBlockBean.testme();
} catch (NamingException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
Ofcourse that I get NamingException. anyone has any idea?
thanks,
ray.
Try using
#Stateless(mappedName="OperatorBlockBean")
#Local{ OperatorBlockBeanLocal.class }
public class OperatorBlockBean implements OperatorBlockBeanLocal
You can also use EJB injection in your servlet and not do a lookup. Here's how:
#EJB OperatorBlockBeanLocal operatorBlockBean;
The EJB will injected so you don't have to do a lookup.
Related
I wrote the follow piece of code and It works but i'm not sure why.
What I wanted is to customize the jdbc configuration of spring-data-jdbc and I extended the configuration with another, but... what really happen in the IoC Container?
JdbcConfiguration is #Configuration annotated bean that instantiates a
JdbcCustomConversions and i'm able to override this behavior subclassing the whole configuration and specifying ma own method, but i'm not really sure why.
#Configuration
public class CustomJdbcConfiguration extends JdbcConfiguration{
#Override
protected JdbcCustomConversions jdbcCustomConversions() {
return new JdbcCustomConversions(Collections.singletonList(CLobToStringConverter.INSTANCE));
}
#ReadingConverter
enum CLobToStringConverter implements Converter<Clob, String>{
INSTANCE;
#Override
public String convert(Clob source) {
try {
return IOUtils.toString(source.getCharacterStream());
} catch (IOException | SQLException e) {
throw new RuntimeException(e);
}
}
}
}
I'm using Spring 3.2.5 without full new JSR-356 WebSockets support.
I would like to have singleton-bean reference in my #ServerEndpoint WebSocket server, which is instantiated by servlet container itself, not in Spring context.
What is the clean way to do it?
My current solution: I made #Service singleton bean with instance in static field:
#Service
public class WebSocketSupportBean {
private volatile static WebSocketSupportBean instance = null;
public static WebSocketSupportBean getInstance() {
return instance;
}
public WebSocketSupportBean() {
instance = this;
}
and just getting it in #ServerEndpoint by static method, disconnecting user if null returned (if bean not jet created during server startup but user connects):
You can setup websockets with spring framework 3.x
I developed a small proof-of-concept application to demonstrate how, based on Rossen Stoyanchev's SpringConfiguration released with spring-core 4.0.
The application sets up a websocket server endpoint with uri /wstest which will use a #Autowired spring bean to select a greeting word and reply to a websocket message.
The websocket connection is initiated and messages sent by an html page (index.html) running in a browser that supports websockets.
The Endpoint registration is made by a ServletContextListener at context initialization and when the endpoint is instantiated it will be wired with spring:
#WebListener
public class MyApplication implements ServletContextListener {
private final static String SERVER_CONTAINER_ATTRIBUTE = "javax.websocket.server.ServerContainer";
#Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext container = sce.getServletContext();
final ServerContainer serverContainer = (ServerContainer) container.getAttribute(SERVER_CONTAINER_ATTRIBUTE);
try {
serverContainer.addEndpoint(new MyEndpointConfig(MyEndpoint.class, "/wstest"));
} catch (DeploymentException e) {
e.printStackTrace();
}
}
}
And the Endpoint is:
#Component
public class MyEndpoint extends Endpoint {
#Autowired
MyService myService;
#Override
public void onOpen(Session session, EndpointConfig config) {
session.addMessageHandler(new MyMessageHandler(session));
}
class MyMessageHandler implements MessageHandler.Whole<String> {
final Session session;
public MyMessageHandler(Session session) {
this.session = session;
}
#Override
public void onMessage(String message) {
try {
String greeting = myService.getGreeting();
session.getBasicRemote().sendText(greeting + ", got your message (" + message + "). Thanks ! (session: " + session.getId() + ")");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Checkout the full source and ready to run example on my Github page.
You have to add bean definition in the configuration of spring.
The solution i found to integrate JSR 356 websocket #ServerEndpoint is to turn off the Servlet container's scan for WebSocket endpoints by spring which can be done by registering #Bean in your Spring Configuration. By this spring not overrides normal JSR 356 websocket by spring STOMP websocket which is the part of the websocket.
#ServerEndpoint(value="/chatMessage")
public class ChatEndpoint{
// Normal websocket body goes here.
}
Adding Beans in your Configuration as:
#Configuration
public class WebsocketConfig{
#Bean
public ChatEndpoint chatEndpoint(){
return new ChatEndpoint();
}
// main one is ServerEndpointExporter which prevents Servlet container's scan for WebSocket
#Bean
public ServerEndpointExporter endpointExporter(){
return new ServerEndpointExporter();
}
}
This all done for you. But you should remove configurator = SpringConfigurator.class from #ServerEndpoint.
I am using Spring Websocket 4.0.0 and it works fine.
You can also see this Link.
If you alright then follow this Link also for concept.
Note that, Normally you should make websocket configuration separately from the main configuration of your spring.
Try
#ServerEndpoint(value = "/ws", configurator = SpringConfigurator.class)
And add maven dependency
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
</dependency>
You can make your #ServerEndpoint object extend SpringBeanAutowiringSupport. Then just make it aware of beans that gets constructed within a Spring-based web application this way:
#PostConstruct
public void init() {
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}
This way #Autowired annotation will worl correctly:
#Autowired MyService myService;
try this,it works for me
#Component
#ServerEndpoint(value = "/instantMessageServer",configurator = SpringConfigurator.class)
public class InstantMessageServer{
private static IChatService chatService;
#Autowired
public InstantMessageServer(IChatService chatService){
this.chatService = chatService;
}
public InstantMessageServer(){}
}
I found this solution on https://spring.io/blog/2013/05/23/spring-framework-4-0-m1-websocket-support
but there is one more glitch,the class annotated with #ServerEndpoint cant acquire httpsession with SpringConfigurator,there is no a override of method modifyhandler in it.Maybe we create a seperate Configurator extends SpringConfigurator and override that method would be a workaroud.
It is better to build a real-time web application with spring-websocket and messaging api,I think.
public class ModifiedServerEndpointConfigurator extends SpringConfigurator{
#Override
public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
HttpSession httpSession = (HttpSession) request.getHttpSession();
sec.getUserProperties().put(HttpSession.class.getName(),httpSession);
super.modifyHandshake(sec, request, response);
}
}
I have a web project using Resteasy (which in turn uses Weld) and is deployed to Tomcat 7.0.22 (I put the specific version here in case this issue is particular to this version).
I have a ServletContextListener that looks like this:
#WebListener
public class ApplicationInitialisationListener implements ServletContextListener {
// create a logger here
#Inject
HealthCheck healthCheck;
#Override
public void contextInitialized(ServletContextEvent event) {
if (healthCheck == null) {
log.error("healthCheck is null");
}
}
#Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
}
After deploying to Tomcat, healthCheck is null was logged, and I also noticed this line in the log:
<2013-11-13 13:27:40,191> <pack> INFO pool-2-thread-1 org.jboss.weld.environment.tomcat7.Tomcat7Container - Tomcat 7 detected, CDI injection will be available in Servlets and Filters. Injection into Listeners is not supported
Question 1: why is CDI injection not available in Listeners?
I looked into this answer, and it says Load on startup via #Startup. There is currently no equivalent to this in CDI.
Question 2: is the issue described in Question 1 a consequence of this?
Question 3: I am using org.jboss.weld.servlet:weld-servlet:1.2.0.Beta1. Is there any update on startup support in later versions?
Related Questions I Looked
startup class in Weld
Here is a workaround I discovered that can inject CDI beans when an application starts.
The requirement of the problem can be summarized as:
inject a CDI bean when the application starts
do something with the bean
Solution outline line:
Create a WebListener that calls BeanManager.fireEvent(new SomeDummyEvent())
Create an ApplicationScoped bean that responds to SomeDummyEvent and injects the CDI bean
Example code:
#WebListener
public class ApplicationInitialisationListener implements ServletContextListener {
private static final Logger LOG = Logger.getLogger(ApplicationInitialisationListener.class);
#Override
public void contextInitialized(ServletContextEvent event) {
BeanManager beanManager = lookUpBeanManager();
if (beanManager != null) {
beanManager.fireEvent(new SomeDummyEvent());
LOG.info("beanManager fired SomeDummyEvent.");
} else {
LOG.error("beanManager is null. Cannot fire startup event.");
}
}
#Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
public BeanManager lookUpBeanManager() {
try {
// See reference below about how I came up with this
InitialContext iniCtx = new InitialContext();
BeanManager result = (BeanManager) iniCtx.lookup("java:comp/env/BeanManager");
return result;
} catch (NamingException e) {
LOG.error("Could not construct BeanManager.", e);
return null;
}
}
public static class SomeDummyEvent implements Serializable {
}
}
#ApplicationScoped
public class InitializationResourceBean {
private static final Logger LOG = Logger.getLogger(InitializationResourceBean.class);
#Inject
HealthCheck healthCheck;
public void listen(#Observes ApplicationInitialisationListener.SomeDummyEvent event) {
}
#PostConstruct
public void init() {
// Do something with healthCheck
}
#PreDestroy
public void destroy() {
// Do some other thing with healthCheck
}
}
References:
http://struberg.wordpress.com/tag/cdi/
From: http://docs.jboss.org/weld/reference/latest-master/en-US/html/environments.html#_tomcat
"Tomcat 7 and 8 are supported. Context activation/deactivation and dependency injection into Servlets and Filters works out of the box. Injection into Servlet listeners works on Tomcat 7.0.50 and newer."
So perhaps you can upgrade your Tomcat?
Now, all this is much easy to do with deltaspike servlet module
#ApplicationScoped
public class InitializationResourceBean {
#Inject
HealthCheck healthCheck;
public void onCreate(#Observes #Initialized ServletContext context) {
//Do initialisation stuff here.
if(HealthCheck != null) {
;
}
}
public void onDestroy(#Observes #Destroyed ServletContext context) {
System.out.println("Destroyed ServletContext: " + context.getServletContextName());
}
}
http://deltaspike.apache.org/documentation/servlet.html
I am learning Java EE and JSP. I have created an Enterprise Application project in NetBeans.
I have the EJB project where all beans are and a WAR project where all web/client stuff is.
My problem is that the annotation #EJB does not instantiate my Bean in the WAR application. Can I use #EJB outside the EJB application?
In the EJB project, I have these files:
CustomerRemote.java
#Remote
public interface CustomerRemote {
public Customer createCustomer();
public Customer getCustomer(int customerId);
public void removeCustomer();
}
CustomerBean.java
#Stateless
public class CustomerBean implements CustomerRemote {
#PersistenceContext(unitName="testPU")
private EntityManager entityManager;
#Override
public Customer createCustomer() {
throw new UnsupportedOperationException("Not supported yet.");
}
#Override
public void removeCustomer() {
}
#Override
public Customer getCustomer(int customerId) {
throw new UnsupportedOperationException("Not supported yet.");
}
}
In the WAR project, I have a file that my JSP page uses to communicate with the EJB stuff. The problem is that the CustomerRemote object is never instantiated. #EJB annotation does not seem to work because customerRemote always is null. But when instantiating it with the lookup method, it works! So why does not #EJB work?
public class CustomerProxyBean {
#EJB
private CustomerRemote customerRemote;
public CustomerProxyBean() {
// try {
// InitialContext context = new InitialContext();
// customerRemote = (CustomerRemote)context.lookup("java:app/SimpleShop-ejb/CustomerBean");
//
// } catch (NamingException ex) {
// Logger.getLogger(CustomerProxyBean.class.getName()).log(Level.SEVERE, null, ex);
// }
}
#EJB annotation will work only in cases where your class is container-managed, that is EJB, servlet, JSP... In your case you put it into plain old Java object (POJO) so injection will not work, as you have experienced. Write your CustomerProxyBean as a stateless session bean, and you'll see the change.
Alternatively, if you want to avoid JNDI for some reason, you can use CDI and #Inject annotation to inject EJB and achieve wished behaviour, even in POJO:
#Inject
private CustomerRemote customerRemote;
I have created an EJB timer with a local interface and I am not able to do JNDI lookup for it from a ServletContextListener.
Here is part of the EJB code:
#Stateless
#LocalBinding(jndiBinding = "TimedFileDeletion")
public class TimedFileDeletionBean implements TimedFileDeletionBeanLocal {
#Resource
TimerService timerService;
private String timerInfo = "FileDeletionTimer";
public void startTimer() {
....
}
public boolean isItRunning() {
....
}
#Timeout
public void timeout(Timer timer) {
....
}
}
Here is the local interface:
public interface TimedFileDeletionBeanLocal {
public void startTimer();
public boolean isItRunning();
}
And here is the ServletContextListener:
public class StartupEventHandler implements ServletContextListener {
TimedFileDeletionBeanLocal timedFileDeletionBeanLocal;
public StartupEventHandler() {
try {
InitialContext ic = new InitialContext();
timedFileDeletionBeanLocal = (TimedFileDeletionBeanLocal) ic.lookup("java:comp/env/ejb/TimedFileDeletion");
} catch (NamingException e) {
e.printStackTrace();
}
}
public void contextInitialized(ServletContextEvent arg0) {
if(!timedFileDeletionBeanLocal.isItRunning()) {
timedFileDeletionBeanLocal.startTimer();
}
}
public void contextDestroyed(ServletContextEvent arg0) {
}
}
For the lookup I also used the following Strings but none of the worked:
- java:comp/env/TimedFileDeletion
- java:comp/TimedFileDeletion
- java:TimedFileDeletion
- TimedFileDeletion
In all cases I was getting a javax.naming.NameNotFoundException.
Any advice would be appreciated.
While starting JBoss it logs all the local/remote interfaces & their jndi configuration.
JBoss startup log :
15:26:47,394 INFO [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
hrms/AccountSummarySessionBean/local - EJB3.x Default Local Business Interface
hrms/AccountSummarySessionBean/local-com.cc.hrms.bl.accounts.generalaccount.session.AccountSummarySessionBeanLocal - EJB3.x Local Business Interface
Lookup :
initialCtx.lookup("hrms/AccountSummarySessionBean/local-com.cc.hrms.bl.accounts.generalaccount.session.AccountSummarySessionBeanLocal");
I am using JBoss-5 & have generalized method for lookup, just giving interface name.
You can modify it accordingly.