/*
* Copyright 2015 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.cloud.client.hypermedia;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import java.net.URI;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.client.Traverson;
import org.springframework.util.Assert;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestOperations;
import org.springframework.web.client.RestTemplate;
/**
* A REST resource that is defined by a service reference and a traversal operation within that service.
*
* @author Oliver Gierke
*/
@Slf4j
@RequiredArgsConstructor
public class DiscoveredResource implements RemoteResource {
private final ServiceInstanceProvider provider;
private final TraversalDefinition traversal;
private RestOperations restOperations = new RestTemplate();
private @Getter Link link = null;
/**
* Configures the {@link RestOperations} to use to execute the traversal and verifying HEAD calls.
*
* @param restOperations can be {@literal null}, resorting to a default {@link RestTemplate} in that case.
*/
public void setRestOperations(RestOperations restOperations) {
this.restOperations = restOperations == null ? new RestTemplate() : restOperations;
}
/**
* Verifies the link to the current
*/
public void verifyOrDiscover() {
this.link = link == null ? discoverLink() : verify(link);
}
/**
* Verifies the given {@link Link} by issuing an HTTP HEAD request to the resource.
*
* @param link must not be {@literal null}.
* @return
*/
private Link verify(Link link) {
Assert.notNull(link, "Link must not be null!");
try {
String uri = link.expand().getHref();
log.debug("Verifying link pointing to {}…", uri);
restOperations.headForHeaders(uri);
log.debug("Successfully verified link!");
return link;
} catch (RestClientException o_O) {
log.debug("Verification failed, marking as outdated!");
return null;
}
}
private Link discoverLink() {
try {
ServiceInstance service = provider.getServiceInstance();
if (service == null) {
return null;
}
URI uri = service.getUri();
String serviceId = service.getServiceId();
log.debug("Discovered {} system at {}. Discovering resource…", serviceId, uri);
Traverson traverson = new Traverson(uri, MediaTypes.HAL_JSON);
Link link = traversal.buildTraversal(traverson).asTemplatedLink();
log.debug("Found link pointing to {}.", link.getHref());
return link;
} catch (RuntimeException o_O) {
this.link = null;
log.debug("Target system unavailable. Got: ", o_O.getMessage());
return null;
}
}
}