The teacher from my Java-coding class has published on his web page an example of what he expects us to code for ourselves. When I tried to recreate the same code within my own lab, however, I have been facing several errors. Here is the code:
public class StudentRepositoryImpl extends Repository<Student, Long> implements StudentRepositoryCustom {
private static final Logger log = LoggerFactory.getLogger(StudentRepositoryImpl.class);
public StudentRepositoryImpl()
{
super(Student.class);
}
#Override
#Transactional
public List<Student> findAllWithLabsSqlQuery()
{
log.trace("findAllWithLabsSqlQuery: method entered");
HibernateEntityManager hibernateEntityManager = getEntityManager().unwrap(HibernateEntityManager.class);
Session session = hibernateEntityManager.getSession();
Query query = session.createSQLQuery("select distinct {s.*}, {sd.*}, {d.*}" +
" from student s" +
" left join student_lab sd on sd.student_id = s.id" +
" left join lab d on d.id = sd.lab_id")
.addEntity("s", Student.class)
.addJoin("sd", "s.studentLabs")
.addJoin("d", "sd.lab")
.addEntity("s", Student.class)
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
List<Student> students = query.list();
log.trace("findAllWithLabsSqlQuery: students={}", students);
return students;
}
#Override
#Transactional
public List<Student> findAllWithLabsJpql() {
log.trace("findAllWithLabsJpql: method entered");
javax.persistence.Query query = getEntityManager().createQuery("select distinct s from Student s" +
" left join fetch s.studentLabs sd" +
" left join fetch sd.lab d");
List<Student> students = query.getResultList();
log.trace("findAllWithLabsJpql: students={}", students);
return students;
}
#Override
#Transactional
public List<Student> findAllWithLabsJpaCriteria() {
log.trace("findAllWithLabsJpaCriteria: method entered");
CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Student> query = criteriaBuilder.createQuery(Student.class);
query.distinct(Boolean.TRUE);
Root<Student> from = query.from(Student.class);
Fetch<Student, StudentLab> studentLabFetch = from.fetch(Student_.studentLabs, JoinType.LEFT);
studentLabFetch.fetch(StudentLab_.discipline, JoinType.LEFT);
List<Student> students = getEntityManager().createQuery(query).getResultList();
log.trace("findAllWithLabsJpaCriteria: students={}", students);
return students;
}
}
The errors I am facing are:
1 - the super method ("Cannot resolve method 'super(java.lang.Class)'")
2 - every getEntityManager function ("Cannot resolve method 'getEntityManager'")
3 - the "Student_" and "StudentLab_" ("Cannot resolve symbol")
In his project the same code, albeit with class name modifications, works. Is it something to do with the .iml or pom.xml files?
Here are the imported libraries:
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.jpa.HibernateEntityManager;
import org.hibernate.jpa.internal.EntityManagerFactoryImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.criteria.*;
import java.util.List;
import ro.ubb.books.core.model.*;
import ro.ubb.books.core.repository.*;
If you have also copied pom.xml, try running following command.
mvn clean package
Note : mvn(maven) must be installed.
Related
Can i use play framework linked to an existing database (Example SAP DBB) to only display :
Dashboards (Queries)
Charts (Queries)
I developped an authentication page, suddenly, i did not tought about how to extract data from an existing database without declaring models!
What is the good way to only extract with many queries data and display it on views scala (Play framework JAVA) ?
Thank you so much
We also have many existing databases, without having a complete model of each table in Play applications. I create a case class in the Play application for all necessary fields, also a subset of all columns. It's Scala code, but also possible with Java, of course.
case class Positionstext(akt_abnr: Int
, akt_text_art: Int
, akt_text_pos: Int
, akt_text: String) {
}
The carefully assembled SQL command retrieves rows from one or more tables.
def positionstexte(x: Int) : List[Positionstext] = {
DB.withConnection{ connection =>
val select =
""" select plr_ak_texte.akt_abnr
, plr_ak_texte.akt_text_art
, plr_ak_texte.akt_text_pos
, plr_ak_texte.akt_text
from plrv11.plr_ak_texte
, plrv11.plr_auftr_status
where plr_ak_texte.akt_abnr = plr_auftr_status.as_abnr
and plr_ak_texte.akt_aend_ix = plr_auftr_status.as_aend_ix
and plr_ak_texte.akt_abnr = ?
and plr_ak_texte.akt_text_art = 7
and plr_auftr_status.as_aend_ix <> 99
"""
val prepareStatement = connection.prepareStatement(select)
prepareStatement.setInt(1, x)
val rs = prepareStatement.executeQuery
var list: ListBuffer[Positionstext] = scala.collection.mutable.ListBuffer()
while (rs.next) {
list += new Positionstext(rs.getInt("akt_abnr")
, rs.getInt("akt_text_art")
, rs.getInt("akt_text_pos")
, rs.getString("akt_text"))
}
rs.close()
prepareStatement.close()
list.toList
}
And that's it! The SQL command already does most of the work by using sub-queries, joins etc.
All desired objects are in the list now and can display in the view.
Thank you for your return,
This is what i did and it works pretty fine :
package controllers;
import models.Sysuser;
import models.DataI;
import models.DataII;
import play.mvc.Controller;
import play.mvc.Result;
import play.mvc.Security;
import views.html.sitemap.index;
import javax.inject.*;
import java.util.concurrent.CompletionStage;
import play.libs.concurrent.HttpExecutionContext;
import static java.util.concurrent.CompletableFuture.supplyAsync;
import io.ebean.*;
import play.Logger;
import java.util.List;
import play.libs.Json;
import java.util.*;
import java.util.stream.*;
#Security.Authenticated(Secured.class)
public class SiteMap extends Controller {
private final HttpExecutionContext httpExecutionContext;
private static final Logger.ALogger logger = Logger.of(SiteMap.class);
#Inject
public SiteMap(HttpExecutionContext httpExecutionContext) {
this.httpExecutionContext = httpExecutionContext;
}
public CompletionStage<Result> index() {
return supplyAsync(() -> {
return ok(views.html.sitemap.index.render(Sysuser.findByUserName(request().username()), QueryI(), QueryII() ));
}, httpExecutionContext.current());
}
/**
* Custom Query 1
*/
public List<DataI> QueryI() {
final String sql = "SELECT sysuser_id, role_id "
+"from sysuser_role "
+"where sysuser_id = '1' "
+"and role_id in ('1','2','3','4','5') ";
final RawSql rawSql = RawSqlBuilder.parse(sql).create();
Query<DataI> query = Ebean.find(DataI.class);
query.setRawSql(rawSql);
List<DataI> L = query.findList();
return(L);
}
/**
* Custom Query 2
*/
public List<DataII> QueryII() {
final String sql = "SELECT sysuser.name, sysuser.active, department.description "
+"from sysuser "
+"left join department on department.id = sysuser.department_id "
+"where sysuser.id = '2' ";
final RawSql rawSql = RawSqlBuilder.parse(sql).create();
Query<DataII> query = Ebean.find(DataII.class);
query.setRawSql(rawSql);
List<DataII> L = query.findList();
return(L);
}
}
I am using Java instead of Scala, however, i don't think that there is a need of these codes such as :
1- DB.withConnection{ connection =>
2- val prepareStatement = connection.prepareStatement(select)
....and what else...
What do you think about my code? is it optimal ? I am going to use complexe queries to fill some dashboards in this template : https://adminlte.io/themes/v3/index.html
I'd like to use org.springframework.data.domain.Pageable with com.querydsl.jpa.impl.JPAQueryis there a way or is there a solid workaround how to make Pageable work with JPAQuery?
So I found nice why to make them work together posting full example:
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Order;
import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.PathBuilder;
import com.querydsl.jpa.impl.JPAQuery;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import javax.persistence.EntityManager;
public class Example {
public void example(Pageable pageable, EntityManager em){
QCustomer qCustomer = QCustomer.customer;
JPAQuery<?> query = new JPAQuery<>(em);
query.from(qCustomer);
BooleanBuilder builder = new BooleanBuilder();
builder.and(qCustomer.email.likeIgnoreCase("c#m.c"));
JPAQuery<?> where = query.where(builder);
// This for loop is making it work with Pagable
query.offset(pageable.getOffset());
query.limit(pageable.getPageSize());
PathBuilder<Customer> entityPath = new PathBuilder<>(Customer.class, "customer");
for (Sort.Order order : pageable.getSort()) {
PathBuilder<Object> path = entityPath.get(order.getProperty());
query.orderBy(new OrderSpecifier(Order.valueOf(order.getDirection().name()), path));
}
List<Customer> resultList = query.createQuery().getResultList();
}
}
Im an amateur programming ambitious to learn, but I've encountered a new type of problem that I don't even know where to begin to look - memory leaks in java. I've searched around and can't really find anything that would help me. I used Tomcat v9.0 and Java 1.8. I don't even know what code you need to see in order to help.
I get this warning when im trying to send a request to my REST api
VARNING: The web application [School] appears to have started a thread named [pool-2-thread-1] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
sun.misc.Unsafe.park(Native Method)
java.util.concurrent.locks.LockSupport.parkNanos(Unknown Source)
java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(Unknown Source)
java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(Unknown Source)
java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(Unknown Source)
java.util.concurrent.ThreadPoolExecutor.getTask(Unknown Source)
java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
java.lang.Thread.run(Unknown Source)
The server can work for one or two requests then it just stops. Since im new to this type of problem I have no idea what might cause it, and searching around didn't really help me in my amateurish ways. I'm guessing however that im creating threads in some way but they're not being closed.
The controller i tried to reach with a get method
package se.consys.controllers;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.persistence.NoResultException;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.PATCH;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import se.consys.Entities.Course;
import se.consys.Entities.Lecture;
import se.consys.Entities.Student;
import se.consys.Entities.Teacher;
import se.consys.Utilities.HibernateUtility;
import se.consys.dataaccess.DaoGenericHibernateImpl;
import se.consys.params.LocalDateParam;
import se.consys.params.LocalDateTimeParam;
import se.consys.params.MapHelper;
import se.consys.services.GenericService;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
#SuppressWarnings("rawtypes, unchecked")
#Path("courses")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class CourseController {
private GenericService courseService = GenericService.getGenericService(new DaoGenericHibernateImpl<>(Course.class));
private GenericService teacherService = GenericService.getGenericService(new DaoGenericHibernateImpl<>(Teacher.class));
private GenericService studentService = GenericService.getGenericService(new DaoGenericHibernateImpl<>(Student.class));
private String noCourseFoundMsg = "No course found with the specified id.";
#GET
public Response getAll() {
List<Course> courses = courseService.findAll();
return Response.status(200).build();
}
#GET
#Path("/{id}")
public Response getById(#PathParam("id") int id) {
try {
Course course = (Course) courseService.findById(id);
return Response.ok().entity(course).build();
} catch (NoResultException e) {
System.out.println(noCourseFoundMsg);
return Response.status(204).build();
}
}
#SuppressWarnings("unchecked")
#POST
public Response create(Course entity) {
courseService.create(entity);
return Response.status(201).entity(entity).build();
}
#PATCH
#Path("/{id}")
public Response partialUpdate(#DefaultValue("0") #PathParam("id") int id,
#DefaultValue("null") #QueryParam("name") String courseName,
#DefaultValue("-1") #QueryParam("duration") int durationInMonths,
#DefaultValue("") #QueryParam("end") LocalDateParam endDate,
#DefaultValue("") #QueryParam("start") LocalDateParam startDate,
#DefaultValue("") #QueryParam("timestamp") LocalDateTimeParam timeStamp,
#DefaultValue("-1") #QueryParam("supervisor") int supervisor)
{
Course courseToBeUpdated = (Course) courseService.findById(id);
System.out.println(courseName);
if (courseName != null) courseToBeUpdated.setCourseName(courseName);
if (durationInMonths != -1) courseToBeUpdated.setDurationInMonths(durationInMonths);
if (endDate != null && !endDate.getLocalDate().equals(LocalDate.MIN)) courseToBeUpdated.setEndDate(endDate.getLocalDate());
if (startDate != null && !startDate.getLocalDate().equals(LocalDate.MIN)) courseToBeUpdated.setStartDate(startDate.getLocalDate());
if (timeStamp != null && !timeStamp.getLocalDateTime().equals(LocalDateTime.MIN)) courseToBeUpdated.setTimeStamp(timeStamp.getLocalDateTime());
if (supervisor != -1) courseToBeUpdated.setSupervisor((Teacher) teacherService.findById(supervisor));
courseService.update(courseToBeUpdated);
return Response.status(200).build();
}
#PATCH
#Path("/{id}/students")
public Response partialUpdateOnStudents(
#DefaultValue("0") #PathParam("id") int id,
#DefaultValue("null") #QueryParam("update") String studentString) {
String[] seperatedIds = studentString.split("-");
List<Integer> studentIds = new ArrayList<Integer>();
for (int i = 0; i < seperatedIds.length; i++) {
studentIds.add((int) Integer.parseInt(seperatedIds[i]));
}
List<Student> allStudents = studentService.findAll();
List<Student> StudentsToAddIntoCourse = new ArrayList<Student>();
for (int i = 0; i < allStudents.size(); i++) {
for(int j = 0; j < studentIds.size(); j++) {
if (allStudents.get(i).getId() == studentIds.get(j)) {
StudentsToAddIntoCourse.add(allStudents.get(i));
}
}
}
Course courseToBeUpdated = (Course) courseService.findById(id);
if (studentString != null) courseToBeUpdated.setStudents(StudentsToAddIntoCourse);
courseService.update(courseToBeUpdated);
return Response.status(200).build();
}
#PUT
#Path("/{id}")
public Response update(#DefaultValue("0") #PathParam("id") int id, Course entity) {
try {
Course courseToBeUpdated = (Course) courseService.findById(id);
courseToBeUpdated.setCourseName(entity.getCourseName());
courseToBeUpdated.setDurationInMonths(entity.getDurationInMonths());
courseToBeUpdated.setEndDate(entity.getEndDate());
courseToBeUpdated.setScheduledLectures(entity.getScheduledLectures());
courseToBeUpdated.setStartDate(entity.getStartDate());
courseToBeUpdated.setStudents(entity.getStudents());
courseToBeUpdated.setSupervisor(entity.getSupervisor());
courseToBeUpdated.setTimeStamp(entity.getTimeStamp());
courseService.update(courseToBeUpdated);
return Response.status(200).entity(entity).build();
} catch (NoResultException e) {
System.out.println(noCourseFoundMsg);
return Response.ok().status(204).build();
}
}
#DELETE
#Path("/{id}")
public Response delete(#DefaultValue("0") #PathParam("id") int id) {
try {
Course courseToBeDeleted = (Course) courseService.findById(id);
courseService.delete(courseToBeDeleted);
return Response.status(200).build();
} catch (NoResultException e) {
System.out.println(noCourseFoundMsg);
return Response.status(204).build();
}
}
}
I have a suspicion that the problem actually is my generic dao and dao service that probably is completely wrong but works on paper. Im new to generics and managed to throw something together.
DaoGenericHibernateImpl
package se.consys.dataaccess;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import org.hibernate.Session;
import se.consys.Utilities.Helper;
import se.consys.Utilities.HibernateUtility;
import se.consys.services.GenericService;
public class DaoGenericHibernateImpl<T extends Serializable> implements IGenericDao<T> {
Session session = HibernateUtility.getSessionFactory().openSession();
private String activeClassName;
private String wrongClassError = "ERROR: Wrong class used on the established service.";
public DaoGenericHibernateImpl(Class<T> type) {
activeClassName = type.getSimpleName();
}
#Override
public void create(T entity) {
if (entity.getClass().getSimpleName().equals(activeClassName)) {
session.beginTransaction();
session.persist(entity);
session.getTransaction().commit();
} else {
System.out.println(wrongClassError + " Entity has not been saved to the database. "
+ "Class used: " + entity.getClass().getSimpleName() + ". "
+ "Class expected: " + activeClassName + ".");
}
}
#Override
public T update(T entity) {
if (entity.getClass().getSimpleName().equals(activeClassName)) {
session.beginTransaction();
session.merge(entity);
session.getTransaction().commit();
return entity;
} else {
System.out.println(wrongClassError + " Entity has not been updated. "
+ "Class used: " + entity.getClass().getSimpleName() + ". "
+ "Class expected: " + activeClassName + ".");
}
return entity;
}
#Override
public void delete(T entity) {
if (entity.getClass().getSimpleName().equals(activeClassName)) {
session.beginTransaction();
//session.update(entity);
session.delete(entity);
session.getTransaction().commit();
} else {
System.out.println(wrongClassError + " Entity has not been deleted. "
+ "Class used: " + entity.getClass().getSimpleName() + ". "
+ "Class expected: " + activeClassName + ".");
}
}
#Override
public T findById(int id) {
final String HQL_BY_ID = "FROM " + activeClassName + " WHERE id=:id";
#SuppressWarnings("unchecked")
T result = (T) session.createQuery(HQL_BY_ID)
.setParameter("id", id)
.setMaxResults(1)
.getSingleResult();
return result;
}
#Override
public List<T> findAll() {
String HQL_FIND_ALL = "FROM " + activeClassName;
#SuppressWarnings("unchecked")
List<T> result = (List<T>) session.createQuery(HQL_FIND_ALL)
.getResultList();
return result;
}
#Override
public void removeReference(T entity, Class<?> reference) {
Method setter = Helper.findSetter(entity, reference);
try {
setter.invoke(entity, null);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw new RuntimeException(e.getMessage());
}
}
}
I feel like i can just keep adding codeblocks so ill add a link to my github where everything is, hope that is ok.
Thanks for the help.
In general, the first thing you need to think about in this case is that if you can't reason about the memory safety and/or thread safety of your code then you've actually got two problems to solve.
In terms of what you're actually seeing, what you need are the standard tools for identifying what threads are running and what memory is in use. You can find out what threads are running with a tool like jconsole (GUI) or jstack (CLI). They're both included as a standard part of the JDK and will give you a stack trace of all the threads running in the system. They won't necessarily tell you why those threads exist, but the stack traces themselves may help you identify where they're coming from.
The problem you're describing sounds like a runaway thread although it could also be memory related, and the error message suggests that's a likely root cause, so it may also be useful to look into the memory usage. For that, you can also use jconsole (profile section) or jhat & jmap (if you're a CLI-fan). Either of those will tell you what objects exist in the VM heap and what type they are. This information can be incredibly useful but also incredibly distracting - most heaps are dominated by Strings, Maps and Lists, because that's what most programs are built out of. Still, you can often gain useful insights by comparing the difference between two profiles, one taken when 'everything seems fine' and one taken when 'its stopped working'.
Those sorts of tools can help you identify a problem in a running system. Once you've done that you probably want to look at why it wasn't clear from the program text that there was going to be a thread-pool or memory usage issue. Things like using a Map as a cache is a big one. Or implementing equals/hashcode in terms of mutable fields. For threads, anything which may not terminate can jam up a thread pool pretty quickly - blocking IO in a web-server (for example).
I am new to hibernate and am struggling with adding a single projection to a criteria query. I am getting an error with the following code: "java.lang.Integer cannot be cast to [Ljava.lang.Object, on line 29. I know it is something very simple, but I cant figure out what I am doing wrong here!
Code is as follows:
package com.simpleprogrammer;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Projection;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import java.util.Date;
import java.util.List;
import java.util.Objects;
public class Program {
public static void main(String[] args) {
System.out.println(org.hibernate.Version.getVersionString());
System.out.println("Creating session!");
PopulateSampleData();
Session session = HibernateUtilities.getSessionFactory().openSession();
session.beginTransaction();
Criteria criteria = session.createCriteria(User.class);
criteria.add(Restrictions.eq("name", "Joe")).setProjection(Projections.property("id"));
List<Object[]> results = criteria.list();
for(Object[] result : results) {
for (Object o : result)
System.out.println("Name is " + o.toString());
}
session.close();
HibernateUtilities.getSessionFactory().close();
}
private static void PopulateSampleData() {
Session session = HibernateUtilities.getSessionFactory().openSession();
session.beginTransaction();
User joe = CreateUser("Joe", 500, 50, "Good job", "You made it!");
session.save(joe);
User bob = CreateUser("Bob", 300, 20, "Taco time!");
session.save(bob);
User amy = CreateUser("Amy", 250, 200, "Yes!!!");
session.save(amy);
session.getTransaction().commit();
session.close();
}
private static User CreateUser(String name, int goal, int total, String... alerts) {
User user = new User();
user.setName(name);
user.getProtienData().setGoal(goal);
user.addHistory(new UserHistory(new Date(), "Set goal to " + goal));
user.getProtienData().setTotal(total);
user.addHistory(new UserHistory(new Date(), "Set total to " + total));
for (String alert : alerts) {
user.getGoalAlerts().add(new GoalAlert(alert));
}
return user;
}
}
I suspect that criteria.list() is returning List<Integer> instead of List<Object[]> since a single column is fetched.
Try changing
List<Object[]> results = criteria.list();
to
List<Integer> results = criteria.list();
I'm having an issue with my login class. If a user unsuccessfully attempts to login with a username then that user account should be disabled. At runtime there are no errors but nothing changes in my database. Am I doing something wrong with updating my database through Hibernate, I thought I could just use my UserBean.class to access properties, change them and then commit the Hibernate transaction?
Here is my LoginDAO.class:
package com.sga.app.dao;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.FlushMode;
import org.hibernate.Session;
import org.hibernate.context.internal.ManagedSessionContext;
import org.hibernate.criterion.Restrictions;
import org.owasp.encoder.Encode;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.BindingResult;
import com.sga.app.beans.UserBean;
import com.sga.app.hibernate.HibernateUtil;
import com.sga.app.security.LoginFailureEventListener;
import com.sga.app.security.XssRequestWrapper;
#Component("loginDAO")
#Transactional
#Configuration
public class LoginDAO implements
ApplicationListener<AuthenticationFailureBadCredentialsEvent> {
private int loginAttemptsThreshold;
private int failedLoginAttempts;
private static Logger logger = Logger
.getLogger(LoginFailureEventListener.class);
private static Session session;
private Criteria criteria;
private String username;
private boolean enabled;
private String forename;
private String authority;
private XssRequestWrapper xssReqWrapper;
private PreparedStatement prepStmtUsers;
private PreparedStatement prepStmtAuthorities;
private String URL = "jdbc:oracle:thin:system/sgaWebApp#localhost:1521/XE";
private String updateUsersStatement = "insert into users (username, password)
values (:username, :password)";
private String updateAuthoritiesStatement = "insert into authorities (username,
authority) values (:username, :authority)";
#Bean
public LoginDAO loginDAO() {
return new LoginDAO();
}
public void setLoginAttemptsThreshold(int threshold) {
this.loginAttemptsThreshold = threshold;
}
#Transactional
public void loginUser(UserBean user, BindingResult result) {
try {
Connection conn = DriverManager.getConnection(URL);
// clean out any possible XSS injection
String cleanUsernameValueInput = cleanOutXSSVulnerabilities("j_username");
String cleanPasswordValueInput = cleanOutXSSVulnerabilities("j_password");
// OWASP encoding
String safeUsername = Encode.forHtml(cleanUsernameValueInput);
prepStmtUsers.setString(1, safeUsername);
String safePassword = Encode.forHtml(cleanPasswordValueInput);
prepStmtUsers.setString(2, safePassword);
prepStmtAuthorities.setString(1, safeUsername);
String safeUserAuthority = Encode.forHtml(user.getAuthority());
prepStmtAuthorities.setString(2, safeUserAuthority);
// execute login process
prepStmtUsers = conn.prepareStatement(updateUsersStatement);
prepStmtAuthorities = conn
.prepareStatement(updateAuthoritiesStatement);
prepStmtUsers.executeUpdate();
prepStmtAuthorities.executeUpdate();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
} catch (AccessDeniedException accessDenied) {
accessDenied.printStackTrace();
}
}
private String cleanOutXSSVulnerabilities(String input) {
return xssReqWrapper.cleanXSS(input);
}
#Override
public void onApplicationEvent(
AuthenticationFailureBadCredentialsEvent event) {
if (event.getException().getClass()
.equals(UsernameNotFoundException.class)) {
return;
}
// print registration attempts to log file for security investigation if
// required
logger.info("Registration attempt failed: " + event.getException());
logger.info("Registration attempt number: " + event.getTimestamp());
String userId = event.getAuthentication().getName();
logger.info("FAILED LOGIN ATTEMPT NUMBER "
+ recordLoginAttempts(userId));
recordLoginAttempts(userId);
if (recordLoginAttempts(userId) >= loginAttemptsThreshold) {
lockoutUser(userId);
}
}
private int recordLoginAttempts(String userId) {
failedLoginAttempts++;
return failedLoginAttempts;
}
#SuppressWarnings("unchecked")
private ArrayList<UserBean> getUserAccountDetails(String input) {
ArrayList<UserBean> returnValues = new ArrayList<UserBean>();
session = HibernateUtil.createSessionFactory().openSession();
session.setFlushMode(FlushMode.MANUAL);
ManagedSessionContext.bind(session);
session.beginTransaction();
criteria = session.createCriteria(UserBean.class);
List<UserBean> retrievedUser = criteria.add(
Restrictions.like("username", input)).list();
for (UserBean userDetails : retrievedUser) {
logger.debug("USERNAME INSIDE THE GET USER ACCOUNT DETAILS METHOD: "
+ userDetails.getUsername());
logger.debug("AUTHORITY INSIDE THE GET USER ACCOUNT DETAILS METHOD: "
+ userDetails.getAuthority());
returnValues.add(userDetails);
}
session.flush();
session.getTransaction().commit();
session.close();
return returnValues;
}
private void lockoutUser(String userId) {
ArrayList<UserBean> userAccountValues = getUserAccountDetails(userId);
session = HibernateUtil.createSessionFactory().openSession();
session.setFlushMode(FlushMode.MANUAL);
ManagedSessionContext.bind(session);
session.beginTransaction();
for (UserBean user : userAccountValues) {
username = user.getUsername();
forename = user.getForename();
enabled = user.getEnabled();
authority = user.getAuthority();
logger.debug("USERNAME: " + username);
logger.debug("FORENAME: " + forename);
logger.debug("ENABLED BEFORE CHANGE: " + enabled);
user.setEnabled(false);
logger.debug("AUTHORITY BEFORE CHANGE: " + authority);
user.setAuthority("BLOCKED");
}
session.flush();
session.getTransaction().commit();
logger.debug("ENABLED AFTER CHANGE: " + enabled);
logger.debug("AUTHORITY AFTER CHANGE: " + authority);
session.close();
ManagedSessionContext.unbind(HibernateUtil.createSessionFactory());
}
}
I don't think you should be invoking openSession in that manner. I would highly suggest you rewrite the method to not do any "session" related work at all. Let Spring handle it, especially since you are already using #Transactional.
Either way, in the lockoutUser() method, the users you find, aren't bound to the session that gets created after it.
ArrayList<UserBean> userAccountValues = getUserAccountDetails(userId);
session = HibernateUtil.createSessionFactory().openSession();
So, later in the method when you update the user instances of that ArrrayList, the session doesn't realize that the user instances are to be persisted because the session was never tracking them.
Try to have only one session per thread. Each method can have its own transaction, but we rarely come across situations where we need more than one session in a thread. This doesn't seem to be that kind of a situation.
session.flush();
session.getTransaction().commit();
session.close();
Try to delete session.flush(); or put it after session.getTransaction().commit(); may work.
It doesn't appear that you call session.save(Object) or session.update(Object).