Endpoint.java

package org.wikidata.query.rdf.blazegraph.mwapi;

import java.net.MalformedURLException;
import java.net.URL;

import org.openrdf.model.URI;
import org.openrdf.model.Value;

import com.bigdata.bop.IBindingSet;
import com.bigdata.bop.IVariableOrConstant;
import com.bigdata.bop.Var;
import com.bigdata.rdf.internal.IV;

/**
 * Representation of static or variable endpoint.
 * The resulting URL will always be https://HOSTNAME/w/api.php where hostname is either
 * taken from URI or from string.
 * It will be also checked against allowed endpoint allowlist.
 */
public abstract class Endpoint {

    /**
     * Get full endpoint URL relative to a binding set.
     *
     * @return Endpoint URL.
     * @throws MalformedURLException If it's bad URL
     */
    public abstract String getEndpointURL(IBindingSet binding) throws MalformedURLException;

    public static Endpoint create(IVariableOrConstant term, ServiceConfig config) throws MalformedURLException {
        if (term.isConstant()) {
            return new ConstantEndpoint(getURLFromValue(config, ((IV) term.get()).getValue()));
        } else {
            // Since term is not Constant, it must be a Var
            assert term instanceof Var;

            return new VariableEndpoint(config, (Var)term);
        }
    }

    private static String getURLFromValue(ServiceConfig config, Value v) throws MalformedURLException {
        String endpointHost = hostFromValue(v);
        if (!config.validEndpoint(endpointHost)) {
            throw new IllegalArgumentException("Host " + endpointHost + " is not allowed");
        }
        return new URL("https", endpointHost, "/w/api.php").toExternalForm();
    }

    private static String hostFromValue(Value v) throws MalformedURLException {
        if (v instanceof URI) {
            return new URL(v.stringValue()).getHost();
        } else {
            return v.stringValue();
        }
    }

    private static class ConstantEndpoint extends Endpoint {
        private final String endpoint;

        ConstantEndpoint(String endpoint) {
            this.endpoint = endpoint;
        }

        @Override
        public String getEndpointURL(IBindingSet binding) {
            return endpoint;
        }
    }

    private static class VariableEndpoint extends Endpoint {
        private final ServiceConfig config;
        private final Var endpoint;

        VariableEndpoint(ServiceConfig config, Var endpoint) {
            this.config = config;
            this.endpoint = endpoint;
        }

        @Override
        public String getEndpointURL(IBindingSet binding) throws MalformedURLException {
            IV boundValue = (IV)endpoint.get(binding);
            if (boundValue == null) return null;

            return Endpoint.getURLFromValue(config, boundValue.getValue());
        }
    }
}