Ticket #24973: patch-Fix-Sonar-issues-in-GetCapabilitiesParseHelper.patch

File patch-Fix-Sonar-issues-in-GetCapabilitiesParseHelper.patch, 13.2 KB (added by DanProgs <Abenteurer.2901@…>, 22 hours ago)
  • src/org/openstreetmap/josm/data/imagery/GetCapabilitiesParseHelper.java

    ### Eclipse Workspace Patch 1.0
    #P josm
    diff --git src/org/openstreetmap/josm/data/imagery/GetCapabilitiesParseHelper.java src/org/openstreetmap/josm/data/imagery/GetCapabilitiesParseHelper.java
    index 4988e9b..00a7bc2 100644
     
    33
    44import java.io.InputStream;
    55import java.net.MalformedURLException;
    6 import java.net.URL;
     6import java.net.URI;
     7import java.net.URISyntaxException;
    78import java.util.Arrays;
    89import java.util.Locale;
    910import java.util.function.BiPredicate;
    … …  
    9293     */
    9394    public static void moveReaderToEndCurrentTag(XMLStreamReader reader) throws XMLStreamException {
    9495        int level = 0;
    95         QName tag = reader.getName();
     96        final QName tag = reader.getName();
    9697        for (int event = reader.getEventType(); reader.hasNext(); event = reader.next()) {
    9798            if (XMLStreamReader.START_ELEMENT == event) {
    9899                level += 1;
    … …  
    117118     * @throws XMLStreamException if any XML stream error occurs
    118119     */
    119120    public static String getElementTextWithSubtags(XMLStreamReader reader) throws XMLStreamException {
    120         StringBuilder ret = new StringBuilder();
     121        final StringBuilder ret = new StringBuilder();
    121122        int level = 0;
    122         QName tag = reader.getName();
     123        final QName tag = reader.getName();
    123124        for (int event = reader.getEventType(); reader.hasNext(); event = reader.next()) {
    124125            if (XMLStreamReader.START_ELEMENT == event) {
    125126                if (level > 0) {
    … …  
    167168     */
    168169    public static boolean moveReaderToTag(XMLStreamReader reader,
    169170            BiPredicate<QName, QName> equalsFunc, QName... tags) throws XMLStreamException {
    170         QName stopTag = reader.getName();
     171        final QName stopTag = reader.getName();
    171172        int currentLevel = 0;
    172173        QName searchTag = tags[currentLevel];
    173174        QName parentTag = null;
    … …  
    214215     * @throws XMLStreamException See {@link XMLStreamReader}
    215216     */
    216217    public static TransferMode getTransferMode(XMLStreamReader reader) throws XMLStreamException {
    217         QName getQname = QN_OWS_GET;
     218        final QName getQname = QN_OWS_GET;
    218219
    219220        Utils.ensure(getQname.equals(reader.getName()), "WMTS Parser state invalid. Expected element %s, got %s",
    220221                getQname, reader.getName());
    … …  
    238239     * @throws MalformedURLException in case of malformed URL
    239240     * @since 10993
    240241     */
    241     public static String normalizeCapabilitiesUrl(String url) throws MalformedURLException {
    242         URL inUrl = new URL(url);
    243         URL ret = new URL(inUrl.getProtocol(), inUrl.getHost(), inUrl.getPort(), inUrl.getFile());
    244         return ret.toExternalForm();
     242    public static String normalizeCapabilitiesUrl(String url) throws MalformedURLException {       
     243        if (url == null || url.isBlank()) {
     244            throw new MalformedURLException("URL string is null or blank");
     245        }
     246        try {
     247            final URI inUri = new URI(url);
     248            final URI retUri = new URI(inUri.getScheme(), null, inUri.getHost(), inUri.getPort(), inUri.getPath(), inUri.getQuery(), null);
     249            return retUri.toURL().toExternalForm();
     250        } catch (URISyntaxException e) {
     251            throw new MalformedURLException("Invalid URL syntax: " + e.getMessage());
     252        }
    245253    }
    246254
    247255    /**
  • src/org/openstreetmap/josm/data/imagery/TMSCachedTileLoaderJob.java

    diff --git src/org/openstreetmap/josm/data/imagery/TMSCachedTileLoaderJob.java src/org/openstreetmap/josm/data/imagery/TMSCachedTileLoaderJob.java
    index 03a71e2..e3e55e2 100644
     
    66import java.io.ByteArrayInputStream;
    77import java.io.IOException;
    88import java.net.SocketTimeoutException;
     9import java.net.URI;
     10import java.net.URISyntaxException;
    911import java.net.URL;
    1012import java.nio.charset.StandardCharsets;
    1113import java.util.HashSet;
    … …  
    8587
    8688    @Override
    8789    public String getCacheKey() {
    88         if (tile != null) {
    89             TileSource tileSource = tile.getTileSource();
    90             return Optional.ofNullable(tileSource.getName()).orElse("").replace(ICache.NAME_COMPONENT_DELIMITER, "_")
    91                     + ICache.NAME_COMPONENT_DELIMITER
    92                     + tileSource.getTileId(tile.getZoom(), tile.getXtile(), tile.getYtile());
    93         }
    94         return null;
     90        if (tile == null) {
     91            return null;
     92        }
     93        final TileSource tileSource = tile.getTileSource();
     94        return Optional.ofNullable(tileSource.getName()).orElse("").replace(ICache.NAME_COMPONENT_DELIMITER, "_")
     95                + ICache.NAME_COMPONENT_DELIMITER
     96                + tileSource.getTileId(tile.getZoom(), tile.getXtile(), tile.getYtile());
    9597    }
    9698
    9799    /*
    98      *  this doesn't needs to be synchronized, as it's not that costly to keep only one execution
    99      *  in parallel, but URL creation and Tile.getUrl() are costly and are not needed when fetching
    100      *  data from cache, that's why URL creation is postponed until it's needed
     100     * This doesn't need to be synchronized for the entire method, as it's not that costly
     101     * to keep only one execution in parallel. However, URL creation and tile.getUrl()
     102     * are costly and are not needed when fetching data from the cache. That's why
     103     * URL creation is postponed until it's actually needed.
    101104     *
    102      *  We need to have static url value for TileLoaderJob, as for some TileSources we might get different
    103      *  URL's each call we made (servers switching), and URL's are used below as a key for duplicate detection
    104      *
     105     * We need to have a static/stable URL value for TileLoaderJob, as for some TileSources
     106     * we might get different URLs on each call (due to server switching), and URLs are
     107     * used below as a key for duplicate detection.
    105108     */
    106109    @Override
    107110    public URL getUrl() throws IOException {
    108111        if (url == null) {
    109112            synchronized (this) {
    110113                if (url == null) {
    111                     String sUrl = tile.getUrl();
    112                     if (!"".equals(sUrl)) {
    113                         url = new URL(sUrl);
     114                    final String sUrl = tile.getUrl();
     115                    if (sUrl != null && !sUrl.isBlank()) {
     116                        try {
     117                            url = new URI(sUrl).toURL();
     118                        } catch (URISyntaxException e) {
     119                            throw new IOException("Invalid URL format: " + sUrl, e);
     120                        }
    114121                    }
    115122                }
    116123            }
    … …  
    121128    @Override
    122129    public boolean isObjectLoadable() {
    123130        if (cacheData != null) {
    124             byte[] content = cacheData.getContent();
     131            final byte[] content = cacheData.getContent();
    125132            try {
    126133                return content.length > 0 || cacheData.getImage() != null || isNoTileAtZoom();
    127134            } catch (IOException e) {
    … …  
    139146            attributes.setNoTileAtZoom(true);
    140147            return false; // do no try to load data from no-tile at zoom, cache empty object instead
    141148        }
    142         if (isNotImage(headers, statusCode)) {
    143             String message = detectErrorMessage(new String(content, StandardCharsets.UTF_8));
    144             if (!Utils.isEmpty(message)) {
    145                 tile.setError(message);
    146             }
    147             return false;
    148         }
    149         return super.isResponseLoadable(headers, statusCode, content);
     149        if (!isNotImage(headers, statusCode)) {
     150            return super.isResponseLoadable(headers, statusCode, content);
     151        }
     152        final String message = detectErrorMessage(new String(content, StandardCharsets.UTF_8));
     153        if (!Utils.isEmpty(message)) {
     154            tile.setError(message);
     155        }
     156        return false;
    150157    }
    151158
    152159    private boolean isNotImage(Map<String, List<String>> headers, int statusCode) {
    153160        if (statusCode == 200 && headers.containsKey("Content-Type") && !headers.get("Content-Type").isEmpty()) {
    154             String contentType = headers.get("Content-Type").stream().findAny().orElse("").toLowerCase(Locale.ROOT);
     161            final String contentType = headers.get("Content-Type").stream().findAny().orElse("").toLowerCase(Locale.ROOT);
    155162            if (!contentType.startsWith("image")
    156163                && !contentType.startsWith("application/octet-stream")
    157164                && !MVTFile.MIMETYPE.contains(contentType)) {
    … …  
    187194    @Override
    188195    public void loadingFinished(CacheEntry object, CacheEntryAttributes attributes, LoadResult result) {
    189196        this.attributes = attributes; // as we might get notification from other object than our selfs, pass attributes along
    190         Set<TileLoaderListener> listeners = inProgress.remove(getCacheKey());
     197        final Set<TileLoaderListener> listeners = inProgress.remove(getCacheKey());
    191198        boolean status = result == LoadResult.SUCCESS;
    192199
    193200        try {
    … …  
    203210            case SUCCESS:
    204211                handleNoTileAtZoom();
    205212                if (attributes != null) {
    206                     int httpStatusCode = attributes.getResponseCode();
     213                    final int httpStatusCode = attributes.getResponseCode();
    207214                    if (httpStatusCode >= 400 && !isNoTileAtZoom()) {
    208215                        status = false;
    209216                        handleError(attributes);
    … …  
    246253            return;
    247254        }
    248255        if (attributes != null) {
    249             int httpStatusCode = attributes.getResponseCode();
     256            final int httpStatusCode = attributes.getResponseCode();
    250257            if (attributes.getErrorMessage() == null) {
    251258                tile.setError(tr("HTTP error {0} when loading tiles", httpStatusCode));
    252259            } else {
    … …  
    273280     */
    274281    @Override
    275282    protected String getServerKey() {
    276         TileSource ts = tile.getSource();
     283        final TileSource ts = tile.getSource();
    277284        if (ts instanceof AbstractTMSTileSource) {
    278285            return ((AbstractTMSTileSource) ts).getBaseUrl();
    279286        }
    … …  
    292299
    293300    @Override
    294301    protected CacheEntryAttributes parseHeaders(HttpClient.Response urlConn) {
    295         CacheEntryAttributes ret = super.parseHeaders(urlConn);
     302        final CacheEntryAttributes ret = super.parseHeaders(urlConn);
    296303        // keep the expiration time between MINIMUM_EXPIRES and MAXIMUM_EXPIRES, so we will cache the tiles
    297304        // at least for some short period of time, but not too long
    298         long minimumExpiryTime = TimeUnit.SECONDS.toMillis(options.getMinimumExpiryTime());
    299         long nowPlusMin = now + Math.max(MINIMUM_EXPIRES.get(), minimumExpiryTime);
     305        final long minimumExpiryTime = TimeUnit.SECONDS.toMillis(options.getMinimumExpiryTime());
     306        final long nowPlusMin = now + Math.max(MINIMUM_EXPIRES.get(), minimumExpiryTime);
    300307        if (ret.getExpirationTime() < nowPlusMin) {
    301308            ret.setExpirationTime(nowPlusMin);
    302309        }
    303         long nowPlusMax = now + Math.max(MAXIMUM_EXPIRES.get(), minimumExpiryTime);
     310        final long nowPlusMax = now + Math.max(MAXIMUM_EXPIRES.get(), minimumExpiryTime);
    304311        if (ret.getExpirationTime() > nowPlusMax) {
    305312            ret.setExpirationTime(nowPlusMax);
    306313        }
    … …  
    326333
    327334    private boolean tryLoadTileImage(CacheEntry object) throws IOException {
    328335        if (object != null) {
    329             byte[] content = object.getContent();
     336            final byte[] content = object.getContent();
    330337            if (content.length > 0 || tile instanceof VectorTile) {
    331338                try (ByteArrayInputStream in = new ByteArrayInputStream(content)) {
    332339                    tile.loadImage(in);
    333340                    if ((!(tile instanceof VectorTile) && tile.getImage() == null)
    334341                        || ((tile instanceof VectorTile) && !tile.isLoaded())) {
    335                         String s = new String(content, StandardCharsets.UTF_8);
    336                         Matcher m = SERVICE_EXCEPTION_PATTERN.matcher(s);
     342                        final String s = new String(content, StandardCharsets.UTF_8);
     343                        final Matcher m = SERVICE_EXCEPTION_PATTERN.matcher(s);
    337344                        if (m.matches()) {
    338                             String message = Utils.strip(m.group(1));
     345                            final String message = Utils.strip(m.group(1));
    339346                            tile.setError(message);
    340347                            Logging.error(message);
    341348                            Logging.debug(s);
    … …  
    354361
    355362    @Override
    356363    public String detectErrorMessage(String data) {
    357         Matcher xml = SERVICE_EXCEPTION_PATTERN.matcher(data);
    358         Matcher json = JSON_PATTERN.matcher(data);
     364        final Matcher xml = SERVICE_EXCEPTION_PATTERN.matcher(data);
     365        final Matcher json = JSON_PATTERN.matcher(data);
    359366        return xml.matches() ? removeCdata(Utils.strip(xml.group(1)))
    360367            : json.matches() ? Utils.strip(json.group(1))
    361368            : super.detectErrorMessage(data);
    362369    }
    363370
    364371    private static String removeCdata(String msg) {
    365         Matcher m = CDATA_PATTERN.matcher(msg);
     372        final Matcher m = CDATA_PATTERN.matcher(msg);
    366373        return m.matches() ? Utils.strip(m.group(1)) : msg;
    367374    }
    368375}