Help!
Trying to implement Protocol Buffers via Rest (Jersey), but get this exception.
class com.util.ProtobufMessageBodyReader
class com.util.ProtobufMessageBodyWriter
Jul 6, 2010 3:43:37 PM org.apache.coyote.http11.Http11Protocol start
INFO: Starting Coyote HTTP/1.1 on http-9102
Jul 6, 2010 3:43:37 PM org.apache.catalina.startup.Catalina start
INFO: Server startup in 45485 ms
Jul 6, 2010 3:49:00 PM org.apache.catalina.connector.CoyoteAdapter convertURI
SEVERE: Invalid URI encoding; using HTTP default
Jul 6, 2010 3:49:00 PM com.sun.jersey.spi.container.ContainerRequest getEntity
SEVERE: A message body reader for Java type, class com.example.tutorial.ProfileRequestProto$ProfileRequest, and MIME media type, application/x-protobuf, was not found
I loaded ProtobufMessageBodyReader/Writer in the Apache ContextLoader.
From the log above, it seems Tomcat found the class but it apparent it fails when it reads
#Consumes("application/x-protobuf")
Here is ProtobufMessageBodyReader
#Provider
#Component
#Consumes("application/x-protobuf")
public class ProtobufMessageBodyReader implements MessageBodyReader<Message> {
public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return Message.class.isAssignableFrom(type);
}
public Message readFrom(Class<Message> type, Type genericType, Annotation[] annotations,
MediaType mediaType, MultivaluedMap<String, String> httpHeaders,
InputStream entityStream) throws IOException, WebApplicationException {
try {
Method newBuilder = type.getMethod("newBuilder");
GeneratedMessage.Builder<?> builder = (GeneratedMessage.Builder<?>) newBuilder.invoke(type);
return builder.mergeFrom(entityStream).build();
} catch (Exception e) {
throw new WebApplicationException(e);
}
}
#Override
public boolean isReadable(Class<?> arg0, Type arg1, Annotation[] arg2) {
// TODO Auto-generated method stub
return false;
}
And here is ProtobufMessageBodyWriter
#Provider
#Component
#Produces("application/x-protobuf")
public class ProtobufMessageBodyWriter implements MessageBodyWriter<Message> {
public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return Message.class.isAssignableFrom(type);
}
public long getSize(Message m, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return m.getSerializedSize();
}
public void writeTo(Message m, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String,Object> httpHeaders,OutputStream entityStream) throws IOException, WebApplicationException {
entityStream.write(m.toByteArray());
}
Here is the code from client :
URL url = new URL(URL);
HttpURLConnection http = (HttpURLConnection)url.openConnection();
http.setDoInput(true);
http.setDoOutput(true);
http.setUseCaches(false);
http.setRequestMethod("POST");
http.setRequestProperty("Content-Type","application/x-protobuf");
http.setRequestProperty("Accept", "application/x-protobuf");
DataOutputStream stream = new DataOutputStream(http.getOutputStream ());
if(contentType.equals("application/x-protobuf")) {
ProfileRequest.Builder profile = ProfileRequest.newBuilder();
profile.setName("John");
profile.setId("123");
profile.build().writeTo(http.getOutputStream());
}
stream.flush();
stream.close();
And here is the code from server
#POST
#Consumes("application/x-protobuf")
public byte[] processProtoRequest(ProfileRequest protoRequest) {
byte[] result = null;
ProfileRequest.Builder profile = ProfileRequest.newBuilder();
profile.mergeFrom(protoRequest);
result = getProfileProtoResponse(profile);
}catch(Exception e){
}
return result;
}
I cannot figure out what is the problem.
Is there anything with Jersey config? Or something is wrong when I sent protocol request via HTTP?
Any help will be appreciate it.
Thanks
You mostly nailed the issue yourself already I think:
and MIME media type, application/x-protobuf, was not found
[...]
From the log above, it seems Tomcat found the class but it apparent it fails when it reads
#Consumes("application/x-protobuf")
The media types supported by Jersey (or rather JSR-311/JAX-RS) out of the box are defined in class MediaType. To resolve your issue it might be enough to define an appropriate media type for application/x-protobuf, see thread [Jersey] MediaType-s? for a discussion and samples regarding this.
I just met the same problem on my maven+jersey+protobuf project,and I am using tomcat 6. to me the problems is that the Provider Class the tomcat hasn't found.
After I solve this problem the tomcat 6.0 shows like this :
Deploying configuration descriptor jerseydemo2.xml
一月 26, 2015 11:13:41 上午 com.sun.jersey.api.core.WebAppResourceConfig init
信息: Scanning for root resource and provider classes in the Web app resource paths:
/WEB-INF/lib
/WEB-INF/classes
一月 26, 2015 11:13:41 上午 com.sun.jersey.api.core.ScanningResourceConfig logClasses
信息: Root resource classes found:
class sample.hello.resources.AddressBookResource
一月 26, 2015 11:13:41 上午 com.sun.jersey.api.core.ScanningResourceConfig logClasses
信息: Provider classes found:
class sample.pb.ProtobufMessageBodyReader
class sample.pb.ProtobufMessageBodyWriter
一月 26, 2015 11:13:41 上午 com.sun.jersey.server.impl.application.WebApplicationImpl initiate
信息: Initiating Jersey application, version 'Jersey: 1.2-SNAPSHOT 01/27/2010 01:47 AM'
before it showed the Provider classes not found.
my problems is that the web.xml file has set the specific path for the tomcat to find all the resouces. now I have changed it like this:
<?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>ServletAdaptor</servlet-name>
<servlet-class>com.sun.jersey.server.impl.container.servlet.ServletAdaptor</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ServletAdaptor</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
hope it helps you !
Related
I am working on a service hosting several REST API using Java Servlet.
The Servlet uses annotations provided by javax.ws.rs to define the API's URL, HTTP method, etc. So one of them may look like as follows:
#Path("root")
#Service
public class MyClass {
#Path("path")
#Get
#Produces("application/json; charset=UTF-8")
public ResponseObject myAction() { ... }
}
I also have a filter that due to some bug, could throw an exception after executing the servlet. So it behaves as follows:
public class MyFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
chain.doFilter(request, response);
throws new Exception();
}
}
The web.xml contains following definition: (not complete, just those I think might be relevant)
<servlet>
<servlet-name>jersey-servlet</servlet-name>
<servlet-class>
com.sun.jersey.spi.spring.container.servlet.SpringServlet
</servlet-class>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<filter>
<filter-name>MyFilter</filter-name>
<filter-class>myorg.MyFilter</filter-class>
</filter>
When I call this API using different approaches, I get different results.
Using Jersey client and get as string
WebResource resource = client.resource("https://my-service/root/path");
ClientResponse response = resource.get(ClientResponse.class);
String s = response.getEntity(String.class);
This will give me below error:
Caused by: java.io.IOException: Premature EOF
at sun.net.www.http.ChunkedInputStream.readAheadBlocking(ChunkedInputStream.java:565)
at sun.net.www.http.ChunkedInputStream.readAhead(ChunkedInputStream.java:609)
at sun.net.www.http.ChunkedInputStream.read(ChunkedInputStream.java:696)
at java.io.FilterInputStream.read(FilterInputStream.java:133)
at sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:3393)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.Reader.read(Reader.java:140)
at com.sun.jersey.core.util.ReaderWriter.readFromAsString(ReaderWriter.java:171)
at com.sun.jersey.core.util.ReaderWriter.readFromAsString(ReaderWriter.java:157)
at com.sun.jersey.core.provider.AbstractMessageReaderWriterProvider.readFromAsString(AbstractMessageReaderWriterProvider.java:114)
at com.sun.jersey.core.impl.provider.entity.StringProvider.readFrom(StringProvider.java:73)
at com.sun.jersey.core.impl.provider.entity.StringProvider.readFrom(StringProvider.java:58)
at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:634)
Using Jersey client but de-serializing the JSON response into an object
WebResource resource = client.resource("https://my-service/root/path");
ClientResponse response = resource.get(ClientResponse.class);
ResponseObject result = response.getEntity(ResponseObject.class);
This will return successfully and the resulting ResponseObject contains correct content.
Call this API using HTTP tool Postman. This will also return status 200 and correct response body.
Call the API using .Net core library RestSharp
var restClient = new RestClient("https://my-service/");
var request = new RestRequest("/root/path", method);
var response = restClient.Execute(request);
This will fail with following error:
The server returned an invalid or unrecognized response.
at System.Net.Http.HttpConnection.FillAsync()
at System.Net.Http.HttpConnection.ChunkedEncodingReadStream.ReadAsyncCore(Memory`1 buffer, CancellationToken cancellationToken)
at System.Net.Http.HttpConnection.HttpContentReadStream.Read(Byte[] buffer, Int32 offset, Int32 count)
at RestSharp.Extensions.MiscExtensions.ReadAsBytes(Stream input)
at RestSharp.Http.ProcessResponseStream(Stream webResponseStream, HttpResponse response)
at RestSharp.Http.ExtractResponseData(HttpResponse response, HttpWebResponse webResponse)
at RestSharp.Http.GetResponse(HttpWebRequest request)
My question is:
What happened to my HTTP response in this case and why different clients behaved differently ? I guess when MyClass.myAction completed, the serialized return object ResponseObject was already sent to the client. However, when the control was given back to MyFilter, an error was thrown. This must have had some impact on the HTTP response, but what ? And why would this by observed in some cases by some client but ignored by others ?
It's quite easy for me to fix the bug itself - to not throw exception in the filter. But I want to understand more about what happened underneath and appreciate any help.
I've been struggling with a rather absurd problem for a few days now:
The project I'm on is using Spring MVC with FreeMarker for it's templating.
This is running atop a Tomcat container (testing locally using Cargo).
The issue I'm working has the brief of implementing uniform behaviour in a standardised error page but covering covering the various types of errors that may be encountered. (Exceptions bubbling up from back-end services, inadequate permissions, http errors, etc)
So far, the results are as follows (Graphic included):
Fig A: Normal navigation to page - renders as expected.
Fig B & Fig C: Service and Permission Exceptions caught by ControllerAdvice.java - likewise, no issues.
Fig D: Any HTTP Error (yes, even 418 if you trigger that response) - Inner freemarker template is correctly retrieved and populated with bindings but decorations applied by filters fail to trigger.
Currently we're using Spring to configure the servlet handling so the web.xml is beautifully sparse:
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<!--
This application uses the config of the mapping by Spring MVC
This is why you will not see servlet declarations here
The web app is defined in
- butler.SpringWebInit
- butler.SpringWebConfig
-->
<context-param>
<description>Escape HTML form data by default when using Spring tags</description>
<param-name>defaultHtmlEscape</param-name>
<param-value>true</param-value>
</context-param>
<!-- Disabling welcome list file for Tomcat, handling it in Spring MVC -->
<welcome-file-list>
<welcome-file/>
</welcome-file-list>
<!-- Generic Error redirection, allows for handling in Spring MVC -->
<error-page>
<location>/http-error</location>
<!-- Was originally just "/error" it was changed for internal forwarding/proxying/redirection attempts -->
</error-page>
</web-app>
The Configuration is handled by SpringWebInit.java to which I have not made any modifications:
SpringWebInit.java
/**
* Automatically loaded by class org.springframework.web.SpringServletContainerInitializer
*
* #see http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-container-config
*
* According to {#link AbstractSecurityWebApplicationInitializer}, this class should be
* annotated with a Order so that it is loaded before {#link SpringSecurityInit}
*/
#Order(0)
public class SpringWebInit extends AbstractAnnotationConfigDispatcherServletInitializer implements InitializingBean {
private final Logger LOG = LoggerFactory.getLogger(getClass());
#Override
public void afterPropertiesSet() throws Exception {
LOG.info("DispatcherServlet loaded");
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null; // returning null, getRootConfigClasses() will handle this as well
}
#Override
protected String[] getServletMappings() {
return new String[] {"/**"}; // Spring MVC should handle everything
}
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] {SpringWebConfig.class, SpringSecurityConfig.class};
}
#Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter characterEncodingFilter =
new CharacterEncodingFilter(StandardCharsets.UTF_8.name(), true);
return new Filter[] {characterEncodingFilter, new SiteMeshFilter()};
}
}
Which in turn loads The various config for Freemarker and Sitemesh:
SpringWebConfig.java
#EnableWebMvc
#Configuration
#PropertySource("classpath:/butler-init.properties")
#ComponentScan({"butler"})
class SpringWebConfig extends WebMvcConfigurerAdapter implements InitializingBean {
private final Logger LOG = LoggerFactory.getLogger(getClass());
#Autowired
LoggedInUserService loggedInUserService;
#Override
public void afterPropertiesSet() throws Exception {
LOG.info("Web Mvc Configurer loaded");
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(userHeaderInterceptor());
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").addResourceLocations("/static/").setCacheControl(
CacheControl.maxAge(30, TimeUnit.MINUTES).noTransform().cachePublic().mustRevalidate());
}
#Bean
FreeMarkerViewResolver viewResolver() throws TemplateException {
FreeMarkerViewResolver resolver = new FreeMarkerViewResolver();
resolver.setCache(/*true*/false); // Set to false for debugging
resolver.setPrefix("");
resolver.setSuffix(".ftlh");
resolver.setRequestContextAttribute("rContext");
resolver.setContentType("text/html;charset=UTF-8");
DefaultObjectWrapper wrapper =
new DefaultObjectWrapperBuilder(freemarker.template.Configuration.getVersion()).build();
Map<String, Object> attrs = new HashMap<>();
attrs.put("loggedInUserService", wrapper.wrap(loggedInUserService));
resolver.setAttributesMap(attrs);
return resolver;
}
#Bean
FreeMarkerConfigurer freeMarkerConfig() {
Properties freeMarkerVariables = new Properties();
// http://freemarker.org/docs/pgui_config_incompatible_improvements.html
// http://freemarker.org/docs/pgui_config_outputformatsautoesc.html
freeMarkerVariables.put(freemarker.template.Configuration.INCOMPATIBLE_IMPROVEMENTS_KEY,
freemarker.template.Configuration.getVersion().toString());
FreeMarkerConfigurer freeMarkerConfigurer = new FreeMarkerConfigurer();
freeMarkerConfigurer.setDefaultEncoding("UTF-8");
freeMarkerConfigurer.setTemplateLoaderPath("/WEB-INF/mvc/view/ftl/");
freeMarkerConfigurer.setFreemarkerSettings(freeMarkerVariables);
return freeMarkerConfigurer;
}
#Bean
UserHeaderInterceptor userHeaderInterceptor() {
return new UserHeaderInterceptor();
}
#Bean
static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
SiteMeshFilter.java
public class SiteMeshFilter extends ConfigurableSiteMeshFilter {
#Override
protected void applyCustomConfiguration(SiteMeshFilterBuilder builder) {
// Don't use decorator REST api pages
builder.addExcludedPath("/api/*");
builder.addDecoratorPath("/*", Views.DECORATOR_HEADER_FOOTER);
builder.setIncludeErrorPages(true);
}
}
Finally, onto the meat of the problem, the error handling is being handled via a combination of DefaultControllerAdvice.java, which provides the rules for intercepting exceptions and ErrorController.java itself, which handles the mappings and eventually, the message handling (displaying information about the error, adapting according to the type of error, etc)
DefaultControllerAdvice.java
#ControllerAdvice(annotations = Controller.class)
class DefaultControllerAdvice {
private static String EXCEPTION = "butlerexception";
#ExceptionHandler(ServiceException.class)
public String exceptionHandler(ServiceException se, Model model) {
model.addAttribute(EXCEPTION, se.getMessage());
return Views.ERROR;
}
#ExceptionHandler(PermissionException.class)
public String exceptionHandler(PermissionException pe, Model model) {
model.addAttribute(EXCEPTION, "Incorrect Permissions");
return Views.ERROR;
}
/*#ResponseStatus(HttpStatus.NOT_FOUND)
#ExceptionHandler(IOException.class)
public String exceptionHandler(Model model) { // Trying another way of intercepting 404 errors
model.addAttribute(EXCEPTION, "HTTP Error: 404");
return Views.ERROR;
}*/
}
ErrorController.java
#Controller
class ErrorController extends AbstractController {
#Autowired
private LoggedInUserService loggedInUserService;
#RequestMapping(path="error",method = {GET,POST}) // Normal Error Controller, Returns fully decorated page without issue for Exceptions and normal requests.
public String error(RedirectAttributes redirectAttributes, HttpServletResponse response,Model model) {
//if (redirectAttributes.containsAttribute("errorCode")) { // Trying to invisibly use redirection
// Map<String, ?> redirAttribs = redirectAttributes.getFlashAttributes();
// model.addAttribute("butlerexception", "HTTP Error: "+redirAttribs.get("errorCode"));
//} else {
model.addAttribute("butlerexception", "Error");
//}
return ERROR;
}
#RequestMapping("/http-error") // Created to test HTTP requests being proxied via ServiceExceptions, Redirections, etc...
public String httpError(/*RedirectAttributes redirectAttributes,*/ HttpServletResponse response, HttpServletRequest request, Model model){
model.addAttribute("butlerexception", "HTTP Error: " + response.getStatus());
//throw new ServiceException("HTTP Error: " + response.getStatus()); // Trying to piggyback off Exception handling
//redirectAttributes.addFlashAttribute("errorCode", response.getStatus()); // Trying to invisibly use redirection
//redirectAttributes.addFlashAttribute("originalURL",request.getRequestURL());
return /*"redirect:"+*/ERROR;
}
}
So Far, I have tried:
Throwing exceptions to piggy-back off the working ControllerAdvice rules. - Result was undecorated.
Adding in Rules for response codes, IONotFound nad NoHandlerFound exceptions - Result was undecorated.
Redirecting to the error page - Result was decorated correctly, but URL and response codes were incorrect, attempting to mask the URL with the original request URL resulted in the correct URL and code, but the same lack of decoration as before.
Additionally, from the debugging logs, I can see that the filters from Spring Security are triggered normally but the ones involved with decorating the site (for both logged in and anonymous requests) fail to trigger for HTTP errors only.
One of the limiting factors currently is that I cannot gut the system and define it all in the web.xml (as many of the solutions here and in the Spring documentation seem to call for) without causing excessive disruption to development at this stage. (nor do I have the authority to effect such a change (Junior rank))
For Convenience sake, a few of the solutions I've tried so far:
Spring MVC 404 Error Page
404 error redirect in Spring with java config
Generic Error Page not decorated
Custom Error Page Not Decorated by Sitemesh in Spring Security Application
Custom 404 using Spring DispatcherServlet
<error-page> setup doesn't work in Spring MVC
At this point I'm really not sure what else to try, what on earth am I missing here?
Edit: it turned out to be a bug in SiteMesh to do with the triggering of .setContentType(...) that was solved via setting the contentType again after sitemesh in order to trigger decoration: Bug report with description and solution
This turned out to a two-part issue, firstly SiteMesh3's handling of error pages means that it believes it has processed all the filters even when an error causes decorators to be skipped. (expanded upon in this issue on github)
The second part was that SiteMesh3 appears to only buffer pages for decoration when SpringMVC calls .setContentType(...).
This was tripping up since Spring will only trigger this on elements with undefined content type whereas errors have already had their content type defined before they even reach Spring. (expanded upon by my lead in this issue)
My lead managed to solve this by adding a filter after SiteMesh that triggered .setContentType(...) and forced SiteMesh to buffer the page for decoration.
It's a little heavy, since it means that the content type is set twice per request, but it works.
Edit: Originally had a note here asking not to upvote to avoid receiving rep for a solution my lead found, but found a blog post explaining that self-answers don't earn rep - huzzah!
Solution 1:
Check if you have disabled property spring.resources.add-mappings=false. Enabling it could solve the problem. But in my case enabling it removed custom error pages at all.
Solution 2:
Based on comments on github issue https://github.com/sitemesh/sitemesh3/issues/25 declare custom selector inside your SiteMeshFilter:
public class SiteMeshFilter extends ConfigurableSiteMeshFilter {
#Override
protected void applyCustomConfiguration(SiteMeshFilterBuilder builder) {
builder.setCustomSelector(new CustomBasicSelector());
}
private static class CustomBasicSelector extends BasicSelector {
private static final String ALREADY_APPLIED_KEY = BasicSelector.class.getName() + ".APPLIED_ONCE";
public CustomBasicSelector() {
super(true, "text/html");
}
protected boolean filterAlreadyAppliedForRequest(HttpServletRequest request) {
if (request.getDispatcherType().equals(DispatcherType.ERROR)) {
if (Boolean.TRUE.equals(request.getAttribute(ALREADY_APPLIED_KEY + ".ERROR"))) {
return true;
} else {
request.setAttribute(ALREADY_APPLIED_KEY + ".ERROR", true);
return false;
}
}
return super.filterAlreadyAppliedForRequest(request);
}
}
}
On Mac with Oracle java "1.8.0_45" I have create a Jetty base dir with:
# java -jar /Users/afarber/jetty-distribution-9.3.10.v20160621/start.jar jetty.home=/Users/afarber/jetty-distribution-9.3.10.v20160621 jetty.base=/Users/afarber/jetty-base --add-to-startd=http,servlet,webapp,resources,ext,fcgi,websocket,proxy-protocol,deploy
INFO: ext initialised in ${jetty.base}/start.d/ext.ini
INFO: resources initialised in ${jetty.base}/start.d/resources.ini
INFO: server initialised (transitively) in ${jetty.base}/start.d/server.ini
INFO: http initialised in ${jetty.base}/start.d/http.ini
INFO: servlet initialised in ${jetty.base}/start.d/servlet.ini
INFO: fcgi initialised in ${jetty.base}/start.d/fcgi.ini
INFO: proxy-protocol initialised in ${jetty.base}/start.d/proxy-protocol.ini
INFO: webapp initialised in ${jetty.base}/start.d/webapp.ini
INFO: websocket initialised in ${jetty.base}/start.d/websocket.ini
MKDIR: ${jetty.base}/lib
MKDIR: ${jetty.base}/lib/ext
MKDIR: ${jetty.base}/resources
MKDIR: ${jetty.base}/webapps
INFO: Base directory was modified
Then I have put $JETTY_BASE/webapps/ws-servlet-0.1-SNAPSHOT.war produced by the very simple Maven project out of -
WsServlet.java
public class WsServlet extends WebSocketServlet
{
#Override
public void configure(WebSocketServletFactory factory) {
factory.register(EchoListener.class);
}
}
EchoListener.java
public class EchoListener implements WebSocketListener {
private static final Logger LOG = Log.getLogger(EchoListener.class);
private Session mSession;
#Override
public void onWebSocketConnect(Session session) {
LOG.info("onWebSocketConnect {}", session);
mSession = session;
}
#Override
public void onWebSocketText(String message) {
LOG.info("onWebSocketText {}", message);
if (mSession != null && mSession.isOpen()) {
mSession.getRemote().sendString("ECHO: " + message, null);
}
}
}
Finally I have created the $JETTY_BASE/webapps/ws.xml file pointing to the WAR-file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN"
"http://www.eclipse.org/jetty/configure_9_0.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/ws</Set>
<Set name="war"><SystemProperty name="jetty.base"/>/webapps/ws-servlet-0.1-SNAPSHOT.war</Set>
</Configure>
When I start Jetty and then connect to it using simple JavaScript code in browser var ws = new WebSocket("//127.0.0.1:8080/ws"); or the Simple Web Socket Client extension for Chrome the error comes:
# java -Dorg.eclipse.jetty.LEVEL=DEBUG -jar /Users/afarber/jetty-distribution-9.3.10.v20160621/start.jar jetty.base=/Users/afarber/jetty-base
....
WARN:oejs.ProxyConnectionFactory:qtp1993134103-12: Bad character 13 for SelectChannelEndPoint#26ba5622{/127.0.0.1:49883<->8080,Open,in,out,-,-,0/30000,ProxyConnection#49376d8e}{io=1/0,kio=1,kro=1}
Here is the full Jetty log, what have I missed here please?
UPDATE:
I have also tried connecting to ws://127.0.0.1:8080/ws-servlet-0.1-SNAPSHOT and tried adding annotations like #WebServlet(name = "WsServlet", urlPatterns = { "/ws" })- but that does not help. Also I have tried the older version 9.3.9.v20160517.
UPDATE 2:
Is the root cause the PROXY Protocol, which I have to use at my production server, because I offload SSL and normal connections to HAProxy? From the doc I read that 13 is sent as the first byte.
UPDATE 3:
The problem has been solved by adding a trailing slash: ws://127.0.0.1:8080/ws/
Given error:
INFO: Starting service Catalina Feb 15, 2016 2:23:09 PM
org.apache.catalina.core.StandardEngine startInternal INFO: Starting
Servlet Engine: Apache Tomcat/8.0.23 Feb 15, 2016 2:23:09 PM
org.apache.catalina.util.SessionIdGeneratorBase createSecureRandom
INFO: Creation of SecureRandom instance for session ID generation
using [SHA1PRNG] took [116] milliseconds. Feb 15, 2016 2:23:09 PM
org.apache.catalina.core.ContainerBase startInternal SEVERE: A child
container failed during start java.util.concurrent.ExecutionException:
org.apache.catalina.LifecycleException: Failed to start component
[StandardEngine[Catalina].StandardHost[localhost].StandardContext[/storyboard]]
at java.util.concurrent.FutureTask.report(FutureTask.java:122) at
java.util.concurrent.FutureTask.get(FutureTask.java:192) at
org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:917)
at
org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:871)
at
org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at
org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1409)
at
org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1399)
at java.util.concurrent.FutureTask.run(FutureTask.java:266) at
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745) Caused by:
org.apache.catalina.LifecycleException: Failed to start component
[StandardEngine[Catalina].StandardHost[localhost].StandardContext[/storyboard]]
at
org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154)
... 6 more Caused by: java.lang.NoClassDefFoundError:
com/j256/ormlite/support/ConnectionSource at
java.lang.Class.getDeclaredFields0(Native Method) at
java.lang.Class.privateGetDeclaredFields(Class.java:2575) at
java.lang.Class.getDeclaredFields(Class.java:1908) at
org.apache.catalina.util.Introspection.getDeclaredFields(Introspection.java:106)
at
org.apache.catalina.startup.WebAnnotationSet.loadFieldsAnnotation(WebAnnotationSet.java:256)
at
org.apache.catalina.startup.WebAnnotationSet.loadApplicationListenerAnnotations(WebAnnotationSet.java:86)
at
org.apache.catalina.startup.WebAnnotationSet.loadApplicationAnnotations(WebAnnotationSet.java:63)
at
org.apache.catalina.startup.ContextConfig.applicationAnnotationsConfig(ContextConfig.java:334)
at
org.apache.catalina.startup.ContextConfig.configureStart(ContextConfig.java:774)
at
org.apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.java:305)
at
org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
at
org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:90)
at
org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5066)
at
org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
... 6 more Caused by: java.lang.ClassNotFoundException:
com.j256.ormlite.support.ConnectionSource at
org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1305)
at
org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1157)
... 20 more
Web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<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" version="3.1">
<servlet>
<servlet-name>UploadImage</servlet-name>
<servlet-class>com.home.storyboard.UploadServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>UploadCanvas</servlet-name>
<servlet-class>com.home.storyboard.UploadCanvas</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UploadImage</servlet-name>
<url-pattern>/uploadimage</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>UploadCanvas</servlet-name>
<url-pattern>/uploadcanvas</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>StoryServlet</servlet-name>
<servlet-class>com.home.storyboard.StoryServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>StoryServlet</servlet-name>
<url-pattern>/StoryServlet</url-pattern>
</servlet-mapping>
<listener>
<description>ServletContextListener</description>
<listener-class>com.home.storyboard.StartupListener</listener-class>
</listener>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
StartupListener
package com.home.storyboard;
import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.jdbc.JdbcConnectionSource;
import java.sql.SQLException;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import com.home.storyboard.DAOdb;
public class StartupListener implements ServletContextListener{
private final static String DATABASE_URL = "jdbc:sqlite:testdb.db";
ConnectionSource connectionSource = null;
#Override
public void contextInitialized(ServletContextEvent sce) {
try {
// create our data-source for the database
connectionSource = new JdbcConnectionSource(DATABASE_URL);
DAOdb db = new DAOdb(connectionSource);
sce.getServletContext().setAttribute("db", db);
}catch(SQLException e){
System.out.println(e.getMessage());
}
}
#Override
public void contextDestroyed(ServletContextEvent sce) {
// destroy the data source which should close underlying connections
DAOdb db = (DAOdb)sce.getServletContext().getAttribute("db");
db.close();
}
}
DAOdb class
package com.home.storyboard;
import java.sql.SQLException;
import java.util.List;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.dao.DaoManager;
import com.j256.ormlite.dao.GenericRawResults;
import com.j256.ormlite.table.TableUtils;
import com.j256.ormlite.support.ConnectionSource;
public class DAOdb {
// we are using the in-memory H2 database
private final ConnectionSource connectionSource;
private Dao<User, Integer> userDAO;
private Dao<Profile,Integer> profileDAO;
private Dao<Story, Integer> storyDAO;
private String lastError;
public DAOdb(ConnectionSource connectionSource){
this.connectionSource=connectionSource;
try{
userDAO = DaoManager.createDao(connectionSource, User.class);
TableUtils.createTable(connectionSource, User.class);
profileDAO = DaoManager.createDao(connectionSource, Profile.class);
TableUtils.createTable(connectionSource, Profile.class);
storyDAO = DaoManager.createDao(connectionSource, Story.class);
TableUtils.createTable(connectionSource, Story.class);
}catch(SQLException e){
lastError = e.getMessage().toString();
}
}
/**
* DAO Functions to fetch data
*/
public void addStory(Story S) {
try{
storyDAO.create(S);
lastError = null;
} catch (Exception e) {
lastError = e.getMessage().toString();
}
}
public List<Story> getStoriesbyUsername(String username) {
String uname =username;
List<Story> storyList = null;
User user = getUserbyUsername(uname);
Integer uid =user.getId();
try{
GenericRawResults<String[]> stories = storyDAO.queryRaw(
"select count(*) from stories where userid = uid");
// there should be 1 result
List<String[]> results = stories.getResults();
// the results array should have 1 value
Integer usercount = results.size();
// this should print the number of orders that have this account-id
if(usercount<=0){
lastError="'No story exists by username'+' '+ username";
}else{
storyList = storyDAO.queryBuilder()
.where()
.eq(Story.USERID_FIELD_NAME, uid)
.query();
}
}catch(SQLException e){
lastError = e.getMessage().toString();
}
return storyList;
}
}
Your question is far too long and involved. The important part of it is this caused by exception:
java.lang.ClassNotFoundException: com.j256.ormlite.support.ConnectionSource at ...
For some reason your application does not have the ConnectionSource class. Maybe you are not including both the ORMLite JDBC as well as core jar? Make sure to follow the getting started documentation which talks about this:
Users that are connecting to SQL databases via JDBC connections will need to download the ormlite-jdbc-4.48.jar and ormlite-core-4.48.jar files. For use with Android applications, you should download the ormlite-android-4.48.jar and ormlite-core-4.48.jar files instead. For either JDBC or Android you will also need the ormlite-core release which has the ORMLite backend implementations.
If you are using a war, find the jar location and make sure both ORMLite jars are there. If you already have the core in your application then I'm not sure what is going wrong.
Hope this helps.
Class not found exception was resolved after uploading Ormlite core and Ormlite jdbc jars in the lib/ext folder of Java JRE. This is not the optimum solution. But for now it works for me.
I'm trying to get EJB to work with Glassfish v3. I'm working on a Java EE Web application with Servlets.
When I deploy this web app to Glassfish, it registers the EJB class into the
java:global JNDI tree. But, when I try to inject an instance of this into my
Servlet I got a NameNotFoundException.
When I look at the logs of my server, the Servlet tries to do the look up in java:comp/env.
Can someone help me to solve this?
Relevant code for the login part:
UserDao.java
#Local
public interface UserDao {
public User find(Long id);
public List<User> findAll();
public List<User> paginate(int offset, int nbentry) throws IllegalArgumentException, IllegalStateException;
public User findUserByUsernameAndPassword(String username, String password);
public User create(User user) throws UserException;
public User update(User user) throws UserException;
public Boolean delete(User user) throws UserException;
public int count();
}
JpaUserDao.java
#Stateless
public class JpaUserDao implements UserDao {
private Logger log = Logger.getLogger(JpaUserDao.class.getSimpleName());
#PersistenceContext(unitName = "YouFood-PU")
private EntityManager em;
#Override
public User create(User user) throws UserException {
try {
em.persist(user);
} catch (Exception e) {
throw new UserException("Creation of the user: " + user
+ " failed, please try later or contact the webmaster");
}
return user;
}
#Override
public User update(User user) throws UserException {
try {
em.persist(em.merge(user));
} catch (Exception e) {
throw new UserException("Update of the user: " + user
+ " failed, please try later or contact the webmaster");
}
return user;
}
#Override
public Boolean delete(User user) throws UserException {
try {
em.remove(em.merge(user));
return true;
} catch (Exception e) {
throw new UserException("Deletion of the user: " + user
+ " failed, please try later or contact the webmaster");
}
}
#Override
public User find(Long id) {
User user = new User();
try {
user = em.find(User.class, id);
return user;
} catch (Exception e) {
return null;
}
}
#Override
public User findUserByUsernameAndPassword(String username, String password) {
User user = null;
try {
log.info("findUserByUsernameAndPassword");
user = (User) em
.createQuery(
"SELECT u FROM User AS u where u.username = :username AND u.password = :password ")
.setParameter("username", username)
.setParameter("password", password).getSingleResult();
return user;
} catch (Exception e) {
e.printStackTrace();
log.severe(e.getStackTrace().toString());
return null;
}
}
#SuppressWarnings("unchecked")
#Override
public List<User> findAll() {
List<User> users = null;
try {
users = (List<User>) em.createQuery("SELECT u FROM User u")
.getResultList();
return users;
} catch (Exception e) {
return null;
}
}
#SuppressWarnings("unchecked")
#Override
public List<User> paginate(int offset, int nbentry)
throws IllegalArgumentException, IllegalStateException {
List<User> users = null;
users = (List<User>) em.createQuery("FROM User").setFirstResult(offset)
.setMaxResults(nbentry).getResultList();
return users;
}
#Override
public int count() {
Number count;
count = (Number) em.createQuery("SELECT COUNT(u.id) FROM User")
.getSingleResult();
return count.intValue();
}
}
Authenticator.java
#Stateless
public class Authenticator {
private String userFullName;
private Long userId;
#EJB
private JpaUserDao userDao;
public Authenticator() {}
public AuthenticationError connect(String username, String password)
throws Exception {
String hashed_password = Authenticator.hash(password, "UTF-8");
User user = null;
user = userDao.findUserByUsernameAndPassword(username,
hashed_password);
if (user == null) {
return AuthenticationError.UserNotFound;
}
this.userFullName = user.toString();
this.userId = user.getId();
return AuthenticationError.Success;
}
public Boolean disconnect(HttpSession session) throws Exception {
try {
session.invalidate();
return true;
} catch (Exception e) {
return false;
}
}
public String getUserFullName() {
return this.userFullName;
}
public Long getUserId() {
return this.userId;
}
/**
*
* Static method
*
* #throws Exception
*
*/
public static String hash(String data, String charset) throws Exception {
MessageDigest md = MessageDigest.getInstance("MD5");
md.reset();
md.update(data.getBytes(charset), 0, data.length());
String hash = new BigInteger(1, md.digest()).toString(16);
return hash;
}
}
LoginServlet.java
#WebServlet("/login")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private Logger log = Logger.getLogger(LoginServlet.class.getSimpleName());
#EJB
private Authenticator auth;
/**
* #see HttpServlet#HttpServlet()
*/
public LoginServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* #see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
log.info("LoginServlet.deGet() call");
request.getRequestDispatcher("/jsp/login.jsp").forward(request, response);
}
/**
* #see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//auth = new Authenticator();
log.info("LoginServlet.dePost() call");
String message = null;
String username = request.getParameter("username");
String password = request.getParameter("password");
log.info("username: " + username);
log.info("password: " + password);
try {
AuthenticationError status = auth.connect(username, password);
System.out.println(status);
switch (status) {
case PasswordMissMatch:
message = "Password missmatch";
log.info(message);
request.setAttribute("error", message);
request.getRequestDispatcher("/jsp/login.jsp").forward(request, response);
break;
case Success:
message = "Your are successfully logged in";
log.info(message);
request.setAttribute("success", message);
request.getSession().setAttribute("loggedIn", true);
request.getSession().setAttribute("full_name", auth.getUserFullName());
request.getSession().setAttribute("user_id", auth.getUserId());
break;
case UserNotFound:
message = "Username provided not found in our record";
log.info(message);
request.setAttribute("error", message);
request.getRequestDispatcher("/jsp/login.jsp").forward(request, response);
break;
}
} catch (GeneralSecurityException e) {
message = e.getMessage();
request.setAttribute("error", message);
} catch (Exception e) {
message = e.getMessage();
request.setAttribute("error", message);
}
request.getRequestDispatcher("/home").forward(request, response);
}
}
Glassfish Deploy log
INFO: closing
ATTENTION: DPL8027: Ignore WEB-INF/sun-web.xml in archive
/Users/guillaume/Documents/workspace/Supinfo/YouFood/nbbuild/web/, as GlassFish
counterpart runtime xml WEB-INF/glassfish-web.xml is present in the same
archive.
INFO: Processing PersistenceUnitInfo [
name: YouFood-PU
...]
INFO: Binding entity from annotated class: com.youfood.entity.Menu
INFO: Bind entity com.youfood.entity.Menu on table Menu
INFO: Binding entity from annotated class: com.youfood.entity.DinningRoom
INFO: Bind entity com.youfood.entity.DinningRoom on table DinningRoom
INFO: Binding entity from annotated class: com.youfood.entity.Item
INFO: Bind entity com.youfood.entity.Item on table Item
INFO: Binding entity from annotated class: com.youfood.entity.TTable
INFO: Bind entity com.youfood.entity.TTable on table TTable
INFO: Binding entity from annotated class: com.youfood.entity.Zone
INFO: Bind entity com.youfood.entity.Zone on table Zone
INFO: Binding entity from annotated class: com.youfood.entity.Country
INFO: Bind entity com.youfood.entity.Country on table Country
INFO: Binding entity from annotated class: com.youfood.entity.User
INFO: Bind entity com.youfood.entity.User on table User
INFO: Binding entity from annotated class: com.youfood.entity.Order
INFO: Bind entity com.youfood.entity.Order on table OrderTable
INFO: Binding entity from annotated class: com.youfood.entity.Restaurant
INFO: Bind entity com.youfood.entity.Restaurant on table Restaurant
INFO: Mapping collection: com.youfood.entity.DinningRoom.zones -> Zone
INFO: Mapping collection: com.youfood.entity.Zone.tables -> TTable
INFO: Mapping collection: com.youfood.entity.Country.restaurants -> Restaurant
INFO: Mapping collection: com.youfood.entity.Restaurant.dinningRoom -> DinningRoom
INFO: Hibernate Validator not found: ignoring
INFO: Unable to find org.hibernate.search.event.FullTextIndexEventListener on the classpath. Hibernate Search is not enabled.
INFO: Initializing connection provider: org.hibernate.ejb.connection.InjectedDataSourceConnectionProvider
INFO: Using provided datasource
INFO: RDBMS: MySQL, version: 5.1.54
INFO: JDBC driver: MySQL-AB JDBC Driver, version: mysql-connector-java-5.1.13 ( Revision: ${bzr.revision-id} )
INFO: Using dialect: org.hibernate.dialect.MySQLDialect
INFO: Disabling contextual LOB creation as JDBC driver reported JDBC version [3] less than 4
INFO: Transaction strategy: org.hibernate.ejb.transaction.JoinableCMTTransactionFactory
INFO: instantiating TransactionManagerLookup: org.hibernate.transaction.SunONETransactionManagerLookup
INFO: instantiated TransactionManagerLookup
INFO: Automatic flush during beforeCompletion(): disabled
INFO: Automatic session close at end of transaction: disabled
INFO: JDBC batch size: 15
INFO: JDBC batch updates for versioned data: disabled
INFO: Scrollable result sets: enabled
INFO: JDBC3 getGeneratedKeys(): enabled
INFO: Connection release mode: auto
INFO: Maximum outer join fetch depth: 2
INFO: Default batch fetch size: 1
INFO: Generate SQL with comments: disabled
INFO: Order SQL updates by primary key: disabled
INFO: Order SQL inserts for batching: disabled
INFO: Query translator: org.hibernate.hql.ast.ASTQueryTranslatorFactory
INFO: Using ASTQueryTranslatorFactory
INFO: Query language substitutions: {}
INFO: JPA-QL strict compliance: enabled
INFO: Second-level cache: enabled
INFO: Query cache: disabled
INFO: Cache region factory : org.hibernate.cache.impl.NoCachingRegionFactory
INFO: Optimize cache for minimal puts: disabled
INFO: Structured second-level cache entries: disabled
INFO: Statistics: disabled
INFO: Deleted entity synthetic identifier rollback: disabled
INFO: Default entity-mode: pojo
INFO: Named query checking : enabled
INFO: Check Nullability in Core (should be disabled when Bean Validation is on): disabled
INFO: building session factory
INFO: Not binding factory to JNDI, no JNDI name configured
INFO: JNDI InitialContext properties:{}
INFO: EJB5181:Portable JNDI names for EJB JpaUserDao: [java:global/YouFood/JpaUserDao, java:global/YouFood/JpaUserDao!com.youfood.dao.UserDao]
INFO: EJB5181:Portable JNDI names for EJB Authenticator: [java:global/YouFood/Authenticator!com.youfood.backoffice.utils.Authenticator, java:global/YouFood/Authenticator]
INFO: WEB0671: Loading application [YouFood] at [/web]
INFO: YouFood a été déployé en 1 279 ms.
Server Log Exception
GRAVE: EJB5070: Exception creating stateless session bean : [Authenticator]
ATTENTION: EJB5184:A system exception occurred during an invocation on EJB Authenticator, method: public com.youfood.backoffice.utils.AuthenticationError com.youfood.backoffice.utils.Authenticator.connect(java.lang.String,java.lang.String) throws java.lang.Exception
ATTENTION: javax.ejb.EJBException: javax.ejb.EJBException: javax.ejb.CreateException: Could not create stateless EJB
at com.sun.ejb.containers.StatelessSessionContainer._getContext(StatelessSessionContainer.java:454)
at com.sun.ejb.containers.BaseContainer.getContext(BaseContainer.java:2547)
at com.sun.ejb.containers.BaseContainer.preInvoke(BaseContainer.java:1899)
at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:212)
at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:88)
at $Proxy150.connect(Unknown Source)
at com.youfood.backoffice.utils.__EJB31_Generated__Authenticator__Intf____Bean__.connect(Unknown Source)
at com.youfood.backoffice.servlet.LoginServlet.doPost(LoginServlet.java:61)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:688)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:770)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1542)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:343)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:217)
at com.opensymphony.sitemesh.webapp.SiteMeshFilter.obtainContent(SiteMeshFilter.java:129)
at com.opensymphony.sitemesh.webapp.SiteMeshFilter.doFilter(SiteMeshFilter.java:77)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:217)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:279)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:161)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:331)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
at com.sun.enterprise.v3.services.impl.ContainerMapper$AdapterCallable.call(ContainerMapper.java:317)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:849)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:746)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1045)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:228)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
at java.lang.Thread.run(Thread.java:680)
Caused by: javax.ejb.EJBException: javax.ejb.CreateException: Could not create stateless EJB
at com.sun.ejb.containers.StatelessSessionContainer$SessionContextFactory.create(StatelessSessionContainer.java:726)
at com.sun.ejb.containers.util.pool.NonBlockingPool.getObject(NonBlockingPool.java:247)
at com.sun.ejb.containers.StatelessSessionContainer._getContext(StatelessSessionContainer.java:449)
... 39 more
Caused by: javax.ejb.CreateException: Could not create stateless EJB
at com.sun.ejb.containers.StatelessSessionContainer.createStatelessEJB(StatelessSessionContainer.java:534)
at com.sun.ejb.containers.StatelessSessionContainer.access$000(StatelessSessionContainer.java:95)
at com.sun.ejb.containers.StatelessSessionContainer$SessionContextFactory.create(StatelessSessionContainer.java:724)
... 41 more
Caused by: com.sun.enterprise.container.common.spi.util.InjectionException: Exception lors de la tentative d'injection de l'élément Remote ejb-ref name=com.youfood.backoffice.utils.Authenticator/userDao,Remote 3.x interface =com.youfood.dao.jpa.JpaUserDao,ejb-link=null,lookup=,mappedName=,jndi-name=com.youfood.dao.jpa.JpaUserDao,refType=Session dans class com.youfood.backoffice.utils.Authenticator : Lookup failed for 'java:comp/env/com.youfood.backoffice.utils.Authenticator/userDao' in SerialContext[myEnv={java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFactory, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl, java.naming.factory.url.pkgs=com.sun.enterprise.naming}
at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl._inject(InjectionManagerImpl.java:703)
at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl.inject(InjectionManagerImpl.java:470)
at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl.injectInstance(InjectionManagerImpl.java:171)
at com.sun.ejb.containers.BaseContainer.injectEjbInstance(BaseContainer.java:1694)
at com.sun.ejb.containers.StatelessSessionContainer.createStatelessEJB(StatelessSessionContainer.java:494)
... 43 more
Caused by: javax.naming.NamingException: Lookup failed for 'java:comp/env/com.youfood.backoffice.utils.Authenticator/userDao' in SerialContext[myEnv={java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFactory, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl, java.naming.factory.url.pkgs=com.sun.enterprise.naming} [Root exception is javax.naming.NamingException: Exception resolving Ejb for 'Remote ejb-ref name=com.youfood.backoffice.utils.Authenticator/userDao,Remote 3.x interface =com.youfood.dao.jpa.JpaUserDao,ejb-link=null,lookup=,mappedName=,jndi-name=com.youfood.dao.jpa.JpaUserDao,refType=Session' . Actual (possibly internal) Remote JNDI name used for lookup is 'com.youfood.dao.jpa.JpaUserDao#com.youfood.dao.jpa.JpaUserDao' [Root exception is javax.naming.NamingException: Lookup failed for 'com.youfood.dao.jpa.JpaUserDao#com.youfood.dao.jpa.JpaUserDao' in SerialContext[myEnv={java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFactory, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl, java.naming.factory.url.pkgs=com.sun.enterprise.naming} [Root exception is javax.naming.NameNotFoundException: com.youfood.dao.jpa.JpaUserDao#com.youfood.dao.jpa.JpaUserDao not found]]]
at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:518)
at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:455)
at javax.naming.InitialContext.lookup(InitialContext.java:392)
at javax.naming.InitialContext.lookup(InitialContext.java:392)
at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl._inject(InjectionManagerImpl.java:599)
... 47 more
Caused by: javax.naming.NamingException: Exception resolving Ejb for 'Remote ejb-ref name=com.youfood.backoffice.utils.Authenticator/userDao,Remote 3.x interface =com.youfood.dao.jpa.JpaUserDao,ejb-link=null,lookup=,mappedName=,jndi-name=com.youfood.dao.jpa.JpaUserDao,refType=Session' . Actual (possibly internal) Remote JNDI name used for lookup is 'com.youfood.dao.jpa.JpaUserDao#com.youfood.dao.jpa.JpaUserDao' [Root exception is javax.naming.NamingException: Lookup failed for 'com.youfood.dao.jpa.JpaUserDao#com.youfood.dao.jpa.JpaUserDao' in SerialContext[myEnv={java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFactory, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl, java.naming.factory.url.pkgs=com.sun.enterprise.naming} [Root exception is javax.naming.NameNotFoundException: com.youfood.dao.jpa.JpaUserDao#com.youfood.dao.jpa.JpaUserDao not found]]
at com.sun.ejb.EjbNamingReferenceManagerImpl.resolveEjbReference(EjbNamingReferenceManagerImpl.java:191)
at com.sun.enterprise.container.common.impl.ComponentEnvManagerImpl$EjbReferenceProxy.create(ComponentEnvManagerImpl.java:1109)
at com.sun.enterprise.naming.impl.GlassfishNamingManagerImpl.lookup(GlassfishNamingManagerImpl.java:776)
at com.sun.enterprise.naming.impl.GlassfishNamingManagerImpl.lookup(GlassfishNamingManagerImpl.java:744)
at com.sun.enterprise.naming.impl.JavaURLContext.lookup(JavaURLContext.java:169)
at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:498)
... 51 more
Caused by: javax.naming.NamingException: Lookup failed for 'com.youfood.dao.jpa.JpaUserDao#com.youfood.dao.jpa.JpaUserDao' in SerialContext[myEnv={java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFactory, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl, java.naming.factory.url.pkgs=com.sun.enterprise.naming} [Root exception is javax.naming.NameNotFoundException: com.youfood.dao.jpa.JpaUserDao#com.youfood.dao.jpa.JpaUserDao not found]
at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:518)
at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:455)
at javax.naming.InitialContext.lookup(InitialContext.java:392)
at javax.naming.InitialContext.lookup(InitialContext.java:392)
at com.sun.ejb.EjbNamingReferenceManagerImpl.resolveEjbReference(EjbNamingReferenceManagerImpl.java:186)
... 56 more
Caused by: javax.naming.NameNotFoundException: com.youfood.dao.jpa.JpaUserDao#com.youfood.dao.jpa.JpaUserDao not found
at com.sun.enterprise.naming.impl.TransientContext.doLookup(TransientContext.java:248)
at com.sun.enterprise.naming.impl.TransientContext.lookup(TransientContext.java:215)
at com.sun.enterprise.naming.impl.SerialContextProviderImpl.lookup(SerialContextProviderImpl.java:77)
at com.sun.enterprise.naming.impl.LocalSerialContextProviderImpl.lookup(LocalSerialContextProviderImpl.java:119)
at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:505)
... 60 more
My guess is that you specified names, mapped names and what have you. This is not needed.
Something like the following should work:
EJB:
#Stateless
public class MyBean {
// ...
}
Servlet:
#WebServlet(urlPatterns="/someurl")
public class MyServlet extends HttpServlet {
#EJB
private MyBean myBean;
#Override
public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// ...
}
}
UPDATE:
After seeing your code, the problem is not the injection of the EJB into the Servlet, but the injection of JpaUserDao in Authenticator.
You are injecting it by class, but this will not work since JpaUserDao implements a business interface: UserDao. Because it implements such an interface, there will be no local-view created. As a result, you have to inject using the interface:
#Stateless
public class Authenticator {
private String userFullName;
private Long userId;
#EJB
private UserDao userDao;
// ...
}
As an extra note, the concept of your Authenticator bean is not going to work. It's a stateless bean and its instance variables will have no meaning to the outside world. Thus, getUserFullName() is not guaranteed to return the result you think it will return. It may happen to work momentarily for you in a test when the container happens to select the same bean instance, but this will not work in general.
Even when you hold on to the reference of an Authenticator, it will still not work. The thing is you get a proxy, and the container will potentially direct every call to it to another instance. Think of it as a URL to servers in a web farm where a browser does a call to. You have no guarantee that two successive will go to the exact same physical server.
The authentication that you're trying to do there should be handled by a bean in the web layer and the authentication details put in the HTTP session (additionally, you should maybe use container authentication as well, but that's a whole other thing that's too off-topic here)
There are several ways for injecting a EJB. The most common and simplest solution would be via Dependency Injection as mentioned Arjan Tijms answer.
Another way would be to get a reference via InitialContext.lookup().
In this approach you can choose which lookup name you pass:
Use the class-name of the declaring Bean-Interface:
String jindiName = BeanInterface.class.getName();
InitialContext ctx = new InitialContext();
BeanInterface bi = ctx.lookup(jndiName);
This also works for a remote lookup from any stand-alone client because the interface is public.
Use the JINDI name of the component naming environment:
String jndiName = "java:comp/env/yourejb"
// same as shown above
This will only work inside the same container because the "outside world" do not have access to to the component naming environment.
For a better understanding of jndi names have a look at this.
I hope this helpes, have Fun!
How do I access a Remote EJB component from a stand-alone java client?
Step 1. Use the no-arg InitialContext() constructor in your code.
The most common problem developers run into is passing specific JNDI bootstrapping properties to InitialContext(args). Some other vendors require this step but GlassFish does not. Instead, use the no-arg InitialContext() constructor.
Step 2. Pass the global JNDI name of the Remote EJB to InitialContext.lookup()
Stand-alone java clients do not have access to a component naming environment (java:comp/env) or to the #EJB annotation, so they must explicitly use the global JNDI name to lookup the Remote EJB. (See here for more information on how global JNDI names are assigned to EJB components) Assuming the global JNDI name of the Remote EJB is "FooEJB" :
For Beans with a 3.x Remote Business interface :
Foo foo = (Foo) new InitialContext().lookup("FooEJB");
Note that in the EJB 3.x case the result of the lookup can be directly cast to the remote business interface type without using PortableRemoteObject.narrow().
For EJB 2.1 and earlier session/entity beans :
Object homeObj = new InitialContext().lookup("FooEJB");
FooHome fooHome = (FooHome)
PortableRemoteObject.narrow(homeObj,FooHome.class);
Foo foo = fooHome.create(...)
Step 3. Include the appropriate GlassFish .jars in the java client's classpath.
For GlassFish 3.
Include $GLASSFISH_HOME/glassfish/lib/gf-client.jar in the client's classpath.
E.g., assuming the application classes are in /home/user1/myclasses and the main client class is acme.MyClient :
java -classpath $GLASSFISH_HOME/glassfish/lib/gf-client.jar:/home/user1/myclasses acme.MyClient
Note that the Java EE 6 API classes are automatically included by gf-client.jar so there is no need to explicitly add javaee.jar to the classpath. gf-client.jar refers to many other .jars from the GlassFish installation directory so it is best to refer to it from within the installation directory itself rather than copying it(and all the other .jars) to another location.
Note: gf-client.jar is located in $GLASSFISH_HOME/modules/gf-client.jar in GlassFish v3.