Changeset 8568 in josm for trunk/src/org


Ignore:
Timestamp:
2015-07-04T22:52:23+02:00 (9 years ago)
Author:
wiktorn
Message:

Basic WMTS support.

  • added information about units and to_meter to EPSG projection definitions (needed for WMTS)
  • added WMTSTileSource and WMTSLayer classes
  • a bit of cleanup of AbstractTileSourceLayer and align so it will work properly with WMTS tile definitions
  • added Imagery Preferences panel for WMTS and icon for button
  • added removal of wms: / tms: / wmts: prefix, if user will paste them into the field
  • CachedFile - added possibility to send custom headers with request
  • added support for unit and to_meter in CustomProjection
  • AbstractTMSTileSource cleanups (change of Coordinate to ICoordinate)
  • moved JCSCachedTileLoaderJob.read() to Utils

Addresses: #10623

Tested with Polish WMTS service proivders, Walonnie needs still some debugging, as it is not working right now.

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

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/cache/JCSCachedTileLoaderJob.java

    r8540 r8568  
    22package org.openstreetmap.josm.data.cache;
    33
    4 import java.io.ByteArrayOutputStream;
    54import java.io.FileNotFoundException;
    65import java.io.IOException;
    7 import java.io.InputStream;
    86import java.net.HttpURLConnection;
    97import java.net.URL;
     
    3028import org.openstreetmap.josm.data.cache.ICachedLoaderListener.LoadResult;
    3129import org.openstreetmap.josm.data.preferences.IntegerProperty;
     30import org.openstreetmap.josm.tools.Utils;
    3231
    3332/**
     
    350349
    351350                attributes.setResponseCode(responseCode(urlConn));
    352                 byte[] raw = read(urlConn);
     351                byte[] raw = Utils.readBytesFromStream(urlConn.getInputStream());
    353352
    354353                if (isResponseLoadable(urlConn.getHeaderFields(), responseCode(urlConn), raw)) {
     
    473472    }
    474473
    475     private static byte[] read(URLConnection urlConn) throws IOException {
    476         InputStream input = urlConn.getInputStream();
    477         try {
    478             ByteArrayOutputStream bout = new ByteArrayOutputStream(input.available());
    479             byte[] buffer = new byte[2048];
    480             boolean finished = false;
    481             do {
    482                 int read = input.read(buffer);
    483                 if (read >= 0) {
    484                     bout.write(buffer, 0, read);
    485                 } else {
    486                     finished = true;
    487                 }
    488             } while (!finished);
    489             if (bout.size() == 0)
    490                 return null;
    491             return bout.toByteArray();
    492         } finally {
    493             input.close();
    494         }
    495     }
    496 
    497474    /**
    498475     * TODO: move to JobFactory
  • trunk/src/org/openstreetmap/josm/data/imagery/ImageryInfo.java

    r8526 r8568  
    5656        SCANEX("scanex"),
    5757        /** A WMS endpoint entry only stores the WMS server info, without layer, which are chosen later by the user. **/
    58         WMS_ENDPOINT("wms_endpoint");
     58        WMS_ENDPOINT("wms_endpoint"),
     59        /** WMTS stores GetCapabilities URL. Does not store any information about the layer **/
     60        WMTS("wmts");
    5961
    6062
  • trunk/src/org/openstreetmap/josm/data/projection/CustomProjection.java

    r8533 r8568  
    88import java.util.List;
    99import java.util.Map;
     10import java.util.concurrent.ConcurrentHashMap;
    1011import java.util.regex.Matcher;
    1112import java.util.regex.Pattern;
     
    3536public class CustomProjection extends AbstractProjection {
    3637
     38    private final static Map<String, Double> UNITS_TO_METERS = getUnitsToMeters();
     39    private final static double METER_PER_UNIT_DEGREE = 2 * Math.PI * 6370997 / 360;
     40
    3741    /**
    3842     * pref String that defines the projection
     
    4549    protected String cacheDir;
    4650    protected Bounds bounds;
     51    private double metersPerUnit = METER_PER_UNIT_DEGREE; // default to degrees
    4752
    4853    /**
     
    8994        wktext("wktext", false),  // ignored
    9095        /** meters, US survey feet, etc. */
    91         units("units", true),     // ignored
     96        units("units", true),
    9297        /** Don't use the /usr/share/proj/proj_def.dat defaults file */
    9398        no_defs("no_defs", false),
    9499        init("init", true),
     100        to_meter("to_meter", true),
    95101        // JOSM extensions, not present in PROJ.4
    96102        wmssrs("wmssrs", true),
     
    103109
    104110        /** Map of all parameters by key */
    105         static final Map<String, Param> paramsByKey = new HashMap<>();
     111        static final Map<String, Param> paramsByKey = new ConcurrentHashMap<>();
    106112        static {
    107113            for (Param p : Param.values()) {
     
    198204            if (s != null) {
    199205                this.code = s;
     206            }
     207            s = parameters.get(Param.units.key);
     208            if (s != null) {
     209                this.metersPerUnit = UNITS_TO_METERS.get(s);
     210            }
     211            s = parameters.get(Param.to_meter.key);
     212            if (s != null) {
     213                this.metersPerUnit = parseDouble(s, Param.to_meter.key);
    200214            }
    201215        }
     
    528542        return name != null ? name : tr("Custom Projection");
    529543    }
     544
     545    @Override
     546    public double getMetersPerUnit() {
     547        return metersPerUnit;
     548    }
     549
     550    private static Map<String, Double> getUnitsToMeters() {
     551        Map<String, Double> ret = new ConcurrentHashMap<>();
     552        ret.put("km", 1000d);
     553        ret.put("m", 1d);
     554        ret.put("dm", 1d/10);
     555        ret.put("cm", 1d/100);
     556        ret.put("mm", 1d/1000);
     557        ret.put("kmi", 1852.0);
     558        ret.put("in", 0.0254);
     559        ret.put("ft", 0.3048);
     560        ret.put("yd", 0.9144);
     561        ret.put("mi", 1609.344);
     562        ret.put("fathom", 1.8288);
     563        ret.put("chain", 20.1168);
     564        ret.put("link", 0.201168);
     565        ret.put("us-in", 1d/39.37);
     566        ret.put("us-ft", 0.304800609601219);
     567        ret.put("us-yd", 0.914401828803658);
     568        ret.put("us-ch", 20.11684023368047);
     569        ret.put("us-mi", 1609.347218694437);
     570        ret.put("ind-yd", 0.91439523);
     571        ret.put("ind-ft", 0.30479841);
     572        ret.put("ind-ch", 20.11669506);
     573        ret.put("degree", METER_PER_UNIT_DEGREE);
     574        return ret;
     575    }
    530576}
  • trunk/src/org/openstreetmap/josm/data/projection/Projection.java

    r6069 r8568  
    6868     */
    6969    Bounds getWorldBoundsLatLon();
     70
     71    /**
     72     * Get the number of meters per unit of this projection. This more
     73     * defines the scale of the map, than real conversion of unit to meters
     74     * as this value is more less correct only along great circles.
     75     *
     76     * Used by WMTS to properly scale tiles
     77     * @return meters per unit of projection
     78     *
     79     */
     80    double getMetersPerUnit();
    7081}
  • trunk/src/org/openstreetmap/josm/data/projection/proj/Proj.java

    r7509 r8568  
    6464     */
    6565    double[] invproject(double east, double north);
    66 
    6766}
  • trunk/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java

    r8542 r8568  
    3131import java.util.Set;
    3232import java.util.concurrent.ConcurrentSkipListSet;
     33import java.util.concurrent.atomic.AtomicInteger;
    3334
    3435import javax.swing.AbstractAction;
     
    4445
    4546import org.openstreetmap.gui.jmapviewer.AttributionSupport;
    46 import org.openstreetmap.gui.jmapviewer.Coordinate;
    4747import org.openstreetmap.gui.jmapviewer.MemoryTileCache;
    4848import org.openstreetmap.gui.jmapviewer.OsmTileLoader;
     
    5151import org.openstreetmap.gui.jmapviewer.interfaces.CachedTileLoader;
    5252import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
     53import org.openstreetmap.gui.jmapviewer.interfaces.TemplatedTileSource;
    5354import org.openstreetmap.gui.jmapviewer.interfaces.TileCache;
    5455import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader;
     
    102103    /** do set autoload when creating a new layer */
    103104    public static final BooleanProperty PROP_DEFAULT_AUTOLOAD = new BooleanProperty(PREFERENCE_PREFIX + ".default_autoload", true);
    104     /** do set showerrors when creating a new layer */
     105    /** do show errors per default */
    105106    public static final BooleanProperty PROP_DEFAULT_SHOWERRORS = new BooleanProperty(PREFERENCE_PREFIX + ".default_showerrors", true);
    106107    /** minimum zoom level to show to user */
     
    118119
    119120    private AttributionSupport attribution = new AttributionSupport();
    120     Tile showMetadataTile;
    121121
    122122    // needed public access for session exporter
     
    130130    protected TileCache tileCache;
    131131    protected TileSource tileSource;
    132     //protected  tileMatrix;
    133132    protected TileLoader tileLoader;
    134133
     
    154153    protected abstract TileSource getTileSource(ImageryInfo info) throws IllegalArgumentException;
    155154
    156     protected abstract Map<String, String> getHeaders(TileSource tileSource);
    157 
    158     protected void initTileSource(TileSource tileMatrix) {
    159         this.tileSource = tileMatrix;
    160         attribution.initialize(tileMatrix);
     155    protected Map<String, String> getHeaders(TileSource tileSource) {
     156        if (tileSource instanceof TemplatedTileSource) {
     157            return ((TemplatedTileSource) tileSource).getHeaders();
     158        }
     159        return null;
     160    }
     161
     162    protected void initTileSource(TileSource tileSource) {
     163        attribution.initialize(tileSource);
    161164
    162165        currentZoomLevel = getBestZoom();
    163166
    164         Map<String, String> headers = getHeaders(tileMatrix);
     167        Map<String, String> headers = getHeaders(tileSource);
    165168
    166169        tileLoader = getTileLoaderFactory().makeTileLoader(this, headers);
     
    247250    }
    248251
    249     private int getBestZoom() {
     252    protected int getBestZoom() {
    250253        double factor = getScaleFactor(1); // check the ratio between area of tilesize at zoom 1 to current view
    251254        double result = Math.log(factor)/Math.log(2)/2+1;
     
    273276
    274277    private final class ShowTileInfoAction extends AbstractAction {
    275         private final TileHolder clickedTileHolder;
     278        private transient final TileHolder clickedTileHolder;
    276279
    277280        private ShowTileInfoAction(TileHolder clickedTileHolder) {
     
    349352        }
    350353
     354        @Override
    351355        public Component createMenuComponent() {
    352356            JCheckBoxMenuItem item = new JCheckBoxMenuItem(this);
     
    414418        @Override
    415419        public void actionPerformed(ActionEvent ae) {
    416             double new_factor = Math.sqrt(getScaleFactor(currentZoomLevel));
    417             Main.map.mapView.zoomToFactor(new_factor);
     420            double newFactor = Math.sqrt(getScaleFactor(currentZoomLevel));
     421            Main.map.mapView.zoomToFactor(newFactor);
    418422            redraw();
    419423        }
     
    451455    @Override
    452456    public void hookUpMapView() {
    453         initTileSource(getTileSource(info));
     457        this.tileSource = getTileSource(info);
    454458        projectionChanged(null, Main.getProjection()); // check if projection is supported
     459        initTileSource(this.tileSource);
    455460
    456461        // keep them final here, so we avoid namespace clutter in the class
     
    538543                    @Override
    539544                    protected void finish() {
     545                        // empty - flush is instaneus
    540546                    }
    541547
    542548                    @Override
    543549                    protected void cancel() {
     550                        // empty - flush is instaneus
    544551                    }
    545552                }.run();
     
    642649     */
    643650    public static void setMaxZoomLvl(int maxZoomLvl) {
    644         maxZoomLvl = checkMaxZoomLvl(maxZoomLvl, null);
    645         PROP_MAX_ZOOM_LVL.put(maxZoomLvl);
     651        PROP_MAX_ZOOM_LVL.put(checkMaxZoomLvl(maxZoomLvl, null));
    646652    }
    647653
     
    651657     */
    652658    public static void setMinZoomLvl(int minZoomLvl) {
    653         minZoomLvl = checkMinZoomLvl(minZoomLvl, null);
    654         PROP_MIN_ZOOM_LVL.put(minZoomLvl);
     659        PROP_MIN_ZOOM_LVL.put(checkMinZoomLvl(minZoomLvl, null));
    655660    }
    656661
     
    742747     */
    743748    public boolean decreaseZoomLevel() {
    744         //int minZoom = this.getMinZoomLvl();
    745749        if (zoomDecreaseAllowed()) {
    746750            if (Main.isDebugEnabled()) {
     
    750754            zoomChanged();
    751755        } else {
    752             /*Main.debug("Current zoom level could not be decreased. Min. zoom level "+minZoom+" reached.");*/
    753756            return false;
    754757        }
     
    786789     */
    787790    private Tile getTile(int x, int y, int zoom) {
    788         int max = (1 << zoom);
    789         if (x < 0 || x >= max || y < 0 || y >= max)
     791        if (x < 0 || x >= tileSource.getTileXMax(zoom) || y < 0 || y >= tileSource.getTileYMax(zoom))
    790792            return null;
    791793        return tileCache.getTile(tileSource, x, y, zoom);
     
    10031005        }
    10041006
    1005         /*int xCursor = -1;
     1007        int xCursor = -1;
    10061008        int yCursor = -1;
    1007         if (PROP_DRAW_DEBUG.get()) {
     1009        if (Main.isDebugEnabled()) {
    10081010            if (yCursor < t.getYtile()) {
    10091011                if (t.getYtile() % 32 == 31) {
     
    10261028                xCursor = t.getXtile();
    10271029            }
    1028         }*/
     1030        }
    10291031    }
    10301032
     
    10421044    }
    10431045
    1044     private Coordinate getShiftedCoord(EastNorth en) {
    1045         LatLon ll = getShiftedLatLon(en);
    1046         return new Coordinate(ll.lat(), ll.lon());
     1046    private ICoordinate getShiftedCoord(EastNorth en) {
     1047        return getShiftedLatLon(en).toCoordinate();
    10471048    }
    10481049
     
    11171118
    11181119        private int size() {
    1119             int x_span = x1 - x0 + 1;
    1120             int y_span = y1 - y0 + 1;
    1121             return x_span * y_span;
     1120            int xSpan = x1 - x0 + 1;
     1121            int ySpan = y1 - y0 + 1;
     1122            return xSpan * ySpan;
    11221123        }
    11231124
     
    13551356            }
    13561357            int newzoom = displayZoomLevel + zoomOffset;
    1357             if (newzoom < MIN_ZOOM) {
     1358            if (newzoom < getMinZoomLvl() || newzoom > getMaxZoomLvl()) {
    13581359                continue;
    13591360            }
     
    15131514    public class PrecacheTask implements TileLoaderListener {
    15141515        private final ProgressMonitor progressMonitor;
    1515         private volatile int totalCount;
    1516         private volatile int processedCount = 0;
    1517         private TileLoader tileLoader;
     1516        private int totalCount;
     1517        private AtomicInteger processedCount = new AtomicInteger(0);
     1518        private final TileLoader tileLoader;
    15181519
    15191520        /**
     
    15341535         */
    15351536        public boolean isFinished() {
    1536             return processedCount >= totalCount;
     1537            return processedCount.get() >= totalCount;
    15371538        }
    15381539
     
    15561557        public void tileLoadingFinished(Tile tile, boolean success) {
    15571558            if (success) {
    1558                 this.processedCount++;
     1559                int processed = this.processedCount.incrementAndGet();
    15591560                this.progressMonitor.worked(1);
    1560                 this.progressMonitor.setCustomText(tr("Downloaded {0}/{1} tiles", processedCount, totalCount));
     1561                this.progressMonitor.setCustomText(tr("Downloaded {0}/{1} tiles", processed, totalCount));
    15611562            }
    15621563        }
  • trunk/src/org/openstreetmap/josm/gui/layer/ImageryLayer.java

    r8540 r8568  
    4141import org.openstreetmap.josm.data.ProjectionBounds;
    4242import org.openstreetmap.josm.data.imagery.ImageryInfo;
    43 import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
    4443import org.openstreetmap.josm.data.imagery.OffsetBookmark;
    4544import org.openstreetmap.josm.data.preferences.ColorProperty;
     
    153152
    154153    public static ImageryLayer create(ImageryInfo info) {
    155         ImageryType type = info.getImageryType();
    156         if (type == ImageryType.WMS || type == ImageryType.HTML)
     154        switch(info.getImageryType()) {
     155        case WMS:
     156        case HTML:
    157157            return new WMSLayer(info);
    158         else if (type == ImageryType.TMS || type == ImageryType.BING || type == ImageryType.SCANEX)
     158        case WMTS:
     159            return new WMTSLayer(info);
     160        case TMS:
     161        case BING:
     162        case SCANEX:
    159163            return new TMSLayer(info);
    160         else throw new AssertionError();
     164        default:
     165            throw new AssertionError(tr("Unsupported imagery type: {0}", info.getImageryType()));
     166        }
    161167    }
    162168
  • trunk/src/org/openstreetmap/josm/gui/layer/TMSLayer.java

    r8540 r8568  
    7878    }
    7979
    80     @Override
    81     protected Map<String, String> getHeaders(TileSource tileSource) {
    82         if (tileSource instanceof TemplatedTMSTileSource) {
    83             return ((TemplatedTMSTileSource) tileSource).getHeaders();
    84         }
    85         return null;
    86     }
    87 
    8880    /**
    8981     * Creates and returns a new TileSource instance depending on the {@link ImageryType}
  • trunk/src/org/openstreetmap/josm/gui/preferences/imagery/AddImageryPanel.java

    r8513 r8568  
    1616
    1717import org.openstreetmap.josm.data.imagery.ImageryInfo;
     18import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
    1819import org.openstreetmap.josm.gui.widgets.JosmTextArea;
    1920import org.openstreetmap.josm.gui.widgets.JosmTextField;
     
    8687    }
    8788
     89    protected static String sanitize(String s, ImageryType type) {
     90        String ret = s;
     91        String imageryType = type.getTypeString() + ":";
     92        if (ret.startsWith(imageryType)) {
     93            // remove ImageryType from URL
     94            ret = ret.substring(imageryType.length());
     95        }
     96        return sanitize(ret);
     97    }
     98
    8899    protected final String getImageryName() {
    89100        return sanitize(name.getText());
  • trunk/src/org/openstreetmap/josm/gui/preferences/imagery/AddTMSLayerPanel.java

    r8390 r8568  
    1111
    1212import org.openstreetmap.josm.data.imagery.ImageryInfo;
     13import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
    1314import org.openstreetmap.josm.gui.widgets.JosmTextArea;
    1415import org.openstreetmap.josm.gui.widgets.JosmTextField;
     
    7172            a.append('[').append(z).append(']');
    7273        }
    73         a.append(':').append(getImageryRawUrl());
     74        a.append(':').append(sanitize(getImageryRawUrl(), ImageryType.TMS));
    7475        return a.toString();
    7576    }
  • trunk/src/org/openstreetmap/josm/gui/preferences/imagery/AddWMSLayerPanel.java

    r8426 r8568  
    178178
    179179    protected final String getWmsUrl() {
    180         return sanitize(wmsUrl.getText());
     180        return sanitize(wmsUrl.getText(), ImageryInfo.ImageryType.WMS);
    181181    }
    182182
  • trunk/src/org/openstreetmap/josm/gui/preferences/imagery/ImageryPreference.java

    r8510 r8568  
    389389            activeToolbar.add(new NewEntryAction(ImageryInfo.ImageryType.WMS));
    390390            activeToolbar.add(new NewEntryAction(ImageryInfo.ImageryType.TMS));
     391            activeToolbar.add(new NewEntryAction(ImageryInfo.ImageryType.WMTS));
    391392            //activeToolbar.add(edit); TODO
    392393            activeToolbar.add(remove);
     
    482483                putValue(SHORT_DESCRIPTION, tr("Add a new {0} entry by entering the URL", type.toString()));
    483484                String icon = /* ICON(dialogs/) */ "add";
    484                 if (ImageryInfo.ImageryType.WMS.equals(type))
     485                switch (type) {
     486                case WMS:
    485487                    icon = /* ICON(dialogs/) */ "add_wms";
    486                 else if (ImageryInfo.ImageryType.TMS.equals(type))
     488                    break;
     489                case TMS:
    487490                    icon = /* ICON(dialogs/) */ "add_tms";
     491                    break;
     492                case WMTS:
     493                    icon = /* ICON(dialogs/) */ "add_wmts";
     494                    break;
     495                default:
     496                    break;
     497                }
    488498                putValue(SMALL_ICON, ImageProvider.get("dialogs", icon));
    489499                this.type = type;
     
    493503            public void actionPerformed(ActionEvent evt) {
    494504                final AddImageryPanel p;
    495                 if (ImageryInfo.ImageryType.WMS.equals(type)) {
     505                switch (type) {
     506                case WMS:
    496507                    p = new AddWMSLayerPanel();
    497                 } else if (ImageryInfo.ImageryType.TMS.equals(type)) {
     508                    break;
     509                case TMS:
    498510                    p = new AddTMSLayerPanel();
    499                 } else {
     511                    break;
     512                case WMTS:
     513                    p = new AddWMTSLayerPanel();
     514                    break;
     515                default:
    500516                    throw new IllegalStateException("Type " + type + " not supported");
    501517                }
  • trunk/src/org/openstreetmap/josm/io/CachedFile.java

    r8510 r8568  
    2020import java.util.Enumeration;
    2121import java.util.List;
     22import java.util.Map;
     23import java.util.Map.Entry;
     24import java.util.concurrent.ConcurrentHashMap;
    2225import java.util.zip.ZipEntry;
    2326import java.util.zip.ZipFile;
     
    7275    public static final long DAYS = 24*60*60; // factor to get caching time in days
    7376
     77    private Map<String, String> httpHeaders = new ConcurrentHashMap<>();
     78
    7479    /**
    7580     * Constructs a CachedFile object from a given filename, URL or internal resource.
     
    142147    public CachedFile setCachingStrategy(CachingStrategy cachingStrategy) {
    143148        this.cachingStrategy = cachingStrategy;
     149        return this;
     150    }
     151
     152    /**
     153     * Sets the http headers. Only applies to URL pointing to http or https resources
     154     * @param headers that should be sent together with request
     155     * @return this object
     156     */
     157    public CachedFile setHttpHeaders(Map<String, String> headers) {
     158        this.httpHeaders.putAll(headers);
    144159        return this;
    145160    }
     
    397412        destDirFile = new File(destDir, localPath + ".tmp");
    398413        try {
    399             HttpURLConnection con = connectFollowingRedirect(url, httpAccept, ifModifiedSince);
     414            HttpURLConnection con = connectFollowingRedirect(url, httpAccept, ifModifiedSince, httpHeaders);
    400415            if (ifModifiedSince != null && con.getResponseCode() == HttpURLConnection.HTTP_NOT_MODIFIED) {
    401416                if (Main.isDebugEnabled()) {
     
    464479    public static HttpURLConnection connectFollowingRedirect(URL downloadUrl, String httpAccept, Long ifModifiedSince)
    465480            throws MalformedURLException, IOException {
     481        return connectFollowingRedirect(downloadUrl, httpAccept, ifModifiedSince, null);
     482    }
     483    /**
     484     * Opens a connection for downloading a resource.
     485     * <p>
     486     * Manually follows redirects because
     487     * {@link HttpURLConnection#setFollowRedirects(boolean)} fails if the redirect
     488     * is going from a http to a https URL, see <a href="https://bugs.openjdk.java.net/browse/JDK-4620571">bug report</a>.
     489     * <p>
     490     * This can cause problems when downloading from certain GitHub URLs.
     491     *
     492     * @param downloadUrl The resource URL to download
     493     * @param httpAccept The accepted MIME types sent in the HTTP Accept header. Can be {@code null}
     494     * @param ifModifiedSince The download time of the cache file, optional
     495     * @param headers http headers to be sent together with http request
     496     * @return The HTTP connection effectively linked to the resource, after all potential redirections
     497     * @throws MalformedURLException If a redirected URL is wrong
     498     * @throws IOException If any I/O operation goes wrong
     499     * @throws OfflineAccessException if resource is accessed in offline mode, in any protocol
     500     * @since TODO
     501     */
     502    public static HttpURLConnection connectFollowingRedirect(URL downloadUrl, String httpAccept, Long ifModifiedSince, Map<String, String> headers)
     503            throws MalformedURLException, IOException {
    466504        CheckParameterUtil.ensureParameterNotNull(downloadUrl, "downloadUrl");
    467505        String downloadString = downloadUrl.toExternalForm();
     
    474512            if (ifModifiedSince != null) {
    475513                con.setIfModifiedSince(ifModifiedSince);
     514            }
     515            if (headers != null) {
     516                for (Entry<String, String> header: headers.entrySet()) {
     517                    con.setRequestProperty(header.getKey(), header.getValue());
     518                }
    476519            }
    477520            con.setInstanceFollowRedirects(false);
  • trunk/src/org/openstreetmap/josm/tools/Utils.java

    r8567 r8568  
    1414import java.awt.datatransfer.UnsupportedFlavorException;
    1515import java.io.BufferedReader;
     16import java.io.ByteArrayOutputStream;
    1617import java.io.Closeable;
    1718import java.io.File;
     
    13371338        return hasExtension(file.getName(), extensions);
    13381339    }
     1340
     1341    /**
     1342     * Reads the input stream and closes the stream at the end of processing (regardless if an exception was thrown)
     1343     *
     1344     * @param stream
     1345     * @return byte array of data in input stream
     1346     * @throws IOException
     1347     */
     1348    public static byte[] readBytesFromStream(InputStream stream) throws IOException {
     1349        try {
     1350            ByteArrayOutputStream bout = new ByteArrayOutputStream(stream.available());
     1351            byte[] buffer = new byte[2048];
     1352            boolean finished = false;
     1353            do {
     1354                int read = stream.read(buffer);
     1355                if (read >= 0) {
     1356                    bout.write(buffer, 0, read);
     1357                } else {
     1358                    finished = true;
     1359                }
     1360            } while (!finished);
     1361            if (bout.size() == 0)
     1362                return null;
     1363            return bout.toByteArray();
     1364        } finally {
     1365            stream.close();
     1366        }
     1367    }
    13391368}
Note: See TracChangeset for help on using the changeset viewer.