Commit 4e8616d3 authored by Florian Schäfer's avatar Florian Schäfer

Add URL factory for the Wikidata Action API

Currently there's only the URL to check for existence of entities (and redirects). Many more to come…
parent e3afa272
......@@ -28,7 +28,7 @@ dependencies {
testImplementation "org.junit.jupiter:junit-jupiter-api:${versions.junit}"
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${versions.junit}"
testImplementation "org.junit.vintage:junit-vintage-engine:${versions.junit}"
testImplementation "com.github.spotbugs:spotbugs-annotations:${versions.spotbugs}"
implementation "com.github.spotbugs:spotbugs-annotations:${versions.spotbugs}"
testImplementation("org.openstreetmap.josm:josm-unittest:"){changing=true}
}
......@@ -55,6 +55,9 @@ sourceSets {
java {
srcDirs = ["test/unit"]
}
resources {
srcDirs = ["test/data"]
}
}
}
......@@ -196,4 +199,4 @@ gradle.buildFinished {
it.logger.lifecycle("⏭️ :${it.name} (${it.state.skipMessage})")
}
}
}
\ No newline at end of file
}
// License: GPL. For details, see LICENSE file.
package org.wikipedia.api;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.Nonnull;
import org.openstreetmap.josm.tools.Logging;
public class ApiUrl {
private ApiUrl() {
// Private constructor to avoid instantiation
}
/**
* Concatenates all parameters (nulls are treated like empty strings) to a single string and passes that to
* {@link #url(String)}.
*
* @param part1
* the first part of the URL
* @param part2
* the second part of the URL
* @param moreParts
* the rest of the parts of the URL
* @return the URL that is returned from {@link #url(String)} when passing it the concatenated parts
* @throws IllegalArgumentException
* when the returned URL would be malformed
*/
@Nonnull
public static URL url(@Nonnull final String part1, @Nonnull final String part2, @Nonnull final String... moreParts) {
return url(
Stream.concat(Stream.of(part1, part2), Arrays.stream(moreParts))
.filter(Objects::nonNull)
.collect(Collectors.joining())
);
}
/**
* The same as {@link URL#URL(String)}, except that any {@link MalformedURLException} will be wrapped inside
* an {@link IllegalArgumentException}, which is unchecked.
*
* @param url
* the string to parse as URL
* @return the resulting URL
* @throws IllegalArgumentException
* when the URL parsed from the parameter would be malformed
*/
@Nonnull
public static URL url(@Nonnull final String url) {
try {
return new URL(url);
} catch (MalformedURLException e) {
final String message = "The wikipedia plugin tries to construct a malformed URL!";
Logging.log(Logging.LEVEL_ERROR, message, e);
throw new IllegalArgumentException(message, e);
}
}
}
// License: GPL. For details, see LICENSE file.
package org.wikipedia.api.wikidata_action;
import java.net.URL;
import java.util.Collection;
import javax.annotation.Nonnull;
import org.openstreetmap.josm.tools.Utils;
import org.wikipedia.api.ApiUrl;
import org.wikipedia.tools.RegexUtil;
public class WikidataActionApiUrl {
private static final String BASE_URL = "https://www.wikidata.org/w/api.php";
@Nonnull
public static URL checkEntityExistsUrl(@Nonnull final Collection<String> qIds) {
if (qIds.size() < 1) {
throw new IllegalArgumentException("You must supply at least one Q-ID to construct a checkEntityExists URL.");
}
if (!qIds.stream().allMatch(RegexUtil::isValidQId)) {
throw new IllegalArgumentException("You must supply only Q-IDs as argument to construct a checkEntityExists URL.");
}
return ApiUrl.url(
BASE_URL,
"?action=wbgetentities&format=json&sites=&props=&ids=",
Utils.encodeUrl(String.join("|", qIds))
);
}
}
// License: GPL. For details, see LICENSE file.
package org.wikipedia.tools;
import java.util.regex.Pattern;
public class RegexUtil {
private static final Pattern Q_ID_PATTERN = Pattern.compile("^Q[1-9][0-9]*$");
private RegexUtil() {
// Private constructor to avoid instantiation
}
public static boolean isValidQId(final String value) {
return value != null && Q_ID_PATTERN.matcher(value).matches();
}
}
// License: GPL. For details, see LICENSE file.
package org.wikipedia.api;
import static org.junit.Assert.assertEquals;
import java.net.MalformedURLException;
import java.net.URL;
import org.junit.Test;
public class ApiUrlTest {
@Test(expected = IllegalArgumentException.class)
public void testMalformedUrl() {
ApiUrl.url("malformedURL");
}
@Test(expected = IllegalArgumentException.class)
public void testMalformedMultipartUrl() {
ApiUrl.url("malformed", "Multipart", "U", "R", "L");
}
@Test
public void testUrl() throws MalformedURLException {
assertEquals(new URL("https://example.org"), ApiUrl.url("https://example.org"));
assertEquals(new URL("https://example.org/abc"), ApiUrl.url("https://example.org/", "abc"));
assertEquals(new URL("https://example.org/abc/def/ghi/jkl/mno"), ApiUrl.url("https://example.org/", "abc/", "def/", "ghi/", "jkl/", "mno"));
}
}
// License: GPL. For details, see LICENSE file.
package org.wikipedia.api.wikidata_action;
import static org.junit.Assert.assertEquals;
import java.util.Arrays;
import java.util.Collections;
import org.junit.Test;
public class WikidataActionApiUrlTest {
@Test(expected = IllegalArgumentException.class)
public void testCheckEntityExists_nonQId() {
WikidataActionApiUrl.checkEntityExistsUrl(Collections.singletonList("X1"));
}
@Test(expected = IllegalArgumentException.class)
public void testCheckEntityExists_nonQId2() {
WikidataActionApiUrl.checkEntityExistsUrl(Arrays.asList("Q1", "Q2", "X1"));
}
@Test(expected = IllegalArgumentException.class)
public void testCheckEntityExists_nullId() {
WikidataActionApiUrl.checkEntityExistsUrl(Arrays.asList("Q1", null, "Q3"));
}
@Test(expected = IllegalArgumentException.class)
public void testCheckEntityExists_emptyIdList() {
WikidataActionApiUrl.checkEntityExistsUrl(Collections.emptyList());
}
@Test
public void testCheckEntityExistsUrl() {
assertEquals(
"https://www.wikidata.org/w/api.php?action=wbgetentities&format=json&sites=&props=&ids=Q1",
WikidataActionApiUrl.checkEntityExistsUrl(Collections.singletonList("Q1")).toString()
);
assertEquals(
"https://www.wikidata.org/w/api.php?action=wbgetentities&format=json&sites=&props=&ids=Q1%7CQ42",
WikidataActionApiUrl.checkEntityExistsUrl(Arrays.asList("Q1", "Q42")).toString()
);
assertEquals(
"https://www.wikidata.org/w/api.php?action=wbgetentities&format=json&sites=&props=&ids=Q1%7CQ42%7CQ12345",
WikidataActionApiUrl.checkEntityExistsUrl(Arrays.asList("Q1", "Q42", "Q12345")).toString()
);
assertEquals(
"https://www.wikidata.org/w/api.php?action=wbgetentities&format=json&sites=&props=&ids=Q1%7CQ13%7CQ24%7CQ20150617%7CQ42%7CQ12345",
WikidataActionApiUrl.checkEntityExistsUrl(Arrays.asList("Q1", "Q13", "Q24", "Q20150617", "Q42", "Q12345")).toString()
);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment