I have a requirement to get pdf documents from my system. I'm using Apache Fop for this - and this library is using 2 files to generate pdf - xsl file with structure and styling and xml with data. So I'm getting xsl file from web resources, but now I need to generate xml with data from database. I tried this solution:
I have this interface:
public interface PrintableDocument {
Object getJaxBOjbect(Long personId);
}
That's one of the stateless bean to get object, I need 10 more beans like this to get different data for different documents.
#Stateless
#PrintableDocumentOneQualifier
public class PrintableDocumentOne implements PrintableDocument {
#Inject
private SomeRepository repository;
public Object getJaxBOjbect(Long personId) {
// Getting information from database
// formulating Object with data and returning it
}
}
So now I want to create Factory like this one:
#Stateless
#LocalBean
public class PrintableDocumentsFactory {
#Inject
#PrintableDocumentOneQualifier
private PrintableDocument printableDocumentOne;
#Inject
#PrintableDocumentTwoQualifier
private PrintableDocument printableDocumentTwo;
private Map<String, PrintableDocument> map = new HashMap<>();
#PostConstruct
public void init() {
map.put("one", printableDocumentOne);
map.put("two", printableDocumentTwo);
}
public PrintableDocument getPrintableDocument(String type) {
return map.get(type);
}
}
And on the service bean I want to use this factory:
#Stateless
#Local(DocumentService.class)
public class DocumentServiceBean {
#Inject
private PrintableDocumentsFactory factory;
public byte[] getPdf(InputStream xsl, Long id, String type) {
PrintableDocument printableDocument =
factory.getPrintableDocument(type);
Object jaxBOject = printableDocument.getJaxBObject(id);
//Use this object to get pdf and return it to web controller.
}
}
But now I'm getting null from getPrintableDocument from factory. I think the problem is that I need stateless beans, and they are getting picked back to EJB container, when getPrintableDocument method ends. So my question is: how can I manage this kind of situation?
EDIT 1: Missed PostConstruct annotation on init in Factory. Fixed that, still have the problem.
EDIT 2: If I will have #Singleton on my Factory will it hold just one by one instances of stateless PrintableDocument beans or it will return pooled instances instead? Because now I have to refill strategy holder map on factory when system will need another been to answer the request.
You could try to use #EJB instead of #Inject to inject the PrintableDocumentsFactory into your DocumentServiceBean.
Try adding a #PostConstruct annotation to PrintableDocumentsFactory.init() method. Currently the init method won't be called, so no get registered in the map.
Related
In a Spring application that uses HTTP remoting, I have a service façade module configured as follows (I made the code generic to improve clarity):
#Configuration
public class MyFacadeConfig {
private HttpInvokerServiceExporter facade(Class<?> cls) {
HttpInvokerServiceExporter bean = new HttpInvokerServiceExporter();
// The service referred to by this exporter is already instantiated as another Spring bean with all its dependencies.
bean.setService(appContext.getBean(cls));
bean.setServiceInterface(cls);
return bean;
}
#Bean("/first.service")
public HttpInvokerServiceExporter firstServiceFacade() {
return facade(FirstService.class);
}
#Bean("/second.service")
public HttpInvokerServiceExporter secondServiceFacade() {
return facade(SecondService.class);
}
// ... and so on for the 37 other services
}
where FirstService and SecondService are interfaces with existing implementations whose detail is not needed here.
I have another module that defines 39 proxies (instances of HttpInvokerProxyFactoryBean) corresponding to each of my services exposed through my façade.
So far, everything works properly.
But I would like to make the code more generic, elegant, and robust while mitigating the risk of error (e.g., a bad mapping between a service and its proxy in the future). The way I would like to do this is as follows:
First, I move the façade/proxy metadata into an enumeration:
public enum ConfigBeansFacade {
FIRST("/first", FirstService.class),
SECOND("/second", SecondService.class)
// ... and so on for the 37 other services
;
private String beanName;
private Class<?> serviceInterface;
// Constructor and getters
public String getCompleteBeanName() {
return beanName + ".service";
}
}
Then the configuration of the façade would be simplified in a style similar to the following:
#Configuration
public class MyFacadeConfig {
#Autowired
private ConfigurableBeanFactory beanFactory;
#Autowired
public void configExporters() {
for (ConfigBeansFacade bean : ConfigBeansFacade.values()) {
HttpInvokerServiceExporter exp = new HttpInvokerServiceExporter();
exp.setService(beanFactory.getBean(bean.getServiceInterface()));
exp.setServiceInterface(bean.getServiceInterface());
beanFactory.registerSingleton(bean.getCompleteBeanName(), exp);
}
}
}
I tried every single recipe I found in online forums, including StackOverflow, but there are two constraints not met elsewhere:
When defining the exporters, the underlying services are other Spring beans that are instantiated, initialized, and registered with their own configuration and dependencies through the standard Spring mechanics. There is no direct class instantiation other than the exporters themselves.
I thought about grouping the exporters into a single collection as suggested by some people. The only problem is that Spring MVC uses the HttpInvokerServiceExporter Spring bean names as endpoint URIs when registering the exporters into its own configuration. I must therefore register each exporter as a “first-class citizen” bean with its own bean name into the application context.
Given these constraints, the problem I have arises in (1) when I try to retrieve the underlying services to be encapsulated into exporters: they are not necessarily ready yet, which results into UnsatisfiedDependencyExceptions.
I tried solutions with a #PostContruct-annotated method, with a BeanPostProcessor, with an #Autowired method (as shown above), nothing is working as required.
Does anyone know about a way or a technique to initialize and register multiple beans inside a single method under my constraints described above? Such a method doesn't need to be annotated with #Bean, #Autowired, or any other specific annotation, it's just an example of what I tried.
In the client module, mercifully, the HttpInvokerProxyFactoryBean instances need only the interfaces and the bean names, so constraint (1) above should not apply.
Thanks in advance for any help you can provide...
I'm not 100% I've understood what you're trying to do but I wonder if you could try autowiring a List of beans that implement an interface?
e.g.
public interface MyService {
String getKey();
void doStuff();
}
Then implement as many of these as you require
e.g.
#Component
public class FirstService implements MyService {
public String getKey() {
return "/first";
}
public void doStuff() {
...
}
}
then have a factory bean with the autowired list
#Component
public class MyServiceFactory {
private final List<MyService> services;
#Autowired
public MyServiceFactory(List<MyService> services) {
this.services = services;
}
}
To add more implementations of MyService, simply add them as #Component and Spring magically picks them up and adds them to the list.
Sometimes I find it useful to access my implementations via a Map
#Component
public class MyServiceFactory {
private final Map<String, MyService> services;
#Autowired
public MyServiceFactory(List<MyService> services) {
this.services = services
.stream()
.collect(toMap(MyService::getKey, Function.identity()));
}
public MyService getServiceByKey(String key) {
return services.get(key);
}
}
I find this keeps each implementation nice and self contained (and easy to test). Spring automatically picks up all the components that implement my interface without the factory having a huge number of imports. And I can test the factory easily by mocking the list of implementations.
I have a web application with JAX-RS, CDI and EJB. In each resource I inject a Stateless SessionBean, and my question is whether it is possible to inject the same instances into a provider of JAX-RS and the Stateless SesionBean. I am trying to pass some data that come in each request to the Stateless SesionBean from a ContainerRequestFilter. All EJB components are accessed only by jax rs resources.
Example:
public class Bean {
private String attr;
// getter and setter
}
#Stateless
public class BeanService {
#Inject
Bean bean;
public void doStuff() {
bean.getAttr();
// do something with bean.attr
}
}
#Path("/bean")
public class BeanResource {
#Inject
BeanService service;
#GET
public void doStuff() {
service.doStuff():
}
}
#Provider
public class BeanRequestFilter implements ContainerRequestFilter {
#Inject
Bean bean;
#Override
public void filter(ContainerRequestContext containerRequestContext) throws IOException {
String data = null; // <- get data from request
bean.setAttr(data);
}
}
Update
Change the Bean for Pojo, my only intention is use a class that hold some state that come in every request and can be transmited in each invocation, since the PojoResource to PojoService. I want to do it in this way because all the services retrive this data and I don't want to pass this as parameter on every method.
This looks like your Bean class is essentially request scoped, so changing it to:
#RequestScoped
public class Bean {
...
}
should have the desired effect. The same instance will be injected in both the BeanRequestFilter and the BeanService.
However, I think you may also get what you're looking for by injecting the ContainerRequestContext directly into the BeanService and forgetting about Bean altogether.
#Stateless
public class BeanService {
#Context
ContainerRequestContext containerRequestContext;
public void doStuff() {
// <- get data from request
}
}
If you want the Bean to be a kind of singleton using CDI see the #ApplicationScoped annotation (in that case Bean should be Sersializable)
Or if you want the EJB BeanService to be a singleton see the #Singleton annotation
Before answering the question, Bean should never be updated. A concept of bean is that which provides a service, and uses data to process a request.
That said, you can of course provide data as bean, but then the data needs to be produced at one point to be used, and not to be updated.
I would therefore use the BeanRequestFilter to produce the bean, and let the BeanService inject the produced bean.
This notwithstanding however, i see that this is a request based data? is it a header data?, request parameter? Then i would suggest that you use the jax-rs #QueryParam or #HeaderParam or #PathParam or #FormParam or #CookieParam within the jax-rs resource class, and then provide the data as a domain object parameter to your BeanService thus:
#Path("/api/resource-path")
public class MyResource {
public void processSomething(#QueryParam("qparam") String param, #HeaderParam("hparam") String hParam) {
MyDomain domain = new MyDomain(qParam, hParam);
myService.process(domain);
}
}
I have some beans (of multiple types, CDI, #Stateless and #Singleton beans). Some of their fields shall get injected from database values.
public class MyBean {
#Inject
#DbConfigValue(MyConfig.HOST)
String host;
}
So I added a custom #Qualifier (DbConfigValue) used by a Producer. The producer reads and caches config values from a database and injects them into the beans.
#Singleton
#Lock(LockType.READ)
public class Configuration {
#Produces
#Dependent
#DbConfigValue
public String getDbConfigValue(InjectionPoint point) {
// get key for the config-value from qualifier-annotation of the injected field
String key = point.getAnnotated().getAnnotation(DbConfigValue.class).value();
// i have read+cached database config values in #PostConstruct before
return cachedConfigValues.get(key);
}
}
This works well for initial injection / bean construction. Some web tutorials out there are suggesting this approach.
Now, I think it is reasonable to assume that config values, if stored in DB, might change at runtime. So, whenever an admin changes a database config value, I currently do fire a CDI-event.
Question: is there any way to re-inject values into fields of already-initialized bean-instances? Or is injection always related to instance-creation only?
E.g. I had s.th. similar to this in mind:
public class MyEventListener {
#Inject
BeanManager beanManager;
#Asynchronous
public void onDbConfigValueChangedEvent (#Observes(during = TransactionPhase.AFTER_SUCCESS) DbConfigValueChangedEvent event) {
try {
// could be filtered by custom qualifier:
Set<Bean<?>> beans = beanManager.getBeans(Object.class,new AnnotationLiteral<Any>() {});
for (Bean<?> bean : beans) {
Set<InjectionPoint> points = bean.getInjectionPoints();
// What now? javax.enterprise.inject.spi.Bean is the
// bean-representation only.
// Can I somehow resolve the actual bean-instances here?
// Then update Field via Reflection?
}
}
catch(Exception e){
// ...
}
}
}
I also considered DeltaSpike which has some methods for injection-control. However, I did only find methods to inject into new bean instances, or even with new- or null-CreationalContexts (beans not CDI-managed afterwards)
Please note: I am aware that I can solve this specific use-case by injecting the configuration and explicitly getting the current values on each request like this:
public class MyBean {
#Inject
Configuration config;
public void someMethod(){
String host = config.getConfig(MyConfig.HOST);
// ...
}
}
However, I am wondering about the question in general: is there any support for re-injection? Or if not, do the specs (CDI or Java EE) forbid it?
Depending on how fast/slow your db is, this may be expensive. You could probably leverage some cacheing mechanism in the producer method.
Leverage on Instance injection mechanims, which lazily loads the actual injected bean.
Your Producer (Probably leveraging on some of cache to avoid db calls all the tome)
#Singleton
#Lock(LockType.READ)
public class Configuration {
#Produces
#RequestScoped //May fail if not in a request-context, but for ejb-calls, it is guaranteed to work as CDI has EJB Request Context
#DbConfigValue
public String getDbConfigValue(InjectionPoint point) {
// get key for the config-value from qualifier-annotation of the injected field
String key = point.getAnnotated().getAnnotation(DbConfigValue.class).value();
// i have read+cached database config values in #PostConstruct before
return cachedConfigValues.get(key);
}
}
And the injection points:
#SessionScoped
public class MyBean {
#Inject
#DbConfigValue(MyConfig.HOST)
private Instance<String> host;
public void doSomething() {
String myHost = host.get(); // of course will throw exception if value is failing. It will be resolved with every request.
}
}
I have a stateful bean:
#Stateful
public class ClientContext {
private Band band;
public Band getBand() {
return band;
}
public void setBand(Band band) {
this.band = band;
}
}
I have Arquillian test.
public class RequestTest extends Arquillian {
...
#Inject
private ClientContext context;
#Inject
private RequestProcessor processor;
#Test
public void test() {
context.setBand(new Band());
Assert.assertNotNull(context.getBand());
processor.doSomething();
}
}
And Processor code:
#Stateless
#LocalBean
public class RequestProcessor {
...
#Inject
private ClientContext context;
public void doSomething() {
System.out.println(context.getBand());
}
}
I expect RequestProcessor to print out the Band. But actually I get null every time. What can be wrong or may be I don't understand Stateful beans correctly?
You are answering the question yourself, the main basis about the stateful is the keep just one instance per injection, which will live as long the injecting bean does.
so in you need to share a state between beans, you could use a #SessionBean
To clarify, the #Stateful means one instance are going to be created for each place where you are injecting it, this is useful when you need to bind some actions and their state to ONE component, so, if you need to create some info and then share between other classes you need to pick how you want to share it:
#Singleton: There will be just one instance for the entire app.
#SessionScoped: There will by one instance per client.
#Stateless: Will create one if there is no other available, after it will be release for use of other clients
If you are managing views the you can use too:
#RequestScoped: Will create one instance for each request and then destroys it.
#ViewScoped: The bean will remain as long the client keep making updates within the same view
Based on parameters passed to a method, I need to select from one of many Spring beans that are implementations of the same class, but configured with different parameters.
E.g. if user A invokes the method, I need to call dooFoo() on bean A, but if it's user B then I need to call the very same method, only on bean B.
Is there a 'Springier' way of doing this other than sticking all the beans in a map, and deriving a key from the parameters passed to my method?
We face that issue in our project, and we solve it through a Factory-Like class. The client class -the one that needed the bean at runtime- had an instance of the factory, that was injected through Spring:
#Component
public class ImTheClient{
#Autowired
private ImTheFactory factory;
public void doSomething(
Parameters parameters) throws Exception{
IWantThis theInstance = factory.getInstance(parameters);
}
}
So, the IWantThis instance depends on the runtime value of the parameters parameter. The Factory implementation goes like this:
#Component
public class ImTheFactoryImpl implements
ImTheFactory {
#Autowired
private IWantThisBadly anInstance;
#Autowired
private IAlsoWantThis anotherInstance;
#Override
public IWantThis getInstance(Parameters parameters) {
if (parameters.equals(Parameters.THIS)) {
return anInstance;
}
if (parameters.equals(Parameters.THAT)) {
return anotherInstance;
}
return null;
}
}
So, the factory instance holds reference to both of the posible values of the IWantThis class, being IWantThisBadly and IAlsoWantThis both implementations of IWantThis.
Seems like do you want a ServiceLocator using the application context as registry.
See ServiceLocatorFactoryBean support class for creating ServiceLocators mapping keys to bean names without coupling client code to Spring.
Other option is to use a naming convention or annotation based configuration.
for example, assuming that you annotate Services with #ExampleAnnotation("someId"), you can use something like the following Service Locator to retrieve them.
public class AnnotationServiceLocator implements ServiceLocator {
#Autowired
private ApplicationContext context;
private Map<String, Service> services;
public Service getService(String id) {
checkServices();
return services.get(id);
}
private void checkServices() {
if (services == null) {
services = new HashMap<String, Service>();
Map<String, Object> beans = context.getBeansWithAnnotation(ExampleAnnotation.class);
for (Object bean : beans.values()) {
ExampleAnnotation ann = bean.getClass().getAnnotation(ExampleAnnotation.class);
services.put(ann.value(), (Service) bean);
}
}
}
}
Sticking them in a map sounds fine. If it's a Spring-managed map (using util:map, or in Java config), that's better than creating it somewhere else, because then Spring owns all the object references and can manage their lifecycle properly.
If the beans (A, B) you are talking about are SessionScope its no problem at all, they will be selected correctly.
public class BusinessLogic {
private BaseClassOfBeanAandB bean;
public void methodCalledByUserAorB() {
bean.doFoo();
}
}