1
\$\begingroup\$

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?

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.