I can't fathom why this isn't working. Inside a Jersey resource method I make an asynchronous call, but the code blocks and never returns. Testing with curl, my terminal just hangs. From application logs, I can tell the request got intercepted and the code was executed.
Using Jersey 2.8 with maven tomcat7 plugin.
I also tried using an Executor Service instead of creating the thread directly, this is how I'd prefer to do it. Changed to creating a thread directly to be close to the documentation.
Jersey code:
#Path("/trade")
public class TradeEndpoint {
// TODO: make this configurable!!
private ExecutorService threadPool = Executors.newFixedThreadPool(10);
private static MyService myService;
static {
//issues getting Spring working, so get it like this
orderFillService = Bootstrapper.getOrderFillService();
}
#GET
public String getFoo() {
return "Foo";
}
#POST
#Path("limit")
#Consumes({ MediaType.APPLICATION_JSON })
public void limitOrder(#Suspended final AsyncResponse response, Model model) {
System.out.println(model);
new Thread( new Runnable() {
public void run() {
myService.doStuff(model);
}
}).start();
System.out.println("SUBMITTED");
}
Web.xml
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<servlet>
<servlet-name>web</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.foo.conf.Application</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>web</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
Related
I have a rest jersey application like this
#ApplicationPath("/rest")
public class HelloApp extends Application
{
public HelloApp() throws Exception {
//also tried throwing Runtimeexcpetion
throw new Exception();
}
#Override
public Set<Class<?>> getClasses()
{
Set<Class<?>> s = new HashSet<Class<?>>();
s.add(HelloWorldService.class);
return s;
}
}
This is the web.xml file
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<display-name>REST Web Application Demo</display-name>
<servlet>
<servlet-name>jersey.hello</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>rest.demo.HelloApp</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey.hello</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
I packaged the above to a war file and then used in the following tomcat embedded program
public class WarExample {
public static void main(String[] args) throws ServletException, LifecycleException {
Tomcat tomcat = new Tomcat();
tomcat.setBaseDir("temp");
tomcat.setPort(8080);
String contextPath = "/";
String warFilePath = "path to war file";
tomcat.getHost().setAppBase(".");
Context context = tomcat.addWebapp(contextPath, warFilePath);
context.addLifecycleListener(new LifecycleListener() {
public void lifecycleEvent(LifecycleEvent event) {
System.out.println(event.getLifecycle().getStateName());
//do something if event.getLifecycle().getState() == LifecycleState.FAILED
}
});
tomcat.start();
tomcat.getServer().await();
}
}
I added a lifecycle listener to context that is returned by adding war as webapp. I am getting Starting and Started states but not seeing any other states here.
Even though i am throwing an exception/runtimeexception from my jersey rest application why is tomcat embedded still not throwing failed state.
i had to add this for tomcat to publish failed state
final Host host = tomcat.getHost();
if (host instanceof StandardHost) {
((StandardHost) tomcat.getHost()).setFailCtxIfServletStartFails(true);
}
I am new to JavaEE and am trying to create a WAR containing an application that performs a task every 30 minutes (and is started when the app is deployed), and a servlet that will allow a client to connect and get status information, using WildFly.
Is this possible? If so, how do I get WildFly to start the long running process, and how do I get it to inject that object into the servlet?
The long running application is in a class ProcessData() which uses ScheduledExecutorService to spawn a thread on a schedule to perform data management tasks, and has a getStatus() method returning a string about the processing.
This is the servlet:
#WebServlet("/procStat")
public class processorServlet extends HTTPServlet {
#Inject
ProcessData processData;
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
resp.setContentType("text/html");
PrintWriter writer = resp.getWriter();
writer.println("<p>" + processData.getStatus() + "</p>");
writer.close();
}
}
Why you need to inject it? Can you initialize it and use it with static method or something? Here is my example for that:
public class HelloWorld extends HttpServlet
{
private static final long serialVersionUID = -1L;
ProcessData processData;
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
// Set response content type
response.setContentType("text/html");
// Actual logic goes here.
PrintWriter out = response.getWriter();
out.println("<h1>" + ProcessData.getStatus() + "</h1>");
}
}
After this the ProcessData class which implements javax.servlet.ServletContextListener
This listener has method which will be executed when web application initialization process is starting.
public class ProcessData implements ServletContextListener
{
private static String message;
private int counter = 0;
Runnable run = new Runnable()
{
#Override
public void run()
{
message = "counter: " + (counter++);
System.out.println(message);
}
};
#Override
public void contextInitialized(ServletContextEvent arg0)
{
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(run, 0, 1, TimeUnit.MINUTES);
}
#Override
public void contextDestroyed(ServletContextEvent arg0)
{
// Empty method
}
public static String getStatus()
{
return message;
}
}
And the web.xml add the servlet and also ServletContextListener like this:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>TestTask</display-name>
<servlet>
<servlet-name>HelloWorld</servlet-name>
<servlet-class>servlet.HelloWorld</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloWorld</servlet-name>
<url-pattern>/HelloWorld</url-pattern>
</servlet-mapping>
<listener>
<listener-class>schedule.ProcessData</listener-class>
</listener>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
I ask before why you need to inject it because if you have a task which is not connected with specific user (like yours is executed regardless if the user is logon or not) then you end up in situation that many users need access to a single data. You need some kind of singleton and yes you can do it with CDI beans or other Injection technology but you also can make it working without this overhead. In my example I do it with static method and static field.
I am trying to register an interceptor for my rest application. The purpouse of this interceptor is to get a token inside the request to validate if the request is valid or not.
I have created a custom tag to achieve this:
#Provider
#Secured
public class AuthenticationFilter implements ContainerRequestFilter{
private static final Logger LOGGER = Logger.getLogger(AuthenticationFilter.class);
UserDAO userDAO = (UserDAO) SpringApplicationContext.getBean("userDAO");
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
// Get the HTTP Authorization header from the request
String authorizationHeader =
requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);
// Check if the HTTP Authorization header is present and formatted correctly
if (authorizationHeader == null || !authorizationHeader.startsWith("BSC")) {
if (authorizationHeader== null){
LOGGER.error("No authorization header");
} else{
LOGGER.error("Authorization header: " + authorizationHeader);
}
throw new NotAuthorizedException("Authorization header must be provided");
}
// Extract the token from the HTTP Authorization header
String token = authorizationHeader.substring("BSC".length());
// Validate the token
boolean ok = validateToken(token);
if (!ok){
LOGGER.error("Not authorized, passed token: " + token);
throw new NotAuthorizedException("Not authorized");
}
}
private boolean validateToken(String token){
boolean ok = userDAO.validateToken(token);
if (ok){
userDAO.updateToken(token);
}else{
userDAO.deleteToken(token);
}
return ok;
}
}
#NameBinding
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.TYPE, ElementType.METHOD})
public #interface Secured {
}
All of the methods with the #Secured tag must pass throught the interceptor.
I have registered the interceptor and the rest service in a class that extends Application:
public class RestApplication extends Application{
private Set<Object> singletons = new HashSet<Object>();
public RestApplication() {
singletons.add(new RestService());
singletons.add(new AuthenticationFilter());
}
#Override
public Set<Object> getSingletons() {
return singletons;
}
}
Then in my web.xml I have registered this class:
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Manufacturing</display-name>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>jersey-serlvet</servlet-name>
<servlet-class>
com.sun.jersey.spi.container.servlet.ServletContainer
</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.everis.manufacturing.application.RestApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey-serlvet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
But it not seems to work, I am calling a service that have the #Secured tag but it isn´t calling the interceptor.
Thanks in advance!
try changing the class RestApplication to extend ResourceConfig instead of Application.
I just managed to call the Google Drive API to enable push notifications for a file.
The code setting up the push notifications look like this:
public class SampleServlet extends AbstractAppEngineAuthorizationCodeServlet {
private final static Logger logger = Logger.getLogger(SampleServlet.class.getName());
private static final long serialVersionUID = 1L;
// Constants omitted
#Override
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException, ServletException {
AuthorizationCodeFlow authFlow = initializeFlow();
Credential credential = authFlow.loadCredential(getUserId(req));
StringBuilder resultFromWatch = new StringBuilder();
Drive drive = new Drive.Builder(Utils.HTTP_TRANSPORT, Utils.JSON_FACTORY, credential).setApplicationName("t").build();
try {
Optional<Channel> channel = watchFile(drive, FILE_ID, CHANNEL_ID, "web_hook", "https://mydomain.appspot.com/drive");
String channelStringTmp;
if (channel.isPresent()) {
channelStringTmp = channel.get().toString();
} else {
channelStringTmp = "null...";
}
resultFromWatch.append(channelStringTmp);
} catch (Exception e) {
resultFromWatch.append(e.getMessage());
}
final UserService userService = UserServiceFactory.getUserService();
final String thisUrl = req.getRequestURI();
// Send the results as the response
PrintWriter respWriter = resp.getWriter();
resp.setStatus(200);
resp.setContentType("text/html");
addLoginLogoutButtons(req, resp, resultFromWatch, userService, thisUrl, respWriter);
}
private static Optional<Channel> watchFile(Drive service, String fileId,
String channelId, String channelType, String channelAddress) throws IOException {
final Channel returnValue;
Channel channel = new Channel();
channel.setId(channelId);
channel.setType(channelType);
channel.setAddress(channelAddress);
Drive.Files tmp = service.files();
returnValue = tmp.watch(fileId, channel).execute();
return Optional.fromNullable(returnValue);
}
#Override
protected AuthorizationCodeFlow initializeFlow() throws ServletException, IOException {
return Utils.initializeFlow();
}
#Override
protected String getRedirectUri(HttpServletRequest req) throws ServletException, IOException {
return Utils.getRedirectUri(req);
}
}
After having called the servlets doGet from my browser and logging in I get this as response:
{
"expiration": "1484565747000",
"id": SAME_ID_AS_DEFINED_IN_SERVLET,
"kind": "api#channel",
"resourceId": A_NEW_ID,
"resourceUri": "https:\/\/www.googleapis.com\/drive\/v3\/files\/FILE_ID?acknowledgeAbuse=false&alt=json"
}
Next step is to define my controller that receives notifications when the file is modified. Looks like this:
#RestController
#RequestMapping("/drive")
public class ConcreteFileWatchController implements FileWatchController {
private final static Logger logger = Logger.getLogger(ConcreteFileWatchController.class.getName());
#RequestMapping(method = RequestMethod.POST)
#ResponseStatus(value = HttpStatus.OK)
#Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
logger.info("Received watch call");
}
}
Finally I try to modify the file after having deployed the application(it is deployed on Google App Engine) and after looking at the logs in GAE I can see that there has been a call. However, my receiving method is not executed. I only see a 302 in the log with a big json attached to it. Can't really see any error except that I don't notice that my method is called. The path even looks correct in the log. What could I be doing wrong?
Details regarding error:
When I go to the log page in Google Cloud I see this 302 message:
11:34:35.957
POST
302
0 B
22 ms
APIs-Google; (+https://developers.google.com/webmasters/APIs-Google.html)
/drive
10.72.94.97 - - [16/Jan/2017:11:34:35 +0100] "POST /drive HTTP/1.1" 302 - - "APIs-Google; (+https://developers.google.com/webmasters/APIs-Google.html)" "mydomain.appspot.com" ms=22 cpu_ms=0 cpm_usd=0 loading_request=0 instance=- app_engine_release=1.9.48 trace_id=d0e888dd3989e353344e40e41758fdf4
There is also a json looking kind of like this:
{
protoPayload: {
#
type: "type.googleapis.com/google.appengine.logging.v1.RequestLog"
appId: "p~blabla"
versionId: "201t113050"
requestId: "587ca1bb00ff05706f727465726261636b656e640001323031373031313674313133303530000100"
ip: "10.76.94.97"
startTime: "2017-01-16T10:34:35.957904Z"
endTime: "2017-01-16T10:34:35.980366Z"
latency: "0.022462s"
method: "POST"
resource: "/drive"
httpVersion: "HTTP/1.1"
status: 302
userAgent: "APIs-Google; (+https://developers.google.com/webmasters/APIs-Google.html)"
host: "blabla.appspot.com"
instanceIndex: -1
finished: true
appEngineRelease: "1.9.48"
traceId: "d0e888dd390f41758fdf4"
first: true
}
insertId: "587cf6df9ded23f7"
httpRequest: {
status: 302
}
resource: {
type: "gae_app"
labels: {…}
}
timestamp: "2017-01-16T10:34:35.957904Z"
labels: {
appengine.googleapis.com/version_id: "2017013050"
clone_id: ""
appengine.googleapis.com/clone_id: ""
appengine.googleapis.com/module_id: "default"
version_id: "20170116t113050"
request_id: "587ca1bb00ff0e9dd0f39f31350001707e6561737974696d657265706f721373031313674313133303530000100"
appengine.googleapis.com/request_id: "587ca1bb00ff0e9dd0f39f31350001707e6561737974696d6572653674313133303530000100"
module_id: "default"
}
logName: "projects/blabla/logs/appengine.googleapis.com%2Frequest_log"
operation: {
id: "587ca1bb00ff0e9dde640001323031373031313674313133303530000100"
producer: "appengine.googleapis.com/request_id"
first: true
last: true
}
}
web.xml:
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
</context-param>
<filter>
<filter-name>CORS</filter-name>
<filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CORS</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>PlusBasicServlet</servlet-name>
<servlet-class>packagename.PlusBasicServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>PlusBasicServlet</servlet-name>
<url-pattern>/plusbasicservlet</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>PlusSampleServlet</servlet-name>
<servlet-class>packagename.PlusSampleServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>PlusSampleServlet</servlet-name>
<url-pattern>/plussampleservlet</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>FileWatchTestServlet</servlet-name>
<servlet-class>packagename.ConcreteFileWatchController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>FileWatchTestServlet</servlet-name>
<url-pattern>/drive</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>PlusSampleAuthCallbackServlet</servlet-name>
<servlet-class>packagename.PlusSampleAuthCallbackServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>PlusSampleAuthCallbackServlet</servlet-name>
<url-pattern>/oauth2callback</url-pattern>
</servlet-mapping>
<security-constraint>
<web-resource-collection>
<web-resource-name>any</web-resource-name>
<url-pattern>/plussampleservlet</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>*</role-name>
</auth-constraint>
</security-constraint>
</web-app>
Screenshot from log:
Since your callback is being served through Spring MVC, make sure you don't have any hidden redirects configured elsewhere. You should first test the callback using a regular servlet:
public class FileWatchTestServlet extends HttpServlet {
private final static Logger logger = Logger.getLogger(FileWatchTestServlet.class.getSimpleName());
#Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
logger.info("Received watch call");
}
}
And in web.xml:
<servlet>
<servlet-name>FileWatchTestServlet</servlet-name>
<servlet-class>com.mydomain.FileWatchTestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>FileWatchTestServlet</servlet-name>
<url-pattern>/drive</url-pattern>
</servlet-mapping>
If the 302 goes away, the issue is with Spring MVC's dispatcher, so you should look there for anything that might cause a redirect (eg. in your view).
My requirement is to call the services from two different modules.But, Some urls can allow both modules,some urls allow for specific to that module.
Below is my current configuration for achieving that
<servlet>
<servlet-name>animals</servlet-name>
<servlet-class>
org.glassfish.jersey.servlet.ServletContainer
</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.lion,com.dog</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>animals</servlet-name>
<url-pattern>/lion/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>animals</servlet-name>
<url-pattern>/dogs/*</url-pattern>
</servlet-mapping>
For example if I have a service called as 'barking' this service is located in com.dog package.Now i can call this service using two urls like below
/lions/barking
/dogs/barking
As per my requirement /lions/barking should show 404 error.But it gives the response.
But some url both should work.Irrespective of where the service is located.
/lions/eat
/dogs/eat
How to do the configuration to achieve that functionality
Any help will be greatly appreciated!!!!
Use a "http Servlet Request Filter" to customise and configure/serve the requests as per your business requirements.
Please find the sample code below:
public class RequestUrlFilter implements Filter {
private static List<String> validUrls = new ArrayList<>();
public void init(FilterConfig filterConfig) throws ServletException {
//Load the valid list of urls here
validUrls.add("/lions/eat");
validUrls.add("/dogs/eat");
validUrls.add("/dogs/barking");
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain)
throws IOException, ServletException {
if(validUrls.contains(((HttpServletRequest)request).getRequestURI()) {
filterChain.doFilter(request,response);
} else {
//Error Response
RequestDispatcher rd = (HttpServletRequest)request.getRequestDispatcher("Error.jsp");
rd.forward(request, response);
}
}
public void destroy() {
}
}