I Already tried many of the aswers about this topic, no one works for me.
I Have a basic CRUD with Spring MVC 4.1.7, Spring Security 3.2.3 working on MySQL + Tomcat7.
The problem is, when i try to POST form with AngularJS, I keep being blocked by error 403 ( access denied ).
I figured out that I need to send my CSRF_TOKEN with the POST request, but I can't figure out HOW!
I Tried so many diferent ways and no one works.
My Files
Controller.js
$scope.novo = function novo() {
if($scope.id){
alert("Update - " + $scope.id);
}
else{
var Obj = {
descricao : 'Test',
saldo_inicial : 0.00,
saldo : 33.45,
aberto : false,
usuario_id : null,
ativo : true
};
$http.post(urlBase + 'caixas/adicionar', Obj).success(function(data) {
$scope.caixas = data;
}).error(function(data) {alert(data)});
}
};
Spring-security.xml
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<!-- enable use-expressions -->
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/seguro**"
access="hasAnyRole('ROLE_USER','ROLE_ADMIN')" />
<intercept-url pattern="/seguro/financeiro**"
access="hasAnyRole('ROLE_FINANCEIRO','ROLE_ADMIN')" />
<!-- access denied page -->
<access-denied-handler error-page="/negado" />
<form-login login-page="/home/" default-target-url="/seguro/"
authentication-failure-url="/home?error" username-parameter="inputEmail"
password-parameter="inputPassword" />
<logout logout-success-url="/home?logout" />
<!-- enable csrf protection -->
<csrf />
</http>
<!-- Select users and user_roles from database -->
<authentication-manager>
<authentication-provider>
<password-encoder hash="md5" />
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="SELECT login, senha, ativo
FROM usuarios
WHERE login = ?"
authorities-by-username-query="SELECT u.login, r.role
FROM usuarios_roles r, usuarios u
WHERE u.id = r.usuario_id
AND u.login = ?" />
</authentication-provider>
</authentication-manager>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<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">
<display-name>Barattie ~ Soluções Integradas</display-name>
<!-- The definition of the Root Spring Container shared by all Servlets
and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/spring-security.xml
/WEB-INF/spring/spring-database.xml
/WEB-INF/spring/spring-hibernate.xml
</param-value>
</context-param>
<context-param>
<param-name>com.sun.faces.writeStateAtFormEnd</param-name>
<param-value>false</param-value>
</context-param>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/home</url-pattern>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- Spring Security -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/erro</location>
</error-page>
UPDATE
I tried to add to rename at client side the xsrf, but I keep getting access denied.
var app = angular.module('myApp', []).config(function($httpProvider) {
$httpProvider.defaults.xsrfCookieName = '_csrf';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRF-Token';
});
** UPDATE 2 **
I tried to implement a filter like this.
package sys.barattie.util;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.web.csrf.CsrfToken;
import org.springframework.web.filter.OncePerRequestFilter;
public class CsrfFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
if (csrf != null) {
Cookie cookie = new Cookie("XSRF-TOKEN", csrf.getToken());
cookie.setPath("/");
response.addCookie(cookie);
}
filterChain.doFilter(request, response);
}
}
And changed my spring security to it.
<csrf token-repository-ref="csrfTokenRepository" />
<beans:bean id="csrfTokenRepository" class="org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository">
<beans:property name="headerName" value="X-XSRF-TOKEN" />
</beans:bean>
Web.xml
<filter>
<filter-name>csrfFilter</filter-name>
<filter-class>sys.barattie.util.CsrfFilter</filter-class>
</filter>
But it is like that the server doesn't run the filter, I've added a System.out.println to it, but can't see the messages in the debug
I did some tests and end up with this.
In my login controller, if my user authentication is successful, I create a token with the name of the AngularJS Token, just like this.
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
if (csrf != null) {
Cookie cookie = new Cookie("XSRF-TOKEN", csrf.getToken());
cookie.setPath("/");
response.addCookie(cookie);
}
After that, I can manage my $http.post successfully.
I don't know if this is the best way, but is the way that worked for me!
Thanks for the help #Joao Evangelista
The main problem is the integration, Angular always look for a cookie name XSRF-TOKEN and Spring sends a CSRF_TOKEN, you need to provide a filter to change this. Something like this:
private static Filter csrfHeaderFilter() {
return new OncePerRequestFilter() {
#Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName())
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN")
String token = csrf.getToken()
if (cookie == null || token != null && !token.equals(cookie.getValue())) {
cookie = new Cookie("XSRF-TOKEN", token)
cookie.setPath("/")
response.addCookie(cookie)
}
}
filterChain.doFilter(request, response)
}
}
}
static CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository()
repository.setHeaderName("X-XSRF-TOKEN")
return repository
}
NOTICE The only example I have is this, is written in Groovy, but is just missing some ;
Then you need to add the filter and the repository to <csrf/> properties, you can explicity set a class implementing a Filter as <bean>, using #Component or declaring this methods as #Bean on a configuration class
Otherwise you can change the $http configuration on Angular, according to docs setting this settings to match Spring token cookie name and header name
xsrfHeaderName – {string} – Name of HTTP header to populate with the XSRF token.
xsrfCookieName – {string} – Name of cookie containing the XSRF token.
More info about this you can check the docs on Usage section
i was facing this problem also, and this is the solution that is working for me (from the Spring documentation), notice that im not using $http. Instead im using $resource.
'
You can ask Spring to save a cookie with Angular's defaults:
<csrf token-repository-ref="tokenRepository"/>
...
</http>
<b:bean id="tokenRepository"
class="org.springframework.security.web.csrf.CookieCsrfTokenRepository"
p:cookieHttpOnly="false"/>
Please notice that if you use $http, there is a field in the config object called xsrfCookieName, where you can set explicitly the name of the cookie. But this option i havent tried it, so i dont know how useful it is.
Best Regards.
This should work:
Class that extends WebSecurityConfigurerAdapter:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
..
And then in your AngularJS you can use any module for csrf, etc.: spring-security-csrf-token-interceptor
I'm using:
-primefaces 4.0
-jsf mojarra 2.2
-google app engine (servlet api 2.5)
and this solution (Getting primefaces p:fileUpload to work under google appengine) doesn't help me because my version of primefaces is higher. There is exception when I'm using my form below with p:commandButton:
java.lang.NoSuchMethodError: javax.servlet.http.HttpServletRequest.getPart(Ljava/lang/String;)Ljavax/servlet/http/Part;
at org.primefaces.component.fileupload.NativeFileUploadDecoder.decodeAdvanced(NativeFileUploadDecoder.java:60)
at org.primefaces.component.fileupload.NativeFileUploadDecoder.decode(NativeFileUploadDecoder.java:37)
at org.primefaces.component.fileupload.FileUploadRenderer.decode(FileUploadRenderer.java:44)
at javax.faces.component.UIComponentBase.decode(UIComponentBase.java:831)
at javax.faces.component.UIInput.decode(UIInput.java:771)
at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.java:1225)
at javax.faces.component.UIInput.processDecodes(UIInput.java:676)
at javax.faces.component.UIForm.processDecodes(UIForm.java:225)
at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.java:1220)
at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.java:1220)
at javax.faces.component.UIViewRoot.processDecodes(UIViewRoot.java:929)
at com.sun.faces.lifecycle.ApplyRequestValuesPhase.execute(ApplyRequestValuesPhase.java:78)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:646)
....
and this is because google don't support servlet api 3.0. I realy can't find a solution for now. Running primefaces 3.5 is not a option because the project is with JSF 2.2 and 2.2 is not compatible with primefaces 3.5.
One usable comment from this topic: How to use PrimeFaces p:fileUpload? Listener method is never invoked or UploadedFile is null
Update: since PrimeFaces 4.x, when used in combination with JSF 2.2 and Servlet 3.0, the filter is not necessary anymore. The Servlet 3.0 / JSF 2.2 native API will be used instead of Apache Commons FileUpload. Other rules however still apply and from the possible causes you can scratch #1 and #2.
My form:
<h:form enctype="multipart/form-data">
<p:fileUpload id="filePhoto" fileUploadListener="#{atlasCasesMB.handleFileUpload}" mode="advanced" dragDropSupport="false"
update=":messages" sizeLimit="614400" fileLimit="3" allowTypes="/(\.|\/)(gif|jpe?g|png)$/" />
</h:form>
In this form fileUploadListener is not invoked.
I've tried to use the solution from this topic: Getting primefaces p:fileUpload to work under google appengine modify the DiskFileItem), but obviously this cannot help because JSF 2.2 uses native API instead of Apache Commons FileUpload.
<filter>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
<init-param>
<param-name>thresholdSize</param-name>
<param-value>2147483647</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
Any suggestions? (Downgrading primefaces and jsf is not an option because the project is in final stage)
The solution ,that I tried, is to force primefaces to use apache common file upload (commons-fileupload-1.3.jar) using this:
<context-param>
<param-name>primefaces.UPLOADER</param-name>
<param-value>commons</param-value>
</context-param>
Then I used the filter:
<filter>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
<init-param>
<param-name>thresholdSize</param-name>
<param-value>2147483647</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
important here is to set thresholdSize so big that write method in some of the apache common classes(I forgot which) is not invoked. And finally add the filter FileUploadFilter from primefaces 4.0 source files: http://www.primefaces.org/downloads.html
All sources that I used to get to this point:
http://davebarber.blog.com/2010/10/15/jsf-2-0-on-google-app-engine/
PrimeFaces 4.0 FileUpload works with Mojarra 2.2 but not MyFaces 2.2
How to use PrimeFaces p:fileUpload? Listener method is never invoked or UploadedFile is null
Getting primefaces p:fileUpload to work under google appengine
This fires :
java.lang.verifyerror inconsistent stackmap frames at branch target
To prevent primefaces to use its native file upload, add the following parameter.
<context-param>
<param-name>primefaces.UPLOADER</param-name>
<param-value>commons</param-value>
</context-param>
Then I used the filter:
<filter>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
<init-param>
<param-name>thresholdSize</param-name>
<param-value>2147483647</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
important here is to set thresholdSize so big that write method in some of the apache common classes(I forgot which) is not invoked. And finally add the filter FileUploadFilter from primefaces 4.0 modified:
package org.primefaces.webapp.filter;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
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 javax.servlet.http.HttpServletRequest;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.gmr.web.multipart.GFileItemFactory;
import org.primefaces.webapp.MultipartRequest;
public class FileUploadFilter implements Filter {
private final static Logger logger = Logger.getLogger(FileUploadFilter.class.getName());
private final static String THRESHOLD_SIZE_PARAM = "thresholdSize";
private final static String UPLOAD_DIRECTORY_PARAM = "uploadDirectory";
private String thresholdSize;
private String uploadDir;
public void init(FilterConfig filterConfig) throws ServletException {
thresholdSize = filterConfig.getInitParameter(THRESHOLD_SIZE_PARAM);
uploadDir = filterConfig.getInitParameter(UPLOAD_DIRECTORY_PARAM);
logger.warning("init:uploadDir=" + uploadDir + "; thresholdSize=" + thresholdSize);
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
boolean isMultipart = ServletFileUpload.isMultipartContent(httpServletRequest);
if (isMultipart) {
logger.warning("Parsing file upload request");
// start change
FileItemFactory diskFileItemFactory = new GFileItemFactory();
/*
* if(thresholdSize != null) { diskFileItemFactory.setSizeThreshold(Integer.valueOf(thresholdSize)); } if(uploadDir != null) { diskFileItemFactory.setRepository(new File(uploadDir)); }
*/
// end change
ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory);
MultipartRequest multipartRequest = new MultipartRequest(httpServletRequest, servletFileUpload);
if (logger.isLoggable(Level.FINE))
logger.fine("File upload request parsed succesfully, continuing with filter chain with a wrapped multipart request");
filterChain.doFilter(multipartRequest, response);
} else {
filterChain.doFilter(request, response);
}
}
public void destroy() {
if (logger.isLoggable(Level.FINE))
logger.fine("Destroying FileUploadFilter");
}
}
Form:
<h:form >
<p:fileUpload id="filePhoto" fileUploadListener="#{atlasCasesMB.handleFileUpload}" mode="advanced" dragDropSupport="false"
update=":messages" sizeLimit="614400" fileLimit="3" allowTypes="/(\.|\/)(gif|jpe?g|png)$/" />
<br />
<p:commandButton value="#{bundle['save']}" actionListener="#{atlasCasesMB.saveCase}" process="#form" />
</h:form>
File upload handler:
public void handleFileUpload(FileUploadEvent event) {
log.warning("handleFileUpload(FileUploadEvent event)");
UploadedFile uploadedFile = event.getFile();
photosArr.add(uploadedFile.getContents());
//photos.add(new File(uploadedFile.getFileName()));
FacesMessage msg = new FacesMessage("Succesful", event.getFile().getFileName() + " is uploaded.");
FacesContext.getCurrentInstance().addMessage(null, msg);
}
List of byte array photos:
private List<byte[]> photosArr;
libraries:
commons-fileupload-1.3.jar
commons-io-2.4.jar
gmultipart-0.2.jar
portlet-2.0.jar
primefaces-4.0.jar
DiskFileItem:
comment UID and inside of write method
and ViewScoped Bean
========================================
there is second way to do this:
using multipart request to jersey:
<p:dialog id="upladPhotoDialog" widgetVar="upladPhotoDlg" header="#{bundle['uploading.photos']}" >
<form action="rest/case" method="post" enctype="multipart/form-data">
<p>#{bundle['upload.photo.select.images.to.upload']}</p>
<br />
<input id="photo1" type="file" name="photo1" />
<br />
<input id="photo2" type="file" name="photo2" />
<br />
<input id="photo3" type="file" name="photo3" />
<br />
<input id="caseId" type="text" name="caseId" style="display:none" value="#{atlasCasesMB.savedCaseId}" />
<br />
<input id="btn-post" class="active btn" type="submit" value="Send" />
</form>
#POST
#Consumes(MediaType.MULTIPART_FORM_DATA)
public void insertPhotoForCase (
#FormDataParam("photo1") InputStream photoIS1,
#FormDataParam("photo2") InputStream photoIS2,
#FormDataParam("photo3") InputStream photoIS3,
#FormDataParam("caseId") String caseId , #Context HttpServletRequest httpRequest , #Context HttpServletResponse httpResponse) {
try {
DataService<Case> das = new CaseDataService();
Case caze = das.find(Integer.parseInt(caseId));
byte[] photoBytes = IOUtils.toByteArray(photoIS1);
if(photoBytes.length != 0 ){
sendPhotoToBlob (createPhoto(caze).getId() ,photoBytes);
}
photoBytes = IOUtils.toByteArray(photoIS2);
if(photoBytes.length != 0 ){
sendPhotoToBlob (createPhoto(caze).getId() ,photoBytes);
}
photoBytes = IOUtils.toByteArray(photoIS3);
if(photoBytes.length != 0 ){
sendPhotoToBlob (createPhoto(caze).getId() ,photoBytes);
}
//currentResponse.sendRedirect("/atlascases.xhtml");
_context.getRequestDispatcher("/atlascases.xhtml").forward(httpRequest, httpResponse);
} catch (Exception e) {
e.printStackTrace();
}
}
file:jersey-multipart-config.properties in src folder with text inside:
bufferThreshold = -1
in web.xml
<servlet>
<servlet-name>Jersey REST Service</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.smartinteractive.medimaging.service</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey REST Service</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
I tried to deploy my app using auth this instructions as :
<application>mytestapp</application>
<version>1</version>
<sessions-enabled>true</sessions-enabled>
<security-constraint>
<web-resource-collection>
<web-resource-name></web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>*</role-name>
</auth-constraint>
</security-constraint>
and I tried this code as well to make user login:
public class GuestbookServlet extends HttpServlet {
#Override
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
UserService userService = UserServiceFactory.getUserService();
User user = userService.getCurrentUser();
if (user != null) {
resp.setContentType("text/plain");
resp.getWriter().println("Hello, " + user.getNickname());
} else {
resp.sendRedirect(userService.createLoginURL(req.getRequestURI()));
}
}
}
... but for some reason I get exception thrown as XML error validating :
An internal error occurred during: "Deploying testapp to Google". XML
error validating C:...\testapp\war\WEB-INF\appengine-web.xml against
C:...\eclipse-jee-indigo-win32\eclipse\plugins\com.google.appengine.eclipse.sdkbundle_1.5.2.r37v201107211953\appengine-java-sdk-1.5.2\docs\appengine-web.xsd
I am not pretty sure what that means so I dearly need your advise how to fix it? Any useful idea is much appreciated.
Thanks
P.S. GWT SDK 2.3
You are mixing the app config file: appengine-web.xml with deployment descriptor: web.xml.
I made website using java.
which work correclty on local host.
but when I deploy it on google app engine.
It give me 404 Error.
Problem link: http://webenggproject.appspot.com/signin.jsp
localhost/signin.jsp [ work correclty on localhost ]
<div class="offset4">
login
signup </div>
Try using Servlet to access your jsp...
Config web.xml :
<servlet>
<servlet-name>Signin</servlet-name>
<servlet-class>com.SigninServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Signin</servlet-name>
<url-pattern>/signin</url-pattern>
</servlet-mapping>
Servlet :
package com;
import java.io.IOException;
import javax.servlet.http.*;
#SuppressWarnings("serial")
public class SigninServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
resp.sendRedirect("signin.jsp");
}
}
dont forget to change your link :
login
I have created a very simple cxf non-spring based Servlet which loads a javax.ws.rs.Application type.
Here is the web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app 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"
version="2.5">
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>
org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet
</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>
com.mycomp.cxf.TestApplication
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
And here is the application:
public class TestApplication extends Application
{
private final Set<Class<?>> classes = new HashSet<Class<?>>();
private final Set<Object> singletons = new HashSet<Object>();
public TestApplication() throws ServletException
{
}
#Override
public Set<Class<?>> getClasses()
{
return classes;
}
#Override
public Set<Object> getSingletons()
{
return singletons;
}
}
The Servlet is failing to load due to: "No resource classes found" and i'm not sure why as it should be ok to have an empty set of classes in Application.
Here is the full stacktrace:
org.apache.cxf.jaxrs.AbstractJAXRSFactoryBean - No resource classes found
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/test] - StandardWrapper.Throwable
org.apache.cxf.service.factory.ServiceConstructionException
at org.apache.cxf.jaxrs.JAXRSServerFactoryBean.create(JAXRSServerFactoryBean.java:122)
at org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet.createServerFromApplication(CXFNonSpringJaxrsServlet.java:304)
at org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet.loadBus(CXFNonSpringJaxrsServlet.java:72)
at org.apache.cxf.transport.servlet.AbstractCXFServlet.init(AbstractCXFServlet.java:78)
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1172)
at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:992)
at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4058)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4371)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:791)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:771)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:525)
at com.springsource.osgi.webcontainer.tomcat.TomcatServletContainer.startWebApplication(TomcatServletContainer.java:120)
at com.springsource.osgi.webcontainer.internal.StandardWebContainer$StandardWebApplication.start(StandardWebContainer.java:100)
at com.springsource.osgi.webcontainer.extender.WebContainerBundleCustomizer.addingBundle(WebContainerBundleCustomizer.java:25)
at org.osgi.util.tracker.BundleTracker$Tracked.customizerAdding(BundleTracker.java:440)
at org.osgi.util.tracker.AbstractTracked.trackAdding(AbstractTracked.java:261)
at org.osgi.util.tracker.AbstractTracked.track(AbstractTracked.java:233)
at org.osgi.util.tracker.BundleTracker$Tracked.bundleChanged(BundleTracker.java:413)
at org.eclipse.osgi.framework.internal.core.BundleContextImpl.dispatchEvent(BundleContextImpl.java:919)
at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:227)
at org.eclipse.osgi.framework.eventmgr.ListenerQueue.dispatchEventSynchronous(ListenerQueue.java:149)
at org.eclipse.osgi.framework.internal.core.Framework.publishBundleEventPrivileged(Framework.java:1349)
at org.eclipse.osgi.framework.internal.core.Framework.publishBundleEvent(Framework.java:1300)
at org.eclipse.osgi.framework.internal.core.BundleHost.startWorker(BundleHost.java:380)
at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:284)
at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:276)
at com.sap.core.js.deployer.watchservice.WARDeployer.deploy(WARDeployer.java:142)
at com.sap.core.js.deployer.watchservice.FileSystemEventsListener.onChange(FileSystemEventsListener.java:26)
at com.springsource.util.io.FileSystemChecker.notifyListeners(FileSystemChecker.java:182)
at com.springsource.util.io.FileSystemChecker.check(FileSystemChecker.java:145)
at com.sap.core.js.deployer.watchservice.WatchTask.run(WatchTask.java:29)
at java.lang.Thread.run(Thread.java:679)
Caused by: javax.ws.rs.WebApplicationException
at org.apache.cxf.jaxrs.AbstractJAXRSFactoryBean.checkResources(AbstractJAXRSFactoryBean.java:238)
at org.apache.cxf.jaxrs.JAXRSServerFactoryBean.create(JAXRSServerFactoryBean.java:85)
... 31 more
10:41:54,580 [ERROR] org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/test] - Servlet /test threw load() exception
javax.ws.rs.WebApplicationException
at org.apache.cxf.jaxrs.AbstractJAXRSFactoryBean.checkResources(AbstractJAXRSFactoryBean.java:238)
at org.apache.cxf.jaxrs.JAXRSServerFactoryBean.create(JAXRSServerFactoryBean.java:85)
at org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet.createServerFromApplication(CXFNonSpringJaxrsServlet.java:304)
at org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet.loadBus(CXFNonSpringJaxrsServlet.java:72)
at org.apache.cxf.transport.servlet.AbstractCXFServlet.init(AbstractCXFServlet.java:78)
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1172)
at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:992)
at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4058)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4371)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:791)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:771)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:525)
at com.springsource.osgi.webcontainer.tomcat.TomcatServletContainer.startWebApplication(TomcatServletContainer.java:120)
at com.springsource.osgi.webcontainer.internal.StandardWebContainer$StandardWebApplication.start(StandardWebContainer.java:100)
at com.springsource.osgi.webcontainer.extender.WebContainerBundleCustomizer.addingBundle(WebContainerBundleCustomizer.java:25)
at org.osgi.util.tracker.BundleTracker$Tracked.customizerAdding(BundleTracker.java:440)
at org.osgi.util.tracker.AbstractTracked.trackAdding(AbstractTracked.java:261)
at org.osgi.util.tracker.AbstractTracked.track(AbstractTracked.java:233)
at org.osgi.util.tracker.BundleTracker$Tracked.bundleChanged(BundleTracker.java:413)
at org.eclipse.osgi.framework.internal.core.BundleContextImpl.dispatchEvent(BundleContextImpl.java:919)
at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:227)
at org.eclipse.osgi.framework.eventmgr.ListenerQueue.dispatchEventSynchronous(ListenerQueue.java:149)
at org.eclipse.osgi.framework.internal.core.Framework.publishBundleEventPrivileged(Framework.java:1349)
at org.eclipse.osgi.framework.internal.core.Framework.publishBundleEvent(Framework.java:1300)
at org.eclipse.osgi.framework.internal.core.BundleHost.startWorker(BundleHost.java:380)
at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:284)
at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:276)
at com.sap.core.js.deployer.watchservice.WARDeployer.deploy(WARDeployer.java:142)
at com.sap.core.js.deployer.watchservice.FileSystemEventsListener.onChange(FileSystemEventsListener.java:26)
at com.springsource.util.io.FileSystemChecker.notifyListeners(FileSystemChecker.java:182)
at com.springsource.util.io.FileSystemChecker.check(FileSystemChecker.java:145)
at com.sap.core.js.deployer.watchservice.WatchTask.run(WatchTask.java:29)
at java.lang.Thread.run(Thread.java:679)
You need to notify your environment of your serviceclasses. You first need to add the service class, otherwise you will just return null in getSingletons()
So just change your now empty constructor to add the service class:
class TestApplication extends Application {
public TestApplication() throws ServletException
{
singletons.add( new com.example.MyService() )
}
....
}
Well, I guess you can't have an empty set of classes as if I add one then it loads successfully, for example:
public TestApplication() throws ServletException
{
singletons.add(someClass);
}