001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.plugins.streetside.io.export; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.awt.image.BufferedImage; 007import java.io.IOException; 008import java.util.HashSet; 009import java.util.Set; 010import java.util.concurrent.ArrayBlockingQueue; 011import java.util.concurrent.ThreadPoolExecutor; 012import java.util.concurrent.TimeUnit; 013 014import org.apache.log4j.Logger; 015import org.openstreetmap.josm.gui.PleaseWaitRunnable; 016import org.openstreetmap.josm.gui.progress.swing.PleaseWaitProgressMonitor; 017import org.openstreetmap.josm.plugins.streetside.StreetsideAbstractImage; 018import org.openstreetmap.josm.plugins.streetside.StreetsideImage; 019 020/** 021 * Export main thread. Exportation works by creating a 022 * {@link StreetsideExportWriterThread} and several 023 * {@link StreetsideExportDownloadThread}. The second ones download every single 024 * image that is going to be exported and stores them in an 025 * {@link ArrayBlockingQueue}. Then it is picked by the first one and written on 026 * the selected folder. Each image will be named by its key. 027 * 028 * @author nokutu 029 * @see StreetsideExportWriterThread 030 * @see StreetsideExportDownloadThread 031 */ 032public class StreetsideExportManager extends PleaseWaitRunnable { 033 034 final static Logger logger = Logger.getLogger(StreetsideExportManager.class); 035 036 private final ArrayBlockingQueue<BufferedImage> queue = new ArrayBlockingQueue<>(10); 037 private final ArrayBlockingQueue<StreetsideAbstractImage> queueImages = new ArrayBlockingQueue<>(10); 038 039 private int amount; 040 private Set<StreetsideAbstractImage> images; 041 private String path; 042 043 private Thread writer; 044 private ThreadPoolExecutor ex; 045 046 /** 047 * Main constructor. 048 * 049 * @param images Set of {@link StreetsideAbstractImage} objects to be exported. 050 * @param path Export path. 051 */ 052 public StreetsideExportManager(Set<StreetsideAbstractImage> images, String path) { 053 super( 054 tr("Downloading") + "…", 055 new PleaseWaitProgressMonitor(tr("Exporting Streetside Images")), 056 true 057 ); 058 this.images = images == null ? new HashSet<>() : images; 059 this.path = path; 060 amount = this.images.size(); 061 } 062 063 @Override 064 protected void cancel() { 065 writer.interrupt(); 066 ex.shutdown(); 067 } 068 069 @Override 070 protected void realRun() throws IOException { 071 // Starts a writer thread in order to write the pictures on the disk. 072 writer = new StreetsideExportWriterThread(path, queue, 073 queueImages, amount, getProgressMonitor()); 074 writer.start(); 075 if (path == null) { 076 try { 077 writer.join(); 078 } catch (InterruptedException e) { 079 logger.error(e); 080 } 081 return; 082 } 083 ex = new ThreadPoolExecutor(20, 35, 25, TimeUnit.SECONDS, 084 new ArrayBlockingQueue<>(10)); 085 for (StreetsideAbstractImage image : images) { 086 if (image instanceof StreetsideImage) { 087 try { 088 ex.execute(new StreetsideExportDownloadThread( 089 (StreetsideImage) image, queue, queueImages)); 090 } catch (Exception e) { 091 logger.error(e); 092 } 093 } 094 try { 095 // If the queue is full, waits for it to have more space 096 // available before executing anything else. 097 while (ex.getQueue().remainingCapacity() == 0) { 098 Thread.sleep(100); 099 } 100 } catch (Exception e) { 101 logger.error(e); 102 } 103 } 104 try { 105 writer.join(); 106 } catch (InterruptedException e) { 107 logger.error(e); 108 } 109 } 110 111 @Override 112 protected void finish() { 113 } 114}