I'm trying to migrate from EJB2.x to EJB3.x and i'm using Wildfly 9.0.0.
The old EJB2.x is working in JBoss 4.2.2 and this is how it looks like:
public interface WUFFacadeRemote extends EJBObject {
public ClientData getItems(ClientData data);
public ClientData save(ClientData data);
}
public interface WUFFacadeHome extends EJBHome {
public WUFFacadeRemote create();
}
public class WUFFacade {
public ClientData getItems(ClientData data) {
//code here
}
public ClientData save(ClientData data) {
//code here
}
}
public class WUFAction extends HttpServlet implements IAction {
public void doPost(HttpServletRequest request, HttpServletResponse response) {
...
Object objRef = ic.lookup("java:comp/env/wUF");
com.wuf.WUFFacadeHome home = (com.wuf.WUFFacadeHome) PortableRemoteObject.narrow(objRef, com.wuf.WUFFacadeHome.class);
engine = home.create();
//engine gets the reference, and I can use it normally.
...
}
}
I also have the ejb-jar.xml and it's working. Now, the solution I was thinking to EJB3.x and Wildfly 9.0.0 is as below:
#WebServlet(urlPatterns = "windows/wUF.do", loadOnStartup = 1)
public class WUFAction extends HttpServlet implements IAction {
#EJB
private WUFFacadeRemote engine;
public void doPost(HttpServletRequest request, HttpServletResponse response) {
//Here I should be able to use my engine.
//Wildfly starts and I call the page, engine is not null at this moment,
//but after I call the page again, it becomes null and remains null.
}
}
#Stateless
#Remote(WUFFacadeRemote.class)
public class WUFFacade extends RootFacade implements WUFFacadeRemote, Serializable {
public WUFFacade() { }
#EJB
FUFHome home;
public ClientData getItems(ClientData data) {
//code here
}
public ClientData save(ClientData data) {
//code here
}
private Col load(ClientData data,InitialContext ic) {
//here i'm calling home.
// but home is always null. It was supposed to have the #EJB reference initialized.
//But instead I get a null pointer...
home.findByFilter(loader);
}
}
#Remote(FUFHome.class)
public interface FUFHome {
FUF create(FUFValue fUFValue);
FUF findByPrimaryKey(FUFPK pk);
Collection findByFilter(FacadeLoader loader);
}
public interface WUFFacadeRemote{
public ClientData getItems(ClientData data);
public ClientData save(ClientData data);
}
I don't have ejb-jar.xml anymore, the deploy is sucessfully done and Wildfly starts with no errors. Then the first time I call the page in question, it seems that #EJB is working (Debug is "Proxy for remote EJB StatelessEJBLocator for "bus-facade/WUFFacade", view is interface com.wuf.WUFFacadeRemote, affinity is None"), the value is not null, but for all subsequent calls, my variable is null and I got a NullPointerException.
I really don't know what i'm doing wrong (maybe i'm completely lost), but to me, #EJB should be working correctly like that. What am I missing? Thanks.
As i'm using EJB3.x i'm just using annotations now, (this seems to be ok).
JNDIs:
JNDI bindings for session bean named FUF in deployment
java:global/fumo/bus-entities-fumo/FUF!apyon.components.fumo.fuf.FUF
java:app/bus-entities-fumo/FUF!apyon.components.fumo.fuf.FUF
java:module/FUF!apyon.components.fumo.fuf.FUF
java:global/fumo/bus-entities-fumo/FUF
java:app/bus-entities-fumo/FUF
java:module/FUF
JNDI bindings for session bean named WUFFacade
java:global/fumo/bus-facade-fumo/WUFFacade!apyon.fumo.wuf.WUFFacadeRemote
java:app/bus-facade-fumo/WUFFacade!apyon.fumo.wuf.WUFFacadeRemote
java:module/WUFFacade!apyon.fumo.wuf.WUFFacadeRemote
java:jboss/exported/fumo/bus-facade-fumo/WUFFacade!apyon.fumo.wuf.WUFFacadeRemote
java:global/fumo/bus-facade-fumo/WUFFacade
java:app/bus-facade-fumo/WUFFacade
java:module/WUFFacade
I think I found a possible solution to the problem. I'll still try to find another one, but this is good so far.
After changing to a .war and keeping my other projects in .ears it's working. Maybe the problem was because I have a RootController servlet im my main.ear, which is the starting point of the aplication. The context starts there and then it redirects to fumo.ear (now fumo.war).
For some reason, I always was getting a null in my EJB after entering a page. It was always hapening when I first entered a JSP and tried to call the page again. My solution to this is:
#WebServlet(urlPatterns = "windows/wUF.do", loadOnStartup = 1)
public class WUFAction extends HttpServlet {
private WUFFacadeRemote engine;
public void doGet(HttpServletRequest req, HttpServletResponse resp) {
doPost(req, resp);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) {
if(engine == null) {
InitialContext ic;
try {
ic = new InitialContext();
engine = (WUFFacadeRemote) ic.lookup("java:global/fumo/WUFFacade!fumo.wuf.WUFFacadeRemote");
} catch (NamingException e) {
e.printStackTrace();
}
}
//here I always have the context now.
}
}
And as a .war my structure now looks like this:
So other annotations like #Inject and #EJB are now working. Always when i'm being redirect from a JSP calling a Servlet or some action, I first check if the context is not null, otherwise I lookup it. My #Stateless are working and the #PersistenceContext and #Remote are working too.
#Stateless
public class WUFFacade implements WUFFacadeRemote {
#Inject
private FUFRules rules;
#EJB
private FUFHome home;
private Col load(ClientData data, InitialContext ic) throws InterfaceException {
try {
// home here is nor null anymore.
Collection res = (Collection) home.findByFilter(loader);
...
} catch (InterfaceException e) {
e.printStackTrace();
}
...
return data;
}
}
So I'd like to thank everyone who helped in the thread. It was a good way to understand and see the problem or to find a workaround. As I said, I'll still try the .ear in the future, but as a simplified packaging it definitely works.
Related
Where executor service should be declared so it is available to other servlets and not new thread gets created for every new request
Can I do something like this and whenever need to send email, forward request to this servlet
Can you please suggest better design to use ExecutorService in servlet or any other way to send email from servlet?
public class EmailTestServlet extends HttpServlet
{
ExecutorService emailThreadPool = null;
public void init()
{
super.init();
emailThreadPool = Executors.newFixedThreadPool(3);
}
protected void doGet(HttpServletRequest request,HttpServletResponse response)
{
sendEmail(); //it will call emailThreadPool.execute();
}
public void destroy()
{
super.destroy();
}
}
Depends on whether CDI is available at your environment. It is available out the box in normal Jakarta EE servers, but in case of barebones servletcontainers such as Tomcat or Jetty you'd need to manually install and configure it. It's relatively trivial though and gives a lot of benefit: How to install and use CDI on Tomcat?
Then you can simply create an application scoped bean for the job like below:
#ApplicationScoped
public class EmailService {
private ExecutorService executor;
#PostConstruct
public void init() {
executor = Executors.newFixedThreadPool(3);
}
public void send(Email email) {
executor.submit(new EmailTask(email));
}
#PreDestroy
public void destroy() {
executor.shutdown();
}
}
In order to utilize it, simply inject it in whatever servlet or bean where you need it:
#WebServlet("/any")
public class AnyServlet extends HttpServlet {
#Inject
private EmailService emailService;
#Override
protected void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
Email email = new Email();
// ...
emailService.send(email);
}
}
In case you find yourself in the unfortunate situation that you cannot use CDI, then you'll have to remove the #ApplicationScoped annotation from the EmailService class and reinvent the wheel by simulating whatever CDI is doing under the covers by manually fiddling with ServletContext#get/setAttribute() to simulate an application scoped bean. It might look like this:
#WebListener
public class ApplicationScopedBeanManager implements ServletContextListener {
#Override
public void contextCreated(ServletContextEvent event) {
EmailService emailService = new EmailService();
emailService.init();
event.getServletContext().setAttribute(EMAIL_SERVICE, emailService);
}
#Override
public void contextDestroyed(ServletContextEvent event) {
EmailService emailService = (EmailService) event.getServletContext().getAttribute(EMAIL_SERVICE);
emailService.destroy();
}
}
In order to utilize it, rewrite the servlet as follows:
#WebServlet("/any")
public class AnyServlet extends HttpServlet {
private EmailService emailService;
#Override
public void init() {
emailService = (EmailService) getServletContext().getAttribute(EMAIL_SERVICE);
}
#Override
protected void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
Email email = new Email();
// ...
emailService.send(email);
}
}
See also:
What is recommended way for spawning threads from a servlet in Tomcat
How to run a background task in a servlet based web application?
Background process in Servlet
I want to read text data fixtures (CSV files) at the start on my application and put it in my database.
For that, I have created a PopulationService with an initialization method (#PostConstruct annotation).
I also want them to be executed in a single transaction, and hence I added #Transactional on the same method.
However, the #Transactional seems to be ignored :
The transaction is started / stopped at my low level DAO methods.
Do I need to manage the transaction manually then ?
Quote from legacy (closed) Spring forum:
In the #PostConstruct (as with the afterPropertiesSet from the InitializingBean interface) there is no way to ensure that all the post processing is already done, so (indeed) there can be no Transactions. The only way to ensure that that is working is by using a TransactionTemplate.
So if you would like something in your #PostConstruct to be executed within transaction you have to do something like this:
#Service("something")
public class Something {
#Autowired
#Qualifier("transactionManager")
protected PlatformTransactionManager txManager;
#PostConstruct
private void init(){
TransactionTemplate tmpl = new TransactionTemplate(txManager);
tmpl.execute(new TransactionCallbackWithoutResult() {
#Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
//PUT YOUR CALL TO SERVICE HERE
}
});
}
}
I think #PostConstruct only ensures the preprocessing/injection of your current class is finished. It does not mean that the initialization of the whole application context is finished.
However you can use the spring event system to receive an event when the initialization of the application context is finished:
public class MyApplicationListener implements ApplicationListener<ContextRefreshedEvent> {
public void onApplicationEvent(ContextRefreshedEvent event) {
// do startup code ..
}
}
See the documentation section Standard and Custom Events for more details.
As an update, from Spring 4.2 the #EventListener annotation allows a cleaner implementation:
#Service
public class InitService {
#Autowired
MyDAO myDAO;
#EventListener(ContextRefreshedEvent.class)
public void onApplicationEvent(ContextRefreshedEvent event) {
event.getApplicationContext().getBean(InitService.class).initialize();
}
#Transactional
public void initialize() {
// use the DAO
}
}
Inject self and call through it the #Transactional method
public class AccountService {
#Autowired
private AccountService self;
#Transactional
public void resetAllAccounts(){
//...
}
#PostConstruct
private void init(){
self.resetAllAccounts();
}
}
For older Spring versions which do not support self-injection, inject BeanFactory and get self as beanFactory.getBean(AccountService.class)
EDIT
It looks like that since this solution has been posted 1.5 years ago developers are still under impression that if a method,
annotated with #Transactional, is called from a #PostContruct-annotated method invoked upon the Bean initialization, it won't be actually executed inside of Spring Transaction, and awkward (obsolete?) solutions get discussed and accepted instead of this very simple and straightforward one and the latter even gets downvoted.
The Doubting Thomases :) are welcome to check out an example Spring Boot application at GitHub which implements the described above solution.
What actually causes, IMHO, the confusion: the call to #Transactional method should be done through a proxied version of a Bean where such method is defined.
When a #Transactional method is called from another Bean, that another Bean usually injects this one and invokes its proxied (e.g. through #Autowired) version of it, and everything is fine.
When a #Transactional method is called from the same Bean directly, through usual Java call, the Spring AOP/Proxy machinery is not involved and the method is not executed inside of Transaction.
When, as in the suggested solution, a #Transactional method is called from the same Bean through self-injected proxy (self field), the situation is basically equivalent to a case 1.
#Platon Serbin's answer didn't work for me. So I kept searching and found the following answer that saved my life. :D
The answer is here No Session Hibernate in #PostConstruct, which I took the liberty to transcribe:
#Service("myService")
#Transactional(readOnly = true)
public class MyServiceImpl implements MyService {
#Autowired
private MyDao myDao;
private CacheList cacheList;
#Autowired
public void MyServiceImpl(PlatformTransactionManager transactionManager) {
this.cacheList = (CacheList) new TransactionTemplate(transactionManager).execute(new TransactionCallback(){
#Override
public Object doInTransaction(TransactionStatus transactionStatus) {
CacheList cacheList = new CacheList();
cacheList.reloadCache(MyServiceImpl.this.myDao.getAllFromServer());
return cacheList;
}
});
}
The transaction part of spring might not be initialized completely at #PostConstruct.
Use a listener to the ContextRefreshedEvent event to ensure, that transactions are available:
#Component
public class YourService
implements ApplicationListener<ContextRefreshedEvent> // <= ensure correct timing!
{
private final YourRepo repo;
public YourService (YourRepo repo) {this.repo = repo;}
#Transactional // <= ensure transaction!
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
repo.doSomethingWithinTransaction();
}
}
Using transactionOperations.execute() in #PostConstruct or in #NoTransaction method both works
#Service
public class ConfigurationService implements ApplicationContextAware {
private static final Logger LOG = LoggerFactory.getLogger(ConfigurationService.class);
private ConfigDAO dao;
private TransactionOperations transactionOperations;
#Autowired
public void setTransactionOperations(TransactionOperations transactionOperations) {
this.transactionOperations = transactionOperations;
}
#Autowired
public void setConfigurationDAO(ConfigDAO dao) {
this.dao = dao;
}
#PostConstruct
public void postConstruct() {
try { transactionOperations.execute(new TransactionCallbackWithoutResult() {
#Override
protected void doInTransactionWithoutResult(final TransactionStatus status) {
ResultSet<Config> configs = dao.queryAll();
}
});
}
catch (Exception ex)
{
LOG.trace(ex.getMessage(), ex);
}
}
#NoTransaction
public void saveConfiguration(final Configuration configuration, final boolean applicationSpecific) {
String name = configuration.getName();
Configuration original = transactionOperations.execute((TransactionCallback<Configuration>) status ->
getConfiguration(configuration.getName(), applicationSpecific, null));
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
}
}
I have migrated my app from Glassfish 2.2.1 to JBoss AS 6.
Previously i have a generic class for lookup the ejbs, Below is the code:
public class BeanUtil {
private static InitialContext ctx;
public static <T> T create(Class<T> type){
try {
ctx = new InitialContext();
return (T)ctx.lookup(type.getName());
} catch (NamingException e) {
e.printStackTrace();
}
return null;
}
}
The above class works fine for lookup in glassfish.
But after migrating the code to JBoss AS 6. I always get javax.naming.NameNotFoundException
Below is one of my ejb class.
#Remote
public interface OperationPerformed {
public void addRandomNo(String randomNos);
}
#Stateless
#Remote(OperationPerformed.class)
public class OperationPerformedImpl implements OperationPerformed {
public void addRandomNo(String randomNos) {
}
}
If i give the complete jndi name which jboss made during deployment of my app, then i can easily lookup the same. But i want generic code for lookup.
Below is the code which i invoke for lookup a bean:
OperationPerformed operationPerformed =
BeanUtil.create(OperationPerformed.class);
Please suggest if i am doing something wrong.
I think you can convert class name to jndi name and look it up normally
Some suggestions:
It's quite unusual to use #Remote annotation on interface and implementation at the same time. Remove this annotation from your stateless bean, it's redundant.
I agree with other posters:
don't use remote interface for local lookups and injections, create another interface and mark it with #Local.
when it comes to JVM-local operations #EJB injection is vastly supperior comparing to manual JNDI lookup (see responses to http://stackoverflow.com/questions/12681436/ejb-annotation-vs-jndi-lookup and similar questions on SO).
To sum it all:
create OperationPerformedLocal.java :
#Local
public interface OperationPerformedLocal {
public void addRandomNo(String randomNos);
}
modify your SLSB:
#Stateless
public class OperationPerformedImpl implements OperationPerformedLocal, OperationPerformed {
public void addRandomNo(String randomNos) {
}
}
and use injection rather than jndi lookup whenever possible:
#EJB
private OperationPerformedLocal operationPerformed;
In case of WAR modules some CDI #Injection magic should work, but I haven't got any real experience with it yet.
Now, if you insist on using plain JNDI lookups and want them to be as generic as possible, I came up with this solution:
public class BeanUtil {
private static InitialContext ctx;
public static <T, C> T create(Class<C> implType, Class<T> interfaceType) {
try {
ctx = new InitialContext();
return (T)ctx.lookup(implType.getSimpleName()+"/local");
} catch (NamingException e) {
e.printStackTrace();
}
return null;
}
}
you can use it this way:
try {
OperationPerformedLocal operationPerformed =
BeanUtil.create(OperationPerformedImpl.class, OperationPerformedLocal.class);
operationPerformed.addRandomNo("123");
} catch (Exception e) {
e.printStackTrace();
}
It's ugly I know, I'm kind of embarassed posting it.
It's not portable, forces you to know interface and implementation classes and "/local" part is hardcoded making it even more ugly ::sigh::.
Placing EJB-JAR(s) into EAR can complicate things a little bit further, jndi-name will be prefixed with EAR name:
return (T)ctx.lookup("earName/" + implType.getSimpleName() + "/local");
Moreover, it'll probably break if SLSB has changed name i.e. #Stateless(name="someNewName").
I was reading the tutorial on this page:
http://edocs.bea.com/docs/cd/E13222_01/wls/docs81/medrec_tutorials/ejbgen.html#858279
And I have the following file BankAccountEJB.java
import javax.ejb.CreateException;
import javax.ejb.EntityBean;
import javax.ejb.EntityContext;
public abstract class BankAccountEJB implements EntityBean {
private EntityContext context;
public void setEntityContext(EntityContext aContext) {
context = aContext;
}
public void ejbActivate() {
}
public void ejbPassivate() {
}
public void ejbRemove() {
}
public void unsetEntityContext() {
context = null;
}
public void ejbLoad() {
}
public void ejbStore() {
}
public abstract String getName();
public abstract void setName(String name);
public abstract Float getBalance();
public abstract void setBalance(Float balance);
public java.lang.Long ejbCreate(String name, Float balance) throws CreateException {
if (name == null) {
throw new CreateException("The field \"key\" must not be null");
}
// TODO add additional validation code, throw CreateException if data is not valid
setName(name);
setBalance(balance);
return null;
}
public void ejbPostCreate(java.lang.Long key) {
// TODO populate relationships here if appropriate
}
}
and I run java weblogic.tools.ejbgen.EJBGen -ddOnlyGen BankAccountEJB.java which produces the following error:
Exception in thread "main" com.bea.wls.ejbgen.EJBGenException: ejbName is a required attribute
at com.bea.wls.ejbgen.Bean.createBeanSpecificTags(Bean.java:202)
at com.bea.wls.ejbgen.Bean.(Bean.java:127)
at com.bea.wls.ejbgen.EntityBean.(EntityBean.java:76)
at com.bea.wls.ejbgen.EJBFactory.createBean(EJBFactory.java:135)
at com.bea.wls.ejbgen.EJBFactory.createBean(EJBFactory.java:99)
at com.bea.wls.ejbgen.EJBGenSGen.initModule(EJBGenSGen.java:106)
at com.bea.sgen.SGen.run(SGen.java:205)
at com.bea.wls.ejbgen.EJBGen.main(EJBGen.java:212)
at com.bea.wls.ejbgen.EJBGen.main(EJBGen.java:238)
at weblogic.tools.ejbgen.EJBGen.main(EJBGen.java:21)
Any input will be greatly appreciated~!
Note: Are you still running Weblogic 8.1 - it's already reached end of life. Also ejbgen works with EJB 2.x and over the last 2 years, development has moved on to EJB 3, so i'd advise you to catch up on those.
Now to your specific problem.
Your code does not seem to have the required annotations for ejbgen to work.
Annotations like this which are used in generation of the descriptors.
* #ejbgen:entity
* ejb-name = containerManaged
* table-name = ejbAccounts
* data-source-name = examples-dataSource-demoPool
* prim-key-class = AccountPK
* invalidation-target = ServiceDesignEJB
As your URL says the code in the tutorial has the right data as a sample - make sure you replicate those correctly in your own code.
EJBGen uses annotations in the bean
file to generate the deployment
descriptor files and the EJB Java
source files. EJB files in the MedRec
application are already annotated for
EJBGen.
For another version of ejbgen, see http://www.beust.com/ejbgen/
I've configured my GWT app with Guice as documented here. With this setup the app works fine.
However what I'd like to do now is get a GWTTestCase to call a service using GWT RPC. To this end I've done this,
Updated my <app>JUnit.gwt.rpc so that the service URL maps to GuiceRemoteServiceServlet
Added an init() method to GuiceRemoteServiceServlet to initialise the Injector as per this comment
Unfortunately I'm still getting an error,
com.google.inject.ProvisionException: Guice provision errors:
Caused by: com.google.inject.OutOfScopeException: Cannot access scoped object. Either we are not currently inside an HTTP Servlet request, or you may have forgotten to apply com.google.inject.servlet.GuiceFilter as a servlet filter for this request.
at com.google.inject.servlet.GuiceFilter.getContext(GuiceFilter.java:132)
at com.google.inject.servlet.GuiceFilter.getRequest(GuiceFilter.java:118)
at com.google.inject.servlet.InternalServletModule$1.get(InternalServletModule.java:35)
.....
The object it's trying to provision is ServletContext. The cause of the error is due to the fact the GuiceFilter hasn't been called so the ServletContext hasn't been bound to ThreadLocal.
Is there any way of getting past this?
In the Junit environment you aren't getting two things that you normally get from the servlet container: the setup/destroy help from the GuiceServletContextListener and the filtering of the GuiceFilter, so you need to do these bits yourself.
You basically need to create another servlet that wraps your servlet and does all the setup/filtering that you'd normally see done by the servlet container; what I recommend is something like this:
Suppose your servlet is called AdriansGuicedGwtServiceServlet. Then create this in your testing directory:
public class TestAdriansGuicedGwtServiceServlet extends AdriansGuicedGwtServiceServlet {
private GuiceFilter filter;
#Override
public void init() {
super.init();
// move your injector-creating code here if you want to
// (I think it's cleaner if you do move it here, instead of leaving
// it in your main servlet)
filter = new GuiceFilter();
filter.init(new FilterConfig() {
public String getFilterName() {
return "GuiceFilter";
}
public ServletContext getServletContext() {
return TestAdriansGuicedGwtServiceServlet.this.getServletContext();
}
public String getInitParameter(String s) {
return null;
}
public Enumeration getInitParameterNames() {
return new Vector(0).elements();
}
});
}
#Override
public void destroy() {
super.destroy();
filter.destroy();
}
private void superService(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
super.service(req, res);
}
#Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
filter.doFilter(new FilterChain() {
public void doFilter (ServletRequest request, ServletResponse response)
throws IOException, ServletException {
superService(request, response);
}
});
}
}
And then in your <app>Junit.gwt.rpc have it map in TestAdriansGuicedGwtServiceServlet instead of your real servlet.