From 39de154e18c6ae59cb01aa1bda17dcba58d526fb Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Mon, 29 Oct 2007 12:32:28 +0000 Subject: [PATCH] SWS-217 --- .../samples/airline/dao/jpa/JpaFlightDao.java | 12 ++++-- .../airline/dao/jpa/JpaFrequentFlyerDao.java | 10 ++++- .../AcegiFrequentFlyerSecurityService.java | 11 ++++- .../FrequentFlyerSecurityService.java | 4 +- .../StubFrequentFlyerSecurityService.java | 5 ++- .../airline/service/AirlineService.java | 11 +++-- .../service/NoSuchFrequentFlyerException.java | 41 +++++++++++++++++++ .../service/impl/AirlineServiceImpl.java | 3 +- .../ws/MarshallingAirlineEndpoint.java | 11 ++--- .../airline/ws/XPathAirlineEndpoint.java | 6 ++- .../airline/dao/jpa/JpaFlightDaoTest.java | 5 +++ .../dao/jpa/JpaFrequentFlyerDaoTest.java | 5 ++- 12 files changed, 101 insertions(+), 23 deletions(-) create mode 100644 samples/airline/src/main/java/org/springframework/ws/samples/airline/service/NoSuchFrequentFlyerException.java diff --git a/samples/airline/src/main/java/org/springframework/ws/samples/airline/dao/jpa/JpaFlightDao.java b/samples/airline/src/main/java/org/springframework/ws/samples/airline/dao/jpa/JpaFlightDao.java index 52017077..c3185767 100644 --- a/samples/airline/src/main/java/org/springframework/ws/samples/airline/dao/jpa/JpaFlightDao.java +++ b/samples/airline/src/main/java/org/springframework/ws/samples/airline/dao/jpa/JpaFlightDao.java @@ -18,6 +18,7 @@ package org.springframework.ws.samples.airline.dao.jpa; import java.util.List; import javax.persistence.EntityManager; +import javax.persistence.NoResultException; import javax.persistence.PersistenceContext; import javax.persistence.Query; @@ -39,7 +40,7 @@ public class JpaFlightDao implements FlightDao { String toAirportCode, Interval interval, ServiceClass serviceClass) throws DataAccessException { - Query query = entityManager.createQuery("FROM Flight f WHERE f.from.code = :from " + + Query query = entityManager.createQuery("SELECT f FROM Flight f WHERE f.from.code = :from " + "AND f.to.code = :to AND f.departureTime >= :start AND f.departureTime <= :end AND " + "f.serviceClass = :class"); query.setParameter("from", fromAirportCode); @@ -56,10 +57,15 @@ public class JpaFlightDao implements FlightDao { public Flight getFlight(String flightNumber, DateTime departureTime) { Query query = entityManager - .createQuery("FROM Flight f WHERE f.number = :number AND f.departureTime = :departureTime"); + .createQuery("SELECT f FROM Flight f WHERE f.number = :number AND f.departureTime = :departureTime"); query.setParameter("number", flightNumber); query.setParameter("departureTime", departureTime); - return (Flight) query.getSingleResult(); + try { + return (Flight) query.getSingleResult(); + } + catch (NoResultException e) { + return null; + } } public Flight update(Flight flight) { diff --git a/samples/airline/src/main/java/org/springframework/ws/samples/airline/dao/jpa/JpaFrequentFlyerDao.java b/samples/airline/src/main/java/org/springframework/ws/samples/airline/dao/jpa/JpaFrequentFlyerDao.java index 0449c812..b7cb58df 100644 --- a/samples/airline/src/main/java/org/springframework/ws/samples/airline/dao/jpa/JpaFrequentFlyerDao.java +++ b/samples/airline/src/main/java/org/springframework/ws/samples/airline/dao/jpa/JpaFrequentFlyerDao.java @@ -17,6 +17,7 @@ package org.springframework.ws.samples.airline.dao.jpa; import javax.persistence.EntityManager; +import javax.persistence.NoResultException; import javax.persistence.PersistenceContext; import javax.persistence.Query; @@ -32,9 +33,14 @@ public class JpaFrequentFlyerDao implements FrequentFlyerDao { private EntityManager entityManager; public FrequentFlyer get(String username) throws DataAccessException { - Query query = entityManager.createQuery("FROM FrequentFlyer f WHERE f.username = :username"); + Query query = entityManager.createQuery("SELECT f FROM FrequentFlyer f WHERE f.username = :username"); query.setParameter("username", username); - return (FrequentFlyer) query.getSingleResult(); + try { + return (FrequentFlyer) query.getSingleResult(); + } + catch (NoResultException e) { + return null; + } } } diff --git a/samples/airline/src/main/java/org/springframework/ws/samples/airline/security/AcegiFrequentFlyerSecurityService.java b/samples/airline/src/main/java/org/springframework/ws/samples/airline/security/AcegiFrequentFlyerSecurityService.java index e1b3cea6..c09c794a 100644 --- a/samples/airline/src/main/java/org/springframework/ws/samples/airline/security/AcegiFrequentFlyerSecurityService.java +++ b/samples/airline/src/main/java/org/springframework/ws/samples/airline/security/AcegiFrequentFlyerSecurityService.java @@ -26,6 +26,7 @@ import org.springframework.dao.DataAccessException; import org.springframework.transaction.annotation.Transactional; import org.springframework.ws.samples.airline.dao.FrequentFlyerDao; import org.springframework.ws.samples.airline.domain.FrequentFlyer; +import org.springframework.ws.samples.airline.service.NoSuchFrequentFlyerException; /** * Implementation of the FrequentFlyerSecurityService that uses Acegi. @@ -59,8 +60,14 @@ public class AcegiFrequentFlyerSecurityService implements FrequentFlyerSecurityS } @Transactional - public FrequentFlyer getFrequentFlyer(String username) { - return frequentFlyerDao.get(username); + public FrequentFlyer getFrequentFlyer(String username) throws NoSuchFrequentFlyerException { + FrequentFlyer frequentFlyer = frequentFlyerDao.get(username); + if (frequentFlyer != null) { + return frequentFlyer; + } + else { + throw new NoSuchFrequentFlyerException(username); + } } @Transactional diff --git a/samples/airline/src/main/java/org/springframework/ws/samples/airline/security/FrequentFlyerSecurityService.java b/samples/airline/src/main/java/org/springframework/ws/samples/airline/security/FrequentFlyerSecurityService.java index 57431e0a..5f442ea9 100644 --- a/samples/airline/src/main/java/org/springframework/ws/samples/airline/security/FrequentFlyerSecurityService.java +++ b/samples/airline/src/main/java/org/springframework/ws/samples/airline/security/FrequentFlyerSecurityService.java @@ -17,6 +17,7 @@ package org.springframework.ws.samples.airline.security; import org.springframework.ws.samples.airline.domain.FrequentFlyer; +import org.springframework.ws.samples.airline.service.NoSuchFrequentFlyerException; /** * Defines the business logic for handling frequent flyers. @@ -30,8 +31,9 @@ public interface FrequentFlyerSecurityService { * * @param username the username * @return the frequent flyer with the given username, or null if not found + * @throws NoSuchFrequentFlyerException when the frequent flyer cannot be found */ - FrequentFlyer getFrequentFlyer(String username); + FrequentFlyer getFrequentFlyer(String username) throws NoSuchFrequentFlyerException; /** * Returns the FrequentFlyer that is currently logged in. diff --git a/samples/airline/src/main/java/org/springframework/ws/samples/airline/security/StubFrequentFlyerSecurityService.java b/samples/airline/src/main/java/org/springframework/ws/samples/airline/security/StubFrequentFlyerSecurityService.java index cb32da1c..df2c0035 100644 --- a/samples/airline/src/main/java/org/springframework/ws/samples/airline/security/StubFrequentFlyerSecurityService.java +++ b/samples/airline/src/main/java/org/springframework/ws/samples/airline/security/StubFrequentFlyerSecurityService.java @@ -17,6 +17,7 @@ package org.springframework.ws.samples.airline.security; import org.springframework.ws.samples.airline.domain.FrequentFlyer; +import org.springframework.ws.samples.airline.service.NoSuchFrequentFlyerException; /** * Stub implementation of FrequentFlyerSecurityService. This implementation is used by default by {@link @@ -34,12 +35,12 @@ public class StubFrequentFlyerSecurityService implements FrequentFlyerSecuritySe john.setMiles(10); } - public FrequentFlyer getFrequentFlyer(String username) { + public FrequentFlyer getFrequentFlyer(String username) throws NoSuchFrequentFlyerException { if (john.getUsername().equals(username)) { return john; } else { - return null; + throw new NoSuchFrequentFlyerException(username); } } diff --git a/samples/airline/src/main/java/org/springframework/ws/samples/airline/service/AirlineService.java b/samples/airline/src/main/java/org/springframework/ws/samples/airline/service/AirlineService.java index 593d9f18..b61dadfc 100644 --- a/samples/airline/src/main/java/org/springframework/ws/samples/airline/service/AirlineService.java +++ b/samples/airline/src/main/java/org/springframework/ws/samples/airline/service/AirlineService.java @@ -67,14 +67,17 @@ public interface AirlineService { * @param passengers the list of passengers for the flight to book. Can be either {@link Passenger} objects with * a first and last name, or {@link FrequentFlyer} objects with a username. * @return the created ticket - * @throws NoSuchFlightException if a flight with the specified flight number and departure time does not exist - * @throws NoSeatAvailableException if not enough seats are available for the flight + * @throws NoSuchFlightException if a flight with the specified flight number and departure time does not + * exist + * @throws NoSeatAvailableException if not enough seats are available for the flight + * @throws NoSuchFrequentFlyerException if a specified {@link FrequentFlyer} cannot be found * @see org.springframework.ws.samples.airline.domain.Passenger * @see org.springframework.ws.samples.airline.domain.FrequentFlyer */ - @Transactional(rollbackFor = {NoSuchFlightException.class, NoSeatAvailableException.class}) + @Transactional(readOnly = false, + rollbackFor = {NoSuchFlightException.class, NoSeatAvailableException.class, NoSuchFrequentFlyerException.class}) Ticket bookFlight(String flightNumber, DateTime departureTime, List passengers) - throws NoSuchFlightException, NoSeatAvailableException; + throws NoSuchFlightException, NoSeatAvailableException, NoSuchFrequentFlyerException; /** * Returns the amount of frequent flyer award miles for the currently logged in frequent flyer. diff --git a/samples/airline/src/main/java/org/springframework/ws/samples/airline/service/NoSuchFrequentFlyerException.java b/samples/airline/src/main/java/org/springframework/ws/samples/airline/service/NoSuchFrequentFlyerException.java new file mode 100644 index 00000000..3b8a8216 --- /dev/null +++ b/samples/airline/src/main/java/org/springframework/ws/samples/airline/service/NoSuchFrequentFlyerException.java @@ -0,0 +1,41 @@ +/* + * Copyright 2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ws.samples.airline.service; + +import org.springframework.ws.soap.server.endpoint.annotation.FaultCode; +import org.springframework.ws.soap.server.endpoint.annotation.SoapFault; + +/** + * Exception thrown when a specified frequent flyer cannot be found. + * + * @author Rossen Stoyanchev + * @author Arjen Poutsma + */ +@SoapFault(faultCode = FaultCode.CLIENT) +public class NoSuchFrequentFlyerException extends Exception { + + private String username; + + public NoSuchFrequentFlyerException(String username) { + super("No frequent flyer with name [" + username + "]"); + this.username = username; + } + + public String getusername() { + return username; + } +} diff --git a/samples/airline/src/main/java/org/springframework/ws/samples/airline/service/impl/AirlineServiceImpl.java b/samples/airline/src/main/java/org/springframework/ws/samples/airline/service/impl/AirlineServiceImpl.java index 155290b6..fc7e9324 100644 --- a/samples/airline/src/main/java/org/springframework/ws/samples/airline/service/impl/AirlineServiceImpl.java +++ b/samples/airline/src/main/java/org/springframework/ws/samples/airline/service/impl/AirlineServiceImpl.java @@ -34,6 +34,7 @@ import org.springframework.ws.samples.airline.security.StubFrequentFlyerSecurity import org.springframework.ws.samples.airline.service.AirlineService; import org.springframework.ws.samples.airline.service.NoSeatAvailableException; import org.springframework.ws.samples.airline.service.NoSuchFlightException; +import org.springframework.ws.samples.airline.service.NoSuchFrequentFlyerException; /** * Default implementation of the AirlineService interface. @@ -60,7 +61,7 @@ public class AirlineServiceImpl implements AirlineService { } public Ticket bookFlight(String flightNumber, DateTime departureTime, List passengers) - throws NoSuchFlightException, NoSeatAvailableException { + throws NoSuchFlightException, NoSeatAvailableException, NoSuchFrequentFlyerException { Assert.notEmpty(passengers, "No passengers given"); if (logger.isDebugEnabled()) { logger.debug("Booking flight '" + flightNumber + "' on '" + departureTime + "' for " + passengers); diff --git a/samples/airline/src/main/java/org/springframework/ws/samples/airline/ws/MarshallingAirlineEndpoint.java b/samples/airline/src/main/java/org/springframework/ws/samples/airline/ws/MarshallingAirlineEndpoint.java index 3b8b9145..25e150c2 100644 --- a/samples/airline/src/main/java/org/springframework/ws/samples/airline/ws/MarshallingAirlineEndpoint.java +++ b/samples/airline/src/main/java/org/springframework/ws/samples/airline/ws/MarshallingAirlineEndpoint.java @@ -42,6 +42,7 @@ import org.springframework.ws.samples.airline.schema.support.SchemaConversionUti import org.springframework.ws.samples.airline.service.AirlineService; import org.springframework.ws.samples.airline.service.NoSeatAvailableException; import org.springframework.ws.samples.airline.service.NoSuchFlightException; +import org.springframework.ws.samples.airline.service.NoSuchFrequentFlyerException; import org.springframework.ws.server.endpoint.annotation.Endpoint; import org.springframework.ws.server.endpoint.annotation.PayloadRoot; @@ -107,8 +108,8 @@ public class MarshallingAirlineEndpoint implements AirlineWebServiceConstants { * @return the JAXB2 representation of a <BookFlightResponse> */ @PayloadRoot(localPart = BOOK_FLIGHT_REQUEST, namespace = NAMESPACE) - public JAXBElement bookFlight(BookFlightRequest request) - throws NoSeatAvailableException, DatatypeConfigurationException, NoSuchFlightException { + public JAXBElement bookFlight(BookFlightRequest request) throws NoSeatAvailableException, + DatatypeConfigurationException, NoSuchFlightException, NoSuchFrequentFlyerException { if (logger.isDebugEnabled()) { logger.debug("Received BookingFlightRequest '" + request.getFlightNumber() + "' on '" + request.getDepartureTime() + "' for " + request.getPassengers().getPassengerOrUsername()); @@ -121,8 +122,8 @@ public class MarshallingAirlineEndpoint implements AirlineWebServiceConstants { /** Converts between the domain and schema types. */ private Ticket bookSchemaFlight(String flightNumber, XMLGregorianCalendar xmlDepartureTime, - List passengerOrUsernameList) - throws NoSeatAvailableException, NoSuchFlightException, DatatypeConfigurationException { + List passengerOrUsernameList) throws NoSeatAvailableException, + NoSuchFlightException, NoSuchFrequentFlyerException, DatatypeConfigurationException { DateTime departureTime = SchemaConversionUtils.toDateTime(xmlDepartureTime); List passengers = new ArrayList(passengerOrUsernameList.size()); for (Iterator iterator = passengerOrUsernameList.iterator(); iterator.hasNext();) { @@ -143,4 +144,4 @@ public class MarshallingAirlineEndpoint implements AirlineWebServiceConstants { return SchemaConversionUtils.toSchemaType(domainTicket); } -} \ No newline at end of file +} diff --git a/samples/airline/src/main/java/org/springframework/ws/samples/airline/ws/XPathAirlineEndpoint.java b/samples/airline/src/main/java/org/springframework/ws/samples/airline/ws/XPathAirlineEndpoint.java index 89660f24..4f892b50 100644 --- a/samples/airline/src/main/java/org/springframework/ws/samples/airline/ws/XPathAirlineEndpoint.java +++ b/samples/airline/src/main/java/org/springframework/ws/samples/airline/ws/XPathAirlineEndpoint.java @@ -42,6 +42,7 @@ import org.springframework.ws.samples.airline.schema.support.SchemaConversionUti import org.springframework.ws.samples.airline.service.AirlineService; import org.springframework.ws.samples.airline.service.NoSeatAvailableException; import org.springframework.ws.samples.airline.service.NoSuchFlightException; +import org.springframework.ws.samples.airline.service.NoSuchFrequentFlyerException; import org.springframework.ws.server.endpoint.annotation.Endpoint; import org.springframework.ws.server.endpoint.annotation.PayloadRoot; import org.springframework.ws.server.endpoint.annotation.XPathParam; @@ -119,8 +120,9 @@ public class XPathAirlineEndpoint implements AirlineWebServiceConstants { public Source bookFlight(@XPathParam("//tns:flightNumber")String flightNumber, @XPathParam("//tns:departureTime")String departureTimeString, @XPathParam("//tns:passengers/tns:passenger")NodeList passengerNodes, - @XPathParam("//tns:passengers/tns:username")NodeList frequentFlyerNodes) - throws NoSeatAvailableException, NoSuchFlightException, DatatypeConfigurationException, JAXBException { + @XPathParam("//tns:passengers/tns:username")NodeList frequentFlyerNodes) throws + NoSeatAvailableException, NoSuchFlightException, NoSuchFrequentFlyerException, + DatatypeConfigurationException, JAXBException { if (logger.isDebugEnabled()) { logger.debug("Received BookingFlightRequest '" + flightNumber + "' on '" + departureTimeString + "' for " + passengerNodes.getLength() + " passengers and " + frequentFlyerNodes.getLength() + diff --git a/samples/airline/src/test/java/org/springframework/ws/samples/airline/dao/jpa/JpaFlightDaoTest.java b/samples/airline/src/test/java/org/springframework/ws/samples/airline/dao/jpa/JpaFlightDaoTest.java index 52179d38..445d2143 100644 --- a/samples/airline/src/test/java/org/springframework/ws/samples/airline/dao/jpa/JpaFlightDaoTest.java +++ b/samples/airline/src/test/java/org/springframework/ws/samples/airline/dao/jpa/JpaFlightDaoTest.java @@ -111,4 +111,9 @@ public class JpaFlightDaoTest extends AbstractJpaTests { assertEquals("Flight not updated", 0, count); } + public void testNoSuchFlight() { + Flight flight = flightDao.getFlight("INVALID", departureTime); + assertNull("Flight returned", flight); + } + } \ No newline at end of file diff --git a/samples/airline/src/test/java/org/springframework/ws/samples/airline/dao/jpa/JpaFrequentFlyerDaoTest.java b/samples/airline/src/test/java/org/springframework/ws/samples/airline/dao/jpa/JpaFrequentFlyerDaoTest.java index 45f0eaa1..d1c12c18 100644 --- a/samples/airline/src/test/java/org/springframework/ws/samples/airline/dao/jpa/JpaFrequentFlyerDaoTest.java +++ b/samples/airline/src/test/java/org/springframework/ws/samples/airline/dao/jpa/JpaFrequentFlyerDaoTest.java @@ -51,5 +51,8 @@ public class JpaFrequentFlyerDaoTest extends AbstractJpaTests { assertEquals("Invalid last name", "Poutsma", flyer.getLastName()); } - + public void testNoSuchUsername() { + FrequentFlyer flyer = frequentFlyerDao.get("invalid"); + assertNull("FrequentFlyer returned", flyer); + } } \ No newline at end of file