liferay redeploy: root context is null on redeploy - liferay

I have a web application with few spring portlets. Every portlet has an xml with its declared controller, but the services used by the controllers are placed in applicationContext.xml. I know that for every portlet is created one spring application context (from own xml file), and every that context has as root context the spring application context created from applicationContext.xml. That is all beans declared in applicationContext.xml are common for all portlets.
So let's have an example:
xml file for portlet example-portlet.xml:
...
...
controller ExampleController.java:
package example.controller;
#Controller
#RequestMapping(value = "VIEW")
public class NavigareController {
#Autowired
private ExampleService es;
...
}
applicationContext.xml:
...
<context:component-scan base-package="example.service />
...
service ExampleServiceImpl.java:
package example.service;
#Service
public class ExampleServiceImpl implements ExampleService {
...
}
When server starts with the application inside it, the application starts and everything works fine. When the application is redeployed then I have an error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'exampleController'...
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private example.service.ExampleService...
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [example.service.ExampleService]...
In result the portlet is not starting.
I have debugged the lifery's sources and I have found the following code:
package org.springframework.web.portlet
...
public abstract class FrameworkPortlet extends GenericPortletBean
implements ApplicationListener<ContextRefreshedEvent> {
...
protected ApplicationContext initPortletApplicationContext() {
ApplicationContext parent = PortletApplicationContextUtils.getWebApplicationContext(getPortletContext());
ApplicationContext pac = createPortletApplicationContext(parent);
...
The code above, in first case (when server starts with application inside) returns not null parent, but in second case (when application is redeployed) it retuns a null parent. Inside PortletApplicationContextUtils.getWebApplicationContext(getPortletContext()) there is the following code:
Object attr = pc.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
So in first case this attribute is in portlet context, but in the second case it is not in portlet context. The problem is clear, the exampleService bean is not found in null parent.
The question is: Is there any bug in hot deployment process?. Please help me!!!

What is your version of Liferay? If it is 6.1.1 then this is a known issue
http://issues.liferay.com/browse/LPS-29103
If you just need to deploy the portlets once - change order of listeners in web.xml manually as suggested in the ticket.
If you need to redeploy the portlets alot (for development) then the previous solution is very time consuming and the easiest way is to backport the fix from 6.2.0 branch.

Related

How to init Weld 3.0 cid setParameterName on Tomcat 8.5/Servlet 3.1

I'm trying to upgrade an old web app from JSF 2.1.1-FCS to 2.2.14 running in the Tomcat 8.5 Servlet 3.1 container.
The Mojarra JSF minimum requirements (for the latest version I guess, the page doesn't seem clear) says among other things that CDI 1.2 is required with 2.0 recommended.
I added cd-api-2.0 and weld-servlet-shaded-3.0.0.Final along with the other dependencies. Things seem to work until I test some URLs we've been using a long time. Our application has been using a cid parameter. Weld uses the same parameter to track conversations. As a result we get the WELD-000321: No conversation found to restore for id error.
I would like to call the org.jboss.weld.context.http.HttpConversationContext.setParameterName(String cid) as early as possible to modify the value for this web application.
What is the best way to change this value in a Servlet 3.1 Container Context like the one provided by Tomcat 8.5?
Initialize WELD_CONTEXT_ID_KEY in web.xml
Using the web.xml context-param WELD_CONTEXT_ID_KEY allowed me to override the Weld CDI conversation parameter key name from cid to a value of my choosing so I could preserve the legacy usage of cid in my upgraded application and avoid the WELD-000321 error.
<context-param>
<param-name>WELD_CONTEXT_ID_KEY</param-name>
<param-value>customValue</param-value>
</context-param>
This was the simplest solution, but I didn't make the association between that context parameter name and the conversation parameter key or error WELD-000321 when first reading the Weld documentation.
Or set programmatically
I was also able to override the parameter name / context id key programmatically from a custom ServletContextListener.contextInitialized method based on the SO example for getting rid of the NonexistentConversationException. Since I'm on Tomcat 8.5 (Servlet 3.1) I was able to use either #WebListener or the listener element in web.xml. It didn't seem to matter if my web.xml web-app version was the old 2.5 or if I updated it to 3.1.
package ssce;
import java.util.UUID;
import javax.inject.Inject;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import org.jboss.weld.context.http.HttpConversationContext;
#WebListener
public class MyServletContextListener implements ServletContextListener {
#Inject
private HttpConversationContext conversationContext;
#Override
public void contextInitialized(ServletContextEvent sce) {
hideConversationScope();
}
#Override
public void contextDestroyed(ServletContextEvent sce) {
}
/**
* "Hide" conversation scope by replacing its default "cid" parameter name
* by something unpredictable.
*/
private void hideConversationScope() {
conversationContext.setParameterName(UUID.randomUUID().toString());
}
}

How to inject an #Normal (#ApplicationScoped) bean into a #Dependent scope if the bean does not have a no-arg constructor

This post is related to an older SO Post of mine, wherein I was trying to understand the requirements of a no-args constructor by WELD.
Right now, I'm trying to figure out if there is a way in CDI to inject an #ApplicationScoped bean (#Normal) into a #Dependent scope. From what I've read from WELD, the requirements are to have a non-private no-arg constructor to be proxyable. However, I do not have control over the bean definition as it is provided by a library. My code is doing the following:
#Produces
#ApplicationScoped
#Named("keycloakAdmin")
public Keycloak getKeycloakAdminClient(#Named("keycloakDeployment") final KeycloakDeployment deployment) {
String clientId = deployment.getResourceName();
Map<String, Object> clientCredentials = deployment.getResourceCredentials();
// need to set the resteasy client connection pool size > 0 to ensure thread safety (https://access.redhat.com/solutions/2192911)
ResteasyClient client = new ResteasyClientBuilder().connectionPoolSize(CONNECTION_POOL_SIZE).maxPooledPerRoute(CONNECTION_POOL_SIZE)
.defaultProxy("localhost",8888)
.build();
KeycloakBuilder builder = KeycloakBuilder.builder()
.clientId(clientId)
.clientSecret((String) clientCredentials.get(CredentialRepresentation.SECRET))
.realm(deployment.getRealm())
.serverUrl(deployment.getAuthServerBaseUrl())
.grantType(OAuth2Constants.CLIENT_CREDENTIALS)
.resteasyClient(client);
return builder.build();
}
// error thrown here that cannot inject #Normal scoped bean as it is not proxyable because it has no no-args constructor
#Produces
#Dependent
#Named("keycloakRealm")
public RealmRepresentation getKeycloakRealm( #Named("keycloakAdmin") final Keycloak adminClient ){
// error thrown here that cannot inject #Normal scoped bean as it is not proxyable because it has no no-arg
return adminClient.realm(resolveKeycloakDeployment().getRealm()).toRepresentation();
}
The problem is that I do not control the Keycloak bean; it is provided by the library. Consequently, I have no way of providing a no-argument constructor to the bean.
Does this mean it is impossible to do? Are there any workarounds that one can use? This would seem like a significant limitation by WELD, particularly when it comes to #Produceing 3rd party beans.
My goal is to have a single Keycloak bean for the application as it is thread-safe and only needs to be initialized once. However, I want to be able to inject it into non-application-scoped beans.
There is a #Singleton scope which may address my issue, but if #Singleton works for this case, what is the purpose of the 2 different scopes? Under what circumstances would one want a non-proxied singleton (#Singleton) vs a proxied one (#ApplicationScoped)? Or is #Singleton for the entire container, whereas #ApplicationScoped for the application (WAR) only instead? How does it apply to an EAR or multiple ears?

Java SE: #Inject does not work in Bean Validation validators called by RESTEasy

The following code from Hibernate Validator Reference Guide does not work in Java SE when RESTEasy is calling the validation:
public class ValidLicensePlateValidator implements ConstraintValidator<ValidLicensePlate, String> {
#Inject
private VehicleRegistry vehicleRegistry;
//rest of the class
The field vehicleRegistry is never injected.
Note that I have hibernate-validator-cdi.jar on the classpath.
Any idea what could be wrong with my setup? Or is this a bug in RESTEasy?
Here are (possibly misleading) outcomes of my investigation:
During application start RESTEasy shows the info log:
RESTEASY008550: Unable to find CDI supporting ValidatorFactory. Using default ValidatorFactory
From RESTEasy source code it seems that CDI enabled ValidationFactory is being looked up in AbstractValidatorContextResolver calling context.lookup("java:comp/ValidatorFactory") but it fails and non-CDI enabled ValidationFactory is used instead.

WELD-001437: Normal scoped bean class javax.faces.component.UIViewRoot is not proxyable because the type is final or it contains a final method

When deploying a dynamic web project with JSF facet to Eclipse+GlassFish, the following error occurs:
The message says:
WELD-001437: Normal scoped bean class javax.faces.component.UIViewRoot is not proxyable because the type is final or it contains a final method public final void javax.faces.component.UIComponent.popComponentFromEL(javax.faces.context.FacesContext) - com.sun.faces.cdi.ViewProducer#1ccfebd3
How is this caused and how can I solve it? The same codebase and server works fine in Netbeans.
Because your NetBeans project has been worked successful. In this case, You should import exist NetBeans project to Eclipse IDE, don't create new Eclipse project. This make avoid errors or mistakes.
Turn off all other web application servers, avoid port number collision.

How can I initialize a Java FacesServlet

I need to run some code when the FacesServlet starts, but as FacesServlet is declared final I can not extend it and overwrite the init() method.
In particular, I want to write some data to the database during development and testing, after hibernate has dropped and created the datamodel.
Is there a way to configure Faces to run some method, e.g. in faces-config.xml?
Or is it best to create a singleton bean that does the initialization?
Use an eagerly initialized application scoped managed bean.
#ManagedBean(eager=true)
#ApplicationScoped
public class App {
#PostConstruct
public void startup() {
// ...
}
#PreDestroy
public void shutdown() {
// ...
}
}
(class and method names actually doesn't matter, it's free to your choice, it's all about the annotations)
This is guaranteed to be constructed after the startup of the FacesServlet, so the FacesContext will be available whenever necessary. This in contrary to the ServletContextListener as suggested by the other answer.
You could implement your own ServletContextListener that gets notified when the web application is started. Since it's a container managed you could inject resources there are do whatever you want to do. The other option is to create a #Singleton ejb with #Startup and do the work in it's #PostCreate method. Usually the ServletContextListener works fine, however if you have more than one web application inside an ear and they all share the same persistence context you may consider using a #Singleton bean.
Hey you may want to use some aspects here. Just set it to run before
void init(ServletConfig servletConfig)
//Acquire the factory instances we will
//this is from here
Maybe this will help you.

Resources