Business Ser vice Layer

The Business Service Layer is perhaps the most important part of the application. Business logic will normally reside here, and it is important to avoid any dependencies on surrounding layers and implementation technologies (including Spring!) in order to increase reusability and maintainability.


Business logic that is shared across multiple use cases, that does not imply delimitation of a transaction, and that depends only on relationships with other domain objects, rather than service layer objects, may best be coded in persistent domain objects. Follow normal OO design criteria here.


All business logic is contained in the two service classes, and the Web Layer will access this logic via two interfaces. The first one is EventsCalendar, which provides information regarding available shows and scheduled performances. The primary methods are:

public abstract Collection getCurrentGenres();     public abstract Collection getAllGenres();

The second interface is BoxOffice, which provides services geared toward booking available seats, making payments, and so on. The most important methods for this interface are:

public abstract PerformanceWithAvailability[] getAvailabilityForPerformance(Show     throws NoSuchPerformanceException;     public abstract Reservation allocateSeats(ReservationRequest request)     throws RequestedSeatNotAvailableException, NotEnoughSeatsException,         InvalidSeatingRequestException; 

The majority of the business methods simply make a call to the DAO to retrieve the requested information. The allocateSeats method does include a lot more processing, however, so we have chosen to discuss it a bit further here.

public Reservation allocateSeats(ReservationRequest reservationRequest)     throws RequestedSeatNotAvailableException, NotEnoughSeatsException,            InvalidSeatingRequestException {       Performance performance = reservationRequest.getPerformance();   SeatClass seatClass = reservationRequest.getSeatClass();       // Get the available seats for this performance and seat class   Seat[] seats = boxOfficeDao.getAvailableSeatsToBook(performance, seatClass);   if (seats.length < reservationRequest.getNumberOfSeatsRequested()) {     throw new NotEnoughSeatsException(seatClass.getId(),        seats.length, reservationRequest.getNumberOfSeatsRequested());   }       // Pick the correct number of seats   Seat[] seatsRequested =      new Seat[reservationRequest.getNumberOfSeatsRequested()];   System.arraycopy(seats, 0, seatsRequested, 0,     reservationRequest.getNumberOfSeatsRequested());       BigDecimal price = boxOfficeDao.getCostOfSeats(performance, seatsRequested);       // New booking   Booking booking = new Booking();   booking.setDateMade(new Date());   booking.setPrice(reservationRequest.getBookingFee().add(price));   booking.setReservedUntil(reservationRequest.getHoldUntil());   // Add booking and update seat status   boxOfficeDao.reserveSeats(seatsRequested, performance, booking);       // Create a Reservation object   Reservation reservation = new Reservation(seatsRequested, booking);       return reservation; }

We start by getting the available seats for the performance and seat class requested in the Reservation Request. If there aren't enough seats available, a checked exception is thrown, forcing the caller to deal with this situation. As we noted in other chapters, checked exceptions are often inappropriate for infrastructural exceptions. However, they are excellent in cases like this, when the situation definitely is recoverable, rather than a fatal system error. If we have enough seats, then we copy the requested number of seats to an array for further processing. These seats are used to create a booking that is used in the call to the reserve Seats method of the DAO. Finally we create a Reservation object that is returned.

Application Context

The service layer is configured in the applicationContext.xml file. Figure 15-5 shows the structure of this file.

image from book
Figure 15-5

One of the most important aspects of the service layer is the definition of the transaction semantics. This is expressed in applicationContext.xml via a transactional proxy for the business object targets and transaction attributes. The transactional proxy is given the name of the target object, and the web layer will not have to be aware of any of the transaction management that is handled behind the scenes.

We have chosen the TransactionProxyFactoryBean as it is easy to use and provides all the functionality we need for this application. All get* methods are executed in a read-only transaction if one is already started. The allocate* methods will require a transaction because we want to eliminate any chance of double booking seats in the allocateSeats method. This method does its work in a couple of steps and it is essential that no other transaction reserves any of the requested seats until we are done processing. We have chosen to rely on a database lock via a select ... for update statement; for more detail, see the Hibernate query definition mentioned earlier in the section covering the O/R Mapping. This strategy will work well as long as we can control all applications that book seats.

  <!-- Transactional proxies for the primary business objects -->   <bean      >     <property name="target">       <ref local="boxOfficeTarget"/>     </property>     <property name="transactionManager">       <ref bean="transactionManager"/>     </property>     <property name="transactionAttributes">       <props>         <prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop>         <prop key="allocate*">     PROPAGATION_REQUIRED, ISOLATION_READ_COMMITTED,timeout_60,- ApplicationException         </prop>       </props>     </property>   </bean>         <bean      >     <property name="target">       <ref local="eventsCalendarTarget"/>     </property>     <property name="transactionManager">       <ref bean="transactionManager"/>     </property>     <property name="transactionAttributes">       <props>         <prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop>       </props>     </property>   </bean>  

The transaction definitions are then configured to work together with the data access layer in the form of a transaction manager. The transaction manager is defined in the dataAccessContext.xml file that we saw earlier and can easily be altered depending on the data access technology being used. The transactional proxy does not need to know what type of transaction manager is in use.

Professional Java Development with the Spring Framework
Professional Java Development with the Spring Framework
ISBN: 0764574833
EAN: 2147483647
Year: 2003
Pages: 188 © 2008-2017.
If you may any questions please contact us: