ServiceConfig.java
package org.wikidata.query.rdf.blazegraph.mwapi;
import static java.util.Objects.requireNonNull;
import static java.util.function.Function.identity;
import java.io.IOException;
import java.io.Reader;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.apache.commons.validator.routines.DomainValidator;
import org.wikidata.query.rdf.blazegraph.JacksonUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Streams;
/**
* MW API service configuration.
*/
public class ServiceConfig {
private static final DomainValidator DOMAIN_VALIDATOR = DomainValidator.getInstance();
/**
* Map of services, keyed by name.
*/
private final Map<String, ApiTemplate> serviceMap;
/**
* Allowed endpoints.
*/
private final List<String> endpoints;
public ServiceConfig(Reader configReader) throws IOException {
JsonNode mainNode = JacksonUtil.DEFAULT_OBJECT_READER.readTree(configReader);
this.serviceMap = loadJsonConfig(mainNode.get("services"));
this.endpoints = loadEndpoints(mainNode.get("endpoints"));
}
@VisibleForTesting
public ServiceConfig() {
this.serviceMap = Collections.emptyMap();
this.endpoints = Collections.emptyList();
}
/**
* Load set of configs from JSON config file.
* @param node Services node
* @return Map of API templates per name.
*/
private static Map<String, ApiTemplate> loadJsonConfig(JsonNode node) {
requireNonNull(node, "Must have services node");
return Streams.stream(node.fieldNames())
.collect(ImmutableMap.toImmutableMap(
identity(),
fieldName -> ApiTemplate.fromJSON(node.get(fieldName))));
}
/**
* Load list of endpoints.
*/
private static List<String> loadEndpoints(JsonNode node) {
requireNonNull(node, "Must have endpoints node");
Preconditions.checkArgument(node.isArray(), "Endpoints config should be an array");
// Get immutable list of elements' text representations
return Streams.stream(node.elements())
.map(JsonNode::asText)
.collect(ImmutableList.toImmutableList());
}
/**
* Get service template by name.
*/
public ApiTemplate getService(String templateName) {
Preconditions.checkArgument(serviceMap.containsKey(templateName),
"Service name " + templateName + " not found in configuration");
return serviceMap.get(templateName);
}
/**
* Check if endpoint is allowed.
*/
public boolean validEndpoint(String endpointHost) {
if (!DOMAIN_VALIDATOR.isValid(endpointHost)) {
return false;
}
for (String allowedEndpoint: endpoints) {
if ((allowedEndpoint.startsWith(".") && endpointHost.endsWith(allowedEndpoint))
|| endpointHost.equals(allowedEndpoint)) {
return true;
}
}
return false;
}
/**
* Get number of services.
*/
public int size() {
return serviceMap.size();
}
}