I'm using Wicket + EJB3 in an application and I face a problem but I can't find any topic related, so here it is:
I'm using Wicket authentication, and need to use methods from an EJB in the overrided methods authenticate(...).
I can use this EJB in any wicket page, but when it comes to the WebSession, it stays Null, the injection is not working somehow.
My WicketSession class looks something like this:
public class WicketSession extends AuthenticatedWebSession {
#EJB(name = "UserService")
private UserService userService;
private User user = null;
public WicketSession(Request request) {
super(request);
}
#Override
public boolean authenticate(final String login, final String password) {
user = userService.findByLoginPwd(login, password);
return user != null;;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
And my EJB3:
#Remote
public interface UserService {
public User findByLoginPwd(final String login, final String pwd);
}
#Stateless
public class UserServiceImpl implements UserService {
public User findByLoginPwd(final String login, final String pwd) {
[...]
}
}
The Web part with Wicket is packaged in a war, the business part with EJBs is packaged in a jar, and then I make a ear to deploy it on a JOnAS server.
Any help would be highly appreciated =)
Nicolas
I'm pretty sure the injection works with an IComponentInstantiationListener (at least that's how the Spring version works). Update: it does, see this document.
However, Sessions are not components, so a different mechanism is needed. Perhaps there is a way to wire your Session in the Application.newSession() method? You will have to take a look at the implementation of JavaEEComponentInjector and copy what it does when creating your session.
As Sean Patrick Floyd noted, Sessions are not components, so the automatic injection supplied for Wicket components doesn't apply.
A common idiom for injecting stuff in a non-component is to add the line
InjectorHolder.getInjector().inject(this);
to the constructor.
I haven't used this for a WicketSession extension, but I don't know of a reason it won't work.
In JavaEEComponentInjector, the inject method is almost certainly doing a JNDI lookup, and you could do a JNDI lookup yourself to get the object, but this is reusing the existing injection, and if you decide to change injectors (say by extending JavaEEComponentInjector), it ensures that you'll continue to use the same injection.
Related
I'm using MSAL on the front end (PKCE) and azure-active-directory-spring-boot-starter on the server to provide an entity which represents the logged in user and their claims.
I've built a class which wraps Microsoft's UserPrincipal to provide easy access to well-known claims:
import com.microsoft.azure.spring.autoconfigure.aad.UserPrincipal;
public class MyCustomUser {
private UserPrincipal userPrincipal;
public MyCustomUser(UserPrincipal userPrincipal) {
this.userPrincipal = userPrincipal;
}
public String getEmployeeId() {
return String.valueOf(this.userPrincipal.getClaim("emplid"));
}
}
I make this available via a helper class
#Component
public class MyAppSecurityContext {
public MyCustomUser getUser() {
UserPrincipal principal = (UserPrincipal) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
return new MyCustomUser(principal);
}
}
and then use it in my service layer:
#Service
public class AnnouncementServiceImpl implements AnnouncementService {
#Autowired
private MyAppSecurityContext securityContext;
#Override
public List<Announcement> saveAnnouncement(Announcement announcement) {
MyCustomUser currentUser = this.securityContext.getUser();
String empid = currentUser.getEmployeeId();
return this.announcementRepository.saveAnnouncement(empid, announcement);
}
}
This works, but it feels wrong. I'd prefer to have MyCustomUser extend UserPrincipal and have getPrincipal() return my custom type (without effectively re-implementing my own UserPrincipal) instead of providing a facade in front of a member object. The problem is that UserPrincipal's constructor expects JWT concerns, which suggests that this isn't the correct approach. Is there another, more appropriate way to model the user for a Spring security project which relies on client-side claims only?
#Josh.
In azure-active-directory-spring-boot-starter, UserPrincipal is used in AADAuthenticationFilter and AADAppRoleStatelessAuthenticationFilter. Now both of the 2 filters are deprecated.
Could you please use the latest version of azure-spring-boot-starter-active-diectory? Which is 3.7.0, and it works for spring-boot:2.5.0. Since you used UserPrincipal, then you application is a resource server.
Here is the docs: https://github.com/Azure/azure-sdk-for-java/tree/azure-spring-boot-starter-active-directory_3.7.0/sdk/spring/azure-spring-boot-starter-active-directory#accessing-a-resource-server
We have some samples.
You current application is similar to:
https://github.com/Azure-Samples/azure-spring-boot-samples/tree/azure-spring-boot_3.6/aad/azure-spring-boot-sample-active-directory-resource-server-by-filter-stateless
https://github.com/Azure-Samples/azure-spring-boot-samples/tree/azure-spring-boot_3.6/aad/azure-spring-boot-sample-active-directory-resource-server-by-filter
But the 2 usage is deprecated, I suggest you to learn the new way:https://github.com/Azure-Samples/azure-spring-boot-samples/tree/azure-spring-boot_3.6/aad/azure-spring-boot-sample-active-directory-resource-server
I'm developing a translation service that currently works inside another Service. For example:
public Profile getById(int chainId, int profileId, Integer languageId) {
Profile profile = profileRepository.getById(chainId, profileId);
translationService.translate(profile, languageId); // Here
return profile;
}
Now, to avoid to use a translate method on every service method of all the application, and as I only have the language of a user from the controller, I would like to execute the translate method before every Profile (and any other object) is returned to the client.
I tried to implement HandlerInterceptor in a custom interceptor, but it seems it doesn't returns the instance of the object that I'm returning. Anyone could help?
Another way to do it could be to translate every object that came from a select in Hibernate, but I also don't find any good solution to it this way...
The solution was to use Spring AOP. Probably the question wasn't very well explained, but what we needed was a way to intercept the object a user was asking to the backend, because they are able to create their own translations and we save them in the database. We had to return the model with the correct translation for each user, who has their localization in their profile. Here's the way we intercept it:
#Component
#Aspect
public class TranslatorInterceptor extends AccessApiController {
Logger logger = LoggerFactory.getLogger(this.getClass());
#Autowired
public TranslationService translationService;
#Pointcut("execution(* com.company.project.api.controller.*.get*(..))")
public void petitionsStartWithGet() { }
#Pointcut("execution(* com.company.project.api.controller.*.list*(..))")
public void petitionsStartWithList() { }
#Pointcut("execution(* com.company.project.api.controller.*.find*(..))")
public void petitionsStartWithFind() { }
#AfterReturning(pointcut = "petitionsStartWithGet() || petitionsStartWithList() || petitionsStartWithFind()", returning = "result")
public void getNameAdvice(JoinPoint joinPoint, Object result){
translationService.translate(result, getCustomUserDetails().getLanguageId());
logger.debug("Translating " + result.getClass().toString());
}
}
What we do here is to "watch" all the methods in the package "controller" that start by 'get', 'list' or 'find' (getById(), for example) and through this advice, we intercept the object before is sent to Jackson. The method getCustomUserDetails comes from AccessApiController, which is a class we did to provide our Controllers with some information we need.
Is it bad practice to use dependency injection in factory classes? Should I let the users of my framework take care of dependency injection? Should I use approach A or approach B?
SomeUserClass
package com.impl;
#Service
public class SomeUserClass {
#Autowired
private SMSActionFactoryService actionFactoryService:
#Autowired
private PropertyManager properties;
public void doStuff(){
// approach A
SMSAction action = actionFactoryService.createAction("hello");
// approach B
action = SMSActionFactory.createAction(properties, "hello");
// the user should never call Action::doAction.
// It gets called by the framework on a condition.
scheduler.addAction(State.ERROR, action)
}
}
SMSAction
package com.framework;
public class SMSAction extends Action {
public SMSAction(PropertyManager properties, String message){
}
public void doAction(){
}
}
SMSActionFactoryService
package com.framework;
#Service
public class SMSActionFactoryService {
#Autowired
private PropertyManager properties;
public SMSActionFactory createAction(String message) {
return new SMSActionFactoryService(properties, message);
}
}
SMSActionFactory
package com.framework;
public class SMSActionFactory {
public static SMSActionFactory createAction(PropertyManager properties, String message) {
return new SMSActionFactory(properties, message);
}
}
I think you have a context problem, so the answer depends on the context. But I'll give some of my experience, and not a formal (and irrefutable) answer. Based on the title of the answer (practices) I'll give you what I call good practices tips that helped me a lot when I started Spring development.
First of all, let's think about the Dependency Injection you have. You're wiring a field, and we know that the Spring team used to suggest us to use constructor based injection (and assertions for all mandatory dependency) as you can see here. Well, I know it was a problem with the tests framework that couldn't wire the dependencies in an easy way, but now they can. But there's another advantage using this pattern, you can make your bean field final. Another advantage is that you prevent circular dependencies, like X depends on Y and Y depends on X and so on. So, as the first tip, I would suggest you to use something like:
private final SMSActionFactoryService actionFactoryService:
private final PropertyManager properties;
#Autowired
public SomeUserClass(SMSActionFactoryService actionFactoryService,
PropertyManager properties) {
Assert.notNull(actionFactoryService, "The actionFactoryService bean is null, you should provide the bean to run this application");
Assert.notNull(properties, "The properties bean is null, you should provide the bean to run this application");
this.actionFactoryService = actionFactoryService;
this.properties = properties;
}
This way you prevent any other code part to change the field value. As you can see in Spring autowiring setter/constructor PROs and CONs this is a preference subject.
Now, for the second tip, I wouldn't use #Service for a factory, not even #Component because factories needs to be open for extension and close for modification. You're going to understand better if take a look here.
That said friend, I suggest you to embrace approach B.
I have a Java project where I use Jersey (1.17) and Guice (3.0). SessionScoped beans work in local dev, but don't work when deployed on GAE. The problem is that they don't keep session state.
Sessions are enabled in web.xml: <sessions-enabled>true</sessions-enabled>
My Session bean (SessionService) is:
#SessionScoped
public class SessionService implements Serializable {
#Inject transient Logger log;
private Locale locale = Locale.US;
public synchronized Locale getLocale() { return locale; }
public synchronized void setLocale(Locale locale) { this.locale = locale; }
}
and it's bound to Session scope in ServletModule bind(SessionService.class).in(ServletScopes.SESSION);
Controller where I use it is:
#Path("/settings")
public class SettingsController {
#Inject SessionService sessionService;
#GET
#Path("/setLocale")
public Object setLocale(#QueryParam("languageTag") String languageTag) {
sessionService.setLocale(Locale.forLanguageTag(languageTag));
return "OK";
}
#GET
#Path("/getLocale")
public Object getLocale() { return sessionService.getLocale().getLanguage(); }
}
With local dev server it works fine. When deployed on GAE (1.9.5) it sets the locale the first time and then it stays the same forever even though I call setLocale again and again. Why does it not work ?
Strangely enough, I found an obscure way to make it work, but I don't know why it makes it work. To have it running, it's necessary to touch HttpSession before setting locale. Like request.getSession(true).setAttribute("whatever", "bar"). As if server needed to be recalled that SessionService wants to do something with Session. Why is that?
I've found a way how to get desired SessionScoped-like functionality. Don't use #SessionScoped as it apparently does not work on GAE, but instead use Provider<HttpSession>.
So your code will be like
public class SessionService {
#Inject Provider<HttpSession> httpSessionProvider;
public void saveSecurityInfo(Object securityInfo) {
httpSessionProvider.get().setAttribute('sec_info', securityInfo);
}
public Object loadSecurityInfo() {
return httpSessionProvider.get().getAttribute('sec_info');
}
}
In controller you'd insert it as #Inject SessionService sessionService;
I've tested this approach on GAE and it works (keeps information in browser session).
I was just reading this article:
http://www.tutorialized.com/view/tutorial/Spring-MVC-Application-Architecture/11986
which I find great. It explains the layer architecture nicely and I was glad that the architecture I'm working with pretty much is what he describes.
But there's one thing, that I don't seem to get:
First: what exactly is business logic and what is it not? In the article he says (and he's not the only one), that business logic should go in the domain model. So an Account class should have an activate() method that knows how to activate an Account. In my understanding this would involve some persistence work probably. But the domain model should not have a dependency of DAOs. Only the service layer should know about DAOs.
So, is business logic just what a domain entity can do with itself? Like the activate()method would set the active property to true, plus set the dateActivated property to new Date() and then it's the service's task to first call account.activate()and second dao.saveAccount(account)? And what needs external dependencies goes to a service? That's what I did until now mostly.
public AccountServiceImpl implements AccountService
{
private AccountDAO dao;
private MailSender mailSender;
public void activateAccount(Account account)
{
account.setActive(true);
account.setDateActivated(new Date());
dao.saveAccount(account);
sendActivationEmail(account);
}
private void sendActivationEmail(Account account)
{
...
}
}
This is in contrast to what he says, I think, no?
What I also don't get is the example on how to have Spring wire domain objects like Account. Which would be needed should Account send its e-mail on its own.
Given this code:
import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;
public class Account {
private String email;
private MailSender mailSender;
private boolean active = false;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public void setMailSender(MailSender mailSender) {
this.mailSender = mailSender;
}
public void activate() {
if (active) {
throw new IllegalStateException("Already active");
}
active = true;
sendActivationEmail();
}
private void sendActivationEmail() {
SimpleMailMessage msg = new SimpleMailMessage();
msg.setTo(email);
msg.setSubject("Congrats!");
msg.setText("You're the best.");
mailSender.send(msg);
}
}
If I use Hibernate, I could use the DependencyInjectionInterceptorFactoryBean in order to wire mailSender. If I use JDBC instead, I'd really write the follwing cumbersome code? Plus, also when I create a new instance for Account in a MVC controller, for let's say populating it to a model??
BeanFactory beanFactory = new XmlBeanFactory(
new ClassPathResource("chapter3.xml"));
Account account = new Account();
account.setEmail("email#example.com");
((AutowireCapableBeanFactory)beanFactory).applyBeanPropertyValues(
account, "accountPrototype");
account.activate();
This is not reliable and very cumbersome, no? I'd have to ask myself where that object has been created, whenever I see an instance of Account. Plus, if I would go with this approach: I have not a single appContext.xml I could pass, but several, one for persistence, one for the service config. How would I do that? Plus, that would create a completely new context every time such an instance is created or am I missing something?
Is there no better solution to that?
Any help is greatly appreciated.
I think send activation email action is not a part of a business-layer here, your domain logic here is the account activation action, that piece of logic should live in the DomainObject with name Account ( activate() method ). The send activation email action is the part of infrastructure or application layers.
Service is the object that handles account activation request and connects business-layer and others. Service takes the given account, activates them and performs send activation email action of MailSenderService or something like this.
Short sample:
public AccountServiceImpl implements AccountService
{
private AccountDAO dao;
private MailSenderService mailSender;
public void activateAccount(AccountID accountID)
{
Account account = dao.findAccount(accountID);
....
account.activate();
dao.updateAccount(account);
....
mailSender.sendActivationEmail(account);
}
}
The next step that I can suggest is a complete separation of business layer
and a layer of infrastructure. This can be obtained by introducing the
business event. Service no longer has to perform an action to send an
email, it creates event notifying other layers about
account activation.
In the Spring we have two tools to work with events, ApplicationEventPublisher and ApplicationListener.
Short example, service that publish domain events:
public AccountActivationEvent extends ApplicationEvent {
private Account account;
AccountActivationEvent(Account account) {
this.account = account;
}
public Account getActivatedAccount() {
return account;
}
}
public AccountServiceImpl implements AccountService, ApplicationEventPublisherAware
{
private AccountDAO dao;
private ApplicationEventPublisher epublisher;
public void setApplicationEventPublisher(ApplicationEventPublisher epublisher) {
this.epublisher = epublisher;
}
public void activateAccount(AccountID accountID)
{
Account account = dao.findAccount(accountID);
....
account.activate();
dao.updateAccount(account);
....
epublisher.publishEvent(new AccountActivationEvent(account));
}
}
And domain event listener, on the infrastructure layer:
public class SendAccountActivationEmailEventListener
implements ApplicationListener<AccountActivationEvent> {
private MailSenderService mailSender;
....
public final void onApplicationEvent(final AccountActivationEvent event) {
Account account = event.getActivatedAccount():
.... perform mail ...
mailSender.sendEmail(email);
}
}
Now you can add another activation types, logging, other infrastructure stuff support without change and pollute your domain(business)-layer.
Ah, you can learn more about spring events in the documentation.