Not Found in ExternalContext as a Resource Error (Amazon Elastic Beanstalk / Spring Boot / JSF + Primefaces) - spring-boot

I created an app using Spring Boot, JSF + Primefaces. I deployed it to Amazon Elastic Beanstalk, and set the environment variables that project needed to use.
When I tried to access my website, I got this error message:
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Thu Mar 04 07:21:33 UTC 2021
There was an unexpected error (type=Not Found, status=404).
/login.xhtml Not Found in ExternalContext as a Resource
Here is my Faces Config (as java class):
package com.jsf;
#SpringBootApplication
#Configuration
#ComponentScan("com.jsf")
public class HelloJsfApplication {
public static void main(String[] args) {
SpringApplication.run(HelloJsfApplication.class, args);
}
// JSF Configration Başlangıc
#Bean
public ServletRegistrationBean<FacesServlet> facesServletRegistraiton() {
ServletRegistrationBean<FacesServlet> registration = new ServletRegistrationBean<FacesServlet>(
new FacesServlet(), new String[] { "*.xhtml" });
registration.setName("Faces Servlet");
registration.setLoadOnStartup(1);
registration.addUrlMappings("*.xhtml");
return registration;
}
#Bean
public ServletContextInitializer servletContextInitializer() {
return servletContext -> {
servletContext.setInitParameter("com.sun.faces.forceLoadConfiguration", Boolean.TRUE.toString());
servletContext.setInitParameter("primefaces.THEME", "bootstrap");
// Primefaces client browser tarafında kontrol edilebilme örneğin textbox 10
// karakter olmalı vs..
servletContext.setInitParameter("primefaces.CLIENT_SIDE_VALIDATION", Boolean.TRUE.toString());
// Xhtml sayfalarında commentlerin parse edilmemesi.
servletContext.setInitParameter("javax.faces.FACELETS_SKIP_COMMENTS", Boolean.TRUE.toString());
// primefaces icon set için
servletContext.setInitParameter("primefaces.FONT_AWESOME", Boolean.TRUE.toString());
};
}
#Bean
public ServletListenerRegistrationBean<ConfigureListener> jsfConfigureListener() {
return new ServletListenerRegistrationBean<ConfigureListener>(new ConfigureListener());
}
// JSF Configration Sonu
}
my faces config file under webapp/WEB-INF folder:
<?xml version="1.0" encoding="UTF-8"?>
<faces-config 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-facesconfig_2_2.xsd"
version="2.2">
<application>
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>
</faces-config>
and as you see, all my xhtml files are under webapp folder:
my application.properties file (using java params):
server.servlet.context-path = ${CONTEXT_PATH}
server.port = ${PORT}
spring.datasource.url = ${SPRING_DATASOURCE_URL}
spring.datasource.username = ${SPRING_DATASOURCE_USERNAME}
spring.datasource.password = ${SPRING_DATASOURCE_PASSWORD}
spring.jpa.properties.hibernate.dialect = ${SPRING_JPA_DATABASE_PLATFORM}
# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto = ${SPRING_JPA_HIBERNATE_DDL_AUTO}
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=${SPRING_JPA_HIBERNATE_LOB_CREATION}
spring.datasource.driver-class-name=${SPRING_DATASOURCE_DRIVERCLASSNAME}
and here are java parameters that I defined on Amazon (I will not post db params for security reasons):
PORT=5000
CONTEXT_PATH=/
SPRING_DATASOURCE_DRIVERCLASSNAME=org.postgresql.Driver
...
and so on.
Really I run out of solutions. With same packaged jar, I deployed to Heroku with same environment parameters, and it works flawlessly.
Where I am doing wrong with Amazon Elastic Beanstalk?
Kind regards.

I found the problem.
Maven, does not add *.xhtml files inside "jar" package.
Here is the ss of decompiled version of jar packaging (with jd-gui)
..and here is the ss of war packaging:
so if you are think that you did everything correct during development and managing after, check the packaging type.

Related

How to disable SpringBoot autoconfiguration for TomcatServletWebServerFactory in order for a custom spring-starter to provide it?

so I was writing my own SpringBootStarter which was supposed to enable the JNDI lookup in the embedded tomcat of a SpringBoot application.
My sample SpringBoot application has a dependency of my custom SpringBootStarter, which in turn has a dependency on the spring-boot-starter-web. If I create a Configuration class like the following inside the sample SpringBoot application everything works perfectly:
#Configuration
public class SampleSpringBootAppConfig {
#Bean
public TomcatServletWebServerFactory tomcatFactory() {
return new TomcatServletWebServerFactory() {
#Override
protected TomcatWebServer getTomcatWebServer(org.apache.catalina.startup.Tomcat tomcat) {
System.out.println("CONFIGURING CUSTOM TOMCAT WEB SERVER FACTORY ");
tomcat.enableNaming();
return super.getTomcatWebServer(tomcat);
}
#Override
protected void postProcessContext(Context context) {
ContextResource resource = new ContextResource();
resource.setName("myDataSource");
resource.setType(DataSource.class.getName());
resource.setProperty("driverClassName", "org.postgresql.Driver");
resource.setProperty("url", "jdbc:postgresql://localhost:5432/postgres");
resource.setProperty("username", "postgres");
resource.setProperty("password", "postgres");
context.getNamingResources()
.addResource(resource);
}
};
}
Because SpringBoot finds a custom Bean, there won't be an autoconfigured default one / it is overridden and the JNDI is successfully enabled.
However, as soon as I extract this Bean configuration into my auto-configure module of my custom SpringBoot Starter, the following exception is thrown while trying to start the sample SpringBoot application:
org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.context.ApplicationContextException: Unable to start ServletWebServerApplicationContext due to multiple ServletWebServerFactory beans : tomcatServletWebServerFactory,tomcatFactory
I reckon this is due to SpringBoot not finding a customized Bean and therefore creating an autoconfigured default one which also won't be overridden. So now there will be two ServletWebServerFactory beans, the default one and the one from my auto- configure module.
What i tried so far (to no avail) :
annotating my custom Bean with #Primary
setting spring.main.allow-bean-definition-overriding to true
Is there any way to make SpringBoot not initialize a autoconfigured default bean, or any other possible solution to this?
try this
#AutoConfigureBefore(ServletWebServerFactoryAutoConfiguration.class)
I was able to solve this myself by excluding the responsible AutoConfiguration class:
#SpringBootApplication ( exclude = ServletWebServerFactoryAutoConfiguration.class)

Spring property placeholders in application-context.xml inside dependency jar

For my spring boot application I use annotation based configuration and a WebApplicationInitalizer.
One of my dependencies provides a spring configuration in an xml, included in the jar. I use #ImportResource to load the context xml. This seems to work, except for the fact that inside this xml, there are property placeholders, for example ${poolsize:10}
Apparently, spring does not automatically replace these placeholders (I get a NumberFormatException). Is there some extra configuration I need to add?
Our startup class:
public class Application implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext container) throws ServletException {
// Create the 'root' Spring application context
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
// config
rootContext.register(JmsConfiguration.class);
// Manage the lifecycle of the root application context
container.addListener(new ContextLoaderListener(rootContext));
}
}
And the configuration class (we use spring-jms):
#Configuration
#EnableJms
#ComponentScan(basePackages = { "..." })
public class JmsConfiguration implements JmsListenerConfigurer {
// config for jms listener and jaxb, nothing to do with property handling
}
Perhaps I'm mistaken in thinking that using a WebapplicationInitializer is how to use spring boot. Perhaps we don't even need spring boot? The only spring boot related dependency we use is:
<dependency>
<!-- Import dependency management from Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.3.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
Spring dependencies we use:
org.springframework:spring-context:jar:4.3.8.RELEASE:compile
org.springframework:spring-jms:jar:4.3.8.RELEASE:compile
org.springframework:spring-oxm:jar:4.3.8.RELEASE:compile
org.springframework:spring-context:jar:4.3.8.RELEASE:compile
org.springframework:spring-beans:jar:4.3.8.RELEASE:compile
I figured it out thanks #M. Deinum
We don't need spring boot to use the WebApplicationInitializer, but (at least without spring boot) we have to declare our own PropertySourcesPlaceholderConfigurer:
#Configuration
#ImportResource(locations = {"classpath*:/library-context.xml"})
public class MyConfiguration {
#Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
NB. This works out of the box in spring boot thanks to #EnableAutoConfiguration and #PropertyPlaceholderAutoConfiguration which contains the exact same PropertySourcesPlaceholderConfigurer bean

Name is not bound in this Context... Datasource not found

Am building a small Jersey (1.9) REST Service and having a Java class as sub-resource where I connect to local database (Postgres 9.3).
For the datasource I have already add the entries in Context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/userProfile">
<Resource
auth="Container"
driverClassName="org.postgresql.Driver"
maxActive="100"
maxIdle="30"
maxWait="10000"
name="jdbc/apiUserProfile"
password="postgres"
type="javax.sql.DataSource"
url="jdbc:postgresql://localhost:5432/apiUserProfile"
username="postgres"/>
</Context>
When I run the application and call the following resource:
http://localhost:8084/userProfile/rest/user/conn
the page is blank - no content- and the tomcat (8.0) on netbeans (8.1) is throwing Error: Null Pointer Exception
javax.naming.NameNotFoundException: Name [jdbc/apiUserProfile] is not bound in this Context. Unable to find [jdbc].
at org.apache.naming.NamingContext.lookup(NamingContext.java:818)
at org.apache.naming.NamingContext.lookup(NamingContext.java:166)
at org.apache.naming.SelectorContext.lookup(SelectorContext.java:157)
at javax.naming.InitialContext.lookup(InitialContext.java:411)
at net.rest.dao.DbConn.apiUserProfileConn(DbConn.java:23)
at net.rest.service.userProfile.returnDatabaseStatus(userProfile.java:51)
I also already have the JAR files in the librairies:
lib/mysql-connector-java-5.1.39-bin.jar
lib/postgresql-9.3-1100-jdbc4.jar
and here is the sub-resource class for the datasource connection:
package net.rest.dao;
import javax.naming.*;
import javax.sql.*;
public class DbConn {
private static DataSource DbConn = null;
private static Context context = null;
public static DataSource apiUserProfileConn() throws Exception {
if(DbConn != null){
return DbConn;
}
try {
if(context == null){
context = new InitialContext();
}
DbConn = (DataSource) context.lookup("jdbc/apiUserProfile");
}
catch (Exception e) {
e.printStackTrace();
}
return DbConn;
}
}
Any Idea pls. how to fix this..
Many Thanks
a.kasbi
The issue is resolved now.. the Apache Tomcat Doc was very helpful:
http://localhost:8080/docs/jndi-datasource-examples-howto.html
http://localhost:8080/docs/jndi-datasource-examples-howto.html#PostgreSQL
The solution for me was adding the following into context.xml under: META-INF
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/apiRest">
<Resource name="jdbc/apiUserProfile" auth="Container"
type="javax.sql.DataSource" driverClassName="org.postgresql.Driver"
url="jdbc:postgresql://127.0.0.1:5432/apiUserProfile"
username="postgres" password="postgres" maxTotal="20" maxIdle="10"
maxWaitMillis="-1"/>
</Context>
and the following in web.xml:
<resource-ref>
<description>postgreSQL Datasource example</description>
<res-ref-name>jdbc/apiUserProfile</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
The lookup argument in the java Class for the Datasource connection:
...
DbConn = (DataSource) context.lookup("java:/comp/env/jdbc/apiUserProfile");
...
Thanks

Spring+Jersey transactional annotation

Created boilerplate project to expose RESTful API to JPA enabled database. It's using the following versions:
- Spring 3.2.6
- Hibernate 4.3.0
- Jersey 2.5.1
I finally was able to get them playing together, but still some question remains. Here's one of the most puzzling things (see excerpt from REST service class)
#Service
#Path("resources")
#Produces({ MediaType.APPLICATION_JSON })
#Consumes({ MediaType.APPLICATION_JSON })
#Transactional
public class ResourceServices extends AbstractServices<Resource> {
...
}
if class is annotated with #Service, #Transactional annotation is ignored and transaction for the methods is not started. However, when changed to #Component, everything works fine. Couldn't figure out, why.
The entire project can be seen here
I got puzzled by this as well, but finally figured this out.
The jersey-spring module will only import #Component beans from your context. There literally is a beanClass.isAnnotationPresent(Component.class) check in SpringComponentProvider.
Otherwise it appears to only create half-baked request-scoped instances of the bean (I traced this with Thread.dumpStack in service constructor). They seem to have dependency injection, but not AOP.
There's a number of JIRA items already in Jersey's issue tracker: JERSEY-2495, JERSEY-2059, JERSEY-2301
UPDATE: My pull request for these has been merged, this should be fixed in Jersey 2.11.
As mentioned in another answer SpringComponentProvider gets a bean created by Jersey and registers it in the Spring context, but in this case you don't get Spring AOP.
I managed to get it working with AOP the other way around: the bean is created by Spring (so in fact it is a proxy because of AOP) and then is registered in Jersey.
But I had to fix a bug in Jersey's ModelHelper class: https://github.com/jersey/jersey/pull/90
Without this fix Jersey was not able to find the #Path annotation in the Spring proxy.
This is the basic structure:
public class MyApplication extends ResourceConfig {
#Inject
public MyApplication(ServletContext servletContext) {
super(JSONController.class, XSSSecurityFilter.class, JacksonFeature.class);
WebApplicationContext springFactory = WebApplicationContextUtils.getWebApplicationContext(servletContext);
// TODO: scan entire Spring factory for beans annotated with #Path and register them, so we don't need to do this manually.
// Letting Jersey register the beans does not work because in this case Spring will not intercept the calls.
register(springFactory.getBean(UserServiceFacade.class));
}
}
The reason is your Spring has a different container for its annotations and jersey has a different container for its annotations , in order to access your beans in spring container you can refer to the below code ;
I beg to differ from the version your using, I haven't tried with the latest version of jersey:
load spring through web.xml like shown below as normal spring confifuration:
<servlet>
<servlet-name>project-spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:project-spring-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>project-spring</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
Now load your jersey Resources through Application as shown below:
#ApplicationPath("/rest")
public class ResourceLoader extends Application
{
/* (non-Javadoc)
* #see javax.ws.rs.core.Application#getClasses()
*/
#Override
public Set<Class<?>> getClasses()
{
Set<Class<?>> classes = new HashSet<Class<?>>();
loadResourceClasses(classes);
return classes;
}
private void loadResourceClasses(Set<Class<?>> classes)
{
classes.add(StudentResource.class);
}
}
Then in your resource:
#Path("student")
class StudentResource
{
private StudentService studentService;
StudentResource(#Context ServletContext servletContext)
{
ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
this.studentService= applicationContext.getBean(StudentService .class);
}
}
You can get your ApplicationContext where all the beans have been initailized using WebApplicationContextUtils of spring pass the servlet context, and get your bean

Spring #Scheduled is executing task twice when using annotations

I have made task using Spring #Scheduled annotation, but for some reason it is executing task twice. My Spring Framework version is 3.0.2.
#Service
public class ReportService {
#Scheduled(fixedDelay=1000 * 60 * 60* 24)
#Transactional
public void dailyReportTask()
{
... code here ...
}
}
Here is my XML:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.0.xsd">
<task:scheduler id="taskScheduler" />
<task:executor id="taskExecutor" pool-size="1" />
<task:annotation-driven executor="taskExecutor"
scheduler="taskScheduler" />
</beans>
it is happening because of context listener
Just remove
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
from web.xml it should work.
I had this same problem, and I eventually found out that the problem was occurring as a result of the beans being created in the root context as well as the servlet context.
So, to fix this, you need to separate the creation of the beans into the appropriate contexts.
This answer explains really well how to that and was what fixed my problem.
According to this post: http://www.vodori.com/blog/spring3scheduler.html
Spring 3.0.0 Release had a bug where
web apps with a task scheduler would
end up executing scheduled methods
twice. This has been resolved in
Spring 3.0.1.
There has been another bug reported which affects Version/s: 3.0.2
https://jira.springsource.org/browse/SPR-7216
Which should be fixed in Version/s: 3.0.3.
I just had this problem recently and it was caused by my app being deployed twice in Tomcat by eclipse. The problem was that I had renamed my application in eclipse but the "wb-module deploy-name" specified in the "org.eclipse.wst.common.component" .settings file still had the old name.
In the tomcat manager, I could see that I had 2 apps running with different names.
Where are you actually running it? Your PC? Single server? 2 x load-balanced app servers?
Could be it's running on (a) your PC and (b) your server, so it just looks like it's running twice, if you see what I mean: it's correctly running once, just on two distinct locations.
Check if you have any manual scheduler config in your configuration files (through Java/XML). I'ved the same problem, and I discover that my config was loading my scheduler class twice:
In Java:
package com.mywork.br.myschuedulerpackage;
{...}
#Configuration
#EnableScheduling
public class SchedulerConfiguration {
#Bean
public CTXDataImporterScheduler ctxDataImporterScheduler() {
return new CTXDataImporterScheduler();
}
}
In XML applicationContext.xml:
<context:component-scan base-package="com.mywork.br.myschuedulerpackage" />
And in my scheduler class, I had #Component annotation thats was catch by the component scan and loaded a second time causing the #scheduler methods being executed twice.
I removed the Java config and then is working well now!
To solve twice-working of #Scheduled method just delete ContextLoaderListener from you web.xml (if you use web.xml-based application):
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Or if you use WebApplicationInitializer-based application just delete a string that adds ContextLoaderListener:
package com.dropbox.shortener.config;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
public class DropboxShortenerWebApplicationInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext container) throws ServletException {
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(AppConfig.class);
// (!) Delete the next string
// container.addListener(new ContextLoaderListener(rootContext));
AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
dispatcherContext.register(WebConfig.class);
ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
setupCharEncodingFilter(container);
}
private void setupCharEncodingFilter(ServletContext container) {
container.setInitParameter("defaultHtmlEscape", "true");
FilterRegistration charEncodingFilterReg = container.addFilter("CharacterEncodingFilter", CharacterEncodingFilter.class);
charEncodingFilterReg.setInitParameter("encoding", "UTF-8");
charEncodingFilterReg.setInitParameter("forceEncoding", "true");
charEncodingFilterReg.addMappingForUrlPatterns(null, false, "/*");
}
}
Use #Scope(value=ConfigurableBeanFactory.SCOPE_PROTOTYPE) on your bean
Disabling below will work.
<!-- <listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener> -->
One solution I would suggest is to do component scat like this
-In application context
<context:component-scan base-package="com.abc.cde.dao" />
In yourservlet-servlet.xml
<!-- package that had all the #Controller classes -->
I this way the servlet is only loaded if the web.xml is loaded
Similar can be done for task

Resources