iPOJO - NullPointer when using injected service - ipojo

I have defined a service:
public interface TimeProvider {
int getCurrentTime();
}
And an implementation:
#Component
#Provides
#Instantiate
public class FooTimeProvider implements TimeProvider {
...
}
In another class (actually an Activator class), I refer to the service like this:
#Component
#Provides
public class Activator implements BundleActivator {
#Requires
private TimeProvider timeProvider;
...
#Override
public void start(BundleContext bundleContext) throws Exception {
...
timeProvider.getCurrentTime();
}
...
}
But I get a NullPointerException
at package.Activator.__M_start(Activator.java:60)
I installed Arch Gogo and these are the results:
ipojo:instances
Instance org.apache.felix.ipojo.IPOJOURLHandler-0 -> valid
Instance org.apache.felix.ipojo.arch.gogo.Arch-0 -> valid
Instance package.FooTimeProvider-0 -> valid
ipojo:handlers
Handler org.apache.felix.ipojo:controller (VALID)
Handler org.apache.felix.ipojo:provides (VALID)
Handler org.apache.felix.ipojo:properties (VALID)
Handler org.apache.felix.ipojo:callback (VALID)
Handler org.apache.felix.ipojo:requires (VALID)
Handler org.apache.felix.ipojo:architecture (VALID)
ipojo:instance package.FooTimeProvider-0
instance name="package.FooTimeProvider-0" state="valid" bundle="16" component.type="package.FooTimeProvider"
handler name="org.apache.felix.ipojo:provides" state="valid"
provides specifications="[anotherPackage.TimeProvider]" state="registered" service.id="44"
property name="factory.name" value="package.FooTimeProvider"
property name="instance.name" value="package.FooTimeProvider-0"
handler name="org.apache.felix.ipojo:architecture" state="valid"
object name="package.FooTimeProvider#6c7e1f14"
What am I missing?
(The byte code manipulation is done by an Ant task, btw)

Instead of implementing BundleActivator just use:
#Validate
public void start() throws Exception {
...
timeProvider.getCurrentTime();
}

Related

How to send email from a servlet using threads or executor service?

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

How to pass value from rest service to camel route?

I have exposed as service as below
restConfiguration().component("servlet").bindingMode(RestBindingMode.json);
rest("/batchFile").consumes("application/json").post("/routeStart").type(BatchFileRouteConfig.class).to("startRouteProcessor");
Based upon the request from rest service,i would start camel route in processor as below
#Component("startRouteProcessor")
public class StartRouteProcessor implements Processor {
public void process(Exchange exchange) throws Exception {
BatchFileRouteConfig config = exchange.getIn().getBody(BatchFileRouteConfig.class);
String routeId = config.getRouteId();
String sourceLocation = config.getSourceLocation();
exchange.getContext().startRoute(routeId);
}
}
I need to pass the sourceLocation from above bean to below route
#Component
public class FileReaderRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
from("file:sourceLocation")
.log("File Reader Route route started");
}
}
Above is sample code..request you to help me in passing the sourcelocation from StartRouteProcessor to FileReaderRoute
This is not possible, since in your example is FileReaderRoute already started at the time of calling batchFile endpoint.
You can do it in slightly different way.
Extract your FileReaderRoute to direct. Something like:
#Component
public class FileReaderRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
from("direct:fileReaderCommon")
.log("File Reader Route route started");
}
}
And then you can create new route at runtime:
#Component("startRouteProcessor")
public class StartRouteProcessor implements Processor {
public void process(Exchange exchange) throws Exception {
BatchFileRouteConfig config = exchange.getIn().getBody(BatchFileRouteConfig.class);
exchange.getContext().addRoutes(new RouteBuilder() {
#Override
public void configure() throws Exception {
from("file:"+config.getSourceLocation())
.routeId(config.getRouteId())
.to("direct:fileReaderCommon");
}
});
}
}
Do not forget to take sufficient sanitizing of input, since you are allowing user to create file consumer based on user input. In your approach, there is a high risk of path traversal attack.

EJB not initializing in Wildfly 9.0.0 using #EJB

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.

WickeTester - IllegalStateException: No CDI context bound to application

I have Wicket Form and ProjectNameValidator class:
#Inject
ProjectDao dao;
public ProjectNameValidator() {
CdiContainer.get().getNonContextualManager().inject(this);
}
the injection here is because the #Inject annotation works only in Wicket components or Behavior, here is null without the CdiContainer.get().getNonContextualManager().inject(this);
But when I have WicketTester, TestCreateprojectPage:
public class TestCreateProject {
private WicketTester tester;
#Before
public void setUp() throws Exception {
tester = new WicketTester();
}
#Test
public void createProjectPageRendersSuccessfully() {
tester.startPage(CreateProject.class);
tester.assertRenderedPage(CreateProject.class);
}
}
I'm getting exception on the Form in the CreateProject.java in ProjectNameValidator on this row:
CdiContainer.get().getNonContextualManager().inject(this);
IllegalStateException: No DCI Context bound to application.
You have a singleton CdiContainer in your application, that is not initialized in a test scope. So CdiContainer.get() is really null. Find out how to initialize CdiContainer test context, it depends on your implementation, and add it to test setUp().

ServletContext.log() not logging

Log output of my RemoteServiceServlet (GWT) is not shown in Logfiles or Stdout when using getServletContext().log("anything");
For dependency injection I use Google Guice. For my own log output I use slf4j-jdk14. I tried this in Tomcat 6 as well as in Jetty (GWT devmode).
To make it clear, my Servlet:
#Singleton
public class MyServiceServlet extends RemoteServiceServlet implements MyService {
private static final Logger log = LoggerFactory.getLogger(MyServiceServlet.class);
private final ADependency dep;
#Inject
public MyServiceServlet(ADependency dep) {
getServletContext().log("THIS IS NOT SHOWN IN MY LOGS");
log.error("THIS IS SHOWN IN MY LOGS");
this.dep = dep;
}
}
So, where can I find the missing log output or where can I configure the ServletContext-Log?
The ServletContext.log method behavior is container specific. The method I have used to make it consistent is to wrap the ServletConfig passed in through init() in order to create a wrapped ServletContext which uses our own provided logger (Slf4j in this case).
public class Slf4jServletConfigWrapper implements ServletConfig {
private final ServletConfig config;
private final Logger log;
public Slf4jServletConfigWrapper(Logger log, ServletConfig config) {
this.log = log;
this.config = config;
}
public ServletContext getServletContext() {
return new ServletContext() {
public void log(String message, Throwable throwable) {
log.info(message, throwable);
}
public void log(Exception exception, String msg) {
log.info(msg, exception);
}
public void log(String msg) {
log.info(msg);
}
...
Full Slf4jServletConfigWrapper.java code
In your Servlet override the init() method to use the ServletConfig wrapper
public void init(final ServletConfig config) throws ServletException {
super.init(new Slf4jServletConfigWrapper(log, config));
}