Exclude/remove services from Dependency Indejection in JBoss - java

We currently have a project that consists of multiple applications as well as a base library.
Both, the applications as well as the base library contain stateless EJBs and each application might introduce an EJB that inherits from a base library EJBand thus implements the same interface.
A short example:
In the base library we have:
#Stateless
#Local( IUserService.class )
public UserServiceBean implements IUserService {
public void login(String user, String password) {...}
}
In the application we need to override login(...) and thus we have:
#Stateless
#Local( { ISpecificUserService.class, IUserService.class } )
public SpecificUserServiceBean extends UserServiceBean implements ISpecificUserService {
public void login(String user, String password) { ... } //override
}
If I now have another EJB in the application that needs to have a reference to SpecificUserServiceBean I'd do #EJB ISpecificUserService userService;.
However, if there is an EJB in the base library, it would contain #EJB IUserService userService; and here's the problem:
We need to get the specific service in the application be injected in the base library EJB. However, there are two EJBs registered for the same local interface, which means that the container might return the base EJB or the specific EJB.
You could say "Don't add the base library jar as a module in application.xml" but that's not possible right now, since it contains other EJBs that need to be deployed. We could move the EJBs to be overridden to a different jar but since almost every EJB might be overridden, depending on the application, we'd end up with a jar per EJB.
Thus, I'd like to exclude or remove the base EJB from the dependency injection container if there exists a specific override. Since I know that at deploy time, I could also use a configuration file to tell the container not to load a specific EJB class.
I might add a service that modifies the container afterwards but that would be my last resort.
Do you have any ideas on what we could do?
Thanks in advance.
Btw, we're working on JBoss 4.2.3 with EJB 3.0.

The problem is that you're wiring your app partially in the base lib which is bad since you can't override this wiring.
So the solution is to remove #Stateless #Local( IUserService.class ) from UserServiceBean in your base lib; the base lib just provides default implementations for the beans but it must not wire them.
In your apps, you need this code:
#Stateless
#Local( IUserService.class )
public AppUserServiceBean extends UserServiceBean {}
to create the wiring. Move all those beans into a special package which you can copy into each app so you get the default wiring for everything.

Related

How does class gets injected which implements interface method being called in Java or Groovy code?

I have below working groovy code from Spring framework project:
import org.springframework.oxm.Unmarshaller
public class ItemSearchService {
Unmarshaller unmarshaller;
public ItemSearchResponse getObject(InputStream xml) {
ItemSearchResponse its = null;
try {
its = (ItemSearchResponse) unmarshaller.unmarshal(new StreamSource(xml));
} finally {
}
return its;
}
}
Unmarshaller.unmarshall is actually interface method:
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/oxm/Unmarshaller.html
Unmarshaller interface is implemented by several classes.
Who decides which implementing class to inject during runtime and how it decides which class to use?
Does Spring IoC mechanism does this? If so does it pick up one specific implementing class during build time when jar is generated or it does it during run time?
Also how to know which implementing class it actually used?
Will above code work outside of Spring in ordinary Java file assuming dependent jars in classpath?
As soon as it goes about a Grails project (not a pure Spring one), some things should be clarified.
Who decides which implementing class to inject during runtime and how it decides which class to use? Does Spring IoC mechanism does this? If so does it pick up one specific implementing class during build time when jar is generated or it does it during run time?
What Spring does in a plain Spring(Boot) is nicely described by #svr s answer and other documentation on the Internet, but has not much to do with your case.
In Grails the convention-over-configuration doctrine is used, meaning that
by default Bean Autowiring is active
only beans which are declared as Grails artefacts, like Service are auto-injected.
Usually, if you want to autowire a bean of other stereotype, you have to declare it somewhere, otherwise Spring IoC container inside Grails simply won't find it.
You shall check your grails-app/conf/spring folder for resources.groovy (or maybe yaml or xml files depending on version ) and see if your unmarshaller bean is defined there. It should look like:
beans = {
unmarshaller Unmarshaller ....
}
So, basically it doesn't matter how many implementations of Unmarshaller interface are present in all project's jar files. The only thing what matters is what defined in your resources.groovy.
If you want to check the class of the bean in runtime, just log it's class in your service:
class ItemSearchService {
Unmarshaller unmarshaller
ItemSearchResponse getObject(InputStream xml) {
log.info "unmarshaller's class is $unmarshaller.class"
// or
// println "unmarshaller's class is $unmarshaller.class"
}
}
Who decides which implementing class to inject during runtime and how
it decides which class to use?
Does Spring IoC mechanism does this? If so does it pick up one
specific implementing class during build time when jar is generated or
it does it during run time?
Yes Spring IOC container. It happens at run time when the application is run.
Also how to know which implementing class it actually used?
For most part you will have to define bean with implementation to pick. For other cases you can look at the spring auto configuration classes.
Will above code work outside of Spring in ordinary Java file assuming
dependent jars in classpath?
Not sure what you mean outside of Spring but as long as application is packaged correctly it should all work.
Quick Overview
Spring IOC will only inject a bean when found in the application context. An application context loosely is repository of beans.
Classpath Scanning and Registration
Spring scans application to pick up all the stereotyped classes and registers bean definition with application context. Stereotyped annotations include #Component, #Repository, #Service, #Controller, #Configuration. More
Dependency Injection
Spring DI creates the bean and injects them as dependencies into application. You can create dependencies between different application components using the registered beans and spring will autowire these for you. More. There are two types of DI - Constructor based and setter based - Constructor for required dependencies and setter based for optional dependencies. More
There are sensible defaults provided when you use any spring classes. You just have to define the bean where there is no default or you would like to pick different implementation. Application context can be further be enriched by using Spring Boot Auto Configuration where all related classes are wired together to form a coherent entry classes. You can then easily inject these into application for getting started. More
Example
You can define bean in the #Configuration class for a web service module.
#Configuration
public class WSConfig {
#Bean
public Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marsharller = new Jaxb2Marshaller();
marsharller.setContextPath("some package");
}
#Bean
public WebServiceTemplate webServiceTemplate(Jaxb2Marshaller marsharller) {
WebServiceTemplate webServiceTemplate = new WebServiceTemplate(marsharller);
}
}
#RequiredArgsConstructur
public class ItemSearchService {
private final Unmarshaller unmarshaller;
public ItemSearchResponse getObject(InputStream xml) {
ItemSearchResponse its = null;
try {
its = (ItemSearchResponse) unmarshaller.unmarshal(new StreamSource(xml));
} finally {}
return its;
}
}
This similar configuration is automatically taken care by WebServicesAutoConfiguration with ways to customize when using Spring Boot.

CDI instantiate and inject parent-child type beans is either ambigious or child types is not found

I have an interface like:
public interface DateTimeService {
ZonedDateTime now();
void fixTo(ZonedDateTime date);
void forget();
}
and I have two implementations of it. One for production where fixTo and forget throws exceptions and one for testing where we control time. Then I have a CDI config that depending on a flag instantiate the right type.
#ApplicationScoped
public class Configuration {
#Produces
#ApplicationScoped
public DateTimeService dateTimeService(Configuration config) {
if (config.isFakeDateTimeServiceEnabled()) {
return new FakeDateTimeService();
} else {
return new DefaultDateTimeService();
}
}
}
However, I wanted to remove fixTo and forget from DateTimeService as they are only there so we can control time in tests. I made a new interface like:
public interface FakeDateTimeService extends DateTimeService {
// fixto and forget is moved from DateTimeService to here
}
I have a few injection points. Some is in production code, some is in test code. In production code I would like to only be able to access DateTimeSerice, in test code I want be able to get a handle on the extended service.
In prod code:
#Inject
private DateTimeService dateTimeService;
In test code:
#Inject
private FakeDateTimeService dateTimeService;
If I leave the config unchanged, then the test code will never find my extended service (as CDI seems to ignore the run-time type of the instance produced by the producer method).
If I update the config to instantiate both (in this case I can even inject the genuine service into the fake one), then production cannot wire together as fake also implements the DateTimeService interface and it causes ambiguity. At this point I could probably just use a qualifier, but I neither want to change my production code because of this nor have to have a fake date time service exist in production context.
I tried to veto bean creation but I failed to do so.
What I thought would/should work is instantiate the right type and programmatically add it to the bean context but examples I found was for CDI 2.0 while for now, relevant part of my code is stuck on CDI 1.2.
Probably at this point you can tell, that I'm not a CDI expert. So I'm opened for suggestion on good CDI read materials as well as concrete suggestions on this problem.
Otherwise, I'm about to give up and just live with a DateTimeService that have fixTo and forget methods.
Depending on how you are doing it, you could use the following approaches, whereby some of them have already be mentioned in the comments.
With alternatives
For testing you provide an own beans.xml, which defines the alternative for testing, which replaces the production one. You will have to keep them in sync, whereby the test beans.xml contains changes necessary for testing. Depending on the CDI implementation the beans.xml can be left out and #Alternative will be enough.
https://docs.oracle.com/javaee/6/tutorial/doc/gjsdf.html
interface DateTimeService { ... }
// Active during production, beans.xml does not define alternative
class DefaultDateTimeService implements DateTimeService { ... }
// Active during test, beans.xml defines alternative
#Alternative
class FakeDateTimeService implements DateTimeService { ... }
// Injection point stays the same.
#Inject
DateTimeService dateTimeService;
// Used in test environment
<beans ... >
<alternatives>
<class>FakeDateTimeService</class>
</alternatives>
</beans>
With Arquillian
With Aarquillian you can assemble the deployment yourself and exclude the DefaultDateTimeService implementation and replace it with the FakeDateTimeService implementation. With this approach you don't need to hack anything because during test, only FakeDateTimeService implementation will be visible to the CDI container.
http://arquillian.org/guides/getting_started/
With CDI Extension
For testing you could provide an CDI extension and the FakeDateTimeService implementation in the test code, whereby the CDI Extension does veto the DefaultDateTimeService implementation.
package test.extension
public class VetoExtension implements Extension {
public <T> void disableBeans(#Observes ProcessAnnotatedType<T> pat) {
// type matching
if (DefaultDateTimeService.class.isAssignableFrom(pat.getAnnotatedType().getJavaClass())) {
pat.veto();
}
}
}
// Define SPI provider file, assuming test/resources is on CDI classpath
src/test/resources/META-INF/services/javax.enterprise.inject.spi.Extension
// Single line you put in there
test.extension.VetoExtension
Deltaspike #Exclude
Deltaspike is a CDI extension library which provides some useful utilities for CDI development and testing, also a CDITestRunner is provided. The #Exclude annotation is used by an extension which does the same as the example above but already implemented for you.
https://deltaspike.apache.org/
https://deltaspike.apache.org/documentation/test-control.html
https://deltaspike.apache.org/documentation/projectstage.html
You should choose an approach which doesn't pollute your source code and forces you to hack to much to get it running for testing.
I would prefer Arquillian because here you have full control about what is in the deployment and nothing in your production code has to change or be specially implemented so its testable.
With Deltaspike you can exclude production code for testing and replace them with test implementations.
If no additional library or framework can be used I would prefer the alternative approach, because its the least complicated one to use.

Referencing EJB Local home from a POJO class of a separate web application

I am trying to port 2 EJB modules in my application from EJB2.1 to EJB3.0. I am using the Eclipse Kepler IDE and regenerated the session beans using an EJB3.0 configuration. I am not using an ejb-jar.xml because in EJB 3.0 that is supposed to be redundant. I have instead used annotations for marking my bean as Stateless and specifying the Local and Local Home Interfaces. I have still kept the Local Home interface since I wanted the basic structure of my project to be similar to what it was in EJB2.1. I have also done away with the xml bindings for the EJB while migrating.
We are using a WAS 7 application server for deployment and while the EJB is getting successfully deployed without errors, I am getting a naming Exception while looking up my Local Home interface from a separate POJO class of a different web application it is required in. I basically want to call the create() method of the Local Home interface after referencing the EJB Local Home. Adding code samples below:
Session Bean:
#Stateless
#Local(AccessLDAPSessionLocal.class)
#LocalHome(AccessLDAPSessionLocalHome.class)
public class AccessLDAPSessionBean implements AccessLDAPSessionLocal {
//Business Logic
}
Local Interface:
public interface AccessLDAPSessionLocal {
//business Interface
}
Local Home Interface:
public interface AccessLDAPSessionLocalHome extends EJBLocalHome {
public AccessLDAPSessionLocal create() throws CreateException;
}
Pojo class referencing the Local Home interface:
public static AccessLDAPSessionLocal getAccessLDAPSessionBean() throws NamingException, CreateException {
if (accessLDAPSessionBean == null) {
InitialContext context = new InitialContext();
Object obj = context.lookup("java:global/AccessLDAP/AccessLDAPSessionBean!com.ibm.asset.hrportal.core.ejb.ldap.AccessLDAPSessionLocalHome");
accessLDAPSessionBean = ((AccessLDAPSessionLocalHome) obj).create();
}
return accessLDAPSessionBean;
}
Also my Local and Local Home interfaces are inside my EJB client which I use as a jar file, while my Session Bean is inside the actual EJB which is used as an EAR.
Following is the error I am getting:
NamingException::javax.naming.NameNotFoundException: Name global not found in context "java:".
Am I missing some configuration resulting in the failure of JNDI lookup? Any help would be gratefully appreciated. Thanks in advance.
WebSphere Application Server 7.0 is only an implementation of EJB 3.0, but the java:global namespace wasn't added until EJB 3.1, which wasn't implemented in WebSphere Application Server until 8.0. As with all EJB 3.0 implementations, you will need to lookup a vendor-specific binding name. You can find the WebSphere Application Server binding name by looking at the CNTR0167I messages in SystemOut.log. See the EJB 3.0 application bindings overview topic in the Knowledge Center if you would like to customize this binding name.
Regardless, it is not a best practice to directly lookup EJBs by their binding name. Instead, you should use an EJB reference. In EJB 3.0, that means using an annotation like this in an EE managed object (such as a servlet or another EJB):
#EJB
private AccessLDAPSessionLocalHome home;
In this case, the EJB container is required to find a target EJB within the same application that contains the EJB reference, so you do not need to explicitly configure a target binding name for the EJB reference.
If you need to access the EJB reference from a utility class rather than an EE managed class, then declare the EJB reference with a name on a managed class (such as a servlet or another EJB), and look it up from the utility class:
#EJB(name = "ejb/accessHome", beanInterface = AccessLDAPSessionLocalHome.class)
public class MyServlet { ... }
public class MyUtility {
...
InitialContext context = new InitialContext();
Object obj = context.lookup("java:comp/env/ejb/accessHome");
...
}
You can configure multiple such EJB references on the same managed EE class using the #EJBs annotation:
#EJBs({
#EJB(name = "ejb/accessHome", beanInterface = AccessLDAPSessionLocalHome.class),
#EJB(name = "ejb/other" beanInterface = Other.class)
})
public class MyServlet { ... }
If your EJB is packaged in a separate EAR, then note that this is not a portable configuration. See the "Local client views" section of the EJB modules topic in the Knowledge Center. Additionally, you will need to explicitly configure a binding name for the EJB reference.
I think the way you are looking up the ejb is not correct. The JNDI name would be something like "java:comp/env/". ejb-ref-name would be part of your web.xml
Also, you will need to give providerURL and factoryName to the context object before doing the lookup.

How to dynamically lookup an EJB at runtime

I have this scenario where i have my EJB3 beans in a jar file, deployed successfully to Jboss EAP-6.4.
Then I have another web project that looks up these EJB's inside a REST POJO class. I can currently access the EJB's from inside the web project using #Inject and #EJB, but my use case is one that i don't know which beans i need to load until runtime and the list is not static, so i might need to lookup 10 EJB's or none for a particular request etc.
I know I can possibly use
InitialContext.lookup('ejb:/.....')
to retrieve my EJB beans from inside the web project, but is there a way that i can retrieve them without that round trip(i believe), or maybe what am just looking for is a more elegant way to do EJB look-up at runtime just like the statically typed #EJB and #Inject versions.
Any suggestions are greatly appreciated.
EDIT
In my REST POJO classes i don't want to hard code any #Inject or #EJB annotations, rather i want that when a request comes in i look-up(for lack of better word) the EJB's that will handle the request, so all the decision is made at runtime really, as shown below
#Path("/path")
public class TestService {
#GET("/{id}")
public String loadGetPath(#Param id int id){
//at this point i want to dynamically resolve the EJB based on
//the value of id
}
}
Whoopdicity blog: Developing a dynamic JEE service client with CDI seems to have what you are looking for. At the end it claims you can do:
public class MyServiceConsumer {
#Inject #ServiceClient
private MyBusinessService service;
...
}
Instead of
public class MyServiceConsumer {
#EJB(lookup="...")
private MyBusinessService service;
...
}

Root resource from other .jar file cannot be looked up in JAX-RS application

I am trying to build an application ear file with the following structure:
app.ear
--> lib
-- app-domain.jar
-- app-api.jar
-- app-common.jar
...
--> META-INF
-- application.xml
-- glassfish-application.xml
-- MANIFEST.MF
-- app-ejb.jar
-- app-rs.war
The app-api.jar file contains my remote interfaces like
#Remote
public interface LanguageService {
/**
* #return all languages known to the system
*/
List<Language> loadLanguages();
The implementation is contained in the app-ejb.jar file and looks like this:
#Stateless
#Remote(LanguageService.class)
#Path("/language")
public class LanguageServiceImpl extends ValidatingService implements LanguageService {
#PersistenceContext(unitName = "kcalculator")
EntityManager em;
#GET
#Produces("application/json")
#Override
public List<Language> loadLanguages() {
CriteriaQuery<Language> query = createLoadLanguageQuery();
return em.createQuery(query).getResultList();
}
And finally I want to provide this as an JAX-RS web service and thus have my implementation of the javax.rs.Application class in the app-rs.war file, which looks like this:
#ApplicationPath("/resources")
public class MyApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> s = new HashSet<Class<?>>();
s.add(LanguageServiceImpl.class);
return s;
}
This deploys without any problem, the application class is also detected. However, when i finally access the web service an internal server error occurs due to a NPE.
The LanguageServiceImpl cannot be looked up, the log contains the following entry:
Caused by: javax.naming.NameNotFoundException: No object bound to name java:module/LanguageServiceImpl!com.kcalculator.ejb.LanguageServiceImpl
at com.sun.enterprise.naming.impl.GlassfishNamingManagerImpl.lookup(GlassfishNamingManagerImpl.java:741)
at com.sun.enterprise.naming.impl.GlassfishNamingManagerImpl.lookup(GlassfishNamingManagerImpl.java:715)
at com.sun.enterprise.naming.impl.JavaURLContext.lookup(JavaURLContext.java:167)
at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:471)
... 63 more
Hence the file is considered a Pojo, and so the reference to the entity manager is not initialized, which finally results in the Nullpointer exception.
I am kinda stuck, as annotating the bean class and giving it a mapped name is not working. Putting my application class into the ejb.jar file does not solve the problem either.
Can anyone point out what i am missing here?
Additional comment:
What I found out in the meantime: If I add a stateless session bean to my app-rs.war file and register it in MyApplication, it works without any problem. There injecting the LanguageService works, too. So it seems the problem is related to the fact that the service implementing bean class is located in another artifact.
The problem could be that you have an EJB with a remote interface.
JAX-RS 1.1 states in 6.2 that JAX-RS annotations only need to be supported on no-interface beans and local interfaces:
JAX-RS annotations MAY be applied to a bean’s local interface or directly to a no-interface bean.
As indicated in one of the previous comments, a working solution was found by moving the session beans to the web archive as well. Thus the separation between the ejb .jar file and the disclosing web service containing project is gone, however it seems rational to have the services in the artifact that is also supposed to provide the web services.
Thanks for the hints, however it is still not clear to me (according to the specification) why the initially described approach should not be feasible (but i realized it isn't...).

Categories