restx.specs.RestxSpecRepository Maven / Gradle / Ivy
package restx.specs;
import com.google.common.base.Charsets;
import com.google.common.base.Optional;
import com.google.common.collect.*;
import com.google.common.io.CharSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import restx.*;
import restx.common.MoreResources;
import restx.factory.Component;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.util.Collection;
import java.util.Map;
import java.util.regex.Pattern;
/**
* User: xavierhanin
* Date: 4/8/13
* Time: 12:40 PM
*/
@Component
public class RestxSpecRepository {
private static final Logger logger = LoggerFactory.getLogger(RestxSpecRepository.class);
private ImmutableMap allSpecs;
private RestxSpecLoader specLoader;
public RestxSpecRepository(RestxSpecLoader specLoader) {
this.specLoader = specLoader;
}
public Iterable findAll() {
return findAllSpecs().keySet();
}
public Optional findSpecById(String id) {
return Optional.fromNullable(findAllSpecs().get(id));
}
public Iterable findSpecsByOperation(String httpMethod, String path) {
return filterSpecsByOperation(findAllSpecs(), httpMethod, path);
}
public Iterable findSpecsByRequest(RestxRequest request) {
return findWhensMatchingRequest(findAllSpecs(), request);
}
synchronized ImmutableMap findAllSpecs() {
if (allSpecs == null) {
allSpecs = ImmutableMap.copyOf(buildSpecsMap(false));
}
return allSpecs;
}
protected Map buildSpecsMap(boolean searchInSources) {
Map specsMap = Maps.newLinkedHashMap();
Map specs = MoreResources.findResources("", Pattern.compile(".*\\.spec\\.yaml"), searchInSources);
for (final Map.Entry spec : specs.entrySet()) {
try {
specsMap.put(spec.getKey(), specLoader.load(spec.getKey(), new CharSource() {
@Override
public Reader openStream() throws IOException {
return new InputStreamReader(spec.getValue().openStream(), Charsets.UTF_8);
}
}));
} catch (Exception e) {
logger.warn("exception while loading restx spec " + spec + ": " + e, e);
}
}
return specsMap;
}
Iterable filterSpecsByOperation(ImmutableMap allSpecs,
String httpMethod, String path) {
StdRestxRequestMatcher matcher = new StdRestxRequestMatcher(httpMethod, path);
Collection specs = Lists.newArrayList();
for (Map.Entry spec : allSpecs.entrySet()) {
for (When when : spec.getValue().getWhens()) {
if (when instanceof WhenHttpRequest) {
WhenHttpRequest request = (WhenHttpRequest) when;
String requestPath = request.getPath();
if (!requestPath.startsWith("/")) {
requestPath = "/" + requestPath;
}
if (requestPath.indexOf("?") != -1) {
requestPath = requestPath.substring(0, requestPath.indexOf("?"));
}
Optional extends RestxRequestMatch> match = matcher.match(request.getMethod(), requestPath);
if (match.isPresent()) {
specs.add(spec.getKey());
break;
}
}
}
}
return specs;
}
Iterable findWhensMatchingRequest(ImmutableMap allSpecs, RestxRequest restxRequest) {
Collection matchingRequestsSpecs = Lists.newArrayList();
for (Map.Entry spec : allSpecs.entrySet()) {
for (When when : spec.getValue().getWhens()) {
if (when instanceof WhenHttpRequest) {
WhenHttpRequest request = (WhenHttpRequest) when;
String requestPath = request.getPath();
if (!requestPath.startsWith("/")) {
requestPath = "/" + requestPath;
}
StdRequest stdRequest = StdRequest.builder()
.setBaseUri("http://restx.io") // baseUri is required but we won't use it
.setHttpMethod(request.getMethod()).setFullPath(requestPath).build();
if (restxRequest.getHttpMethod().equals(stdRequest.getHttpMethod())
&& restxRequest.getRestxPath().equals(stdRequest.getRestxPath())) {
MapDifference> difference =
Maps.difference(restxRequest.getQueryParams(), stdRequest.getQueryParams());
if (difference.entriesOnlyOnRight().isEmpty()
&& difference.entriesDiffering().isEmpty()) {
matchingRequestsSpecs.add(request);
break;
}
}
}
}
}
return matchingRequestsSpecs;
}
}