Read web.xml file from an ejb bean - jsf

I want to know the authentication type if it is ldap realm or jdbc realm
I am not getting any solution in this problem
So i proposed to read the web.xml file from the jsf project
What i want is to read this file in the ejb project by an ejb bean
Is there any other solution other than my proposal

If you know the name of the realm you can get an instance of it and check the type with instanceof like this:
import com.sun.enterprise.security.auth.realm.Realm;
//...
Realm realm = Realm.getInstance("realmName");
if (realm instanceof JDBCRealm) {
// do something
}
If you don't have the name you may try your solution but I can't say if it will work because I think it will be difficult to get access to the ServletContext inside an EJB.

Related

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?

Exception when registering the JMX bean MessageHistory from Spring Integration into a Spring XD Module

If I try to use the Message History bean from Spring Integration "int:message-history" when developing a Spring XD module, it fails when try to export the JMX bean.
I've seen that the naming strategy used is org.springframework.xd.dirt.module.jmx.ModuleObjectNamingStrategy
I already open a ticket for that https://jira.spring.io/browse/XD-3748
Is there any workaround for that? Like explicitly use another MBeanExporter and add a different name for the bean?
It's a bug in the ModuleObjectNamingStrategy; I'll see if I can come up with a work-around.
Thanks Gary, for now I have implemented other class like the ModuleObjectNamingStrategy and changed the mbean-exporters.xml to use that one if the bean is the messageHistoryConfigurer I create the ObjectName instance like:
String name = domain +":name=messageHistoryConfigurer";
ObjectName originalName = new ObjectName(name);

How to make a serviceloader created class handle container managed objects

I'm currently writing a library where I want the user of my library to implement an interface. From within my library I'm calling this implementation.
I'm using ServiceLoader to instantiate the implementation provided by the integrator and it works just fine. The integrator calls a start() method in my library and in the end he gets something in return. The implementation is used to give me some things along the way that I need in order to get to the final result.
(I'm deliberately not using CDI or any other DI container 'cause I want to create a library that can be used anywhere. In a desktop application, a spring application an application using guice...)
Now I'm facing a problem. I'm creating a showcase in which I'm using my own library. It's a webapplication where I'm using jsf and CDI. When I instantiate the implementation provided in said webapp from within my library, I'm dealing with a non-container managed object. But since this implementation needs to use container managed objects I'm kinda screwed since this can never work.
Example:
Interface in lib:
public interface Example{
public abstract String getInfo();
}
Implementation in war:
public class ExampleImpl implements Example{
#Inject
private ManagedBean bean;
public String getInfo(){
return bean.getSomethingThatReturnsString();
}
}
As you can see this is a huge problem in the way my library is build since the bean will always be null... This means no one using a DI container can use my library. I know I can get the managedbean by doing a FacesContext lookup and get the managedbean but more importantly, my library isn't very well designed if you think about it.
So to conclude my question(s):
Is there any way I can make the serviceloader use a DI container to instantiate the class?
Anyone who knows a better way to fix my problem?
Anyone who knows a better way to get the things I need without making the integrator implement an interface but I can get information from the integrator?
I know this is a quite abstract question but I'm kinda stuck on this one.
Thanks in advance
As the implementation of Example is not performed within the CDI container the injection doesn't happen. What you can do is to lookup the bean manually using the BeanManager. According to the docs, the BeanManager is bound to the jndi name java:comp/BeanManager. Using the following code you can get the BeanManager within your implementation class and lookup the dependencies manually:
InitialContext context = new InitialContext();
BeanManager beanManager = (BeanManager) context.lookup("java:comp/BeanManager");
Set<Bean<?>> beans = beanManager.getBeans(YourBean.class, new AnnotationLiteral<Default>() {});
Bean<YourBean> provider = (Bean<YourBean>) beans.iterator().next();
CreationalContext<YourBean> cc = beanManager.createCreationalContext(provider);
YourBean yourBean = (YourBean) beanManager.getReference(provider, YourBean.class, cc);
where YourBean is the dependency you are looking for.

ManagedBean Inheritance & Common Name

In one of our applications we have two classes of users,
Internal Users (class InternalUser extends User)
External Users (class ExternalUser extends User)
We are using these as session-scoped managed beans (basically to inject the logged-in user's details, which has some common detail in the class User and a few specific details in each of the 2 classes stated above).
Can I have the same name for both the managed beans (here "loggedInUser")?
Faces is throwing an exception "Managed bean named 'loggedInUser' has already been registered. Replacing existing managed bean class..."
How can we manage this scenario?
One way is to just not make it a JSF managed bean. Make the bean associated with the login form a request/view scoped one and put the User instance in the session scope youself.
E.g.
User user = service.find(username, password);
if (user != null) {
externalContext.getSessionMap().put("user", user);
}
It'll be available as #{user} in EL scope (and thus also be injectable via #ManagedProperty in other beans on exactly that expression). In the find() method, you can just return either InternalUser or ExternalUser accordingly.
Perhaps a managed bean named CurrentUser with an Internal/ExternalUser as a member? In my own application, I am not sure I'd inject this required data by making the User sub-classes double as business objects and managed beans the way you are attempting to do it.

liferay redeploy: root context is null on redeploy

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.

Resources