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.List; 010import java.util.Set; 011import java.util.concurrent.ArrayBlockingQueue; 012import java.util.concurrent.ThreadPoolExecutor; 013import java.util.concurrent.TimeUnit; 014 015import org.apache.log4j.Logger; 016import org.openstreetmap.josm.gui.PleaseWaitRunnable; 017import org.openstreetmap.josm.gui.progress.swing.PleaseWaitProgressMonitor; 018import org.openstreetmap.josm.plugins.streetside.StreetsideAbstractImage; 019import org.openstreetmap.josm.plugins.streetside.StreetsideImage; 020import org.openstreetmap.josm.plugins.streetside.StreetsideImportedImage; 021 022/** 023 * Export main thread. Exportation works by creating a 024 * {@link StreetsideExportWriterThread} and several 025 * {@link StreetsideExportDownloadThread}. The second ones download every single 026 * image that is going to be exported and stores them in an 027 * {@link ArrayBlockingQueue}. Then it is picked by the first one and written on 028 * the selected folder. Each image will be named by its key. 029 * 030 * @author nokutu 031 * @see StreetsideExportWriterThread 032 * @see StreetsideExportDownloadThread 033 */ 034public class StreetsideExportManager extends PleaseWaitRunnable { 035 036 final static Logger logger = Logger.getLogger(StreetsideExportManager.class); 037 038 private final ArrayBlockingQueue<BufferedImage> queue = new ArrayBlockingQueue<>(10); 039 private final ArrayBlockingQueue<StreetsideAbstractImage> queueImages = new ArrayBlockingQueue<>(10); 040 041 private int amount; 042 private Set<StreetsideAbstractImage> images; 043 private String path; 044 045 private Thread writer; 046 private ThreadPoolExecutor ex; 047 048 /** 049 * Main constructor. 050 * 051 * @param images Set of {@link StreetsideAbstractImage} objects to be exported. 052 * @param path Export path. 053 */ 054 public StreetsideExportManager(Set<StreetsideAbstractImage> images, String path) { 055 super( 056 tr("Downloading") + "…", 057 new PleaseWaitProgressMonitor(tr("Exporting Streetside Images")), 058 true 059 ); 060 this.images = images == null ? new HashSet<>() : images; 061 this.path = path; 062 amount = this.images.size(); 063 } 064 065 /** 066 * Constructor used to rewrite imported images. 067 * 068 * @param images 069 * The set of {@link StreetsideImportedImage} object that is going to 070 * be rewritten. 071 * @throws IOException 072 * If the file of one of the {@link StreetsideImportedImage} objects 073 * doesn't contain a picture. 074 */ 075 public StreetsideExportManager(List<StreetsideImportedImage> images) throws IOException { 076 this(null, null); 077 for (StreetsideImportedImage image : images) { 078 queue.add(image.getImage()); 079 queueImages.add(image); 080 } 081 amount = images.size(); 082 } 083 084 @Override 085 protected void cancel() { 086 writer.interrupt(); 087 ex.shutdown(); 088 } 089 090 @Override 091 protected void realRun() throws IOException { 092 // Starts a writer thread in order to write the pictures on the disk. 093 writer = new StreetsideExportWriterThread(path, queue, 094 queueImages, amount, getProgressMonitor()); 095 writer.start(); 096 if (path == null) { 097 try { 098 writer.join(); 099 } catch (InterruptedException e) { 100 logger.error(e); 101 } 102 return; 103 } 104 ex = new ThreadPoolExecutor(20, 35, 25, TimeUnit.SECONDS, 105 new ArrayBlockingQueue<>(10)); 106 for (StreetsideAbstractImage image : images) { 107 if (image instanceof StreetsideImage) { 108 try { 109 ex.execute(new StreetsideExportDownloadThread( 110 (StreetsideImage) image, queue, queueImages)); 111 } catch (Exception e) { 112 logger.error(e); 113 } 114 } else if (image instanceof StreetsideImportedImage) { 115 try { 116 queue.put(((StreetsideImportedImage) image).getImage()); 117 queueImages.put(image); 118 } catch (InterruptedException e) { 119 logger.error(e); 120 } 121 } 122 try { 123 // If the queue is full, waits for it to have more space 124 // available before executing anything else. 125 while (ex.getQueue().remainingCapacity() == 0) { 126 Thread.sleep(100); 127 } 128 } catch (Exception e) { 129 logger.error(e); 130 } 131 } 132 try { 133 writer.join(); 134 } catch (InterruptedException e) { 135 logger.error(e); 136 } 137 } 138 139 @Override 140 protected void finish() { 141 } 142}