--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>\r
+<classpath>\r
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>\r
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>\r
+ <classpathentry kind="src" path="src"/>\r
+ <classpathentry kind="output" path="bin"/>\r
+</classpath>\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>\r
+<projectDescription>\r
+ <name>org.simantics.filesystem.services</name>\r
+ <comment></comment>\r
+ <projects>\r
+ </projects>\r
+ <buildSpec>\r
+ <buildCommand>\r
+ <name>org.eclipse.jdt.core.javabuilder</name>\r
+ <arguments>\r
+ </arguments>\r
+ </buildCommand>\r
+ <buildCommand>\r
+ <name>org.eclipse.pde.ManifestBuilder</name>\r
+ <arguments>\r
+ </arguments>\r
+ </buildCommand>\r
+ <buildCommand>\r
+ <name>org.eclipse.pde.SchemaBuilder</name>\r
+ <arguments>\r
+ </arguments>\r
+ </buildCommand>\r
+ <buildCommand>\r
+ <name>org.eclipse.pde.ds.core.builder</name>\r
+ <arguments>\r
+ </arguments>\r
+ </buildCommand>\r
+ </buildSpec>\r
+ <natures>\r
+ <nature>org.eclipse.pde.PluginNature</nature>\r
+ <nature>org.eclipse.jdt.core.javanature</nature>\r
+ </natures>\r
+</projectDescription>\r
--- /dev/null
+eclipse.preferences.version=1\r
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled\r
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8\r
+org.eclipse.jdt.core.compiler.compliance=1.8\r
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error\r
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error\r
+org.eclipse.jdt.core.compiler.source=1.8\r
--- /dev/null
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Workspace Size Monitoring Service
+Bundle-SymbolicName: org.simantics.filesystem.services
+Bundle-Version: 1.0.0.qualifier
+Bundle-Activator: org.simantics.filesystem.services.internal.Activator
+Require-Bundle: org.eclipse.core.runtime,
+ org.eclipse.osgi.services,
+ org.simantics.utils.datastructures,
+ org.slf4j.api
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Bundle-ActivationPolicy: lazy
+Bundle-Vendor: Semantum Oy
+Export-Package: org.simantics.filesystem.services.sizetracker
+Service-Component: OSGI-INF/org.simantics.filesystem.services.internal.sizetracker.DirectorySizeServiceImpl.xml
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="activate" deactivate="deactivate" name="org.simantics.filesystem.services.internal.sizetracker.DirectorySizeServiceImpl">
+ <service>
+ <provide interface="org.simantics.filesystem.services.sizetracker.DirectorySizeService"/>
+ </service>
+ <implementation class="org.simantics.filesystem.services.internal.sizetracker.DirectorySizeServiceImpl"/>
+</scr:component>
\ No newline at end of file
--- /dev/null
+source.. = src/\r
+output.. = bin/\r
+bin.includes = META-INF/,\\r
+ .,\\r
+ OSGI-INF/\r
--- /dev/null
+package org.simantics.filesystem.services.internal;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+/**
+ * @author Tuukka Lehtonen
+ * @since 1.31.0
+ */
+public class Activator implements BundleActivator {
+
+ private static BundleContext context;
+
+ static BundleContext getContext() {
+ return context;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
+ */
+ public void start(BundleContext bundleContext) throws Exception {
+ Activator.context = bundleContext;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
+ */
+ public void stop(BundleContext bundleContext) throws Exception {
+ Activator.context = null;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+package org.simantics.filesystem.services.internal.sizetracker;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.simantics.filesystem.services.sizetracker.DirectorySizeService;
+import org.simantics.filesystem.services.sizetracker.SizeTracker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Tuukka Lehtonen
+ * @since 1.31.0
+ */
+@Component
+public class DirectorySizeServiceImpl implements DirectorySizeService {
+
+ private Logger logger = LoggerFactory.getLogger(DirectorySizeServiceImpl.class);
+
+ private final Map<Path, SizeTrackerImpl> trackers = new HashMap<>();
+
+ @Override
+ public SizeTracker track(Path directory) throws IOException {
+ synchronized (trackers) {
+ SizeTrackerImpl tracker = trackers.get(directory);
+ if (tracker != null)
+ return tracker;
+ tracker = new SizeTrackerImpl(this, directory);
+ try {
+ tracker.start();
+ trackers.put(directory, tracker);
+ return tracker;
+ } catch (IOException e) {
+ safeCloseTracker(tracker);
+ throw e;
+ }
+ }
+ }
+
+ void removeTracker(Path path) {
+ synchronized (trackers) {
+ trackers.remove(path);
+ }
+ }
+
+ public void shutdown() {
+ synchronized (trackers) {
+ trackers.forEach((p,t) -> safeCloseTracker(t));
+ trackers.clear();
+ }
+ }
+
+ private void safeCloseTracker(SizeTrackerImpl t) {
+ try {
+ t.close();
+ } catch (IOException e) {
+ logger.error("Error closing size tracker {}", t, e);
+ }
+ }
+
+ @Activate
+ public void activate() {
+ //System.out.println("Activated DirectorySizeServiceImpl");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ //System.out.println("Deactivated DirectorySizeServiceImpl");
+ shutdown();
+ }
+
+}
--- /dev/null
+package org.simantics.filesystem.services.internal.sizetracker;
+
+import java.nio.file.Path;
+
+import org.simantics.filesystem.services.sizetracker.SizeChangeEvent;
+
+/**
+ * @author Tuukka Lehtonen
+ * @since 1.31.0
+ */
+public class SizeChangeEventImpl implements SizeChangeEvent {
+
+ private final Path path;
+ private final long oldSize;
+ private final long newSize;
+
+ public SizeChangeEventImpl(Path path, long oldSize, long newSize) {
+ this.path = path;
+ this.oldSize = oldSize;
+ this.newSize = newSize;
+ }
+
+ @Override
+ public Path path() {
+ return path;
+ }
+
+ @Override
+ public long newSize() {
+ return newSize;
+ }
+
+ @Override
+ public long oldSize() {
+ return oldSize;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+package org.simantics.filesystem.services.internal.sizetracker;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.Consumer;
+import java.util.function.LongConsumer;
+
+import org.simantics.filesystem.services.sizetracker.SizeChangeEvent;
+import org.simantics.filesystem.services.sizetracker.SizeTracker;
+import org.simantics.utils.datastructures.file.DirectorySizeTracker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Tuukka Lehtonen
+ * @since 1.31.0
+ *
+ * TODO: change to use quiet time and "post notification" to throttle updates
+ */
+public class SizeTrackerImpl implements SizeTracker {
+
+ private Logger logger = LoggerFactory.getLogger(SizeTrackerImpl.class);
+
+ private Path path;
+ private DirectorySizeServiceImpl service;
+ private DirectorySizeTracker tracker;
+ private CopyOnWriteArrayList<Consumer<SizeChangeEvent>> listeners = new CopyOnWriteArrayList<>();
+ private volatile long oldSize = 0L;
+
+ private LongConsumer theListener = newSize -> {
+ long os = oldSize;
+ oldSize = newSize;
+ //logger.info(path + ": size changed: " + ((double) os / (1024.0*1024.0)) + " MB -> " + ((double) newSize / (1024.0*1024.0)) + " MB");
+ fireSizeChange(os, newSize);
+ };
+
+ public SizeTrackerImpl(DirectorySizeServiceImpl service, Path path) throws IOException {
+ this.service = service;
+ this.path = path;
+ this.tracker = DirectorySizeTracker.startTracker(theListener);
+ }
+
+ public SizeTrackerImpl start() throws IOException {
+ new Thread(() -> {
+ try {
+ synchronized (SizeTrackerImpl.this) {
+ if (tracker != null)
+ tracker.track(path);
+ }
+ } catch (IOException e) {
+ logger.error("Failed to start tracking size of directory " + path, e);
+ }
+ }, "SizeTrackerStarter").start();
+ return this;
+ }
+
+ @Override
+ public synchronized void close() throws IOException {
+ if (tracker == null)
+ return;
+ tracker.close();
+ tracker = null;
+ service.removeTracker(path);
+ }
+
+ @Override
+ public Path path() {
+ return path;
+ }
+
+ @Override
+ public long size() {
+ return oldSize;
+ }
+
+ @Override
+ public void addListener(Consumer<SizeChangeEvent> listener) {
+ listeners.add(listener);
+ }
+
+ @Override
+ public void removeListener(Consumer<SizeChangeEvent> listener) {
+ listeners.remove(listener);
+ }
+
+ private void fireSizeChange(long oldSize, long newSize) {
+ SizeChangeEvent e = new SizeChangeEventImpl(path, oldSize, newSize);
+ listeners.forEach(c -> c.accept(e));
+ }
+
+}
--- /dev/null
+package org.simantics.filesystem.services.sizetracker;
+
+import java.io.IOException;
+import java.nio.file.Path;
+
+/**
+ * @author Tuukka Lehtonen
+ * @since 1.31.0
+ */
+public interface DirectorySizeService {
+
+ SizeTracker track(Path directory) throws IOException;
+
+}
--- /dev/null
+package org.simantics.filesystem.services.sizetracker;
+
+import java.nio.file.Path;
+
+/**
+ * @author Tuukka Lehtonen
+ * @since 1.31.0
+ */
+public interface SizeChangeEvent {
+
+ Path path();
+
+ long newSize();
+
+ long oldSize();
+
+}
--- /dev/null
+package org.simantics.filesystem.services.sizetracker;
+
+import java.io.Closeable;
+import java.nio.file.Path;
+import java.util.function.Consumer;
+
+/**
+ * @author Tuukka Lehtonen
+ * @since 1.31.0
+ */
+public interface SizeTracker extends Closeable {
+
+ Path path();
+ long size();
+
+ void addListener(Consumer<SizeChangeEvent> listener);
+ void removeListener(Consumer<SizeChangeEvent> listener);
+
+}
<module>org.simantics.export.core</module>
<module>org.simantics.export.ui</module>
<module>org.simantics.fastlz</module>
+ <module>org.simantics.filesystem.services</module>
<module>org.simantics.fileimport</module>
<module>org.simantics.fileimport.ui</module>
<module>org.simantics.g2d</module>
version="0.0.0"
unpack="false"/>
+ <plugin
+ id="org.simantics.filesystem.services"
+ download-size="0"
+ install-size="0"
+ version="0.0.0"
+ unpack="false"/>
+
<plugin
id="org.simantics.backup.ontology"
download-size="0"