FacesContext in a #WebListener - jsf-2.2

I need build some jsf urls in a #WebListener.
I thought I could use a snippet of code like this one
final FacesContext currentInstance = FacesContext.getCurrentInstance();
final String actionURL = currentInstance.getApplication().getViewHandler()
.getActionURL(currentInstance, viewId);
because the javadoc of the .getCurrentInstance() asserts it can be "[...] called during application initialization or shutdown" but it doesn't work because it returns null.
Do I miss somenthing? Any other way to build a url given the viewId?
Thanks

The FacesContext.getCurrentInstance() method does return a valid facesContext instance between the linstener (com.sun.faces.config.ConfigureListener in my case) initialization and the first run of the FacesServlet, in which the facesContext set up by the listener is released.
My problem was I was letting Wildfly add the listener and it was added just after mine. Forcing its loading in the web-fragment.xml/web.xml
<listener>
<listener-class>com.sun.faces.config.ConfigureListener</listener-class>
</listener>
<listener>
<listener-class>com.company.project.somepackages.Listener</listener-class>
</listener>
let my listener have the context initialized.
That code above however didn't work because the viewHandler when tries to resolve the contextPath uses the externalContext.getRequestContextPath() method, that obviously returns null, and not the externalContext.getApplicationContextPath() that could return the correct value.

Related

spring4gwt error:Spring bean not found: querySenior

I am trying to make gwt-2.7 work with spring-4.2.3.Configurations are:
web.xml
<!-- spring config -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Spring GWT integration -->
<servlet>
<servlet-name>springGwtRemoteServiceServlet</servlet-name>
<servlet-class>org.spring4gwt.server.SpringGwtRemoteServiceServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>springGwtRemoteServiceServlet</servlet-name>
<url-pattern>/idp_web/service/*</url-pattern>
</servlet-mapping>
applicationContext.xml
<beans
...
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
....
default-lazy-init="true">
<!-- auto-inject bean by annotation mechanism -->
<context:component-scan
base-package="com.vsi.idp.analysis.server,
com.vsi.idp.base.server,
com.vsi.idp.kpi.server,
com.vsi.idp.map.server,//SeniorQueryServiceImpl is under this package
com.vsi.idp.statistics.server" />
//other configurations
</beans>
GWT services
#RemoteServiceRelativePath("service/querySenior")
public interface SeniorQueryService extends RemoteService{...}
service impl
#Service("querySenior")
public class SeniorQueryServiceImpl extends RemoteServiceServlet implements SeniorQueryService{...}
Spock unit test works fine
#ContextConfiguration(locations = "file:war/WEB-INF/applicationContext.xml")
public class SeniorQueryServiceImplTest extends Specification{
#Autowired
SeniorQueryServiceImpl service
def "query by full address"(){
//blabla
}
}
Running gwt project tells:
Failed to load resource: the server responded with a status of 500 (Server Error)
Error stack looks like:
[WARN] Exception while dispatching incoming RPC call
java.lang.IllegalArgumentException: Spring bean not found: querySenior
at org.spring4gwt.server.SpringGwtRemoteServiceServlet.getBean(SpringGwtRemoteServiceServlet.java:96)
at org.spring4gwt.server.SpringGwtRemoteServiceServlet.getBean(SpringGwtRemoteServiceServlet.java:55)
at org.spring4gwt.server.SpringGwtRemoteServiceServlet.processCall(SpringGwtRemoteServiceServlet.java:31)
at com.google.gwt.user.server.rpc.RemoteServiceServlet.processPost(RemoteServiceServlet.java:373)
I think:
1,"500(server error)" tells that gwt has recognized spring service
2,spring service unit test works fine,so spring configuration is right
The problem may come from spring4gwt,and how to solve this problem?
This really should be a working solution.
SpringGwtRemoteServiceServlet#getBean
protected Object getBean(String name) {
WebApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
if (applicationContext == null) {
throw new IllegalStateException("No Spring web application context found");
}
if (!applicationContext.containsBean(name)) {
throw new IllegalArgumentException("Spring bean not found: " + name);
}
return applicationContext.getBean(name);
}
We can see that Exception comes because there was no bean in applicationContext
Try to implicitly declare this bean in applicatinContext.
Recomendation
If you are a fun on RPC I recommend you to take a look at GWTP and their GWT dispatch module.
Approach is similar to Spring4Gwt, but it is much better to communicate with Command pattern.
With regular GWT RPC approach services in big projects becomes a mess of really lot's of
methods at one place, and you will be not happy to create a new Async pair for any new method.
Or the best approach will be to communicate with JSON and avoid GWT serialization approach, your will be happy and easy to integrate with you App later.

Spring unit test 404\unknown url in mock mvc

I would like to test that when an unknown url is requested and a 404 error is generated that my web app actually redirects to the right place.
I havent been able to get this working, I think because tomcat is handling the 404 errors so the forwardedUrl is always null for the tests. I know this works in reality because if I enter some rubbish into the url my app does redirect to my custom page.
My unit test looks like:
#Test
public void testUnknownUrl() throws Exception {
mockMvc.perform(get("/url_doesnt_exist"))
.andExpect(status().isNotFound())
.andExpect(forwardedUrl("/static/error/Sorry.html"));
}
My web.xml configuration is:
<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>/</url-pattern>
</servlet-mapping>
<error-page>
<error-code>404</error-code>
<location>/static/error/Sorry.html</location>
</error-page>
The mapping for /static is defined in my spring config like:
<resources mapping="/static/**" location="/resources/" />
Ultimately I would like to mock a request to an unknown url and then check that the page being returned is /static/error/Sorry.html.
Am I doing something wrong or is this not the way to handle 404 etc in spring? The check of the forwarded url in the unit test is always null.
A slightly different question but related all the same is, at what point does the tomcat error handling get invoked over and above the spring controller advice handling?
I'm not sure about the configuration with the /static path in your web.xml, it shouldn't be like that depending on your dispatcher-servlet (default name) configuration; but as far as I can tell you are in the right path.
This is what I have for mine:
#WebAppConfiguration
#ActiveProfiles("development")
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = AppConfig.class)
public class ErrorControllerTest {
#Autowired
private WebApplicationContext context;
private MockMvc mockMvc;
#Before
public void setUp() {
mockMvc = MockMvcBuilders.webAppContextSetup(context)/*.alwaysExpect(status().isOk())*/.build();
}
#Test
public void testError() throws Exception {
mockMvc.perform(get("/error").contentType(MediaType.TEXT_HTML))
.andExpect(status().isOk()) // See "alwaysExpect" above
.andExpect(view().name("error"))
.andExpect(forwardedUrl("/WEB-INF/views/error.jsp"));
}
#Test
public void testResourceNotFound() throws Exception {
mockMvc.perform(get("/resource-not-found").contentType(MediaType.TEXT_HTML))
.andExpect(status().isNotFound())
.andExpect(view().name("resource-not-found"))
.andExpect(forwardedUrl("/WEB-INF/views/resource-not-found.jsp"));
}
}
Sample project is here. I'm using JSPs but you can switch to .html just by changing the InternalResourceViewResolver configuration.
I am using spring 3 and after some reading around I have found out the dispatcher servlet just returns a response code without throwing an exception which I guess is why tomcat always handles this.
Removing the error page tags from web.xml results in a tomcat generic 404 page, so I think the answer to this is to upgrade to spring 4 where I can then pass an init param to the dispatcher servlet requesting it throw an error for a page not found.
I am happy to be corrected on this though as it may help my understanding.

WebApplicationContext appears to ignore Import annotation

I am having a problem where the Spring WebApplicationContext appears to be ignoring the #Import annotation on a #Configuration-annotated config class in my web app. It is not a Spring MVC web app.
The problem occurs during processing of the contextInitialized event of a custom ServletContextListener which used to be able to successfully retrieve this bean when I was using XML configuration, but is now not finding this bean now that I have (apparently incorrectly) converted to the use of #Configuration-annotated classes.
The symptoms I see are:
During app startup, I see this output from the Spring framework:
INFO: No annotated classes found for specified class/package
[org.imaginary.spring.config.Instrumented]
Later, when my contextInitialized() method is invoked and I call getBean(), I get a NoSuchBeanDefinition exception
My config classes are factored in such a way that I have, for example, two high-level config classes, one for a "Production" configuration, and another for an "Instrumented" configuration. These top-level config classes are themselves completely empty, but they make use the #Import annotation to (I'm hoping) bring in the relevant bean definitions for that kind of configuration.
For example, here is the Instrumented configuration class:
package org.imaginary.spring.config;
import org.imaginary.spring.config.instrumentation.InstrumentationDependencies;
import org.imaginary.spring.config.servlets.ServletDependencies;
#Configuration
#Import( {InstrumentationDependencies.class, ServletDependencies.class } )
public class Instrumented
{
}
...for the purposes of this example, here is the InstrumentationDependencies config class, defined in a different package:
package org.imaginary.spring.config.instrumentation;
#Configuration
public class InstrumentationDependencies
{
#Bean
public IEventSink eventSinkImpl()
{
return new InstrumentationEventSinkImpl();
}
}
Here is (a stripped-down version of) the contextInitialized() method:
#Override
public void contextInitialized( ServletContextEvent ctxEvent )
{
try
{
if (_publisher == null)
{
WebApplicationContext springContext = WebApplicationContextUtils.getWebApplicationContext(ctxEvent.getServletContext());
_eventSink = (IEventSink)springContext.getBean("eventSinkImpl");
}
_eventSink.startReceiving();
}
catch ( Exception e )
{
// handle exception
}
}
Here are the relevant entries from my web.xml:
<context-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>org.imaginary.spring.config.Instrumented</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.imaginary.MyContextListener</listener-class>
</listener>
Any ideas what I have missed?
In this case, there is nothing wrong with the Spring configuration classes or configuration. The problem was in fact a build issue - the config classes had been added to a package that wasn't getting included in the main web app jar, so the class files weren't present. I was surprised that there wasn't a NoClassDefFoundError exception thrown, as this error leaves the impression that the class exists, it just isn't annotated:
No annotated classes found for specified class/package
[your.class.here].

How to load applicationContext.xml

I trying to load an applicationContext.xml from java class in a web application using
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
and
ApplicationContext context = new FileSystemXmlApplicationContext("applicationContext.xml");
My question is how to load applicationContext.xml from a java class. The applicationContext.xml is WEB-INF. Is that possible?
You can use the ContextLoaderListener in your web.xml file:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Then you can use the WebApplicationContext to load the context:
WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(servlet.getServletContext());
Hope this helps.
A ContextLoaderListener is used when you want to load a specific context that will act as your context root. If you want to load additional contexts for whatever reason, you can define your own ServletContextListener, create your ApplicationContext instances, and put them in the ServletContext attributes so that they are available to the web application
public class AdditionalContextListener implements ServletContextListener {
#Override
public void contextDestroyed(ServletContextEvent sce) {
// destroy those contexts maybe
}
#Override
public void contextInitialized(ServletContextEvent sce) {
ApplicationContext context = ...; // get your context
sce.getServletContext().setAttribute("someContextIdentifier", context);
}
}

How to stop overiding a bean in Spring

I noticed that if you define a bean with same id in two xml files, it would be overiden in the second file.
Say in file a.xml i have
<bean id="abc" />
Say in file b.xml i have
<bean id="abc" />
then the bean "abc" of b.xml is picked up. Is there a way in Spring to stop from overiding i.e should be unique no matter how many xml have the bean abc.
You can disable the feature to disallow beanoverriding by calling the setAllowBeanDefinitionOverriding and pass false. This has to be done early on before anything is loaded. You would either need to create your own custom ContextLoader for this or (if you are on Spring 3.1 or up) you can create an ApplicationContextInitializer and register this in your web.xml.
public class OverrideDisablingApplicationContextInitializer implements ApplicationContextInitializer {
public void void initialize(<? extends ConfigurableApplicationContext> applicationContext);
if (applicationContext instanceof AbstractRefreshableApplicationContext) {
(AbstractRefreshableApplicationContext (applicationContext)).setAllowBeanDefinitionOverriding(false);
}
}
in your web.xml add the following (for the ContextLoaderListener use an init-param for the DispatcherServlet when needed)
<context-param>
<param-name>contextInitializerClasses</param-name>
<param-value>your.package.here.OverrideDisablingApplicationContextInitializer<param-value>
</context-param>
From the top of my head this should disable the overriding behavior. If you use springs WebApplicationInitializer it is even easier as you are probably constructing the ApplicationContext yourself, you can then simply call the method directly and no ApplicationContextInitializer is needed.
Links
ApplicationContextInitializer javadoc
AbstractRefreshableApplicationContext.setAllowBeanDefinitionOverriding javadoc
Also:
final ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext();
ctx.setAllowBeanDefinitionOverriding(false);
ctx.setConfigLocations(shardContextImport);
ctx.setParent(refreshedEvent.getApplicationContext());
ctx.refresh();

Resources