Recover environment properties sent to EJB - java

I have a Delegate that instanciate the corresponding Bean sending credentials (Josso Authentication) through InitialContext as shown here.
At Bean, I've tried to recover Josso Data with SessionContext, as shown below:
#Resource private SessionContext context;
The problem I'm facing is that I couldn't retrieve Josso Data at Bean scope. I've tried "context.getEnvironment()" but this method is deprecated and I didn't find any alternative.
In order to find a solution, I've tried:
context.lookup(JNDI_BEAN_NAME);
context.lookup("java:comp/env/JNDI_BEAN_NAME")
context.lookup("java:comp/env")
But the two first commands only return me the Bean itself and the last one only return me global variables.
What is the correct alternative to "context.getEnvironment()"?

java:comp/env finds container-managed resources only and is read-only at runtime. If you want, you can expose a local interface that gets Josso credentials from the delegate.
#Local
public interface AuthenticatorLocal {
void getJossoCredentials();
}
Otherwise, you can just use context.getCallerPrincipal().

Related

How to inject a scoped-proxy bean into a singleton bean by using constructor injection

I'm developing a web application using Spring MVC, and want to have a request scoped Date bean which indicates when each request happens. To define such Date bean, I have written a following bean definition into application context xml.
<bean id="now"
class="java.util.Date"
scope="request">
<aop:scoped-proxy/>
</bean>
Injecting this bean into a singleton bean by using field injection works fine.
public class ASingletonBean {
#Autowired
private Date now;
...
}
But I don't want to use field injection because it's not recommended. My IDE suggests to use constructor injection instead.
public class ASingletonBean{
private final Date now;
#Autowired
public ASingletonBean(Date now) {
this.now = now;
}
}
Now the code above throws a following exception when the application launches.
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'scopedTarget.java.util.Date#0':
Scope 'request' is not active for the current thread;
consider defining a scoped proxy for this bean if you intend to refer to it from a singleton;
nested exception is java.lang.IllegalStateException:
No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread?
If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet:
In this case, use RequestContextListener or RequestContextFilter to expose the current request.
How can I avoid this error?
Please, don't do that. Creating a new bean (you don't need) on every request is an overhead that can be easily avoided. Instead create a class + bean that implements java.util.function.Supplier for example:
#Component
class DateTimeProvider implements java.util.function.Supplier<Date> {
...
}
and then inject this java.util.function.Supplier<Date> into your `ASingletonBean'. This way, you will be able to get a current date/time when processing a request.
And few additional notes:
Use JodaTime or JDK8 JavaTime API instead of java.util.Date,
If you cannot use JDK8 (java.util.function.Supplier was added in JDK8) then you can either create your own interface or use one provided by Guava,
If you need a very precise timing for the received request then you should consider creating some sort of a "time stamping" filter, most likely by extending org.springframework.web.filter.OncePerRequestFilter class.
Edited - to answer a questions from comment:
"why it is preferable to using request-scoped bean" - A bean would always have to be injected to any business component you would create. Seems a bit much for just having a 'request timestamp'.
The request object you receive from the outside world should be translated into some sort of a 'domain request' (that contains the timestamp) and then handled internally only in its domain form. (read more on: Hexagonal Architecture a.k.a Ports and Adapters, Domain Driver Design). Why so? Because one can easily imagine that a request that now enters the system only by the means of HTTP request could enter the system in the form of JMS message or batch import operation - then you would only need to provide a new adapter to the system and entire logic inside core domain would not change.
If you are using Spring Boot then it is enough to create a bean that extends org.springframework.web.filter.OncePerRequestFilter#OncePerRequestFilter and implement your logic inside the only method that needs to be implemented. Spring will automatically use your filter.
Though Rafal G's answer makes sense and explains good practices, I've also found a dirty way to solve the problem.
The workaround is to inject not Date bean but a "provider" bean instead. First, you define that provider bean as aop:scoped-proxy bean.
<bean id="currentLocalDateTimeProvider"
class="com.example.CurrentLocalDateTimeProvider"
init-method="init"
scope="request">
<aop:scoped-proxy/>
</bean>
CurrentLocalDateTimeProvider's is defined as below:
import java.time.LocalDateTime;
public class CurrentLocalDateTimeProvider {
private LocalDateTime now;
public void init() {
now = LocalDateTime.now();
}
public LocalDateTime now() {
return now;
}
}
And inject this into singleton beans.
public class ASingletonBean {
#Autowired
private final CurrentLocalDateTimeProvider provider;
}
Then call it's now method to get the request time stamp.
Hope this helps someone :)

Using java annotation with dynamic parameter

What I'm trying to achieve is have a #Resource with a dynamic name parameter. Specifically, I want to inject a DataSource object using #Resource(name = "{JNDI_NAME_PARAM}") because we can have many datasources configured in an application server, and the datasource used by the application is defined in an .xml or .config file. Since I do not know the name of the datasource during compile time I need to be able to get it at runtime. Right now I'm injecting a custom #ApplicationScoped bean which creates a datasource in its #PostConstruct method using InitialContext().lookup(). However I'm curious (mostly because it is more elegant) as to how I could achieve injection using the #Resource annotation.
I COULD create a custom default JNDI name in the app server and change the datasource it points to when needed but this can't work with more than one deployment and many times we have the application deployed twice, once in a test database and once in a production database so having the JNDI point at two different datasources at the same time.
You can use the Method based injection.
It requires the setter method (setMyDB).
public class Test {
public javax.sql.DataSource myDB;
#Resource(name="student")
private void setMyDB(javax.sql.DataSource ds) {
myDB = ds;
}
}
If the names are known, we can have multiple resources under
#Resources({
#Resource(your type)
#Resource(your type)
})

Is there a way to inject dependency in code using interface?

I want to get the reference to some Stateless bean inside my code. The problem is I only know the Interface it is implementing (i do not know the name, classname or any other).
Normally for any other EJB i would use #EJB annotation with an Interface
private #EJB MyInt myInt;
Do anyone know if it is possible to get it via code like for ex:
MyInt myInt = new InitialContext().lookuup(MyInt.class);
?
Unfortunately, in the case where you have multiple implementations for the same interface, you need to specify which implementation you want. Thus, you will need the implementation's mapped name or you will need the JNDI name in order to look it up like that. Your Application Server administrator should be able to provide the JNDI name for you.
If you are going to want to swap out implementations at runtime then you cannot use injection. You will have to do a JNDI lookup.
We built a little factory to lookup a stateless session bean by getting the JNDI name from a configuration table in our database. This enables you to swap out implementations by changing the JNDI name in the database table.
Here is an example of our bean lookup method:
public static Object getBean(String jndiName) throws NamingException {
Object bean = null;
Context ctx = new InitialContext();
bean = ctx.lookup(jndiName);
return bean;
}
I hope this helps. :)
I am supposing that you want to lookup a remote EJB since you don't know the concrete class name. The remote EJBs are registered in the RMI registry (consider a map <JndiName, RemoteObject>). Even if the service provider don't specify a JNDI name for the remote service, the application server creates the JNDI name based on the service interface name and register in the RMI registry.
So the client will need to know the JNDI name to lookup the service.

Re initialize bean in spring during runtime

I'm wondering if there is possibility to recreate a bean which was already created in java configuration on web app startup.
What I want to do is to reconfigure bean settings.
For example I create new bean with path to database:
#Bean
public TestBean getTestBean() {
TestBean tb = new TestBean("some_path_taken_from_external_point");
return tb;
}
During runtime I want to change the path. Let's assume that this bean doesn't have the setter method for database path.
I will have some kind of event and a listener for this event. Listener should reinitialize TestBean with new path.
Is this possible?
I was thinking of some kind of wrapper. In such case I would have class TestBeanWrapper which will have method get() which will return TestBean instance and recreate(String path) which will create new object with given path.
I'm not sure exactly if such wrapper would work for me, as the TestBean is a class from external library, and I'm not sure if it's not injected somewhere (but probably it's not injected).
More possible is that the other beans may rely on TestBean, so they also must be reinitialized (in case if they won't have setters for my TestBean).
Is this even possible in Spring (4.1) ? What is the best approach for such cases?
So I'm still unsure why you would want to change the path but I have 2 suggestions:
1. Look at setting the scope on the Bean.
By setting the scope on the bean, you can regenerate the bean based on context. Look at Bean Scopes for more information.
2. Look at maybe using a controller or a service.
Controllers and services allow getters and setters which may give you more control.

is it not allowed to implement a single local interface by two stateless beans?

I am getting following exception when a Local Interface is implemented by two Stateless beans, in which one having normal functionality and other having some enhanced functionality in it.
java.lang.RuntimeException: could not
resolve global JNDI name for #EJB for
container UserBean: reference class:
org.app.SecurityServiceLocal ejbLink:
duplicated in Some.jar
Finally I came to know why I am getting this exception
I have used #EJB annotation to inject a Stateless bean into another Stateless bean Name UserBean with following code
#Stateless(name="UserBean")
#EJB(name="app/SecurityService",
beanInterface=SecurityServiceLocal.class)
public class UserBean implements UserRemote{
}
If you check the injection details I was injecting SecurityServiceLocal, which was implemented by two Stateless bean classes name SercurityServiceBean and SecurityServiceEnhaBean. So, container is in ambiguity state to decide which bean to inject in as both are implementing same interface.
This can be resolved by specifying some more information like beanName property value in #EJB annotation. There you need to provide which stateless bean class needs to be injected by using bean name(declared at that bean level (or) in ejb-jar.xml). check the code to identify the change in the injection mapping
#Stateless(name="UserBean")
#EJB(name="app/SecurityService",
beanInterface=SecurityServiceLocal.class,
beanName="SecurityServiceEnha")
public class UserBean implements UserRemote{
}
It's hard to say for sure without seeing code. A good first step would be to use the optional mappedName="" attribute on your session beans' annotion to give each a unique JNDI name. You'll have to use an equivalent mappedName attribute in your client to make sure you are using the bean that you intent.

Categories