Skip to content

Commit

Permalink
WIP: Resolve addresses by three word addresses
Browse files Browse the repository at this point in the history
  • Loading branch information
Sandra Thieme committed Feb 26, 2018
1 parent 079a45f commit 230c380
Show file tree
Hide file tree
Showing 14 changed files with 396 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,12 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import javax.servlet.http.HttpServletRequest;

import static net.contargo.iris.address.w3w.ThreeWordMatcher.isThreeWordAddress;

import static org.slf4j.LoggerFactory.getLogger;

import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
Expand Down Expand Up @@ -139,6 +142,15 @@ public ListOfAddressListsResponse addressesByAddressDetails(@RequestParam(requir
}
}

if (isThreeWordAddress(street)) {
Optional<AddressDto> addressDto = addressDtoService.getAddressesByThreeWords(street.trim());

if (addressDto.isPresent()) {
addressListDtos = singletonList(new AddressListDto("Result for three words " + street,
singletonList(addressDto.get())));
}
}

Map<String, String> addressDetails = NominatimUtil.parameterMap(street, postalCode, city, country, name);

if (addressListDtos.isEmpty()) {
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/net/contargo/iris/address/dto/AddressDtoService.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import java.util.List;
import java.util.Map;
import java.util.Optional;


/**
Expand Down Expand Up @@ -96,4 +97,14 @@ public interface AddressDtoService {
* @return a list of matching addresses
*/
List<AddressDto> getAddressesByQuery(String query);


/**
* Returns an optional {@link AddressDto} matching the given three word address.
*
* @param threeWords a three word address
*
* @return an optional address
*/
Optional<AddressDto> getAddressesByThreeWords(String threeWords);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.toList;
Expand Down Expand Up @@ -101,4 +102,13 @@ public List<AddressDto> getAddressesByQuery(String query) {

return addressServiceWrapper.getAddressesByQuery(query).stream().map(AddressDto::new).collect(toList());
}


@Override
public Optional<AddressDto> getAddressesByThreeWords(String threeWords) {

Optional<Address> optionalAddress = addressServiceWrapper.getAddressByThreeWords(threeWords);

return optionalAddress.map(AddressDto::new);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import net.contargo.iris.address.staticsearch.StaticAddress;
import net.contargo.iris.address.staticsearch.service.StaticAddressNotFoundException;
import net.contargo.iris.address.staticsearch.service.StaticAddressService;
import net.contargo.iris.address.w3w.ThreeWordClient;
import net.contargo.iris.address.w3w.ThreeWordClientException;
import net.contargo.iris.normalizer.NormalizerService;

import org.apache.commons.lang.StringUtils;
Expand All @@ -19,6 +21,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Pattern;

import static net.contargo.iris.address.nominatim.service.AddressDetailKey.CITY;
Expand Down Expand Up @@ -46,14 +49,16 @@ public class AddressServiceWrapper {
private final StaticAddressService staticAddressService;
private final AddressCache addressCache;
private final NormalizerService normalizerService;
private final ThreeWordClient threeWordClient;

public AddressServiceWrapper(AddressService addressService, StaticAddressService staticAddressService,
AddressCache cache, NormalizerService normalizerService) {
AddressCache cache, NormalizerService normalizerService, ThreeWordClient threeWordClient) {

this.addressService = addressService;
this.staticAddressService = staticAddressService;
this.addressCache = cache;
this.normalizerService = normalizerService;
this.threeWordClient = threeWordClient;
}

/**
Expand Down Expand Up @@ -225,4 +230,18 @@ public List<Address> getAddressesByQuery(String query) {

return addresses;
}


public Optional<Address> getAddressByThreeWords(String threeWords) {

try {
GeoLocation resolvedLocation = threeWordClient.resolve(threeWords);

return Optional.of(getAddressForGeoLocation(resolvedLocation));
} catch (ThreeWordClientException e) {
LOG.info("Cannot resolve three word address {}: {}", threeWords, e.getMessage());

return Optional.empty();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package net.contargo.iris.address.w3w;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

import net.contargo.iris.GeoLocation;

import java.math.BigDecimal;


/**
* @author Sandra Thieme - thieme@synyx.de
*/
class ForwardW3wResponse {

private final W3wResponseGeometry geometry;
private final W3wResponseStatus status;

@JsonCreator
ForwardW3wResponse(@JsonProperty("geometry") W3wResponseGeometry geometry,
@JsonProperty("status") W3wResponseStatus status) {

this.geometry = geometry;
this.status = status;
}

GeoLocation toGeolocation() {

return new GeoLocation(geometry.lat, geometry.lon);
}


boolean error() {

return status.code != null;
}


Integer errorCode() {

return status.code;
}


String errorMessage() {

return status.message;
}

private static class W3wResponseGeometry {

private final BigDecimal lat;
private final BigDecimal lon;

@JsonCreator
private W3wResponseGeometry(@JsonProperty("lat") BigDecimal lat,
@JsonProperty("lng") BigDecimal lon) {

this.lat = lat;
this.lon = lon;
}
}

private static class W3wResponseStatus {

private final Integer code;
private final String message;

@JsonCreator
private W3wResponseStatus(@JsonProperty("code") Integer code,
@JsonProperty("message") String message) {

this.code = code;
this.message = message;
}
}
}
47 changes: 47 additions & 0 deletions src/main/java/net/contargo/iris/address/w3w/ThreeWordClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package net.contargo.iris.address.w3w;

import net.contargo.iris.GeoLocation;

import org.springframework.http.ResponseEntity;

import org.springframework.web.client.RestTemplate;


/**
* @author Sandra Thieme - thieme@synyx.de
*/
public class ThreeWordClient {

private static final String FORWARD_URL =
"https://api.what3words.com/v2/forward?addr={w3wAddress}&key={apiKey}&lang=de";

private final RestTemplate restTemplate;
private final String apiKey;

public ThreeWordClient(RestTemplate restTemplate, String apiKey) {

this.restTemplate = restTemplate;
this.apiKey = apiKey;
}

public GeoLocation resolve(String threeWords) {

ResponseEntity<ForwardW3wResponse> response = restTemplate.getForEntity(FORWARD_URL, ForwardW3wResponse.class,
threeWords, apiKey);

checkErrorStatus(response.getBody(), threeWords);

return response.getBody().toGeolocation();
}


private static void checkErrorStatus(ForwardW3wResponse response, String threeWords) {

if (response.error()) {
Integer code = response.errorCode();
String message = response.errorMessage();

throw new ThreeWordClientException(code, message, threeWords);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package net.contargo.iris.address.w3w;

/**
* @author Sandra Thieme - thieme@synyx.de
*/
public class ThreeWordClientException extends RuntimeException {

ThreeWordClientException(Integer code, String message, String threeWords) {

super("API of w3w returned error code " + code + " with message '" + message
+ "' for three word address '" + threeWords + "'");
}
}
17 changes: 17 additions & 0 deletions src/main/java/net/contargo/iris/address/w3w/ThreeWordMatcher.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package net.contargo.iris.address.w3w;

import java.util.regex.Pattern;


/**
* @author Sandra Thieme - thieme@synyx.de
*/
public class ThreeWordMatcher {

private static final Pattern THREE_WORD_PATTERN = Pattern.compile("^\\p{L}+\\.\\p{L}+\\.\\p{L}+$");

public static boolean isThreeWordAddress(String input) {

return input != null && THREE_WORD_PATTERN.matcher(input.trim()).matches();
}
}
12 changes: 10 additions & 2 deletions src/main/resources/application-context.xml
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,16 @@
</bean>
</constructor-arg>
<constructor-arg name="normalizerService" ref="normalizerService"/>
<constructor-arg name="threeWordClient" ref="threeWordClient"/>
</bean>


<bean id="threeWordClient" class="net.contargo.iris.address.w3w.ThreeWordClient">
<constructor-arg>
<bean class="org.springframework.web.client.RestTemplate"/>
</constructor-arg>
<constructor-arg name="apiKey" value="${w3w.apikey}"/>
</bean>

<bean id="addressListFilter" class="net.contargo.iris.address.service.AddressListFilterImpl"/>

<bean id="addressDtoService" class="net.contargo.iris.address.dto.AddressDtoServiceImpl">
Expand Down Expand Up @@ -401,7 +409,7 @@
</bean>
</constructor-arg>
</bean>

<bean id="postcodeCitySuburbStaticAddressMappingProcessor" class="net.contargo.iris.address.staticsearch.service.PostcodeCitySuburbStaticAddressMappingProcessor">
<constructor-arg name="next" ref="postcodeCityStaticAddressMappingProcessor"/>
<constructor-arg name="normalizerService" ref="normalizerService"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import static net.contargo.iris.address.nominatim.service.AddressDetailKey.CITY;
import static net.contargo.iris.address.nominatim.service.AddressDetailKey.COUNTRY;
Expand Down Expand Up @@ -192,4 +193,16 @@ public void getAddressesByQuery() {
assertThat(addresses, hasSize(1));
assertThat(addresses.get(0).getDisplayName(), is("Gartenstr. 67, Karlsruhe (Südweststadt)"));
}


@Test
public void getAddressesByThreeWords() {

when(addressServiceWrapperMock.getAddressByThreeWords("riches.lofts.guessing")).thenReturn(Optional.of(
new Address("German Chancellery")));

Optional<AddressDto> dto = sut.getAddressesByThreeWords("riches.lofts.guessing");

assertThat(dto.get().getDisplayName(), is("German Chancellery"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import net.contargo.iris.address.nominatim.service.AddressService;
import net.contargo.iris.address.staticsearch.StaticAddress;
import net.contargo.iris.address.staticsearch.service.StaticAddressService;
import net.contargo.iris.address.w3w.ThreeWordClient;
import net.contargo.iris.normalizer.NormalizerService;

import org.junit.Before;
Expand Down Expand Up @@ -61,6 +62,8 @@ public class AddressServiceWrapperCachingUnitTest {
private StaticAddressService staticAddressServiceMock;
@Mock
private AddressCache addressCacheMock;
@Mock
private ThreeWordClient threeWordClientMock;

@Before
public void setup() {
Expand All @@ -69,7 +72,7 @@ public void setup() {
when(normalizerServiceMock.normalize(CITY_NAME)).thenReturn(CITY_NAME_NORMALIZED);

sut = new AddressServiceWrapper(addressServiceMock, staticAddressServiceMock, addressCacheMock,
normalizerServiceMock);
normalizerServiceMock, threeWordClientMock);
}


Expand Down
Loading

0 comments on commit 230c380

Please sign in to comment.