Should I close the session before closing the resource resolver - osgi

I have simple service, lets use resourceResolver and session for some logic:
#Component(immediate = true)
#Service(value = ServiceInterface.class)
public class ServiceInterfaceImpl implements ServiceInterface {
//Some fields
#Reference
private ResourceResolverFactory resolverFactory;
private void someMethod() {
ResourceResolver resourceResolver = null;
try {
resourceResolver = resolverFactory.getServiceResourceResolver(null);
Session session = resourceResolver.adaptTo(Session.class)
someMethod2(resourceResolver);
someMethod3(session);
} catch (LoginException e) {
log.error(e.getMessage(), e);
} finally {
if (resourceResolver != null && resourceResolver.isLive()) {
resourceResolver.close();
}
}
}
//Some implementation
}
Should I close the session, or it will be closed in automatically resourceResolver.close()?

The session will be automatically closed, when you close the ResourceResolver, so resourceResolver.close() is enough. You can dig into the code to find the place where this happens. If you get a session repo.loginAdministrative(), you should logout the session at the end, but this is not the recommended way to obtain a jcr session.

Related

How To Maintain Session In Spring Boot MicroService

I am new to Spring MicroService i know how to handle session in Springboot monolithic application but can you please tell me how to handle session in microservice when we communicate with another microservice from one, and how to handle session if multiple instance of a microservice is running.
It's a complicated question and needs some extra logic to be written.
So, all methods, that may be called from one service to another should be parameterized and look like this:
public int externalCall(Session session)
{
if(sessionManager.isAliveSession(session)
{
sessionManager.touch(session);
//do some actions
}
else
{
throw new UnknownSessionException();
}
}
Then you should have one more service or module to deal with sessions. In my code I called it sessionManager.
It may possibly have such methods:
public interface SessionManager
{
/**
* to create session object in database, for example,
* with expiration date, create date etc.
*/
public void createSession();
/**
* to set the fact, that this session is
* still used and update its expiration time
*/
public void touch(Session session);
/**
* checks if session with this
* id is not expired.
*/
public boolean isAliveSession(Session session);
}
Here is an example how to call externalCall from the other service.
You will need to create class like this to perform session-based calls:
public class SessionTemplate
{
private SessionManager sessionManager;
private AtomicReference<SessionTO> session = new AtomicReference();
public <T> T execute(Callback<T> callback) {
Session session = this.getSession();
try {
return callback.doInSeance(session);
} catch (UnknownSessionException e) {
// exception may happen in externalCall method
session = this.createSession(session);
return callback.doInSeance(session);
}
}
private Session getSession() {
if (this.session.get() == null) {
synchronized(this) {
if (this.session.get() == null) {
this.session.set(this.createSession());
}
}
}
return (Session)this.session.get();
}
private Session createSession()
{
// create session in your DB
return sessionManager.createSession();
}
}
Now your remote calls will be performed like this:
public int getSmthFromRemote()
{
return sessionTemplate.execute(session -> microService.externalCall(session));
}

If and else block is executed during spring method annotated as Transactional

When I go to /confirmation-account link, in tomcat console I can see that if and else block is also executed. I can see:
print from ColorConsoleHelper.getGreenLog("loginView") and from ColorConsoleHelper.getGreenLog("confirmationAccountView")
This is really strange behavior. Why?
#RequestMapping(value = "/confirmation-account", method = RequestMethod.GET)
#Transactional
public ModelAndView displayConfirmationAccountPage(ModelAndView modelAndView, #RequestParam Map<String, String> requestParams) {
final int ACTIVE_USER = 1;
// find the user associated with the confirmation token
UserEntity userEntity = userService.findUserByConfirmationToken(requestParams.get("token"));
// this should always be non-null but we check just in case
if (userEntity!=null) {
// set the confirmation token to null so it cannot be used again
userEntity.setConfirmationToken(null);
// set enabled user
userEntity.setEnabled(ACTIVE_USER);
// save data: (token to null and active user)
saveAll(userEntity.getTrainings());
/*
RedirectAttributes won't work with ModelAndView but returning a string from the redirecting handler method works.
*/
modelAndView.addObject("successMessage", "Konto zostało pomyślnie aktywowane!");
modelAndView.setViewName("loginView");
ColorConsoleHelper.getGreenLog("loginView");
} else {
ColorConsoleHelper.getGreenLog("confirmationAccountView");
modelAndView.addObject("errorMessage", "Link jest nieprawidłowy...");
modelAndView.setViewName("confirmationAccountView");
}
return modelAndView;
}
public void saveAll(List<TrainingUserEntity> trainingUserEntityList) {
for ( TrainingUserEntity trainingUserEntity : trainingUserEntityList) {
entityManagerService.mergeUsingPersistenceUnitB(trainingUserEntity);
}
}
public void mergeUsingPersistenceUnitB(Object object) {
EntityManager entityManager = getEntityManagerPersistenceUnitB();
EntityTransaction tx = null;
try {
tx = entityManager.getTransaction();
tx.begin();
entityManager.merge(object);
tx.commit();
}
catch (RuntimeException e) {
if ( tx != null && tx.isActive() ) tx.rollback();
throw e; // or display error message
}
finally {
entityManager.close();
}
}
Below solution & explanation:
Because of /confirmation-account link is invoke twice, what is caused by dynamic proxy and #Transactional method annotated in controller It is mandatory to check how many displayConfirmationAccountPage method is invoked. It is workaround.
What do you think it is good or not to annotated #Transactional controller method?

Spring Boot CrudRepository able to read, but not write

So I've been working on an extremely simple website over the past 2 days, but I figured it would be neat to somehow link the website with a Discord bot. For the Discord bot part, I've been using the JDA library.
The issue I'm running in to is that I seem to be unable to use the save method. However, the findById and findAll seem to work perfectly fine. The way I have my code setup can be found below.
#Controller
public class IndexController extends ListenerAdapter {
private static boolean botStarted = false;
#Autowired
private NewsPostRepository newsPostRepository;
#GetMapping("/")
public String getIndex(ModelMap map) {
// TODO: add news post images.
NewsPost savedNewsPost = newsPostRepository.save(new NewsPost("Controller", "Posted through controller",
new byte[]{}, new Date(), true));
System.out.println(savedNewsPost);
return "index";
}
#GetMapping("/start")
public String startBot() {
if (!botStarted) {
try {
JDA jda = new JDABuilder(AccountType.BOT)
.setToken("my-token")
.addEventListener(this)
.buildBlocking(); // Blocking vs async
} catch (LoginException e) {
e.printStackTrace();
} catch (RateLimitedException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
botStarted = true;
}
}
return "redirect:/";
}
#Override
public void onMessageReceived(MessageReceivedEvent messageReceivedEvent) {
User author = messageReceivedEvent.getAuthor();
MessageChannel channel = messageReceivedEvent.getChannel();
Message message = messageReceivedEvent.getMessage();
if (!author.isBot()) {
if (message.getContent().startsWith("!news")) {
NewsPost savedNewsPost = newsPostRepository.save(new NewsPost("Discord", "Posted through Discord",
new byte[]{}, new Date(), true));
System.out.println(savedNewsPost);
}
}
}
}
The repository:
public interface NewsPostRepository extends CrudRepository<NewsPost, String> {
}
The weird thing is, that when I go to the index page, the NewsPost saves perfectly fine, and is visible in the database.
When I try to use the Discord bot to add a NewsPost, it returns an object in the same way it would in the method for the index, with an ID that is not null and should be usable to find it in the database, however, this entry is nowhere to be found. No exception appears either. Keep in mind that both of these save() calls are identical.
I've tried to use a service and adding #Transactional but so far nothing has worked.

Using JPA Listener to set Current User

I'm currently having a problem using a JPA Listener to update/persist the current user updating/creating an object. Here is the JPAListener's code
private static UserSession userSession = null;//Scoped-session bean
// yes i know i'm accessing a session stored in HTTP in persistence layer
#PreUpdate
public void preUpdate(AbstractDAOAuditedEntity abstractEntity) {
abstractEntity.setModificationDate(new Date());
// use userSession here to set currentUser or system
}
#PrePersist
public void prePersist(AbstractDAOAuditedEntity abstractEntity) {
// same
}
public static void setUserSession(UserSession userSession) {
DAOEntityListener.userSession = userSession;
}
If i do it while processing an HttpRequest it works, because userSession is bound to an Http Session managed by spring.
But now i have a new usage, i'm receiving data from a JmsMessage, this mean i'm running in a thread without HttpContext, and so the listener crash when trying to use userSession.
As a really quick and really dirty fix i did the following :
boolean haveUser = true;
try {
userSession.getUser();
} catch (Exception e) {
haveUser = false;
}
if (!haveUser) {}
My question is not so about how to make it works but how i should have handle this properly, whether i'm in HttpContext or not ?

vertx authentication and session management

I am using Vert.x in backend and AngularJS for my frontend.
Vert.x server receives HTTP actions using both POST and GET methods. Somehow I am getting different session ids for each request.
Following is the code snippet from my LoginFormHandler class handle routine.
authProvider.authenticate(authInfo, res -> {
if (res.succeeded()) {
Session session = context.session();
io.vertx.ext.auth.User user = res.result();
session.put("user", user);
req.response().setStatusCode(204).end("user Login success");
//...
}
//...
}
I am putting user object inside the current session. Then I move to new page and send a POST request to the Vert.x server. Inside that POST handler, I am trying to get the session object:
Session session = context.session();
io.vertx.ext.auth.User user = session.get("user");
I am not getting the user. Also when I print session ID, I get different values for both sessions.
I have following code in start routine for the thread.
router.route().handler(CookieHandler.create());
router.route().handler(
SessionHandler.create(LocalSessionStore.create(vertx)));
AuthProvider ap = new MyAuthProvier();
router.route().handler(UserSessionHandler.create(ap));
AuthHandler basicAuthHandler = BasicAuthHandler.create(ap);
router.route("/Services/rest/user/auth").handler(MyFormLoginHandler.create(ap));
router.route("/Services/*").handler(basicAuthHandler);
Try using a new handler for authentication.
router.route("/Services/rest/user/auth").handler(new MyFormLoginHandler());
router.route("/Services/*").handler(basicAuthHandler);
Implement the handler as below
class MyFormLoginHandler implements Handler<RoutingContext> {
public void handle(RoutingContext routingContext) {
HttpServerResponse response = routingContext.response();
Session session = routingContext.session();
routingContext.request().bodyHandler(new Handler<Buffer>() {
public void handle(Buffer buf)
{
....
for (User u : users){
if (u.getPassword().equals(passwd)){
session.put("user", u.getUserName());
response.setStatusCode(204).end("User Authenticated");
break;
}
}
};
});
}
}
Access the user from session.
class TestRequest implements Handler<RoutingContext> {
public void handle(RoutingContext routingContext) {
Session session = routingContext.session();
routingContext.request().bodyHandler(new Handler<Buffer>() {
public void handle(Buffer buf) {
.....
String userName = session.get("user");
.....
};
});
}
}

Resources