I am creating a project about hotel reservations. I created a udirection one to many relationship between users and reservations. That is, A user can have many reservations.
Here is the User class.
@Entity
@Table(name="tbluser")
@FilterDef(name="statusFilter")
public class User {
private long userID;
private String email, password, firstName, lastName, middleName, gender, addressNo, street, city, userType, telNo, mobileNo;
private Date birthday;
private List<Reservation> reservations = new ArrayList<>();
private int status = 1;
private int passwordStatus = 1;
public User() { }
public User(String email, String password, String firstName, String lastName, String middleName, String gender,
String addressNo, String street, String city, String userType, String telNo, String mobileNo, Date birthday) {
this.email = email;
this.password = password;
this.firstName = firstName;
this.lastName = lastName;
this.middleName = middleName;
this.gender = gender;
this.addressNo = addressNo;
this.street = street;
this.city = city;
this.userType = userType;
this.telNo = telNo;
this.mobileNo = mobileNo;
this.birthday = birthday;
}
@Id @GeneratedValue
public long getUserID() {
return userID;
}
private void setUserID(long userID) {
this.userID = userID;
}
// other getters/setters
@OneToMany(cascade=CascadeType.ALL,orphanRemoval=true)
@JoinColumn(name="userID")
@Filter(name="statusFilter",condition="status = 1")
@OrderBy("checkInDate")
public List<Reservation> getReservations() {
return reservations;
}
public void setReservations(List<Reservation> reservations) {
this.reservations = reservations;
}
}
There is nothing special in the Reservation class so I didn't post it here. Now I'm just doing CRUD on them but I'm not sure if what I'm doing is bad practice or not. I would like my code for updating Reservation entities to be reviewed.
I'm trying to follow the "session per request" pattern so I wrote the creation of session object in a servlet filter. Here's the code:
// SessionFactory is created in a servlet context listener
public void init(FilterConfig config) throws ServletException {
context = config.getServletContext();
sessionFactory = (SessionFactory)context.getAttribute("factory");
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest)request;
String url = req.getRequestURI();
if (url.endsWith(".html")) { // so only filter servlets
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
session.enableFilter("statusFilter"); // for viewing
request.setAttribute("session", session);
chain.doFilter(request, response);
session.getTransaction().commit();
} else {
chain.doFilter(request, response);
}
}
Now there are a lot of methods I would be using through the project, I put them in a Utils class. Here are some of them related to update. Each method will have a reference to a HTTPServletRequest so they can retrieve the hibernate session associated with the request. There should be a HTTPSession for these methods to be called, the user should be logged in.
// the parameter "id" is retrieve from viewreservations.jsp when the "edit" button is clicked
public static Reservation loadReservation(HttpServletRequest request) {
Session session = (Session)request.getAttribute("session");
Reservation reservation = session.load(Reservation.class, Long.parseLong(request.getParameter("id")));
return reservation;
}
// the parameter "userid" is retrieved from the session when the user logs in
public static User loadUser(HttpServletRequest request) {
Session session = (Session)request.getAttribute("session");
User user = session.load(User.class, (long)request.getSession().getAttribute("userid"));
return user;
}
// check if there are dates that overlap with the user's input dates. I added a User arguement so I can prevent the object curretnly being updated to be compared
public static boolean existReservations(HttpServletRequest request, User user, Date checkInDate, Date checkOutDate, long reservationID) {
List<Reservation> res = user.getReservations();
for (Reservation r : res) {
if (r.getReservationID() != reservationID) {
if (checkInDate.compareTo(r.getCheckOutDate()) <= 0 && checkOutDate.compareTo(r.getCheckInDate()) >= 0) {
return true;
}
}
}
return false;
}
// repopulate fields by iterating through request parameters
public static void populateFields(HttpServletRequest request) {
Map<String, String[]> parameters = request.getParameterMap();
for (String key : parameters.keySet()) {
request.setAttribute(key, parameters.get(key)[0]);
}
}
Here are some parts of the viewreservations.jsp
<c:forEach var="reservation" items="${reservations}">
// display
<td>
<form action="updatereservation.html" method="post" align="center">
<input type="hidden" name="checkInDate" value="${reservation.strCheckInDate}">
<input type="hidden" name="checkOutDate" value="${reservation.strCheckOutDate}">
<input type="hidden" name="roomType" value="${reservation.roomType}">
<input type="hidden" name="id" value="${reservation.reservationID}">
<input type="image" src="images/edit.jpg" height="30" width="30" alt="Submit" value="edit">
</form>
</td>
<td>
<form action="deletereservation.html" method="post" align="center">
<input type="hidden" name="checkInDate" value="${reservation.strCheckInDate}">
<input type="hidden" name="checkOutDate" value="${reservation.strCheckOutDate}">
<input type="hidden" name="roomType" value="${reservation.roomType}">
<input type="hidden" name="id" value="${reservation.reservationID}">
<input type="image" src="images/delete.jpg" height="30" width="30" alt="Submit" value="delete">
</form>
</td>
</tr>
</c:forEach>
The servlet that will be called if the edit button is clicked. It will forward the to a updatereservation.jsp:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
populateFields(request); // including the "id" parameter that has reservation.ReservationID mset in viewreservations.jsp
request.getRequestDispatcher("updatereservation.jsp").forward(request, response);
}
The submit part of updatereservation.jsp
<form method="post" action="processupdatereservation.html" class="form-horizontal" id="reservation">
// html fields with ${values}
<input type="hidden" name="id" value="${id}"> // reservation.ReservationID
<input type="submit" class="btn btn-success"name="submit" value="Update Now" id="submit"/>
</form>
The servlet that will process the update:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Reservation reservation = loadReservation(request);
Date checkInDate = getDate(request.getParameter("checkInDate"));
Date checkOutDate = getDate(request.getParameter("checkOutDate"));
if (!existReservations(request, loadUser(request), checkInDate, checkOutDate)) {
reservation.setCheckInDate(checkInDate);
reservation.setCheckOutDate(checkOutDate);
reservation.setRoomType(request.getParameter("roomType"));
response.sendRedirect(request.getContextPath()+"/user/viewreservations.html");
} else {
request.setAttribute("message", "Reservations out of range.");
populateFields(request);
request.getRequestDispatcher("updatereservation.jsp").forward(request, response);
}
}
The viewreservations.html servlet, will forward to viewreservations.jsp after update:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setAttribute("reservations", loadUser(request).getReservations());
request.getRequestDispatcher("viewreservations.jsp").forward(request, response);
}
Overall I'm doing this also with logical delete and insert as well. Am I following the session per request pattern? Are there problems on how I implemented methods from the Utils class? Is it bad that they all have a reference to HTTPServletRequest? Are there better ways of updating an entity? How can I improve this code and make it faster?