...
 
Commits (14)
import com.github.spotbugs.SpotBugsTask
import net.ltgt.gradle.errorprone.javacplugin.CheckSeverity
import org.openstreetmap.josm.gradle.plugin.task.GeneratePluginList
import java.nio.file.Files
import java.nio.file.Paths
import java.time.Duration
import java.time.Instant
import org.openstreetmap.josm.gradle.plugin.task.GeneratePluginList
import com.github.spotbugs.SpotBugsTask
buildscript {
repositories {
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
classpath "net.ltgt.gradle:gradle-errorprone-javacplugin-plugin:0.3"
classpath "net.ltgt.gradle:gradle-errorprone-plugin:0.0.16"
}
}
plugins {
id "java"
......@@ -25,26 +15,32 @@ plugins {
id "com.github.ben-manes.versions" version "0.20.0"
id "com.github.spotbugs" version "1.6.2"
id "org.openstreetmap.josm" version "0.5.0"
id "net.ltgt.errorprone" version "0.0.16" apply(false)
id "net.ltgt.errorprone-javacplugin" version "0.3" apply(false)
}
// Set up Errorprone
def errorproneChecks = [
"DefaultCharset": CheckSeverity.ERROR,
"StringEquality": CheckSeverity.ERROR,
"ConstantField": CheckSeverity.WARN,
"FieldCanBeFinal": CheckSeverity.WARN,
"LambdaFunctionalInterface": CheckSeverity.WARN,
"MethodCanBeStatic": CheckSeverity.WARN,
"MultiVariableDeclaration": CheckSeverity.WARN,
"PrivateConstructorForUtilityClass": CheckSeverity.WARN,
"UngroupedOverloads": CheckSeverity.WARN,
"WildcardImport": CheckSeverity.WARN
]
if (JavaVersion.current().java9Compatible) {
apply plugin: "net.ltgt.errorprone-javacplugin"
// TODO: add the errorprone checks
} else {
apply plugin: "net.ltgt.errorprone"
tasks.withType(JavaCompile) {
options.compilerArgs += [
"-Xep:DefaultCharset:ERROR",
"-Xep:StringEquality:ERROR",
"-Xep:ConstantField:WARN",
"-Xep:FieldCanBeFinal:WARN",
"-Xep:LambdaFunctionalInterface:WARN",
"-Xep:MethodCanBeStatic:WARN",
"-Xep:MultiVariableDeclaration:WARN",
"-Xep:PrivateConstructorForUtilityClass:WARN",
"-Xep:RemoveUnusedImports:WARN",
"-Xep:UngroupedOverloads:WARN",
"-Xep:WildcardImport:WARN"
]
errorproneChecks.forEach { name, severity ->
options.compilerArgs.add("-Xep:$name:$severity")
}
}
}
......@@ -60,7 +56,6 @@ repositories {
jcenter()
}
dependencies {
packIntoJar("com.fasterxml.jackson.core:jackson-databind:2.9.5")
errorprone("com.google.errorprone:error_prone_core:${versions.errorprone}")
testImplementation("org.junit.jupiter:junit-jupiter-api:${versions.junit}")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${versions.junit}")
......@@ -70,11 +65,13 @@ dependencies {
testImplementation("com.github.tomakehurst:wiremock:2.18.0")
testImplementation("org.awaitility:awaitility:3.1.2")
}
task copyToLib(type: Sync) {
from(configurations.packIntoJar)
into(file("$projectDir/lib"))
def ivyModule = new XmlParser().parse(new File("$projectDir/ivy.xml"))
logger.info("Dependencies from ivy.xml (added to configuration `packIntoJar`):")
ivyModule.dependencies.dependency.each {
logger.info("* ${it.@org}:${it.@name}:${it.@rev}")
project.dependencies.packIntoJar("${it.@org}:${it.@name}:${it.@rev}")
}
classes.dependsOn(copyToLib)
test {
useJUnitPlatform()
......
<?xml version="1.0" encoding="utf-8"?>
<project name="wikipedia" default="dist" basedir=".">
<project xmlns:ivy="antlib:org.apache.ivy.ant" name="wikipedia" default="dist" basedir=".">
<property name="plugin.src.dir" value="src/main/java"/>
<!-- edit the properties of this plugin in the file `gradle.properties` -->
......@@ -22,4 +22,24 @@
</fileset>
</copy>
</target>
<property name="ivy.home" value="${user.home}/.ant"/>
<property name="ivy.jar.dir" value="${ivy.home}/lib"/>
<property name="ivy.jar.file" value="${ivy.jar.dir}/ivy.jar"/>
<target name="download-ivy">
<mkdir dir="${ivy.jar.dir}"/>
<get src="https://jcenter.bintray.com/org/apache/ivy/ivy/2.4.0/ivy-2.4.0.jar" dest="${ivy.jar.file}" usetimestamp="true"/>
</target>
<target name="init-ivy" depends="download-ivy">
<path id="ivy.lib.path">
<fileset dir="${ivy.jar.dir}" includes="*.jar"/>
</path>
<taskdef resource="org/apache/ivy/ant/antlib.xml" uri="antlib:org.apache.ivy.ant" classpathref="ivy.lib.path"/>
</target>
<target name="pre-compile" description="retrieve dependencies with Ivy" depends="init-ivy">
<ivy:retrieve/>
</target>
</project>
<ivy-module version="2.0">
<info organisation="org.openstreetmap.josm.plugins" module="wikipedia"/>
<dependencies>
<dependency org="com.fasterxml.jackson.core" name="jackson-databind" rev="2.9.6"/>
<dependency org="org.wikidata.wdtk" name="wdtk-wikibaseapi" rev="0.9.0"/>
<dependency org="org.wikidata.wdtk" name="wdtk-dumpfiles" rev="0.9.0"/>
</dependencies>
</ivy-module>
......@@ -10,7 +10,7 @@ public final class Caches {
public static final CacheAccess<String, String> API_RESPONSES = JCSCacheManager.getCache(
"api",
1,
1_000,
10_000,
new File(Config.getDirs().getCacheDirectory(false), "plugin/wikipedia").getAbsolutePath()
);
......
......@@ -13,9 +13,13 @@ import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.actions.JosmAction;
import org.openstreetmap.josm.data.osm.DataSet;
import org.openstreetmap.josm.data.osm.OsmPrimitive;
import org.openstreetmap.josm.gui.Notification;
import org.openstreetmap.josm.io.remotecontrol.AddTagsDialog;
import org.openstreetmap.josm.tools.I18n;
import org.openstreetmap.josm.tools.ImageProvider;
import org.openstreetmap.josm.tools.Logging;
import org.wikipedia.WikipediaApp;
import org.wikipedia.WikipediaPlugin;
import org.wikipedia.data.WikipediaEntry;
public class WikipediaAddNamesAction extends JosmAction {
......@@ -29,15 +33,21 @@ public class WikipediaAddNamesAction extends JosmAction {
@Override
public void actionPerformed(ActionEvent e) {
final WikipediaEntry wp = WikipediaEntry.parseTag("wikipedia", getWikipediaValue());
List<String[]> tags = new ArrayList<>();
WikipediaApp.forLanguage(wp.lang).getInterwikiArticles(wp.article).stream()
if (wp == null) {
new Notification(I18n.tr("Could not add names. Wikipedia tag is not recognized!"))
.setIcon(WikipediaPlugin.W_IMAGE.setMaxSize(ImageProvider.ImageSizes.LARGEICON).get())
.show();
} else {
List<String[]> tags = new ArrayList<>();
WikipediaApp.forLanguage(wp.lang).getInterwikiArticles(wp.article).stream()
.filter(this::useWikipediaLangArticle)
.map(i -> new String[]{"name:" + i.lang, i.article})
.forEach(tags::add);
if (Logging.isDebugEnabled()) {
Logging.debug(tags.toString());
if (Logging.isDebugEnabled()) {
Logging.debug(tags.toString());
}
AddTagsDialog.addTags(tags.toArray(new String[tags.size()][]), "Wikipedia", getLayerManager().getEditDataSet().getSelected());
}
AddTagsDialog.addTags(tags.toArray(new String[tags.size()][]), "Wikipedia", getLayerManager().getEditDataSet().getSelected());
}
private boolean useWikipediaLangArticle(WikipediaEntry i) {
......
......@@ -3,10 +3,6 @@ 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 org.openstreetmap.josm.tools.Logging;
public class ApiUrl {
......@@ -14,28 +10,6 @@ public class 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
*/
public static URL url(final String part1, final String part2, 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.
......@@ -51,7 +25,7 @@ public class ApiUrl {
try {
return new URL(url);
} catch (MalformedURLException e) {
final String message = "The wikipedia plugin tries to construct a malformed URL!";
final String message = String.format("The wikipedia plugin tries to construct a malformed URL!: %s", url);
Logging.log(Logging.LEVEL_ERROR, message, e);
throw new IllegalArgumentException(message, e);
}
......
......@@ -3,19 +3,26 @@ package org.wikipedia.api.wikidata_action;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import org.openstreetmap.josm.tools.HttpClient;
import org.openstreetmap.josm.tools.Utils;
import org.wikipedia.api.ApiQuery;
import org.wikipedia.api.ApiUrl;
import org.wikipedia.api.SerializationSchema;
import org.wikipedia.api.wikidata_action.json.QueryResult;
import org.wikipedia.api.wikidata_action.json.SitematrixResult;
import org.wikipedia.api.wikidata_action.json.WbgetclaimsResult;
import org.wikipedia.api.wikidata_action.json.WbgetentitiesResult;
import org.wikipedia.tools.RegexUtil;
/**
* Utility class for getting queries against the Wikidata Action API
* @param <T> the type which is returned as a result of the query
*/
public final class WikidataActionApiQuery<T> extends ApiQuery<T> {
static URL defaultUrl = ApiUrl.url("https://www.wikidata.org/w/api.php");
private static final String FORMAT_PARAMS = "format=json&utf8=1&formatversion=1";
......@@ -23,29 +30,60 @@ public final class WikidataActionApiQuery<T> extends ApiQuery<T> {
private final String queryString;
private WikidataActionApiQuery(final String query, final SerializationSchema<T> schema, final long cacheExpiryTime) {
super(defaultUrl, schema, cacheExpiryTime);
this.queryString = query;
/**
* Convenience constructor
* @see #WikidataActionApiQuery(String, SerializationSchema, long, Function)
*/
private WikidataActionApiQuery(final String queryString, final SerializationSchema<T> schema) {
this(queryString, schema, -1, it -> it);
}
private WikidataActionApiQuery(final String query, final SerializationSchema<T> schema) {
this(query, schema, -1);
/**
* Convenience constructor
* @see #WikidataActionApiQuery(String, SerializationSchema, long, Function)
*/
private <S> WikidataActionApiQuery(final String queryString, final SerializationSchema<S> schema, final Function<S, T> converter) {
this(queryString, schema, -1, converter);
}
private <S> WikidataActionApiQuery(final String queryString, final SerializationSchema<S> schema, final Function<S, T> converter) {
super(defaultUrl, schema, -1, converter);
/**
* A query against the Wikidata Action API
* @param queryString the query string containing the arguments of this query
* @param schema the {@link SerializationSchema} that defines how deserialization of the response is handled
* @param cacheExpiryTime the number of milliseconds for which the response will stay in the cache
* @param converter a function that maps the
* @param <S> the type to which the {@link SerializationSchema} deserializes
*/
private <S> WikidataActionApiQuery(final String queryString, final SerializationSchema<S> schema, final long cacheExpiryTime, final Function<S, T> converter) {
super(defaultUrl, schema, cacheExpiryTime, converter);
this.queryString = queryString;
}
public String getQueryString() {
String getQueryString() {
return queryString;
}
public static WikidataActionApiQuery<SitematrixResult> sitematrix() {
/**
* @return a query for all wikimedia sites
*/
public static WikidataActionApiQuery<SitematrixResult.Sitematrix> sitematrix() {
return new WikidataActionApiQuery<>(
FORMAT_PARAMS + "&action=sitematrix",
SitematrixResult.SCHEMA,
2_592_000_000L // = 1000*60*60*24*30 = number of ms in 30 days
TimeUnit.DAYS.toMillis(30),
SitematrixResult::getSitematrix
);
}
/**
* @return a query for all languages that are used in Wikidata (e.g. for labels)
*/
public static WikidataActionApiQuery<Map<String, String>> queryLanguages() {
return new WikidataActionApiQuery<>(
FORMAT_PARAMS + "&action=query&meta=siteinfo&siprop=languages",
QueryResult.SCHEMA,
TimeUnit.DAYS.toMillis(30),
QueryResult::getLangMap
);
}
......@@ -77,24 +115,40 @@ public final class WikidataActionApiQuery<T> extends ApiQuery<T> {
);
}
public static WikidataActionApiQuery<Map<String, String>> wbgetentitiesLabels(final String qId) {
public static WikidataActionApiQuery<Map<String, WbgetentitiesResult.Entity.Label>> wbgetentitiesLabels(final String qId) {
if (!RegexUtil.isValidQId(qId)) {
throw new IllegalArgumentException("Invalid Q-ID: " + qId);
}
return new WikidataActionApiQuery<>(
FORMAT_PARAMS + "&action=wbgetentities&props=labels&ids=" + qId,
WbgetentitiesResult.SCHEMA,
TimeUnit.MINUTES.toMillis(10),
result -> result.getEntities().values().stream().findFirst().map(WbgetentitiesResult.Entity::getLabels).orElse(new HashMap<>())
);
}
public static WikidataActionApiQuery<WbgetclaimsResult> wbgetclaims(final String qId) {
public static WikidataActionApiQuery<Collection<WbgetentitiesResult.Entity.Sitelink>> wbgetentitiesSitelinks(final String qId) {
RegexUtil.requireValidQId(qId);
return new WikidataActionApiQuery<>(
FORMAT_PARAMS + "&action=wbgetentities&props=sitelinks&ids=" + qId,
WbgetentitiesResult.SCHEMA,
TimeUnit.MINUTES.toMillis(10),
result -> result.getEntities().values().stream()
.findFirst()
.map(WbgetentitiesResult.Entity::getSitelinks)
.orElse(Collections.emptyList())
);
}
public static WikidataActionApiQuery<Collection<WbgetclaimsResult.Claim>> wbgetclaims(final String qId) {
if (!RegexUtil.isValidQId(qId)) {
throw new IllegalArgumentException("Invalid Q-ID: " + qId);
}
return new WikidataActionApiQuery<>(
FORMAT_PARAMS + "&action=wbgetclaims&props=&entity=" + qId,
WbgetclaimsResult.SCHEMA
WbgetclaimsResult.SCHEMA,
TimeUnit.MINUTES.toMillis(10),
WbgetclaimsResult::getClaims
);
}
......
package org.wikipedia.api.wikidata_action.json;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.DeserializationFeature;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.wikipedia.api.SerializationSchema;
public final class QueryResult {
public static final SerializationSchema<QueryResult> SCHEMA = new SerializationSchema<>(
QueryResult.class,
mapper -> mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
);
private final Query query;
@JsonCreator
public QueryResult(@JsonProperty("query") final Query query) {
this.query = query;
}
private static class Query {
private final List<Language> languages;
@JsonCreator
Query(@JsonProperty("languages") final Collection<Language> languages) {
this.languages = new ArrayList<>(languages);
}
private static class Language implements Comparable<Language> {
private final String code;
private final String name;
@JsonCreator
Language(@JsonProperty("code") final String code, @JsonProperty("*") final String name) {
this.code = code;
this.name = name;
}
@Override
public int compareTo(Language other) {
return this.code.compareTo(other.code);
}
}
}
public Map<String, String> getLangMap() {
return query.languages.stream().collect(Collectors.toMap(it -> it.code, it -> it.name));
}
}
......@@ -17,6 +17,9 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Stream;
import org.wikipedia.api.SerializationSchema;
import org.wikipedia.tools.RegexUtil;
......@@ -36,7 +39,7 @@ public final class SitematrixResult {
@JsonCreator
public SitematrixResult(@JsonProperty("sitematrix") final Sitematrix sitematrix) {
this.sitematrix = sitematrix;
this.sitematrix = Objects.requireNonNull(sitematrix);
}
public Sitematrix getSitematrix() {
......@@ -59,6 +62,12 @@ public final class SitematrixResult {
return Collections.unmodifiableCollection(specialSites);
}
public Optional<Site> getSiteForDbname(final String dbname) {
return Stream.concat(languages.stream().flatMap(it -> it.getSites().stream()), specialSites.stream())
.filter(it -> dbname != null && dbname.equals(it.getDbName()))
.findFirst();
}
public static class Deserializer extends StdDeserializer<Sitematrix> {
private final ObjectMapper mapper;
public Deserializer(final ObjectMapper mapper) {
......@@ -102,6 +111,7 @@ public final class SitematrixResult {
this.name = name;
if (sites != null) {
this.sites.addAll(sites);
this.sites.forEach(it -> it.language = this);
}
}
......@@ -124,18 +134,22 @@ public final class SitematrixResult {
private final boolean closed;
private final String code;
private final String dbName;
private final String siteName;
private final String url;
private Language language;
@JsonCreator
public Site(
@JsonProperty("url") final String url,
@JsonProperty("dbname") final String dbName,
@JsonProperty("code") final String code,
@JsonProperty("closed") final String closed
@JsonProperty("closed") final String closed,
@JsonProperty("sitename") final String siteName
) {
this.closed = closed != null;
this.code = code;
this.dbName = dbName;
this.siteName = siteName;
this.url = url;
}
......@@ -154,6 +168,14 @@ public final class SitematrixResult {
return dbName;
}
public Language getLanguage() {
return language;
}
public String getSiteName() {
return siteName;
}
public String getUrl() {
return url;
}
......
......@@ -122,9 +122,9 @@ public final class WbgetclaimsResult {
return property;
}
static interface DataValue {
public interface DataValue {
static class Deserializer extends CustomDeserializer<DataValue> {
class Deserializer extends CustomDeserializer<DataValue> {
Deserializer(ObjectMapper mapper) {
super(mapper);
}
......@@ -139,6 +139,7 @@ public final class WbgetclaimsResult {
case "quantity": return mapper.treeToValue(nodeValue, QuantityValue.class);
case "globecoordinate": return mapper.treeToValue(nodeValue, GlobecoordinateValue.class);
case "time": return mapper.treeToValue(nodeValue, TimeValue.class);
case "monolingualtext": return mapper.treeToValue(nodeValue, MonolingualTextValue.class);
default:
Logging.warn("Unknown type: " + type.textValue());
}
......@@ -150,7 +151,7 @@ public final class WbgetclaimsResult {
static class GlobecoordinateValue implements DataValue {
private final double latitude;
private final double longitude;
private final double altitude;
private final Double altitude;
private final double precision;
private final String globe;
......@@ -158,7 +159,7 @@ public final class WbgetclaimsResult {
GlobecoordinateValue(
@JsonProperty("latitude") final double latitude,
@JsonProperty("longitude") final double longitude,
@JsonProperty("altitude") final double altitude,
@JsonProperty("altitude") final Double altitude,
@JsonProperty("precision") final double precision,
@JsonProperty("globe") final String globe
) {
......@@ -169,9 +170,14 @@ public final class WbgetclaimsResult {
this.globe = globe;
}
public LatLon toLatLon() {
private LatLon toLatLon() {
return new LatLon(latitude, longitude);
}
@Override
public String toString() {
return toLatLon().toDisplayString();
}
}
static class TimeValue implements DataValue {
......@@ -199,6 +205,11 @@ public final class WbgetclaimsResult {
this.precision = precision;
this.calendarModel = calendarModel;
}
@Override
public String toString() {
return time;
}
}
static class QuantityValue implements DataValue {
......@@ -219,6 +230,11 @@ public final class WbgetclaimsResult {
this.lowerBound = lowerBound;
this.upperBound = upperBound;
}
@Override
public String toString() {
return amount + " " + unit;
}
}
static class ItemValue implements DataValue {
......@@ -230,13 +246,39 @@ public final class WbgetclaimsResult {
this.entityType = entityType;
this.id = id;
}
@Override
public String toString() {
return id + " (" + entityType + ")";
}
}
static class StringValue implements DataValue {
private final String value;
StringValue(String value) {
StringValue(final String value) {
this.value = value;
}
@Override
public String toString() {
return value;
}
}
static class MonolingualTextValue implements DataValue {
private final String langCode;
private final String text;
@JsonCreator
MonolingualTextValue(@JsonProperty("language") final String langCode, @JsonProperty("text") final String text) {
this.langCode = langCode;
this.text = text;
}
@Override
public String toString() {
return text + " (" + langCode + ")";
}
}
}
......
......@@ -136,7 +136,7 @@ public final class WbgetentitiesResult {
private final String id;
private final String type;
private final Map<String, Sitelink> sitelinks = new HashMap<>();
private final Map<String, String> labels = new HashMap<>();
private final Map<String, Label> labels = new HashMap<>();
@JsonCreator
public Entity(
......@@ -151,7 +151,7 @@ public final class WbgetentitiesResult {
this.sitelinks.putAll(sitelinks);
}
if (labels != null) {
labels.values().forEach(label -> this.labels.put(label.getLanguage(), label.getValue()));
labels.values().forEach(label -> this.labels.put(label.getLangCode(), label));
}
}
......@@ -163,7 +163,7 @@ public final class WbgetentitiesResult {
return type;
}
public Map<String, String> getLabels() {
public Map<String, Label> getLabels() {
return Collections.unmodifiableMap(labels);
}
......@@ -186,7 +186,7 @@ public final class WbgetentitiesResult {
this.value = value;
}
public String getLanguage() {
public String getLangCode() {
return language;
}
......
......@@ -20,7 +20,7 @@ public class WikipediaActionApiQuery<T> extends ApiQuery<T> {
private final String queryString;
private WikipediaActionApiQuery(final IWikipediaSite site, final String queryString, SerializationSchema<T> schema) {
super(ApiUrl.url(site.getSite().getUrl(), "/w/api.php"), schema);
super(ApiUrl.url(site.getSite().getUrl() + "/w/api.php"), schema);
this.queryString = Objects.requireNonNull(queryString);
}
......
......@@ -24,8 +24,8 @@ public class WikipediaSite implements IWikipediaSite {
*/
public WikipediaSite(final String langCode) throws IOException, IllegalArgumentException {
Objects.requireNonNull(langCode);
final SitematrixResult sitematrix = ApiQueryClient.query(WikidataActionApiQuery.sitematrix());
language = sitematrix.getSitematrix().getLanguages().stream()
final SitematrixResult.Sitematrix sitematrix = ApiQueryClient.query(WikidataActionApiQuery.sitematrix());
language = sitematrix.getLanguages().stream()
.filter(it -> langCode.equals(it.getCode()))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException(I18n.tr("''{0}'' is an illegal language code!", langCode)));
......
package org.wikipedia.gui;
import java.awt.BorderLayout;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
public class ProgressJPanel extends JPanel {
private final JProgressBar PROGRESS_BAR = new JProgressBar();
ProgressJPanel() {
setLayout(new BorderLayout());
PROGRESS_BAR.setStringPainted(true);
}
protected synchronized void showProgress(final String message) {
if (!isAncestorOf(PROGRESS_BAR)) {
add(PROGRESS_BAR, BorderLayout.NORTH);
}
PROGRESS_BAR.setIndeterminate(true);
PROGRESS_BAR.setString(message);
revalidate();
repaint();
}
protected synchronized void hideProgress() {
remove(PROGRESS_BAR);
revalidate();
repaint();
}
}
package org.wikipedia.gui;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import org.openstreetmap.josm.gui.Notification;
import org.openstreetmap.josm.tools.I18n;
import org.wikipedia.WikipediaPlugin;
import org.wikipedia.api.ApiQueryClient;
import org.wikipedia.api.wikidata_action.WikidataActionApiQuery;
import org.wikipedia.api.wikidata_action.json.WbgetclaimsResult;
class WikidataInfoClaimPanel extends ProgressJPanel {
private final JPanel mainPanel;
private String qIdBeingDownloaded;
WikidataInfoClaimPanel() {
super();
this.mainPanel = new JPanel();
add(new JScrollPane(mainPanel), BorderLayout.CENTER);
}
void downloadStatementsFor(final String qId) {
this.qIdBeingDownloaded = qId;
new Thread(() -> {
try {
mainPanel.removeAll();
showProgress(I18n.tr("Download statements for {0}…", qId));
final Collection<WbgetclaimsResult.Claim> result = ApiQueryClient.query(WikidataActionApiQuery.wbgetclaims(qId));
if (qIdBeingDownloaded != null && qIdBeingDownloaded.equals(qId)) {
synchronized (mainPanel) {
mainPanel.removeAll();
mainPanel.setLayout(new GridLayout(result.size(), 1));
result.forEach(claim -> {
final WbgetclaimsResult.Claim.MainSnak.DataValue value = claim.getMainSnak().getDataValue(); // nullable
mainPanel.add(new StatementPanel(claim.getMainSnak().getProperty(), value == null ? I18n.tr("Unknown datatype!") : value.toString()));
});
hideProgress();
}
}
} catch (IOException e) {
new Notification(I18n.tr("Failed to download statements for Wikidata item {0}!", qId))
.setIcon(WikipediaPlugin.W_IMAGE.get())
.show();
}
hideProgress();
}).start();
}
}
package org.wikipedia.gui;
import java.awt.BorderLayout;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import org.openstreetmap.josm.gui.Notification;
import org.openstreetmap.josm.tools.I18n;
import org.openstreetmap.josm.tools.Logging;
import org.openstreetmap.josm.tools.Pair;
import org.wikipedia.WikipediaPlugin;
import org.wikipedia.api.ApiQueryClient;
import org.wikipedia.api.wikidata_action.WikidataActionApiQuery;
import org.wikipedia.api.wikidata_action.json.WbgetentitiesResult;
/**
* Panel displaying the labels for a Wikidata item
*/
class WikidataInfoLabelPanel extends ProgressJPanel {
private final LabelTableModel tableModel = new LabelTableModel(this);
private final JTable table = new JTable(tableModel);
WikidataInfoLabelPanel() {
add(new JScrollPane(table), BorderLayout.CENTER);
}
void downloadLabelsFor(final String qId) {
tableModel.downloadLabelsFor(qId);
}
private static class LabelTableModel extends AbstractTableModel {
private final WikidataInfoLabelPanel parent;
private String qIdBeingDownloaded;
private final List<Pair<WbgetentitiesResult.Entity.Label, String>> valueMap = new ArrayList<>();
LabelTableModel(final WikidataInfoLabelPanel parent) {
this.parent = parent;
}
void downloadLabelsFor(final String qId) {
qIdBeingDownloaded = qId;
new Thread(() -> {
try {
parent.showProgress(I18n.tr("Download labels for {0}…", qId));
valueMap.clear();
parent.table.revalidate();
parent.revalidate();
parent.repaint();
final Map<String, WbgetentitiesResult.Entity.Label> newValues = ApiQueryClient.query(WikidataActionApiQuery.wbgetentitiesLabels(qId));
final Map<String, String> languages = new HashMap<>();
try {
languages.putAll(ApiQueryClient.query(WikidataActionApiQuery.queryLanguages()));
} catch (IOException e) {
Logging.warn("Could not download language names! Only the language codes are displayed.", e);
}
synchronized (valueMap) {
if (qIdBeingDownloaded != null && qIdBeingDownloaded.equals(qId)) {
valueMap.clear();
valueMap.addAll(
newValues.values().stream()
.map(it -> Pair.create(it, languages.containsKey(it.getLangCode()) ? languages.get(it.getLangCode()) : it.getLangCode()))
.sorted(Comparator.comparing(it -> it.a.getLangCode()))
.collect(Collectors.toList())
);
parent.table.revalidate();
}
}
} catch (IOException e) {
new Notification(I18n.tr("Failed to download labels for {0}!", qId)).setIcon(WikipediaPlugin.W_IMAGE.get()).show();
}
parent.hideProgress();
}).start();
}
@Override
public int getRowCount() {
return valueMap.size();
}
@Override
public int getColumnCount() {
return 3;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
switch (columnIndex) {
case 0: return valueMap.get(rowIndex).a.getLangCode();
case 1: return valueMap.get(rowIndex).b;
case 2:
default: return valueMap.get(rowIndex).a.getValue();
}
}
@Override
public String getColumnName(int column) {
switch (column) {
case 0: return I18n.tr("language code");
case 1: return I18n.tr("language");
case 2:
default: return I18n.tr("label");
}
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return columnIndex == 3;
}
}
}
package org.wikipedia.gui;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.Collection;
import java.util.Comparator;
import java.util.Optional;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import org.openstreetmap.josm.gui.Notification;
import org.openstreetmap.josm.tools.GBC;
import org.openstreetmap.josm.tools.I18n;
import org.openstreetmap.josm.tools.Logging;
import org.openstreetmap.josm.tools.OpenBrowser;
import org.wikipedia.WikipediaPlugin;
import org.wikipedia.api.ApiQueryClient;
import org.wikipedia.api.wikidata_action.WikidataActionApiQuery;
import org.wikipedia.api.wikidata_action.json.SitematrixResult;
import org.wikipedia.api.wikidata_action.json.WbgetentitiesResult;
import org.wikipedia.data.WikipediaSite;
public class WikidataInfoSitelinkPanel extends ProgressJPanel {
private final JPanel mainPanel;
private String qIdBeingDownloaded;
WikidataInfoSitelinkPanel() {
this.mainPanel = new JPanel();
this.mainPanel.setLayout(new GridBagLayout());
add(new JScrollPane(mainPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER), BorderLayout.CENTER);
}
void downloadSitelinksFor(final String qId) {
this.qIdBeingDownloaded = qId;
new Thread(() -> {
try {
mainPanel.removeAll();
showProgress(I18n.tr("Download sitelinks for {0}…", qId));
final Collection<WbgetentitiesResult.Entity.Sitelink> sitelinks =
ApiQueryClient.query(WikidataActionApiQuery.wbgetentitiesSitelinks(qId));
final SitematrixResult.Sitematrix sitematrix = ApiQueryClient.query(WikidataActionApiQuery.sitematrix());
if (qIdBeingDownloaded != null && qIdBeingDownloaded.equals(qId)) {
synchronized (mainPanel) {
mainPanel.removeAll();
final GBC gbc = GBC.std().fill().grid(0, 0);
sitelinks.stream()
.sorted(Comparator.comparing(WbgetentitiesResult.Entity.Sitelink::getSite))
.forEach(sitelink -> {
final Optional<SitematrixResult.Sitematrix.Site> site = sitematrix.getSiteForDbname(sitelink.getSite());
if (!site.isPresent()) {
Logging.warn("Could not find site {0} for sitelink {1}!", sitelink.getSite(), sitelink.getTitle());
}
site.ifPresent(s -> {
final JButton linkButton = new JButton();
linkButton.setAction(new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
final String uri = s.getUrl() + "/w/index.php?title=" + URLEncoder.encode(sitelink.getTitle());
final String error = OpenBrowser.displayUrl(uri);
if (error != null) {
new Notification(I18n.tr("Can't open website {0} in browser! Error message: {1}", uri, error))
.setIcon(WikipediaPlugin.W_IMAGE.get())
.show();
}
}
});
linkButton.setText(
s.getDbName() + ": " + s.getSiteName() + (s.getLanguage() == null ? "" : " " + s.getLanguage().getName())
);
mainPanel.add(linkButton, gbc);
gbc.gridy++;
});
});
hideProgress();
}
}
} catch (IOException e) {
new Notification(I18n.tr("Failed to download sitelinks for Wikidata item {0}!", qId))
.setIcon(WikipediaPlugin.W_IMAGE.get())
.show();
}
hideProgress();
}).start();
}
}
......@@ -5,10 +5,7 @@ import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.util.Collections;
import java.util.Map;
......@@ -20,7 +17,6 @@ import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import org.openstreetmap.josm.data.osm.DataSelectionListener;
import org.openstreetmap.josm.data.osm.DataSet;
......@@ -30,7 +26,6 @@ import org.openstreetmap.josm.data.osm.event.DataSetListenerAdapter;
import org.openstreetmap.josm.gui.MainApplication;
import org.openstreetmap.josm.gui.Notification;
import org.openstreetmap.josm.gui.dialogs.ToggleDialog;
import org.openstreetmap.josm.tools.GBC;
import org.openstreetmap.josm.tools.I18n;
import org.openstreetmap.josm.tools.OpenBrowser;
import org.wikipedia.WikipediaPlugin;
......@@ -38,6 +33,9 @@ import org.wikipedia.data.WikidataEntry;
import org.wikipedia.data.WikipediaEntry;
import org.wikipedia.tools.OsmPrimitiveUtil;
/**
* Toggle dialog that displays infos about the currently selected Wikidata item.
*/
public class WikidataInfoToggleDialog extends ToggleDialog {
private static final Logger L = Logger.getLogger(WikidataInfoToggleDialog.class.getName());
private static final String EMPTY_STRING = "";
......@@ -55,17 +53,17 @@ public class WikidataInfoToggleDialog extends ToggleDialog {
private final JPanel infoPanel = new JPanel(new BorderLayout());
private final JTabbedPane tabs = new JTabbedPane();
private final JPanel labelTab = new JPanel();
private final JPanel statementTab = new JPanel();
private final JPanel linkTab = new JPanel();
private final JButton webLinkButton = new JButton();
private final WikidataInfoLabelPanel labelTab = new WikidataInfoLabelPanel();
private final WikidataInfoClaimPanel statementTab = new WikidataInfoClaimPanel();
private final WikidataInfoSitelinkPanel linkTab = new WikidataInfoSitelinkPanel();
private final DataSelectionListener selectionListener = it -> updateSelection();
private final DataSelectionListener selectionListener = it -> updateDisplayedItem();
private final DataSetListener datasetListener = new DataSetListenerAdapter(it -> {
if (it.getType() == AbstractDatasetChangedEvent.DatasetEventType.TAGS_CHANGED) {
updateSelection();
updateDisplayedItem();
}
});
private String displayedItem;
public WikidataInfoToggleDialog(final WikipediaToggleDialog wikiDialog) {
super(
......@@ -97,35 +95,13 @@ public class WikidataInfoToggleDialog extends ToggleDialog {
infoPanel.add(basicInfoPanel, BorderLayout.NORTH);
infoPanel.add(tabs, BorderLayout.CENTER);
// Set up statement tab
statementTab.setLayout(new GridBagLayout());
final GridBagConstraints constraints = new GridBagConstraints();
constraints.anchor = GridBagConstraints.NORTH;
constraints.gridx = 0;
constraints.gridy = 0;
constraints.insets = new Insets(1, 1, 1, 1);
constraints.fill = GridBagConstraints.BOTH;
// At the moment only dummy content
constraints.weightx = 1;
statementTab.add(new StatementPanel("instance of", "example", "dummy content"), constraints);
constraints.gridy++;
statementTab.add(new StatementPanel("start date", "42"), constraints);
constraints.gridy++;
statementTab.add(new StatementPanel("architect", "John Doe"), constraints);
constraints.gridy++;
constraints.weighty = 1;
statementTab.add(GBC.glue(0, 0), constraints);
linkTab.add(webLinkButton);
tabs.add(I18n.tr("Statements"), statementTab);
tabs.add(I18n.tr("Labels"), labelTab);
tabs.add(I18n.tr("Links"), linkTab);
// Set up listeners
this.wikiDialog.list.addListSelectionListener(event -> updateSelection());
this.wikiDialog.list.addListSelectionListener(event -> updateDisplayedItem());
MainApplication.getLayerManager().addAndFireActiveLayerChangeListener(event -> {
System.out.println("Fire active layer change");
final DataSet previous = event.getPreviousDataSet();
final DataSet current = event.getSource().getActiveDataSet();
if (previous != null) {
......@@ -137,7 +113,7 @@ public class WikidataInfoToggleDialog extends ToggleDialog {
current.addDataSetListener(datasetListener);
}
});
updateSelection();
updateDisplayedItem();
}
/**
......@@ -152,8 +128,10 @@ public class WikidataInfoToggleDialog extends ToggleDialog {
* Whenever it is possible that the content of the info panel should be updated, call this method.
* It checks for the currently selected items in the active dataset and in the Wikidata list. The panel is updated.
*/
private void updateSelection() {
mainPanel.removeAll();
private void updateDisplayedItem() {
if (!isShowing()) {
return;
}
final DataSet dataset = MainApplication.getLayerManager().getActiveDataSet();
final Map<String, Integer> wdTagsInDataset =
dataset == null
......@@ -164,43 +142,67 @@ public class WikidataInfoToggleDialog extends ToggleDialog {
.map(Optional::get)
.collect(Collectors.groupingBy(it -> it, Collectors.summingInt(it -> 1)));
if (wdTagsInDataset.isEmpty()) {
// No OSM objects with valid wikidata=* tags are selected
final WikipediaEntry entry = this.wikiDialog.list.getSelectedValue();
if (entry instanceof WikidataEntry) {
setTitle(entry.article);
nameLabel.setText(((WikidataEntry) entry).label);
descriptionLabel.setText(((WikidataEntry) entry).description);
qidLabel.setText(entry.article);
mainPanel.add(new JScrollPane(infoPanel));
displayItem(entry.article, ((WikidataEntry) entry).label, ((WikidataEntry) entry).description);
} else {
setTitle(null);
messageLabel.setText(I18n.tr("No Wikidata item is selected!"));
mainPanel.add(messagePanel);
displayMessage(null, I18n.tr("No Wikidata item is selected!"));
}
} else if (wdTagsInDataset.size() >= 2) {
final String itemList = wdTagsInDataset.entrySet().stream().map(it -> it.getKey() + " (" + it.getValue() + "×)").collect(Collectors.joining(", "));
setTitle(itemList);
messageLabel.setText(I18n.tr("More than one OSM object is selected: {0}", itemList));
mainPanel.add(messagePanel);
// More than one OSM object with valid wikidata=* tag is selected
final String itemList = wdTagsInDataset.entrySet().stream()
.map(it -> it.getKey() + " (" + it.getValue() + "×)")
.collect(Collectors.joining(", "));
displayMessage(itemList, I18n.tr("More than one OSM object is selected: {0}", itemList));
} else { // size == 1
// An OSM object or multiple OSM objects with exactly one valid wikidata=* tag (multiple tags with same value count as one)
final String qId = wdTagsInDataset.keySet().iterator().next();
displayItem(qId, EMPTY_STRING, EMPTY_STRING);
}
}
private synchronized void displayItem(final String qId, final String label, final String description) {
if (qId != null && !qId.equals(getDisplayedItem())) {
mainPanel.removeAll();
setTitle(qId);
nameLabel.setText(EMPTY_STRING);
descriptionLabel.setText(EMPTY_STRING);
qidLabel.setText(qId);
mainPanel.add(new JScrollPane(infoPanel));
webLinkButton.setAction(new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
final String uri = "https://www.wikidata.org/wiki/" + qId;
final String error = OpenBrowser.displayUrl(uri);
if (error != null) {
new Notification(I18n.tr("Can't open website {0} in browser! Error message: {1}", uri, error)).setIcon(WikipediaPlugin.W_IMAGE.get()).show();
}
}
});
webLinkButton.setText(I18n.tr("Open item {0} in browser", qId));
nameLabel.setText(label);
descriptionLabel.setText(description);
setDisplayedItem(qId);
labelTab.downloadLabelsFor(qId);
statementTab.downloadStatementsFor(qId);
linkTab.downloadSitelinksFor(qId);
mainPanel.add(infoPanel);
mainPanel.revalidate();
mainPanel.repaint();
}
}
private synchronized void displayMessage(final String title, final String message) {
mainPanel.removeAll();
setTitle(title);
setDisplayedItem(null);
messageLabel.setText(message);
mainPanel.add(messagePanel);
mainPanel.revalidate();
mainPanel.repaint();
}
private void setDisplayedItem(final String qId) {
this.displayedItem = qId;
setTitle(qId);
qidLabel.setText(qId);
}
private String getDisplayedItem() {
return displayedItem;
}
@Override
protected void stateChanged() {
super.stateChanged();
updateDisplayedItem();
}
}
......@@ -23,6 +23,12 @@ public class RegexUtil {
return value != null && Q_ID_PATTERN.matcher(value).matches();
}
public static void requireValidQId(final String value) {
if (!isValidQId(value)) {
throw new IllegalArgumentException("Q-ID is invalid!");
}
}
/**
* Validates that a given string matches "[a-z]{2,3}wiki".
* This has to be improved in the future to exactly allow only existing site IDs and allow other wikimedia sites
......
......@@ -14,15 +14,10 @@ public class ApiUrlTest {
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"));
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"));
}
}
package org.wikipedia.api.wikidata_action;
import org.junit.Rule;
import org.junit.Test;
import org.openstreetmap.josm.testutils.JOSMTestRules;
import org.wikipedia.api.ApiQueryClient;
import org.wikipedia.testutils.ResourceFileLoader;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
public class QueryResultTest extends WikidataActionApiTestAbstract {
@Test
public void test() throws IOException, URISyntaxException {
simpleJsonStub(ResourceFileLoader.getResourceBytes(WikidataActionApiQueryTest.class, "response/query/languages.json"));
final Map<String, String> languages = ApiQueryClient.query(WikidataActionApiQuery.queryLanguages());
assertEquals(445, languages.size());
assertEquals("Deutsch", languages.get("de"));
assertEquals("English", languages.get("en"));
assertEquals("français", languages.get("fr"));
assertEquals("فارسی", languages.get("fa"));
assertEquals("עברית", languages.get("he"));
assertEquals("адыгабзэ", languages.get("ady-cyrl"));
assertEquals("中文(中国大陆)\u200E", languages.get("zh-cn"));
assertFalse(languages.containsKey("xyz"));
simpleRequestVerify("format=json&utf8=1&formatversion=1&action=query&meta=siteinfo&siprop=languages");
}
}
......@@ -4,6 +4,7 @@ import static org.junit.Assert.assertEquals;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
......@@ -12,19 +13,19 @@ import org.wikipedia.api.ApiQueryClient;
import org.wikipedia.api.wikidata_action.json.WbgetclaimsResult;
import org.wikipedia.testutils.ResourceFileLoader;
public class WbgetclaimsTest extends AbstractWikidataActionApiTest {
public class WbgetclaimsTest extends WikidataActionApiTestAbstract {
@Test
public void test() throws IOException, URISyntaxException {
simpleJsonStub(ResourceFileLoader.getResourceBytes(WikidataActionApiQueryTest.class, "response/wbgetclaims/Q2.json"));
final WbgetclaimsResult result = ApiQueryClient.query(WikidataActionApiQuery.wbgetclaims("Q2"));
final Collection<WbgetclaimsResult.Claim> result = ApiQueryClient.query(WikidataActionApiQuery.wbgetclaims("Q2"));
assertEquals(216, result.getClaims().size()); // Total number of claims
assertEquals(WbgetclaimsResult.Claim.RANK.PREFERRED, result.getClaims().stream().filter(it -> "Q2$9bbb058a-48ab-0a81-e88e-82bba6b2abe5".equals(it.getId())).findFirst().get().getRank());
assertEquals("P31", result.getClaims().stream().filter(it -> "Q2$50fad68d-4f91-f878-6f29-e655af54690e".equals(it.getId())).findFirst().get().getMainSnak().getProperty());
assertEquals(216, result.size()); // Total number of claims
assertEquals(WbgetclaimsResult.Claim.RANK.PREFERRED, result.stream().filter(it -> "Q2$9bbb058a-48ab-0a81-e88e-82bba6b2abe5".equals(it.getId())).findFirst().get().getRank());
assertEquals("P31", result.stream().filter(it -> "Q2$50fad68d-4f91-f878-6f29-e655af54690e".equals(it.getId())).findFirst().get().getMainSnak().getProperty());
final Map<String, List<WbgetclaimsResult.Claim>> claimMap = result.getClaims().stream().collect(Collectors.groupingBy(it -> it.getMainSnak().getProperty()));
final Map<String, List<WbgetclaimsResult.Claim>> claimMap = result.stream().collect(Collectors.groupingBy(it -> it.getMainSnak().getProperty()));
assertEquals(97, claimMap.keySet().size()); // Number of different properties for which claims exist
simpleRequestVerify("format=json&utf8=1&formatversion=1&action=wbgetclaims&props=&entity=Q2");
......
......@@ -15,7 +15,7 @@ import org.wikipedia.api.ApiQueryClient;
import org.wikipedia.api.wikidata_action.json.WbgetentitiesResult;
import org.wikipedia.testutils.ResourceFileLoader;
public class WikidataActionApiQueryTest extends AbstractWikidataActionApiTest {
public class WikidataActionApiQueryTest extends WikidataActionApiTestAbstract {
@Test(expected = IllegalArgumentException.class)
public void testWbgetentities_nonQId() {
......@@ -121,13 +121,13 @@ public class WikidataActionApiQueryTest extends AbstractWikidataActionApiTest {
public void testWikidataItemLabelQuery() throws IOException, URISyntaxException {
simpleJsonStub(ResourceFileLoader.getResourceBytes(WikidataActionApiQueryTest.class, "response/wbgetentities/labels_Q42.json"));
final Map<String, String> result = ApiQueryClient.query(WikidataActionApiQuery.wbgetentitiesLabels("Q42"));
final Map<String, WbgetentitiesResult.Entity.Label> result = ApiQueryClient.query(WikidataActionApiQuery.wbgetentitiesLabels("Q42"));
assertEquals(138, result.size());
assertEquals("Douglas Adams", result.get("en"));
assertEquals("Дуглас Адамс", result.get("ru"));
assertEquals("더글러스 애덤스", result.get("ko"));
assertEquals("ಡಾಗ್ಲಸ್ ಆಡಮ್ಸ್", result.get("tcy"));
assertEquals("Douglas Adams", result.get("en").getValue());
assertEquals("Дуглас Адамс", result.get("ru").getValue());
assertEquals("더글러스 애덤스", result.get("ko").getValue());
assertEquals("ಡಾಗ್ಲಸ್ ಆಡಮ್ಸ್", result.get("tcy").getValue());
simpleRequestVerify("format=json&utf8=1&formatversion=1&action=wbgetentities&props=labels&ids=Q42");
}
......
......@@ -18,7 +18,8 @@ import org.junit.Before;
import org.junit.Rule;
import org.openstreetmap.josm.testutils.JOSMTestRules;
public abstract class AbstractWikidataActionApiTest {
// Name must not end in "Test", so "Abstract" put at the end.
public abstract class WikidataActionApiTestAbstract {
@Rule
public WireMockRule wmRule = new WireMockRule(wireMockConfig().dynamicPort());
......
......@@ -73,7 +73,7 @@ public class WikipediaActionApiQueryTest {
@Override
public SitematrixResult.Sitematrix.Site getSite() {
return new SitematrixResult.Sitematrix.Site("http://localhost:" + wmRule.port(), "dbname", "code", "false");
return new SitematrixResult.Sitematrix.Site("http://localhost:" + wmRule.port(), "dbname", "code", "false", "Wikipedia");
}
@Override
......
......@@ -6,11 +6,11 @@ import static org.junit.Assert.assertEquals;
import java.io.IOException;
import java.net.URISyntaxException;
import org.junit.Test;
import org.wikipedia.api.wikidata_action.AbstractWikidataActionApiTest;
import org.wikipedia.api.wikidata_action.WikidataActionApiTestAbstract;
import org.wikipedia.api.wikidata_action.WikidataActionApiQueryTest;
import org.wikipedia.testutils.ResourceFileLoader;
public class WikipediaSiteTest extends AbstractWikidataActionApiTest {
public class WikipediaSiteTest extends WikidataActionApiTestAbstract {
@Test
public void testSites() throws IOException, URISyntaxException {
......