package org.docear.plugin.services.upload; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.net.URI; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import java.util.Set; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import org.docear.plugin.core.DocearController; import org.docear.plugin.core.features.DocearMapModelExtension; import org.docear.plugin.core.io.DirectoryObserver; import org.docear.plugin.core.logging.DocearLogger; import org.docear.plugin.services.ServiceController; import org.docear.plugin.services.communications.CommunicationsController; import org.freeplane.features.map.MapModel; import org.freeplane.plugin.workspace.WorkspaceUtils; public abstract class UploadController { private final File uploadBufferDirectory = new File(CommunicationsController.getController().getCommunicationsQueuePath(), "mindmaps"); private static FileFilter zipFilter = new FileFilter() { public boolean accept(File f) { return (f != null && f.getName().toLowerCase().endsWith(".zip")); } }; private final Map<String, MapModel> mapUploadQueue = new HashMap<String, MapModel>(); private final Set<DirectoryObserver> observers = new HashSet<DirectoryObserver>(); private final Runnable packerRunner = new Runnable() { public void run() { createPackages(); } }; private final CyclicUploadPacker packerThread = new CyclicUploadPacker(packerRunner, (180)); //every 3 minutes private final UploadThread uploadThread = new UploadThread(this); /** * @return */ public abstract boolean isInformationRetrievalAllowed(); /** * @return */ public abstract boolean isBackupAllowed(); /** * Provides the time in minutes until the next upload cycle should be started * * @return time to wait until the next upload cycle */ public abstract int getUploadInterval(); /** * @return */ public File[] getUploadPackages() { return getUploadDirectory().listFiles(zipFilter); } /** * @return */ public File getUploadDirectory() { if (!uploadBufferDirectory.exists()) { uploadBufferDirectory.mkdirs(); } return uploadBufferDirectory; } /** * @param map */ public void addMapToUpload(MapModel map) { boolean backup = isBackupAllowed(); boolean ir = isInformationRetrievalAllowed(); File file = map.getFile(); if(file == null || (!backup && !ir)) { return; } DocearMapModelExtension mapExt = map.getExtension(DocearMapModelExtension.class); if(mapExt != null && mapExt.getMapId() != null) { synchronized (mapUploadQueue) { mapUploadQueue.put(mapExt.getMapId(), map); } } } /** * @param observer */ public void addUploadDirectoryObserver(DirectoryObserver observer) { synchronized (observers) { observers.add(observer); } } /** * @param observer */ public void removeUploadDirectoryObserver(DirectoryObserver observer) { synchronized (observers) { observers.remove(observer); } } /** * @return */ protected Thread getPacker() { return this.packerThread; } /** * @return */ protected Thread getUploader() { return this.uploadThread; } /** * */ private void createPackages() { synchronized (mapUploadQueue) { Iterator<Entry<String, MapModel>> iter = mapUploadQueue.entrySet().iterator(); while(iter.hasNext()) { Entry<String, MapModel> entry = iter.next(); createMapPackage(entry.getValue()); iter.remove(); } } } /** * @param file */ protected final void fireFileCreated(File file) { synchronized (observers) { for(DirectoryObserver observer : observers) { observer.fileCreated(file); } } } /** * @param file */ protected final void fireFileRemoved(File file) { synchronized (observers) { for(DirectoryObserver observer : observers) { observer.fileRemoved(file); } } } /** * @param map */ private void createMapPackage(final MapModel map) { if (map == null) { return; } final Properties meta = getMapProperties(map); if (meta == null) { return; } Thread thread = new Thread() { public void run() { try { File backupFile = new File(getUploadDirectory().getAbsolutePath(), System.currentTimeMillis() + "_" + map.getFile().getName() + ".zip"); FileOutputStream fout = null; ZipOutputStream out = null; InputStream in = null; try { fout = new FileOutputStream(backupFile); out = new ZipOutputStream(fout); in = new FileInputStream(map.getFile()); ZipEntry entry = new ZipEntry("metadata.inf"); out.putNextEntry(entry); meta.store(out, ""); entry = new ZipEntry(map.getFile().getName()); out.putNextEntry(entry); while (true) { int data = in.read(); if (data == -1) { break; } out.write(data); } out.flush(); } finally { in.close(); out.close(); fout.close(); fireFileCreated(backupFile); DocearController.getController().removeWorkingThreadHandle(this.getName()); } } catch (Exception e) { DocearLogger.warn("org.docear.plugin.services.upload.UploadController.createMapPackage(): "+e.getMessage()); } } }; DocearController.getController().addWorkingThreadHandle(thread.getName()); thread.start(); } /** * @param map * @return */ private Properties getMapProperties(MapModel map) { ServiceController serviceController = ServiceController.getController(); DocearController docearController = DocearController.getController(); DocearMapModelExtension dmme = map.getExtension(DocearMapModelExtension.class); if (dmme == null) { return null; } boolean isLibraryMap = false; for (URI uri : DocearController.getController().getLibrary().getMindmaps()) { if (uri != null && map != null) { String path = map.getFile().getAbsolutePath(); File f = WorkspaceUtils.resolveURI(uri); if (f != null && f.getAbsolutePath().equals(path)) { isLibraryMap = true; } } } String typeName = (dmme.getType() == null ? "" : dmme.getType().name()); Properties properties = new Properties(); properties.put("mindmap_id", dmme.getMapId()); properties.put("timestamp", ""+System.currentTimeMillis()); properties.put("is_library_map", new Boolean(isLibraryMap).toString()); properties.put("backup", new Boolean(serviceController.isBackupAllowed()).toString()); properties.put("allow_content_research", new Boolean(serviceController.isResearchAllowed()).toString()); properties.put("allow_information_retrieval", new Boolean(serviceController.isInformationRetrievalSelected()).toString()); properties.put("allow_usage_research", new Boolean(serviceController.isUsageMiningAllowed()).toString()); properties.put("allow_recommendations", new Boolean(serviceController.isRecommendationsAllowed()).toString()); if (typeName != null && typeName.trim().length()>0) { properties.put("map_type", typeName); } properties.put("map_version", dmme.getVersion()); properties.put("application_name", docearController.getApplicationName()); properties.put("application_version", docearController.getApplicationVersion()); properties.put("application_status", docearController.getApplicationStatus()); properties.put("application_status_version", docearController.getApplicationStatusVersion()); properties.put("application_build", ""+docearController.getApplicationBuildNumber()); properties.put("application_date", docearController.getApplicationBuildDate()); properties.put("filesize", ""+map.getFile().length()); properties.put("filename", map.getFile().getName()); properties.put("filepath", map.getFile().getAbsolutePath()); return properties; } /** * */ public void finishThreads() { String runnerID = Integer.toHexString(this.hashCode()); DocearController.getController().addWorkingThreadHandle(runnerID); packerRunner.run(); DocearController.getController().removeWorkingThreadHandle(runnerID); } public void shutdown() { this.packerThread.terminate(); this.uploadThread.terminate(); } }