diff --git a/airline/client/spring-ws/pom.xml b/airline/client/spring-ws/pom.xml
index e24f23b..3585a20 100644
--- a/airline/client/spring-ws/pom.xml
+++ b/airline/client/spring-ws/pom.xml
@@ -29,6 +29,11 @@
spring-ws-core
+
+ org.springframework.ws
+ spring-ws-security
+
+
org.springframework.ws
spring-ws-test
diff --git a/airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/GetFlights.java b/airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/GetFlights.java
index 75229a0..4ca07af 100644
--- a/airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/GetFlights.java
+++ b/airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/GetFlights.java
@@ -49,8 +49,13 @@ public class GetFlights extends WebServiceGatewaySupport {
getFlightsRequest.setDepartureDate(departureDate);
System.out.println("Requesting flights on " + departureDate);
- GetFlightsResponse response = (GetFlightsResponse) getWebServiceTemplate().marshalSendAndReceive(getFlightsRequest);
- System.out.println("Got " + response.getFlight().size() + " results");
+ GetFlightsResponse response = null;
+ try {
+ response = (GetFlightsResponse) getWebServiceTemplate().marshalSendAndReceive(getFlightsRequest);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ System.out.println("Got " + response.getFlight().size() + " results");
if (response.getFlight().size() > 0) {
// Book the first flight using John Doe as a frequent flyer
BookFlightRequest bookFlightRequest = new BookFlightRequest();
diff --git a/airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/GetFrequentFlyerMileage.java b/airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/GetFrequentFlyerMileage.java
index be0aafe..1f93fce 100644
--- a/airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/GetFrequentFlyerMileage.java
+++ b/airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/GetFrequentFlyerMileage.java
@@ -35,7 +35,5 @@ public class GetFrequentFlyerMileage extends WebServiceGatewaySupport {
"");
getWebServiceTemplate().sendSourceAndReceiveToResult(source, new StreamResult(System.out));
-
}
-
}
diff --git a/airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/SpringWsMain.java b/airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/SpringWsMain.java
index 62c0e48..6e91a54 100644
--- a/airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/SpringWsMain.java
+++ b/airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/SpringWsMain.java
@@ -29,5 +29,8 @@ public class SpringWsMain {
GetFlights getFlights = ctx.getBean(GetFlights.class);
getFlights.getFlights();
+
+ GetFrequentFlyerMileage getFrequentFlyerMileage = ctx.getBean(GetFrequentFlyerMileage.class);
+ getFrequentFlyerMileage.getFrequentFlyerMileage();
}
}
diff --git a/airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/WsConfiguration.java b/airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/WsConfiguration.java
index 4860a70..6241a5c 100644
--- a/airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/WsConfiguration.java
+++ b/airline/client/spring-ws/src/main/java/org/springframework/ws/samples/airline/client/sws/WsConfiguration.java
@@ -3,8 +3,10 @@ package org.springframework.ws.samples.airline.client.sws;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
+import org.springframework.ws.client.support.interceptor.ClientInterceptor;
import org.springframework.ws.soap.SoapMessageFactory;
import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
+import org.springframework.ws.soap.security.wss4j2.Wss4jSecurityInterceptor;
@Configuration(proxyBeanMethods = false)
public class WsConfiguration {
@@ -23,7 +25,8 @@ public class WsConfiguration {
}
@Bean
- GetFlights getFlights(SoapMessageFactory messageFactory, Jaxb2Marshaller marshaller) {
+ GetFlights getFlights(SoapMessageFactory messageFactory, Jaxb2Marshaller marshaller,
+ Wss4jSecurityInterceptor securityInterceptor) {
GetFlights getFlights = new GetFlights(messageFactory);
getFlights.setDefaultUri("http://localhost:8080/airline-server/services");
@@ -33,10 +36,24 @@ public class WsConfiguration {
}
@Bean
- GetFrequentFlyerMileage getFrequentFlyerMileage(SoapMessageFactory messageFactory) {
+ GetFrequentFlyerMileage getFrequentFlyerMileage(SoapMessageFactory messageFactory, Jaxb2Marshaller marshaller,
+ Wss4jSecurityInterceptor securityInterceptor) {
GetFrequentFlyerMileage getFrequentFlyerMileage = new GetFrequentFlyerMileage(messageFactory);
getFrequentFlyerMileage.setDefaultUri("http://localhost:8080/airline-server/services");
+ getFrequentFlyerMileage.setMarshaller(marshaller);
+ getFrequentFlyerMileage.setUnmarshaller(marshaller);
+ getFrequentFlyerMileage.setInterceptors(new ClientInterceptor[] { securityInterceptor });
return getFrequentFlyerMileage;
}
+
+ @Bean
+ Wss4jSecurityInterceptor securityInterceptor() {
+
+ Wss4jSecurityInterceptor securityInterceptor = new Wss4jSecurityInterceptor();
+ securityInterceptor.setSecurementActions("UsernameToken");
+ securityInterceptor.setSecurementUsername("john");
+ securityInterceptor.setSecurementPassword("changeme");
+ return securityInterceptor;
+ }
}
diff --git a/airline/server/pom.xml b/airline/server/pom.xml
index a5d13b3..ea884bd 100644
--- a/airline/server/pom.xml
+++ b/airline/server/pom.xml
@@ -36,16 +36,15 @@
spring-boot-starter-web-services
-
-
-
-
-
-
-
-
-
-
+
+ org.springframework.ws
+ spring-ws-security
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
org.springframework.ws
diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/AirlineServerApplication.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/AirlineServerApplication.java
index c49df5d..1d52b3e 100644
--- a/airline/server/src/main/java/org/springframework/ws/samples/airline/AirlineServerApplication.java
+++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/AirlineServerApplication.java
@@ -2,8 +2,9 @@ package org.springframework.ws.samples.airline;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
-@SpringBootApplication
+@SpringBootApplication(exclude = SecurityAutoConfiguration.class)
public class AirlineServerApplication {
public static void main(String[] args) {
diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/FlightDao.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/FlightDao.java
index 6e3c2b0..453e4e1 100644
--- a/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/FlightDao.java
+++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/FlightDao.java
@@ -35,12 +35,4 @@ public interface FlightDao extends CrudRepository {
@Param("class") ServiceClass serviceClass);
Flight findFlightByNumberAndDepartureTime(String flightNumber, ZonedDateTime departureTime);
-
- /**
- * @deprecated Migrate to {@link #save(Object)}.
- */
- @Deprecated
- default Flight update(Flight flight) {
- return save(flight);
- }
}
diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/FrequentFlyerDao.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/FrequentFlyerDao.java
index a2e9c7e..3c63fe4 100644
--- a/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/FrequentFlyerDao.java
+++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/dao/FrequentFlyerDao.java
@@ -16,20 +16,13 @@
package org.springframework.ws.samples.airline.dao;
-import org.springframework.dao.DataAccessException;
+import java.util.Optional;
+
import org.springframework.data.repository.CrudRepository;
import org.springframework.ws.samples.airline.domain.FrequentFlyer;
public interface FrequentFlyerDao extends CrudRepository {
- /**
- * @deprecated Migrate to {@link #findByUsername(String)}.
- */
- @Deprecated
- default FrequentFlyer get(String username) throws DataAccessException {
- return findByUsername(username);
- }
-
- FrequentFlyer findByUsername(String username);
+ Optional findByUsername(String username);
}
diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/domain/FrequentFlyer.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/domain/FrequentFlyer.java
index 42d541f..a73c5ac 100644
--- a/airline/server/src/main/java/org/springframework/ws/samples/airline/domain/FrequentFlyer.java
+++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/domain/FrequentFlyer.java
@@ -85,8 +85,10 @@ public class FrequentFlyer extends Passenger {
return username.hashCode();
}
+ @Override
public String toString() {
- return username;
+ return "FrequentFlyer{" + "username='" + username + '\'' + ", password='" + password + '\'' + ", miles=" + miles
+ + '}';
}
public void addMiles(int miles) {
diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/security/FrequentFlyerDetails.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/security/FrequentFlyerDetails.java
new file mode 100644
index 0000000..d3b2124
--- /dev/null
+++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/security/FrequentFlyerDetails.java
@@ -0,0 +1,65 @@
+package org.springframework.ws.samples.airline.security;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.ws.samples.airline.domain.FrequentFlyer;
+
+public class FrequentFlyerDetails implements UserDetails {
+
+ private static final List GRANTED_AUTHORITIES = List
+ .of(new SimpleGrantedAuthority("ROLE_FREQUENT_FLYER"));
+
+ private FrequentFlyer frequentFlyer;
+
+ public FrequentFlyerDetails(FrequentFlyer frequentFlyer) {
+ this.frequentFlyer = frequentFlyer;
+ }
+
+ public FrequentFlyer getFrequentFlyer() {
+ return frequentFlyer;
+ }
+
+ @Override
+ public Collection extends GrantedAuthority> getAuthorities() {
+ return GRANTED_AUTHORITIES;
+ }
+
+ @Override
+ public String getUsername() {
+ return frequentFlyer.getUsername();
+ }
+
+ @Override
+ public String getPassword() {
+ return frequentFlyer.getPassword();
+ }
+
+ @Override
+ public boolean isAccountNonExpired() {
+ return true;
+ }
+
+ @Override
+ public boolean isAccountNonLocked() {
+ return true;
+ }
+
+ @Override
+ public boolean isCredentialsNonExpired() {
+ return true;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "FrequentFlyerDetails{" + "frequentFlyer=" + frequentFlyer + '}';
+ }
+}
diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/security/FrequentFlyerSecurityService.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/security/FrequentFlyerSecurityService.java
new file mode 100644
index 0000000..4873b11
--- /dev/null
+++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/security/FrequentFlyerSecurityService.java
@@ -0,0 +1,29 @@
+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.
+ *
+ * @author Arjen Poutsma
+ */
+public interface FrequentFlyerSecurityService {
+
+ /**
+ * Returns the FrequentFlyer with the given username.
+ *
+ * @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) throws NoSuchFrequentFlyerException;
+
+ /**
+ * Returns the FrequentFlyer that is currently logged in.
+ *
+ * @return the frequent flyer that is currently logged in, or null if not found
+ */
+ FrequentFlyer getCurrentlyAuthenticatedFrequentFlyer();
+
+}
diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/security/SecurityConfiguration.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/security/SecurityConfiguration.java
new file mode 100644
index 0000000..2f68f7d
--- /dev/null
+++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/security/SecurityConfiguration.java
@@ -0,0 +1,37 @@
+package org.springframework.ws.samples.airline.security;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.crypto.password.NoOpPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.web.SecurityFilterChain;
+import org.springframework.ws.samples.airline.dao.FrequentFlyerDao;
+
+@Configuration(proxyBeanMethods = false)
+@EnableMethodSecurity
+public class SecurityConfiguration {
+
+ @Bean
+ SpringSecurityFrequentFlyerService userDetailsService(FrequentFlyerDao frequentFlyerDao) {
+ return new SpringSecurityFrequentFlyerService(frequentFlyerDao);
+ }
+
+ @Bean
+ PasswordEncoder passwordEncoder() {
+ return NoOpPasswordEncoder.getInstance();
+ }
+
+// @Bean
+// SecurityFilterChain securityFilterChain(HttpSecurity security) throws Exception {
+//
+// security.authorizeHttpRequests() //
+// .requestMatchers("/login", "/error", "/logout").permitAll() //
+// .anyRequest().authenticated() //
+// .and() //
+// .csrf().disable();
+//
+// return security.build();
+// }
+}
diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/security/SpringSecurityFrequentFlyerService.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/security/SpringSecurityFrequentFlyerService.java
new file mode 100644
index 0000000..b5518ae
--- /dev/null
+++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/security/SpringSecurityFrequentFlyerService.java
@@ -0,0 +1,65 @@
+package org.springframework.ws.samples.airline.security;
+
+import org.apache.wss4j.common.principal.UsernameTokenPrincipal;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+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 {@link FrequentFlyerSecurityService} that uses Spring Security.
+ *
+ * @author Arjen Poutsma
+ */
+public class SpringSecurityFrequentFlyerService implements FrequentFlyerSecurityService, UserDetailsService {
+
+ private static final Logger log = LoggerFactory.getLogger(SpringSecurityFrequentFlyerService.class);
+
+ private final FrequentFlyerDao frequentFlyerDao;
+
+ public SpringSecurityFrequentFlyerService(FrequentFlyerDao frequentFlyerDao) {
+ this.frequentFlyerDao = frequentFlyerDao;
+ }
+
+ @Override
+ @Transactional
+ public FrequentFlyer getFrequentFlyer(String username) throws NoSuchFrequentFlyerException {
+ return frequentFlyerDao.findByUsername(username) //
+ .orElseThrow(() -> new NoSuchFrequentFlyerException(username));
+ }
+
+ @Override
+ @Transactional
+ public FrequentFlyer getCurrentlyAuthenticatedFrequentFlyer() {
+ Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+
+ if (authentication != null) {
+ UsernameTokenPrincipal principal = (UsernameTokenPrincipal) authentication.getPrincipal();
+ FrequentFlyerDetails frequentFlyerDetails = (FrequentFlyerDetails) loadUserByUsername(principal.getName());
+ return frequentFlyerDetails.getFrequentFlyer();
+ }
+
+ return null;
+ }
+
+ @Override
+ @Transactional
+ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
+ log.debug("Looking up " + username);
+
+ FrequentFlyerDetails details = frequentFlyerDao.findByUsername(username) //
+ .map(FrequentFlyerDetails::new) //
+ .orElseThrow(() -> new UsernameNotFoundException("Frequent flyer '" + username + "' not found"));
+
+ log.debug("Found " + details);
+
+ return details;
+ }
+}
diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/security/StubFrequentFlyerSecurityService.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/security/StubFrequentFlyerSecurityService.java
new file mode 100644
index 0000000..11dc4da
--- /dev/null
+++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/security/StubFrequentFlyerSecurityService.java
@@ -0,0 +1,35 @@
+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 org.springframework.ws.samples.airline.service.impl.AirlineServiceImpl}, to allow it to run without depending
+ * on Spring Security.
+ *
+ * @author Arjen Poutsma
+ */
+public class StubFrequentFlyerSecurityService implements FrequentFlyerSecurityService {
+
+ private FrequentFlyer john;
+
+ public StubFrequentFlyerSecurityService() {
+ this.john = new FrequentFlyer("John", "Doe", "john", "changeme");
+ john.setMiles(10);
+ }
+
+ @Override
+ public FrequentFlyer getFrequentFlyer(String username) throws NoSuchFrequentFlyerException {
+ if (john.getUsername().equals(username)) {
+ return john;
+ } else {
+ throw new NoSuchFrequentFlyerException(username);
+ }
+ }
+
+ @Override
+ public FrequentFlyer getCurrentlyAuthenticatedFrequentFlyer() {
+ return john;
+ }
+}
diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/service/AirlineService.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/service/AirlineService.java
index ee047ae..3932307 100644
--- a/airline/server/src/main/java/org/springframework/ws/samples/airline/service/AirlineService.java
+++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/service/AirlineService.java
@@ -66,4 +66,11 @@ public interface AirlineService {
Ticket bookFlight(String flightNumber, ZonedDateTime departureTime, List passengers)
throws NoSuchFlightException, NoSeatAvailableException, NoSuchFrequentFlyerException;
+ /**
+ * Returns the amount of frequent flyer award miles for the currently logged in frequent flyer.
+ *
+ * @return the amount of frequent flyer miles
+ */
+ int getFrequentFlyerMileage();
}
+
diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/service/impl/AirlineServiceImpl.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/service/impl/AirlineServiceImpl.java
index e889195..f0189fc 100644
--- a/airline/server/src/main/java/org/springframework/ws/samples/airline/service/impl/AirlineServiceImpl.java
+++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/service/impl/AirlineServiceImpl.java
@@ -18,19 +18,20 @@ package org.springframework.ws.samples.airline.service.impl;
import java.time.LocalDate;
import java.time.ZonedDateTime;
import java.util.List;
+import java.util.Optional;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.ws.samples.airline.dao.FlightDao;
import org.springframework.ws.samples.airline.dao.TicketDao;
-import org.springframework.ws.samples.airline.domain.Flight;
-import org.springframework.ws.samples.airline.domain.Passenger;
-import org.springframework.ws.samples.airline.domain.ServiceClass;
-import org.springframework.ws.samples.airline.domain.Ticket;
+import org.springframework.ws.samples.airline.domain.*;
+import org.springframework.ws.samples.airline.security.FrequentFlyerSecurityService;
+import org.springframework.ws.samples.airline.security.StubFrequentFlyerSecurityService;
import org.springframework.ws.samples.airline.service.AirlineService;
import org.springframework.ws.samples.airline.service.NoSeatAvailableException;
import org.springframework.ws.samples.airline.service.NoSuchFlightException;
@@ -51,40 +52,66 @@ public class AirlineServiceImpl implements AirlineService {
private TicketDao ticketDao;
- @Autowired
+ private FrequentFlyerSecurityService frequentFlyerSecurityService = new StubFrequentFlyerSecurityService();
+
public AirlineServiceImpl(FlightDao flightDao, TicketDao ticketDao) {
this.flightDao = flightDao;
this.ticketDao = ticketDao;
}
+ @Autowired(required = false)
+ public void setFrequentFlyerSecurityService(FrequentFlyerSecurityService frequentFlyerSecurityService) {
+ this.frequentFlyerSecurityService = frequentFlyerSecurityService;
+ }
+
@Transactional(readOnly = false,
rollbackFor = { NoSuchFlightException.class, NoSeatAvailableException.class, NoSuchFrequentFlyerException.class })
public Ticket bookFlight(String flightNumber, ZonedDateTime departureTime, List passengers)
throws NoSuchFlightException, NoSeatAvailableException, NoSuchFrequentFlyerException {
Assert.notEmpty(passengers, "No passengers given");
+
if (logger.isDebugEnabled()) {
logger.debug("Booking flight '" + flightNumber + "' on '" + departureTime + "' for " + passengers);
}
+
Flight flight = flightDao.findFlightByNumberAndDepartureTime(flightNumber, departureTime);
+
if (flight == null) {
throw new NoSuchFlightException(flightNumber, departureTime);
} else if (flight.getSeatsAvailable() < passengers.size()) {
throw new NoSeatAvailableException(flight);
}
+
Ticket ticket = new Ticket();
ticket.setIssueDate(LocalDate.now());
ticket.setFlight(flight);
- passengers.forEach(ticket::addPassenger);
+
+ for (Passenger passenger : passengers) {
+ if (passenger instanceof FrequentFlyer && frequentFlyerSecurityService != null) {
+ String username = ((FrequentFlyer) passenger).getUsername();
+ Assert.hasLength(username, "No username specified");
+ FrequentFlyer frequentFlyer = frequentFlyerSecurityService.getFrequentFlyer(username);
+ frequentFlyer.addMiles(flight.getMiles());
+ ticket.addPassenger(frequentFlyer);
+ } else {
+ ticket.addPassenger(passenger);
+ }
+ }
+
flight.substractSeats(passengers.size());
+
flightDao.save(flight);
ticketDao.save(ticket);
+
return ticket;
}
public Flight getFlight(Long id) throws NoSuchFlightException {
- return flightDao.findById(id).orElseThrow(() -> new NoSuchFlightException(id));
+
+ return flightDao.findById(id) //
+ .orElseThrow(() -> new NoSuchFlightException(id));
}
public List getFlights(String fromAirportCode, String toAirportCode, ZonedDateTime departureDate,
@@ -93,13 +120,30 @@ public class AirlineServiceImpl implements AirlineService {
if (serviceClass == null) {
serviceClass = ServiceClass.ECONOMY;
}
+
if (logger.isDebugEnabled()) {
logger.debug("Getting flights from '" + fromAirportCode + "' to '" + toAirportCode + "' on " + departureDate);
}
+
List flights = flightDao.findFlights(fromAirportCode, toAirportCode, departureDate, serviceClass);
+
if (logger.isDebugEnabled()) {
logger.debug("Returning " + flights.size() + " flights");
}
+
return flights;
}
+
+ @Override
+ @PreAuthorize("hasRole('FREQUENT_FLYER')")
+ public int getFrequentFlyerMileage() {
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("Using " + frequentFlyerSecurityService + " for security");
+ }
+
+ return Optional.ofNullable(frequentFlyerSecurityService.getCurrentlyAuthenticatedFrequentFlyer())
+ .map(FrequentFlyer::getMiles) //
+ .orElse(0);
+ }
}
diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/web/FlightsController.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/web/FlightsController.java
index 3ed09a1..09cc56c 100644
--- a/airline/server/src/main/java/org/springframework/ws/samples/airline/web/FlightsController.java
+++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/web/FlightsController.java
@@ -20,7 +20,7 @@ import java.time.LocalDate;
import java.time.ZonedDateTime;
import org.springframework.stereotype.Controller;
-import org.springframework.ui.ModelMap;
+import org.springframework.ui.Model;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
@@ -49,7 +49,7 @@ public class FlightsController {
public String flightList(@RequestParam(value = "from", required = false) String fromAirportCode,
@RequestParam(value = "to", required = false) String toAirportCode,
@RequestParam(value = "departureDate", required = false) String departureDateString,
- @RequestParam(value = "serviceClass", required = false) String serviceClassString, ModelMap model) {
+ @RequestParam(value = "serviceClass", required = false) String serviceClassString, Model model) {
if (ObjectUtils.isEmpty(departureDateString)) {
departureDateString = LocalDate.now().toString();
@@ -58,7 +58,7 @@ public class FlightsController {
serviceClassString = "ECONOMY";
}
ServiceClass serviceClass = ServiceClass.valueOf(serviceClassString);
- ZonedDateTime departureDate = ZonedDateTime.parse(departureDateString);
+ ZonedDateTime departureDate = ZonedDateTime.parse(departureDateString);
if (StringUtils.hasLength(fromAirportCode) && StringUtils.hasLength(toAirportCode)) {
model.addAttribute("from", fromAirportCode);
@@ -72,7 +72,7 @@ public class FlightsController {
}
@GetMapping(value = "{id}")
- public String singleFlight(@PathVariable("id") long id, ModelMap model) throws NoSuchFlightException {
+ public String singleFlight(@PathVariable("id") long id, Model model) throws NoSuchFlightException {
model.addAttribute(airlineService.getFlight(id));
return "flight";
diff --git a/airline/server/src/main/java/org/springframework/ws/samples/airline/ws/AirlineEndpoint.java b/airline/server/src/main/java/org/springframework/ws/samples/airline/ws/AirlineEndpoint.java
index 5f78e98..bc7ea4d 100644
--- a/airline/server/src/main/java/org/springframework/ws/samples/airline/ws/AirlineEndpoint.java
+++ b/airline/server/src/main/java/org/springframework/ws/samples/airline/ws/AirlineEndpoint.java
@@ -24,15 +24,16 @@ import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.List;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.XMLGregorianCalendar;
+import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.ws.samples.airline.domain.FrequentFlyer;
@@ -45,6 +46,8 @@ 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.*;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
/**
* Endpoint that handles the Airline Web Service messages using a combination of JAXB2 marshalling and XPath
@@ -55,7 +58,7 @@ import org.springframework.ws.server.endpoint.annotation.*;
@Endpoint
public class AirlineEndpoint {
- private static final Log logger = LogFactory.getLog(AirlineEndpoint.class);
+ private static final Logger logger = LoggerFactory.getLogger(AirlineEndpoint.class);
private final ObjectFactory objectFactory = new ObjectFactory();
@@ -136,23 +139,38 @@ public class AirlineEndpoint {
NoSuchFrequentFlyerException, DatatypeConfigurationException {
ZonedDateTime departureTime = SchemaConversionUtils.toDateTime(xmlDepartureTime);
- List passengers = new ArrayList(passengerOrUsernameList.size());
+ List passengers = new ArrayList<>(passengerOrUsernameList.size());
- for (Iterator