Even if the <load-on-startup>1</load-on-startup> the servlet does not auto-load
<servlet>
<servlet-name>RestletServlet</servlet-name>
<servlet-class>org.restlet.ext.servlet.ServerServlet</servlet-class>
<init-param>
<param-name>org.restlet.application</param-name>
<param-value>com.mycompany.MyRestletApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
public class MyRestletApplication extends Application {
#Override
public Restlet createInboundRoot() {
String process = ManagementFactory.getRuntimeMXBean().getName();
System.out.println("Started with Process id: " + process);
Router router = new Router(getContext());
router.attachDefault(ServerResource.class);
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
System.out.println("Terminating database");
}));
return router;
}
}
What could be missing here?
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 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).
Below is my web.xml
<servlet>
<servlet-name>DispatcherName</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/spring/webmvc-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Is there any way that I can get the servlet-name "DispatcherName" in my application controller?
I want this to access the controller objects from the XMLWebApplicationContext & to do that I need the RequestDispatcher Name.
Till now this is what I've tried:
webApplicationContext=WebApplicationContextUtils.getWebApplicationContext(GetServletContextWebListner.getServletContext());
XmlWebApplicationContext xmlWebApplicationContext = (XmlWebApplicationContext)GetServletContextWebListner.getServletContext().getAttribute("org.springframework.web.servlet.FrameworkServlet.CONTEXT."+webApplicationContext.getApplicationName().replace("/", ""));
and tried this too
#WebListener
public class GetServletContextWebListner implements ServletContextListener {
private static ServletContext servletContext;
public static ServletContext getServletContext() {
return servletContext;
}
#Override
public void contextInitialized(ServletContextEvent sce) {
servletContext = sce.getServletContext();
}
#Override
public void contextDestroyed(ServletContextEvent sce) {
servletContext = null;
}
}
and
(XmlWebApplicationContext)GetServletContextWebListner.getServletContext().getServletContextName()
Since I'm not able to get the servlet name, I'm using the getApplicationName() but this may vary with the servlet name.
in you controller, you may try :
request.getServletContext().getServletContextName()
Or
RequestContextUtils.getWebApplicationContext(request).getDisplayName()
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>