Changeset 14208 in josm


Ignore:
Timestamp:
2018-08-31T17:28:02+02:00 (3 weeks ago)
Author:
simon04
Message:

fix #16702 - Speed up OSM wiki help using MediaWiki API

Location:
trunk/src/org/openstreetmap/josm
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/preferences/JosmUrls.java

    r14119 r14208  
    2121     */
    2222    private static final String OSM_WEBSITE = "https://www.openstreetmap.org";
     23
     24    /**
     25     * The OSM wiki URL.
     26     */
     27    private static final String OSM_WIKI = "https://wiki.openstreetmap.org";
    2328
    2429    /**
     
    8893
    8994    @Override
     95    public String getOSMWiki() {
     96        if (Config.getPref() != null)
     97            return Config.getPref().get("url.openstreetmap-wiki", OSM_WIKI);
     98        return OSM_WIKI;
     99    }
     100
     101    @Override
    90102    public String getDefaultOsmApiUrl() {
    91103        return DEFAULT_API_URL;
  • trunk/src/org/openstreetmap/josm/gui/dialogs/properties/HelpAction.java

    r13959 r14208  
    77import java.awt.event.KeyEvent;
    88import java.io.IOException;
    9 import java.net.URI;
    10 import java.net.URISyntaxException;
     9import java.io.InputStream;
     10import java.net.URL;
    1111import java.util.ArrayList;
    1212import java.util.Arrays;
     
    1515import java.util.Objects;
    1616import java.util.function.IntFunction;
     17import java.util.stream.Collectors;
    1718
    1819import javax.swing.AbstractAction;
    1920import javax.swing.JTable;
    2021import javax.swing.KeyStroke;
     22import javax.xml.parsers.ParserConfigurationException;
     23import javax.xml.xpath.XPath;
     24import javax.xml.xpath.XPathConstants;
     25import javax.xml.xpath.XPathExpressionException;
     26import javax.xml.xpath.XPathFactory;
    2127
    2228import org.openstreetmap.josm.data.osm.IRelation;
     
    2935import org.openstreetmap.josm.tools.OpenBrowser;
    3036import org.openstreetmap.josm.tools.Utils;
     37import org.openstreetmap.josm.tools.XmlUtils;
     38import org.w3c.dom.Document;
     39import org.w3c.dom.Node;
     40import org.xml.sax.SAXException;
    3141
    3242/**
     
    7484    @Override
    7585    public void actionPerformed(ActionEvent e) {
    76         try {
    77             String base = Config.getPref().get("url.openstreetmap-wiki", "https://wiki.openstreetmap.org/wiki/");
    78             String lang = LanguageInfo.getWikiLanguagePrefix();
    79             final List<URI> uris = new ArrayList<>();
    80             if (tagTable.getSelectedRowCount() == 1) {
    81                 int row = tagTable.getSelectedRow();
    82                 String key = Utils.encodeUrl(tagKeySupplier.apply(row));
    83                 Map<String, Integer> m = tagValuesSupplier.apply(row);
    84                 if (!m.isEmpty()) {
    85                     String val = Utils.encodeUrl(m.entrySet().iterator().next().getKey());
    86                     uris.addAll(getTagURIs(base, lang, key, val));
    87                 }
    88             } else if (membershipTable != null && membershipTable.getSelectedRowCount() == 1) {
    89                 int row = membershipTable.getSelectedRow();
    90                 uris.addAll(getRelationURIs(base, lang, memberValueSupplier.apply(row)));
    91             } else {
    92                 // give the generic help page, if more than one element is selected
    93                 uris.addAll(getGenericURIs(base, lang));
     86        if (tagTable.getSelectedRowCount() == 1) {
     87            int row = tagTable.getSelectedRow();
     88            String key = Utils.encodeUrl(tagKeySupplier.apply(row));
     89            Map<String, Integer> m = tagValuesSupplier.apply(row);
     90            if (!m.isEmpty()) {
     91                String val = Utils.encodeUrl(m.entrySet().iterator().next().getKey());
     92                MainApplication.worker.execute(() -> displayTagHelp(key, val));
    9493            }
    95 
    96             MainApplication.worker.execute(() -> displayHelp(uris));
    97         } catch (URISyntaxException e1) {
    98             Logging.error(e1);
     94        } else if (membershipTable != null && membershipTable.getSelectedRowCount() == 1) {
     95            int row = membershipTable.getSelectedRow();
     96            final IRelation<?> relation = memberValueSupplier.apply(row);
     97            MainApplication.worker.execute(() -> displayRelationHelp(relation));
     98        } else {
     99            // give the generic help page, if more than one element is selected
     100            MainApplication.worker.execute(HelpAction::displayGenericHelp);
    99101        }
    100102    }
    101103
    102104    /**
    103      * Returns a list of URIs for the given key/value.
    104      * @param base OSM wiki base URL
    105      * @param lang Language prefix
     105     * Displays the most specific wiki page for the given key/value.
    106106     * @param key Key
    107107     * @param val Value
    108      * @return a list of URIs for the given key/value by order of relevance
    109      * @throws URISyntaxException in case of internal error
    110      * @since 13522
     108     * @since 14208
    111109     */
    112     public static List<URI> getTagURIs(String base, String lang, String key, String val) throws URISyntaxException {
    113         return Arrays.asList(
    114             new URI(String.format("%s%sTag:%s=%s", base, lang, key, val)),
    115             new URI(String.format("%sTag:%s=%s", base, key, val)),
    116             new URI(String.format("%s%sKey:%s", base, lang, key)),
    117             new URI(String.format("%sKey:%s", base, key)),
    118             new URI(String.format("%s%sMap_Features", base, lang)),
    119             new URI(String.format("%sMap_Features", base))
     110    public static void displayTagHelp(String key, String val) {
     111        final String lang = LanguageInfo.getWikiLanguagePrefix();
     112        final List<String> pages = Arrays.asList(
     113                String.format("%sTag:%s=%s", lang, key, val),
     114                String.format("Tag:%s=%s", key, val),
     115                String.format("%sKey:%s", lang, key),
     116                String.format("Key:%s", key),
     117                String.format("%sMap_Features", lang),
     118                "Map_Features"
    120119        );
     120        displayHelp(pages);
    121121    }
    122122
    123123    /**
    124      * Returns a list of URIs for the given relation.
    125      * @param base OSM wiki base URL
    126      * @param lang Language prefix
     124     * Displays the most specific wiki page for the given relation.
    127125     * @param rel Relation
    128      * @return a list of URIs for the given relation by order of relevance
    129      * @throws URISyntaxException in case of internal error
    130      * @since 13522
    131      * @since 13959 (signature)
     126     * @since 14208
    132127     */
    133     public static List<URI> getRelationURIs(String base, String lang, IRelation<?> rel) throws URISyntaxException {
    134         List<URI> uris = new ArrayList<>();
     128    public static void displayRelationHelp(IRelation<?> rel) {
     129        final String lang = LanguageInfo.getWikiLanguagePrefix();
     130        final List<String> pages = new ArrayList<>();
    135131        String type = rel.get("type");
    136132        if (type != null) {
     
    139135
    140136        if (type != null && !type.isEmpty()) {
    141             uris.add(new URI(String.format("%s%sRelation:%s", base, lang, type)));
    142             uris.add(new URI(String.format("%sRelation:%s", base, type)));
     137            pages.add(String.format("%sRelation:%s", lang, type));
     138            pages.add(String.format("Relation:%s", type));
    143139        }
    144140
    145         uris.add(new URI(String.format("%s%sRelations", base, lang)));
    146         uris.add(new URI(String.format("%sRelations", base)));
    147         return uris;
     141        pages.add(String.format("%sRelations", lang));
     142        pages.add("Relations");
     143        displayHelp(pages);
    148144    }
    149145
    150146    /**
    151      * Returns a list of generic URIs (Map Features).
    152      * @param base OSM wiki base URL
    153      * @param lang Language prefix
    154      * @return a list of generic URIs (Map Features)
    155      * @throws URISyntaxException in case of internal error
    156      * @since 13522
     147     * Displays the localized Map Features.
     148     * @since 14208
    157149     */
    158     public static List<URI> getGenericURIs(String base, String lang) throws URISyntaxException {
    159         return Arrays.asList(
    160             new URI(String.format("%s%sMap_Features", base, lang)),
    161             new URI(String.format("%sMap_Features", base))
     150    public static void displayGenericHelp() {
     151        final String lang = LanguageInfo.getWikiLanguagePrefix();
     152        final List<String> pages = Arrays.asList(
     153                String.format("%sMap_Features", lang),
     154                "Map_Features"
    162155        );
     156        displayHelp(pages);
    163157    }
    164158
    165159    /**
    166      * Display help by searching the forst valid URI in the given list.
    167      * @param uris list of URIs to test
    168      * @since 13522
     160     * Display help by opening the first existing wiki page in the given list.
     161     * @param pages list of wiki page names to test
     162     * @since 14208
    169163     */
    170     public static void displayHelp(final List<URI> uris) {
     164    public static void displayHelp(final List<String> pages) {
    171165        try {
    172166            // find a page that actually exists in the wiki
    173             HttpClient.Response conn;
    174             for (URI u : uris) {
    175                 conn = HttpClient.create(u.toURL(), "HEAD").connect();
    176 
    177                 if (conn.getResponseCode() != 200) {
    178                     conn.disconnect();
    179                 } else {
    180                     long osize = conn.getContentLength();
    181                     if (osize > -1) {
    182                         conn.disconnect();
    183 
    184                         final URI newURI = new URI(u.toString()
    185                                 .replace("=", "%3D") /* do not URLencode whole string! */
    186                                 .replaceFirst("/wiki/", "/w/index.php?redirect=no&title=")
    187                         );
    188                         conn = HttpClient.create(newURI.toURL(), "HEAD").connect();
    189                     }
    190 
    191                     /* redirect pages have different content length, but retrieving a "nonredirect"
    192                      *  page using index.php and the direct-link method gives slightly different
    193                      *  content lengths, so we have to be fuzzy.. (this is UGLY, recode if u know better)
    194                      */
    195                     if (osize > -1 && conn.getContentLength() != -1 && Math.abs(conn.getContentLength() - osize) > 200) {
    196                         Logging.info("{0} is a mediawiki redirect", u);
    197                         conn.disconnect();
    198                     } else {
    199                         conn.disconnect();
    200 
    201                         OpenBrowser.displayUrl(u.toString());
    202                         break;
    203                     }
     167            // API documentation: https://wiki.openstreetmap.org/w/api.php?action=help&modules=query
     168            final URL url = new URL(Config.getUrls().getOSMWiki() + "/w/api.php?action=query&format=xml&titles=" + pages.stream()
     169                    .map(Utils::encodeUrl)
     170                    .collect(Collectors.joining("|"))
     171            );
     172            final HttpClient.Response conn = HttpClient.create(url).connect();
     173            final Document document;
     174            try (InputStream content = conn.getContent()) {
     175                document = XmlUtils.parseSafeDOM(content);
     176            }
     177            conn.disconnect();
     178            final XPath xPath = XPathFactory.newInstance().newXPath();
     179            for (String page : pages) {
     180                String normalized = xPath.evaluate("/api/query/normalized/n[@from='" + page + "']/@to", document);
     181                if (normalized == null || normalized.isEmpty()) {
     182                    normalized = page;
     183                }
     184                final Node node = (Node) xPath.evaluate("/api/query/pages/page[@title='" + normalized + "']", document, XPathConstants.NODE);
     185                if (node != null
     186                        && node.getAttributes().getNamedItem("missing") == null
     187                        && node.getAttributes().getNamedItem("invalid") == null) {
     188                    OpenBrowser.displayUrl(Config.getUrls().getOSMWiki() + "/wiki/" + page);
     189                    break;
    204190                }
    205191            }
    206         } catch (URISyntaxException | IOException e1) {
     192        } catch (IOException | ParserConfigurationException | XPathExpressionException | SAXException e1) {
    207193            Logging.error(e1);
    208194        }
  • trunk/src/org/openstreetmap/josm/spi/preferences/IUrls.java

    r14119 r14208  
    4545
    4646    /**
     47     * Returns the OSM wiki URL.
     48     * @return the OSM wiki URL
     49     * @since 14208
     50     */
     51    String getOSMWiki();
     52
     53    /**
    4754     * Returns the default OSM API URL.
    4855     * @return the default OSM API URL
Note: See TracChangeset for help on using the changeset viewer.