Assign a name to thread on request arrival - spring

I have a JEE7 webapp that uses jax-ws annotations to define some services, and uses spring framework.
I want to assign a name of choice to the thread that serves a request when it arrives.
I thought about putting Thread.currentThread().setName("") and this works fine if I put this row inside every #path annotated method, but it's a bit pointless to add the same code in every method. I am thinking to put it in a earlier stage.
Is there some sort of "#onrequest" annotation to define some code common to all request?
Thanks in advance.

I got this working with a filter. I just declared a new filter in web.xml and then I implemented the filter class.
In web.xml:
<filter>
<filter-name>threadRenamingFilter</filter-name>
<filter-class>RestRequestFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>threadRenamingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
In filter class:
import java.io.IOException;
import java.util.Date;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class RestRequestFilter implements Filter {
private final Log log = LogFactory.getLog(this.getClass());
#Override
public void destroy() {
}
#Override
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException {
//Before request execution
Date now = new Date();
Long startTime = now.getTime();
String newName = startTime.toString();
log.trace("Thread " + newName + " started at: " + now.toString());
//renaming of the thread with the time of spawn
Thread.currentThread().setName(newName);
//Request execution
arg2.doFilter(arg0, arg1);
//After request execution
now = new Date();
Long endTime = now.getTime();
Long executionTime = endTime - startTime;
log.trace("Thread " + newName + " end at: " + now.toString());
log.debug("Thread " + newName + " completed in: " + executionTime + "ms");
}
#Override
public void init(FilterConfig arg0) throws ServletException {
}
}

you can use interceptors to handle that, basically you need to write a class which implements:
http://docs.spring.io/spring/docs/3.2.x/javadoc-api/org/springframework/web/servlet/HandlerInterceptor.html
and wire it with spring. Then in method postHandle or preHandle you do what you want ; )
Here is some tutorial how to do that:
http://viralpatel.net/blogs/spring-mvc-interceptor-example/
you can also take a look at filters.

Related

Run Java with a main in a WebSphere project

Very new to WebSphere as well as packaging Java.
I need to take a Java project that we've been running from the command line as an executable Jar and make it run from WebSphere (since the admin user has been getting auto-logged out at midnight).
I've looked at creating a WAR file, but the ant examples I've looked at invoked a lot of WEB-INF dependencies ... but this project doesn't have that. It has a main entry point in the code.
EARs seem to require EJBs, which I don't think this project uses. Seeing as EJBs have been on their way out for a while I'm not as up to speed on them.
My questions are: What is the simplest way to put my executable JAR into WebSphere?
Bonus points: Do EAR files require EJBs in the project? If so, how do I know if this project invokes them?
The simple answer is to create a war application with a #WebListener:
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
#WebListener
public class ServletInitializer implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println(toString() + " contextInitialized started");
String[] args = new String[] {};
MainClass.main(args);
System.out.println(toString() + " contextInitialized finished");
}
#Override
public void contextDestroyed(ServletContextEvent sce) {
}
}
Replace MainClass.main(args); with your application call (and add any JAR dependencies into WEB-INF/lib).
The thing I don't like about the above is that it's not great to perform intense work during startup. This may make problem determination harder and certain capabilities (e.g. runtime diagnostic trace modification) are unavailable during startup.
You could create a WAS-specific solution by using AdminClient to subscribe to the Server MBean's Stateful notifications.
Otherwise, a standardized way would be to have an EJB #Startup bean which uses the TimerService to start work after some delay which is empirically determined to be an average application server startup time. For example:
import java.util.Calendar;
import java.util.GregorianCalendar;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerConfig;
import javax.ejb.TimerService;
#Singleton
#Startup
public class DeferredInitializer {
public static final int DELAY = Integer.getInteger("DeferredInitializer.DELAY", 60000);
#Resource
TimerService timerService;
#PostConstruct
private void init() throws Throwable {
System.out.println(toString() + " init entry");
TimerConfig timerConfig = new TimerConfig();
timerConfig.setPersistent(false);
timerService.createSingleActionTimer(DELAY, timerConfig);
Calendar c = new GregorianCalendar();
c.add(Calendar.MILLISECOND, DELAY);
System.out.println(toString() + " timer estimated to pop in (" + DELAY + "ms) ~# " + c.getTime());
System.out.println(toString() + " init exit");
}
#Timeout
public void timeout(Timer timer) {
System.out.println(toString() + " timeout entry");
String[] args = new String[] {};
MainClass.main(args);
System.out.println(toString() + " timeout exit");
}
}
Specify the delay with the generic JVM argument -DDeferredInitializer.DELAY=X (X in milliseconds).

How to pass object from controller to step in Spring Batch

I want to pass reqData form My Controller class to Step of my job,Is there any way to achieve the same any help will be appreciated. I have a Object of HttpRequestData which i have revived in controller. Thanks
HttpRequestController.java
package com.npst.imps.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.npst.imps.utils.HttpRequestData;
import com.npst.imps.utils.TransactionResponseData;
import javax.servlet.http.HttpSession;
#RestController
public class HttpRequestController {
TransactionResponseData transactionResponseData;
#Autowired
HttpSession session;
JobExecution jobExecution;
#Autowired
JobLauncher jobLauncher;
#Autowired
Job fundtrans;
String test;
#RequestMapping("/impsft")
public String handleHttpRequest(#RequestBody HttpRequestData reqData) throws Exception {
Logger logger = LoggerFactory.getLogger(this.getClass());
try {
JobParameters jobParameters = new JobParametersBuilder().addLong("time", System.currentTimeMillis()).toJobParameters();
jobExecution = jobLauncher.run(fundtrans, jobParameters);
ExecutionContext context= jobExecution.getExecutionContext();
//context.put("reqData", reqData);
transactionResponseData=(TransactionResponseData) context.get("transactionData");
//System.out.println(context.get("transactionResponseData"));
} catch (Exception e) {
logger.info(e.getMessage());
e.printStackTrace();
}
return reqData+" "+transactionResponseData.getMsg()+",Tid="+transactionResponseData.getTid();
}
}
Below is my step class
I want to get the same reqData in my step class and from here on wards i will put inside step Execution object of doAfter method.
PrepareTransactionId.java
package com.npst.imps.action;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.StepExecutionListener;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.npst.imps.service.TransactionService;
import com.npst.imps.utils.GenericTicketKey;
import com.npst.imps.utils.HttpRequestData;
import com.npst.imps.utils.TicketGenerator;
import com.npst.imps.utils.TransactionResponseData;
#Service
public class PrepareTransactionId implements Tasklet,StepExecutionListener{
static Logger logger = LoggerFactory.getLogger(PrepareTransactionId.class);
String appId;
private static TicketGenerator ticketGenerator = null;
private static GenericTicketKey genericTicketKey = null;
#Autowired
HttpSession session;
#Autowired
TransactionService transactionService;
#Override
public ExitStatus afterStep(StepExecution stepExecution) {
try {
DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
Date date = new Date();
String ticket;
System.out.println("transactionService:: PrepareTransactionId"+transactionService);
TransactionResponseData transactionData=new TransactionResponseData();
System.out.println("reqData::"+reqData);
long value=transactionService.getMaxTid(appId);
logger.info("Max id From db::"+value);
if (value == 0) {
value = System.currentTimeMillis() / 10000;
long l = value;
ticket=l+"";
}
long l = value + 1;
ticketGenerator = TicketGenerator.getInstance(9999999999L, 0, l);
genericTicketKey = new GenericTicketKey(0, false, 10);
ticket = ticketGenerator.getNextEdgeTicketFor(genericTicketKey);
stepExecution.getJobExecution().getExecutionContext().put("ticket", ticket);
ticket=appId+ticket;
System.out.println("tid::"+ticket);
stepExecution.getJobExecution().getExecutionContext().put("tid", ticket);
stepExecution.getJobExecution().getExecutionContext().put("reqData", reqData);
transactionData.setMsg("Request Recived...");
transactionData.setTid(ticket+"");
transactionData.setNodeId(appId);
transactionData.setReqtime(dateFormat.format(date));;
stepExecution.getJobExecution().getExecutionContext().put("transactionData", transactionData);
logger.info("Request Recived with tid::"+ticket);
ExitStatus exist=new ExitStatus("SUCCESS", "success");
return exist.replaceExitCode("SUCCESS");
}
catch(Exception e) {
e.printStackTrace();
return ExitStatus.FAILED;
}
}
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
#Override
public void beforeStep(StepExecution arg0) {
// TODO Auto-generated method stub
}
#Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
return null;
}
}
TL;DR -> You can't.
JobParameters instances can only hold values of types:
String
Long
Date
Double.
The reason behind it is primarily persistence. Remember that all spring batch metadata (including job parameters) goes to a datasource.
To use custom objects, you would need to make sure that your object is immutable and thread-safe.
JobParameters documentation states:
Value object representing runtime parameters to a batch job. Because
the parameters have no individual meaning outside of the JobParameters
they are contained within, it is a value object rather than an entity.
It is also extremely important that a parameters object can be
reliably compared to another for equality, in order to determine if
one JobParameters object equals another. Furthermore, because these
parameters will need to be persisted, it is vital that the types added
are restricted. This class is immutable and therefore thread-safe.
JobParametersBuilder documentation states as well:
Helper class for creating JobParameters. Useful because all
JobParameter objects are immutable, and must be instantiated
separately to ensure typesafety. Once created, it can be used in the
same was a java.lang.StringBuilder (except, order is irrelevant), by
adding various parameter types and creating a valid JobParameters once
finished.
But i promise my objects are ok. Can I use them?
You could, but Spring developers decide to not support this feature a long time ago.
This was discussed in spring forums and even a JIRA ticket was created - status Won't fix.
Related Links
Spring - JobParameters JavaDocs
Spring - JobParametersBuilder JavaDocs
Spring - JIRA Ticket
Spring - Forums Discussion
I will not suggest to pass complete HttpRequestData. Rather than pass only requires information to batch. You can pass this information using JobParameters.
sample code
JobParameters parameters = new JobParametersBuilder().addString("key1",HttpRequestData.gteData)
.addString("key2",HttpRequestData.gteData)
.addString("key3",HttpRequestData.gteData)
.toJobParameters();
now in step you can get JobParameters from StepExecution
putting custom object in JobParameters
HashMap<String, JobParameter>();
JobParameter myParameter = new JobParameter(your custom object);
map.put("myobject", myParameter);
JobParameters jobParameters = new JobParameters(map);

How can i send sms after successful user registration using spring boot

After successful account creation, i have to send an sms to the associated customer.
For this purpose i have exposed sms service as an advice as below.
package com.naresh.advice;
import javax.annotation.PostConstruct;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.naresh.dto.AccountDTO;
import com.naresh.dto.CustomerDTO;
import com.twilio.Twilio;
import com.twilio.rest.api.v2010.account.Message;
import com.twilio.type.PhoneNumber;
#Component
#Aspect
public class SMSService {
#Value("${twilio.sms.authentication_Id:80b7c5a8b73a26a9b588a906d54269c3}")
private String authenticationId;
#Value("${twilio.sms.account_sid:AC038d9532222b3d39fce4b43a5dce9ce1}")
private String accountId;
#Value("${twilio.sms.from_number:+12566662741}")
private String fromNumber;
#PostConstruct
public void init() {
Twilio.init(accountId, authenticationId);
}
#AfterReturning(pointcut = "execution(* com.naresh.service.impl.CustomerServiceImpl.save(..)) && args(customerDTO,..)", returning = "custId")
public void sendSMS(JoinPoint joinPt, CustomerDTO customerDTO, Long custId) {
Message.creator(new PhoneNumber(customerDTO.getMobile()), new PhoneNumber(fromNumber),
"Customer " + custId + " registered successfully...").create();
}
#AfterReturning(pointcut = "execution(* com.naresh.service.impl.AccountServiceImpl.createAccount(..))", returning = "accDTO")
public void sendSMSAcc(JoinPoint joinPt, AccountDTO accDTO) {
CustomerDTO customerDTO = accDTO.getCustomer();
Message.creator(new PhoneNumber(customerDTO.getMobile()), new PhoneNumber(fromNumber),
"Hi " + customerDTO.getName() + ", Your " + accDTO.getAccountType() + " account " + accDTO.getAccNo()
+ " has been registered with us successfully.Your balance is " + accDTO.getBalance())
.create();
}
}
The above is working fine if the account creation task is successful. But if we are getting any error, at that time also success sms is received by the customer.
Please help me.
Thanks in advance
#AfterReturning advice, according to the docs:
is invoked only on normal method return, not if an exception is thrown.
That means, that your methods com.naresh.service.impl.CustomerServiceImpl.save and com.naresh.service.impl.AccountServiceImpl.createAccount return some value but doesn't throw any exception. What is the error your are getting? Does this error affects returned value? The only way is to parse the returned value to find out whether something was wrong.

How to create a Filter as a component and what should I put for annotation?

So, I am working on CQ5. I would like to deploy a bundled component as a service to filter & modify the .inifinity.json output (from sling) to the CQ5.
I am able to build and deploy, and have both the component and bundle being active. However, when a page or call an infinity.json , I don't see the output in log. I suspect because the services not properly installed? or some other service return the call before running my service? not sure. and here is my code:
package com.my.test;
import javax.servlet.*;
import java.io.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import aQute.bnd.annotation.component.*;
#Component(
provide=Filter.class,
immediate=true
)
public class TestFilter implements Filter {
private static final Logger LOGGER = LoggerFactory.getLogger(TestFilter.class);
private FilterConfig filterConfig;
public void init (FilterConfig filterConfig) {
LOGGER.info ("INIT .");
this.setFilterConfig(filterConfig);
}
public void destroy() {
LOGGER.info ("Destroy me NOW!!...");
}
public void doFilter (ServletRequest request, ServletResponse response, FilterChain chain){
try
{
LOGGER.info ("Within Simple Filter ... :) ");
LOGGER.info ("Filtering the Request ...");
chain.doFilter (request, response);
LOGGER.info ("Within Simple Filter ... ");
LOGGER.info ("Filtering the Response ...");
} catch (IOException io) {
LOGGER.info ("IOException raised in SimpleFilter");
} catch (ServletException se) {
LOGGER.info ("ServletException raised in SimpleFilter");
}
}
public FilterConfig getFilterConfig() {
return this.filterConfig;
}
public void setFilterConfig (FilterConfig filterConfig){
this.filterConfig = filterConfig;
}
}
Am I missing anything in the annotation? or anything that I should have done?
Looking the discussion threads here and here, it looks like you need to add annotations to set a sling.filter.scope #Property, and also to declare the #Service.
Something like this:
#Component(
provide=Filter.class,
immediate=true
)
#Service(javax.servlet.Filter.class)
#Properties({
#Property(name = "sling.filter.scope", value = "request")
})
The Sling integration test services source code include a few Filters at [1], that you can use as examples. As David says, you're probably just missing the #Service annotation.
http://svn.apache.org/repos/asf/sling/trunk/launchpad/test-services/src/main/java/org/apache/sling/launchpad/testservices/filters/

Usage examples for Jetty's ProxyServlet.Transparent class

I am trying to use jetty7 to build a transparent proxy setup. Idea is to hide origin servers behind the jetty server so that the incoming request can be forwarded in a transparent manner to the origin servers.
I want to know if I can use jetty's ProxyServlet.Transparent implementation to do so. If yes, can anyone give me some examples.
This example is based on Jetty-9. If you want to implement this with Jetty 8, implement the proxyHttpURI method (See Jetty 8 javadocs.). Here is some sample code.
import java.io.IOException;
import java.net.InetAddress;
import java.net.URI;
import java.util.List;
import java.util.Map;
import java.util.Random;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.eclipse.jetty.servlets.ProxyServlet;
/**
* When a request cannot be satisfied on the local machine, it asynchronously
* proxied to the destination box. Define the rule
*/
public class ContentBasedProxyServlet extends ProxyServlet {
private int remotePort = 8080;
public void setPort(int port) {
this.remotePort = port;
}
public void init(ServletConfig config) throws ServletException {
super.init(config);
}
public void service(ServletRequest request, ServletResponse response) throws IOException, ServletException {
super.service(request, response);
}
/**
* Applicable to Jetty 9+ only.
*/
#Override
protected URI rewriteURI(HttpServletRequest request) {
String proxyTo = getProxyTo(request);
if (proxyTo == null)
return null;
String path = request.getRequestURI();
String query = request.getQueryString();
if (query != null)
path += "?" + query;
return URI.create(proxyTo + "/" + path).normalize();
}
private String getProxyTo(HttpServletRequest request) {
/*
* Implement this method: All the magic happens here. Use this method to figure out your destination machine address. You can maintain
* a static list of addresses, and depending on the URI or request content you can route your request transparently.
*/
}
}
Further more, you can implement a Filter that determines whether the request needs to terminate on the local machine or on the destination machine. If the request is meant for the remote machine, forward the request to this servlet.
// Declare this method call in the filter.
request.getServletContext()
.getNamedDispatcher("ContentBasedProxyServlet")
.forward(request, response);

Resources