AppEngine React and Jersey - The scratchDir you specified is unusable - java

I have a Java-based REST API (via Jersey 1.18) that I've deployed in an AppEngine application alongside a React front end.
My web.xml declares two servlets:
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
...
<servlet>
<servlet-name>react</servlet-name>
<jsp-file>/index.html</jsp-file>
</servlet>
<servlet-mapping>
<servlet-name>react</servlet-name>
<url-pattern>/login</url-pattern>
...
</servlet-mapping>
...
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
</servlet>
<jsp-config>
<taglib>
<taglib-uri>http://www.myapp.com/customtags</taglib-uri>
<taglib-location>/WEB-INF/custom-tags/UserRefTag.tld</taglib-location>
</taglib>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<page-encoding>UTF-8</page-encoding>
</jsp-property-group>
</jsp-config>
and, of course, the Jersey filter:
<filter>
<filter-name>jersey</filter-name>
<filter-class>com.sun.jersey.spi.container.servlet.ServletContainer</filter-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.myapp.servlets;com.myapp.tasks;com.wordnik.swagger.jersey.listing
</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.config.provider.packages</param-name>
<param-value>com.myapp.audit;com.myapp.filters</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.config.property.JSPTemplatesBasePath</param-name>
<param-value>/WEB-INF/jsp</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.config.property.WebPageContentRegex</param-name>
<param-value>/(js|css|(WEB-INF/jsp)|_ah|ipn|woff|woff2|ui|json|html)/.*</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
<param-value>com.myapp.audit.AuditLogInterceptor</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
<param-value>com.myapp.filters.CorsFilter</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>jersey</filter-name>
<url-pattern>/tasks/*</url-pattern>
...
</filter-mapping>
I've specified, in appengine-web.xml the relevant static resources:
<static-files>
<include path="/static/**" expiration="10s"/>
<!-- react ui resources (eg: manifest.json etc) -->
<include path="*.html" expiration="10s"/>
<include path="*.json" expiration="10s"/>
<include path="*.js" expiration="10s"/>
</static-files>
So, ideally, when a user hits an endpoint like /login then it should translate to the react servlet, and be directed to index.html, which is the react app. ReactRouter should then kick in and render the login page. All static, until it checks for a session or something.
This all works wonderfully well in the devserver. When I load /login, it renders my react app. When the react app calls the backend REST endpoints, they all work.
Then, I put it on appengine (standard environment), and it's a different story. The REST endpoints all respond, but the react app doesn't fire. All I get is: Error /login or similar.
When I look in the appengine logs, I see this:
:WARN:oaj.EmbeddedServletOptions:RequestDA26342E: The scratchDir you specified: [/base/data/home/apps/g~myapp-alpha/alpha2.419176782209598562/jsp] is unusable
Googling around, this error appears to be related to directory permissions in the WebContainer, but that's all obfuscated from me, because this is appengine.
What does this error really mean?
What is the problem?
How can I resolve it?

It turns out, after much hacking, that specifying an HTML file in the element was what was causing problems.
Whatever webcontainer appengine uses was trying to compile it, but appengine is supposed to pre-compile all JSPs on upload so it doesn't have to do this. Their setup obviously can't cope with that.
The fix was to move and rename /index.html into /WEB-INF/jsp/index.jsp
It was all perfectly happy then.

Related

Jersey endpoints fail to load if index.html is provided

I have a Jetty Server which serves up an Angular page but also has several Jersey endpoints coded up. My Angular project is in a resources directory, and after building and running, the target looks like this:
WEB-INF
classes
index.html
com/
web.xml
My web.xml looks like this:
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<display-name>Sandbox</display-name>
<servlet>
<servlet-name>Jersey</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<!-- Adds JSON processing to map java classes to JSON text in both directions -->
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<!-- Tell the Jersey framework where to search for services. Also, JAX-RS is needed
for the JSON serialization -->
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.hb.apps.server;org.codehaus.jackson.jaxrs</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
<mime-mapping>
<extension>json</extension>
<mime-type>text/html</mime-type>
</mime-mapping>
With this set up, hitting localhost:8080/Sandbox serves up the single page angular app, however hitting localhost:8080/Sandbox/rest/* tells me that my endpoint cannot be found. The Angular app was introduced after the Jersey app, and prior to the Angular app my Jersey endpoints were working fine with this configuration (minus the welcome-file-list). Why would having an Angular app obscure my Jersey endpoints?
The answer was unrelated to the web.xml. One of my colleagues had assisted me with setting up the project to work with Angular and had removed this block from my pom file:
<resource>
<directory>src/main/webapp</directory>
</resource>

Update .WAR file without causing Tomcat to pause serving web pages in production server

Hi,
When I re-upload my ROOT.war file to my Java Tomcat 8 web server by replacing the existing /usr/share/apache-tomcat-8.0.9/webapps/ROOT.war file with the new one, Tomcat stops serving web pages for about 15 seconds while the WAR file is being over-written by my ftp program. This is irritating as I'd like to be able to change the jsp pages on the fly and allow people to continue using the web site.
This happens using the default configuration of the global web.xml file, and when I changed the jsp servlet parameters to this:
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param>
<param-name>fork</param-name>
<param-value>true</param-value><!-- Changed from false to true -->
</init-param>
<init-param>
<param-name>xpoweredBy</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
<!-- New additions -->
<init-param>
<param-name>development</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>checkInterval</param-name>
<param-value>10</param-value>
</init-param>
<!-- End of new additions -->
</servlet>
Any tips would be appreciated, thanks.
If you have cluster for your application by stooping and upgrading server one by one will help

Configuring Restlet with App engine

I am using google app engine to develop my software's backend using java along with Restlet framework. I have index.jsp under my war directory which I want to treat as default page when somebody goes to my website(e.g. example.com). So I have mentioned it under welcome-file-list section in web.xml.
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
Also, I have my Restlet servlet mapped to "/*" in web.xml.
<servlet-mapping>
<servlet-name>RestletServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
But the problem occurs here, because even the call to default page i.e. example.com, also goes to the restlet which obviously doesn't find the mapping in its router. So I decided to instead map restlet servlet to "/restlet/*".
<servlet-mapping>
<servlet-name>RestletServlet</servlet-name>
<url-pattern>/restlet/*</url-pattern>
</servlet-mapping>
But with this I get the HTTP 404 error because somehow even though web.xml successfully routes the call to restlet, but restlet doesn't find the mapping in this case in its router object. I have obviously changed the mapping in the restlet router to match the new pattern "restlet/*".
router.attach("/restlet/doSomething",DoSomething.class);
It would be really great if someone can help me with this. Following is my complete web.xml:
<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.mWallet.loyaltyCardCase.LoyaltyCardCaseWebService
</param-value>
</init-param>
</servlet>
<!-- Catch all requests -->
<servlet-mapping>
<servlet-name>RestletServlet</servlet-name>
<url-pattern>/restlet/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
Thanks!
Manas
You don't need to change the mapping in the restlet router to match the new pattern "restlet/*" because the restlet router will now be considering "example.com/restlet/" as the base url.
So, if you change the router to match "/restlet/doSomething", your actual url will be "example.com/restlet/restlet/doSomething", which obviously will not work.
So, change your restlet routing to:
router.attach("/doSomething",DoSomething.class);
I did it in my project and its working.
i think you forgot to write below code in web.xml
<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.wa.gwtamazon.server.RestApi</param-value>
</init-param>
<!-- Catch all requests -->
<servlet-mapping>
<servlet-name>RestletServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
and i already answer in this link Restlet API example may will help you.

How to serve static resources from a Vaadin/Spring application?

I have Vaadin web application with spring security integration for authentication. The configuration of the Vaadin servlet is pretty simple:
<servlet>
<servlet-name>Vaadin Application Servlet</servlet-name>
<servlet-class>com.example.SpringApplicationServlet</servlet-class>
<init-param>
<param-name>applicationBean</param-name>
<param-value>mainApplication</param-value>
</init-param>
<init-param>
<param-name>widgetset</param-name>
<param-value>com.example.widgetset.CustomWidgetSet</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Vaadin Application Servlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
The servlet initializes the Spring Context and returns the Vaadin application. I have also configured the security for that and have a custom login form configured like this:
<servlet>
<servlet-name>login</servlet-name>
<jsp-file>/jsp/login.jsp</jsp-file>
</servlet>
<servlet-mapping>
<servlet-name>login</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>login_error</servlet-name>
<jsp-file>/jsp/loginError.jsp</jsp-file>
</servlet>
<servlet-mapping>
<servlet-name>login_error</servlet-name>
<url-pattern>/login_error</url-pattern>
</servlet-mapping>
The login form is styled with an external css and there are also some images. Basically the images are located in /jsp/img and the stylesheet in /jsp/login.css. So the WAR structure looks like:
/jsp
/META-INF
/VAADIN
/WEB-INF
Neither the images nor the css gets loaded, because obviously all those requests are mapped to the vaadin servlet. How can I define some static resources directory, which wouldn't be served by the Vaadin servlet? I have tried the spring mvc:resources but that didn't work. Thank you for your help.
Bye,
Filip
I have figured this out. Although it is rather a workaround. I have mapped the Vaadin Application Servlet to something like /app/* instead of to /* (Remember that in this case you also have to map the same servlet to /VAADIN/*). With this configuration I am able to access the jsp directory from my webapp and everything works fine. I have deleted the whole Spring Resources configuration, as this just didn't work.
So once more, I am still pretty not pretty comfortable with this solution and would rather have my RESOURCES dir configured other way, but the client is happy :). If anyone has got the right solution I would appreciate to read it.
Use a url rewrite filter to get more contro on url mapping.
<filter>
<filter-name>UrlRewriteFilter</filter-name>
<filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>UrlRewriteFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
then map Vaadin application to /vaadin for example and configure url maping in urlrewrite.xml
<rule>
<from>/styles/**</from>
<to last="true">/styles/$1</to>
</rule>
<rule>
<from>/images/**</from>
<to last="true">/images/$1</to>
</rule>
<rule>
<from>/**</from>
<to>/vaadin/$1</to>
</rule>
<outbound-rule>
<from>/vaadin/**</from>
<to>/$1</to>
</outbound-rule>
EDIT
Other option is put static files in /VAADIN/ directory.
I have figured this out. Although it is rather a workaround. I have mapped the Vaadin Application Servlet to something like /app/* instead of to /* (Remember that in this case you also have to map the same servlet to /VAADIN/*). With this configuration I am able to access the jsp directory from my webapp and everything works fine. I have deleted the whole Spring Resources configuration, as this just didn't work.
So once more, I am still pretty not pretty comfortable with this solution and would rather have my RESOURCES dir configured other way, but the c
Might be late but for who is still having problems with serving static content while using vaadin /* mapping, the solution I found was using apache's default servlet org.apache.catalina.servlets.DefaultServlet, so a web.xml will have something like:
<?xml version="1.0" encoding="UTF-8"?>
<web-app
id="WebApp_ID" version="3.0" 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/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<servlet>
<servlet-name>myservlet</servlet-name>
<servlet-class>com.vaadin.server.VaadinServlet</servlet-class>
<init-param>
<param-name>UI</param-name>
<param-value>com.ex.myprj.MyUI</param-value>
</init-param>
<!-- If not using the default widget set-->
<init-param>
<param-name>widgetset</param-name>
<param-value>com.ex.myprj.AppWidgetSet</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>myservlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>Static content Servlet</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Static content Servlet</servlet-name>
<url-pattern>/customer/*</url-pattern>
</servlet-mapping>
</web-app>
So in the example above, despite having vaadin at /*, the /customer/* part will be served as static content by the DefaultServlet

Liferay: Customise the web.xml HeaderFilter added during portlet deployment

I need to customise the deployment of my liferay portlet such that the GWT nocache.js files don't get a 'Expires' HTTP header set.
My war file looks like this:
view.jsp
com.foobar.MyEntryPoint/com.foobar.MyEntryPoint.nocache.js
com.foobar.MyEntryPoint/12312312313213123123123.cache.html
WEB-INF/web.xml
WEB-INF/portlet.xml
WEB-INF/liferay-portlet.xml
... etc
my web.xml is pretty much empty (only has the displayName)
On deployment this is rewritten my liferay to have a series of filters in particalar:
<filter>
<filter-name>Header Filter</filter-name>
<filter-class>com.liferay.portal.kernel.servlet.PortalClassLoaderFilter</filter-class>
<init-param>
<param-name>filter-class</param-name>
<param-value>com.liferay.portal.servlet.filters.header.HeaderFilter</param-value>
</init-param>
<init-param>
<param-name>Cache-Control</param-name>
<param-value>max-age=315360000, public</param-value>
</init-param>
<init-param>
<param-name>Expires</param-name>
<param-value>315360000</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Header Filter</filter-name>
<url-pattern>*.js</url-pattern>
</filter-mapping>
This filter adds an Expires header for about 2020 to the .nocache.js js files... the trouble is these files really shouldn't be cached (the hint is in the name :)
For development purposes I have worked around this by disabling the filter using:
com.liferay.portal.servlet.filters.header.HeaderFilter=false
in portal-ext.properties globaly. What I what I would like to to is one of the following:
Disable HeaderFilter only for this portlet or war file. I can always add my own expires
Add an init-param to the HeaderFilter to match anything other than .nocache.js files
Any ideas how either of these things could be achieved?
Stack: liferay-6.0.1 CE, Windows 7, java 1.6.0_18, GWT 2.0.3
Try to use the url-regex-pattern which is used by Liferay itself:
<filter>
<filter-name>Header Filter</filter-name>
<filter-class>com.liferay.portal.kernel.servlet.PortalClassLoaderFilter</filter-class>
<init-param>
<param-name>filter-class</param-name>
<param-value>com.liferay.portal.servlet.filters.header.HeaderFilter</param-value>
</init-param>
<init-param>
<param-name>url-regex-pattern</param-name>
<!-- the following matches everything except files ending .nocache.js -->
<param-value><![CDATA[^.+(?<!nocache\.js)$]]></param-value>
</init-param>
<init-param>
<param-name>Cache-Control</param-name>
<param-value>max-age=315360000, public</param-value>
</init-param>
<init-param>
<param-name>Expires</param-name>
<param-value>315360000</param-value>
</init-param>
</filter>
If you add this to your web.xml it is not added twice during deployment or deleted.
I don't have experience with Version 6.0 by now so please verify.

Categories