mirror of
https://github.com/elisspace/autopsy.git
synced 2026-09-06 02:24:30 +00:00
Merge branch 'master' of github.com:sleuthkit/autopsy
This commit is contained in:
@@ -4,5 +4,7 @@ HINT_IngestTopComponent=Ingest window
|
||||
OpenIDE-Module-Name=Ingest
|
||||
IngestTopComponent.topLable.text=Image ingest services
|
||||
IngestTopComponent.startButton.text=Start
|
||||
IngestTopComponent.refreshFreqLabel.text=Refresh frequency
|
||||
IngestTopComponent.messageFrame.title=Ingest Messages
|
||||
IngestTopComponent.refreshFreqLabel.text=Refresh frequency
|
||||
IngestTopComponent.refreshFrequencyLabel.text=Refresh Frequency
|
||||
IngestTopComponent.ingestProgressLabel.text=File Ingest Progress
|
||||
|
||||
117
Ingest/src/org/sleuthkit/autopsy/ingest/IngestImageThread.java
Normal file
117
Ingest/src/org/sleuthkit/autopsy/ingest/IngestImageThread.java
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.ingest;
|
||||
|
||||
//ingester worker for image queue
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.swing.SwingWorker;
|
||||
import org.netbeans.api.progress.ProgressHandle;
|
||||
import org.netbeans.api.progress.ProgressHandleFactory;
|
||||
import org.openide.util.Cancellable;
|
||||
import org.sleuthkit.datamodel.Image;
|
||||
|
||||
/**
|
||||
* worker for every ingest image service
|
||||
* there is a separate instance per image / service pair
|
||||
*/
|
||||
public class IngestImageThread extends SwingWorker {
|
||||
|
||||
private Logger logger = Logger.getLogger(IngestImageThread.class.getName());
|
||||
private ProgressHandle progress;
|
||||
private Image image;
|
||||
private IngestServiceImage service;
|
||||
private IngestImageWorkerController controller;
|
||||
private IngestManager manager;
|
||||
|
||||
IngestImageThread(IngestManager manager, Image image, IngestServiceImage service) {
|
||||
this.manager = manager;
|
||||
this.image = image;
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
Image getImage() {
|
||||
return image;
|
||||
}
|
||||
|
||||
IngestServiceImage getService() {
|
||||
return service;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object doInBackground() throws Exception {
|
||||
|
||||
logger.log(Level.INFO, "Starting background processing");
|
||||
|
||||
progress = ProgressHandleFactory.createHandle(service.getName() + " image id:" + image.getId(), new Cancellable() {
|
||||
|
||||
@Override
|
||||
public boolean cancel() {
|
||||
return IngestImageThread.this.cancel(true);
|
||||
}
|
||||
});
|
||||
|
||||
progress.start();
|
||||
progress.switchToIndeterminate();
|
||||
|
||||
controller = new IngestImageWorkerController(this, progress);
|
||||
|
||||
if (isCancelled()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
service.process(image, controller);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.INFO, "Exception in service: " + service.getName() + " image: " + image.getName(), e);
|
||||
}
|
||||
logger.log(Level.INFO,
|
||||
"Done background processing");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done() {
|
||||
try {
|
||||
super.get(); //block and get all exceptions thrown while doInBackground()
|
||||
//notify services of completion
|
||||
if (!this.isCancelled()) {
|
||||
service.complete();
|
||||
}
|
||||
} catch (CancellationException e) {
|
||||
//task was cancelled
|
||||
service.stop();
|
||||
|
||||
} catch (InterruptedException ex) {
|
||||
service.stop();
|
||||
} catch (ExecutionException ex) {
|
||||
service.stop();
|
||||
logger.log(Level.SEVERE, "Fatal error during image ingest from sevice: " + service.getName() + " image: " + image.getName(), ex);
|
||||
} catch (Exception ex) {
|
||||
service.stop();
|
||||
logger.log(Level.SEVERE, "Fatal error during image ingest in service: " + service.getName() + " image: " + image.getName(), ex);
|
||||
} finally {
|
||||
progress.finish();
|
||||
|
||||
//cleanup queues (worker and image/service)
|
||||
manager.removeImageIngestWorker(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.ingest;
|
||||
|
||||
import org.netbeans.api.progress.ProgressHandle;
|
||||
|
||||
/**
|
||||
* passed to the service as a limited way to control this worker
|
||||
* update progress bar, check if job is cancelled
|
||||
*/
|
||||
public class IngestImageWorkerController {
|
||||
|
||||
private IngestImageThread worker;
|
||||
private ProgressHandle progress;
|
||||
|
||||
public IngestImageWorkerController(IngestImageThread worker, ProgressHandle progress) {
|
||||
this.worker = worker;
|
||||
this.progress = progress;
|
||||
}
|
||||
|
||||
public boolean isCancelled() {
|
||||
return worker.isCancelled();
|
||||
}
|
||||
|
||||
public void switchToDeterminate(int workUnits) {
|
||||
if (progress != null) {
|
||||
progress.switchToDeterminate(workUnits);
|
||||
}
|
||||
}
|
||||
|
||||
public void switchToInDeterminate() {
|
||||
if (progress != null) {
|
||||
progress.switchToIndeterminate();
|
||||
}
|
||||
}
|
||||
|
||||
public void progress(int workUnits) {
|
||||
if (progress != null) {
|
||||
progress.progress(worker.getImage().getName(), workUnits);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,7 @@ import org.netbeans.api.progress.ProgressHandle;
|
||||
import org.netbeans.api.progress.ProgressHandleFactory;
|
||||
import org.openide.util.Cancellable;
|
||||
import org.openide.util.Lookup;
|
||||
import org.sleuthkit.autopsy.ingest.IngestMessage.MessageType;
|
||||
import org.sleuthkit.datamodel.FsContent;
|
||||
import org.sleuthkit.datamodel.Image;
|
||||
|
||||
@@ -56,10 +57,13 @@ public class IngestManager {
|
||||
private IngestManagerStats stats;
|
||||
private int updateFrequency;
|
||||
//queues
|
||||
private final Object queueLock = new Object();
|
||||
private final ImageQueue imageQueue = new ImageQueue();
|
||||
private final FsContentQueue fsContentQueue = new FsContentQueue();
|
||||
private IngestThread ingester;
|
||||
private final Object queuesLock = new Object();
|
||||
//workers
|
||||
private IngestFsContentThread fsContentIngester;
|
||||
private List<IngestImageThread> imageIngesters;
|
||||
//services
|
||||
final Collection<IngestServiceImage> imageServices = enumerateImageServices();
|
||||
final Collection<IngestServiceFsContent> fsContentServices = enumerateFsContentServices();
|
||||
|
||||
@@ -70,52 +74,146 @@ public class IngestManager {
|
||||
IngestManager(IngestTopComponent tc) {
|
||||
this.tc = tc;
|
||||
|
||||
imageIngesters = new ArrayList<IngestImageThread>();
|
||||
|
||||
//one time initialization of services
|
||||
for (IngestServiceImage s : imageServices) {
|
||||
s.init(this);
|
||||
}
|
||||
|
||||
//image services are now initialized per instance
|
||||
//for (IngestServiceImage s : imageServices) {
|
||||
// s.init(this);
|
||||
//}
|
||||
|
||||
for (IngestServiceFsContent s : fsContentServices) {
|
||||
s.init(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiple image version of execute, enqueues multiple images and associated services at once
|
||||
* @param services services to execute on every image
|
||||
* @param images images to execute services on
|
||||
*/
|
||||
void execute(final Collection<IngestServiceAbstract> services, final Collection<Image> images) {
|
||||
tc.enableStartButton(false);
|
||||
SwingWorker queueWorker = new EnqueueWorker(services, images);
|
||||
queueWorker.execute();
|
||||
|
||||
//logger.log(Level.INFO, "Queues: " + imageQueue.toString() + " " + fsContentQueue.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* IngestManager entry point, enqueues image to be processed.
|
||||
* Spawns background thread which enumerates all sorted files and executes chosen services per file in a pre-determined order.
|
||||
* Notifies services when work is complete or should be interrupted using complete() and stop() calls.
|
||||
* Does not block and can be called multiple times to enqueue more work to already running background process.
|
||||
* @param services services to execute on the image
|
||||
* @param image image to execute services on
|
||||
*/
|
||||
void execute(final Collection<IngestServiceAbstract> services, final Collection<Image> images) {
|
||||
|
||||
//queuing start
|
||||
tc.enableStartButton(false);
|
||||
SwingWorker queueWorker = new EnqueueWorker(services, images);
|
||||
queueWorker.execute();
|
||||
|
||||
logger.log(Level.INFO, "Queues: " + imageQueue.toString() + " " + fsContentQueue.toString());
|
||||
|
||||
|
||||
void execute(final Collection<IngestServiceAbstract> services, final Image image) {
|
||||
Collection<Image> images = new ArrayList<Image>();
|
||||
images.add(image);
|
||||
execute(services, images);
|
||||
}
|
||||
|
||||
/**
|
||||
* manage current workers
|
||||
* if fsContent service is still running, do nothing and allow it to consume queue
|
||||
* otherwise start /restart fsContent worker
|
||||
*
|
||||
* image workers run per (service,image). Check if one for the (service,image) is already running
|
||||
* otherwise start/restart the worker
|
||||
*/
|
||||
private void startAll() {
|
||||
boolean start = false;
|
||||
if (ingester == null) {
|
||||
start = true;
|
||||
//image ingesters
|
||||
while (hasNextImage()) {
|
||||
//dequeue
|
||||
final QueueUnit<Image, IngestServiceImage> qu =
|
||||
this.getNextImage();
|
||||
//check if such (service,image) already running
|
||||
|
||||
} //if worker had completed, restart it in case data is still enqueued
|
||||
else if (ingester.isDone()
|
||||
&& (hasNextFsContent() || hasNextImage())) {
|
||||
logger.log(Level.INFO, "Restarting ingester thread.");
|
||||
start = true;
|
||||
} else {
|
||||
logger.log(Level.INFO, "Ingester is still running");
|
||||
|
||||
synchronized (this) {
|
||||
for (IngestServiceImage quService : qu.services) {
|
||||
boolean alreadyRunning = false;
|
||||
for (IngestImageThread worker : imageIngesters) {
|
||||
if (!worker.getImage().equals(qu.content)) {
|
||||
continue; //check next worker
|
||||
}
|
||||
//same image, check service (by name, not id, since different instances)
|
||||
if (worker.getService().getName().equals(quService.getName())) {
|
||||
alreadyRunning = true;
|
||||
logger.log(Level.INFO, "Image Ingester <" + qu.content + ", " + quService.getName() + "> is already running");
|
||||
break;
|
||||
}
|
||||
}
|
||||
//checked all workers
|
||||
if (alreadyRunning == false) {
|
||||
logger.log(Level.INFO, "Starting new image Ingester <" + qu.content + ", " + quService.getName() + ">");
|
||||
IngestImageThread newImageWorker = new IngestImageThread(this, qu.content, quService);
|
||||
|
||||
imageIngesters.add(newImageWorker);
|
||||
|
||||
//image services are now initialized per instance
|
||||
quService.init(this);
|
||||
newImageWorker.execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (start) {
|
||||
logger.log(Level.INFO, "Starting new ingester.");
|
||||
ingester = new IngestThread();
|
||||
|
||||
//fsContent ingester
|
||||
boolean startFsContentIngester = false;
|
||||
if (hasNextFsContent()) {
|
||||
if (fsContentIngester
|
||||
== null) {
|
||||
startFsContentIngester = true;
|
||||
logger.log(Level.INFO, "Starting initial FsContent ingester");
|
||||
} //if worker had completed, restart it in case data is still enqueued
|
||||
else if (fsContentIngester.isDone()) {
|
||||
startFsContentIngester = true;
|
||||
logger.log(Level.INFO, "Restarting fsContent ingester");
|
||||
}
|
||||
} else {
|
||||
logger.log(Level.INFO, "no new FsContent enqueued, no ingester needed");
|
||||
}
|
||||
|
||||
if (startFsContentIngester) {
|
||||
fsContentIngester = new IngestFsContentThread();
|
||||
stats = new IngestManagerStats();
|
||||
ingester.execute();
|
||||
fsContentIngester.execute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* stop currently running threads if any (e.g. when changing a case)
|
||||
*/
|
||||
void stopAll() {
|
||||
//empty queues
|
||||
emptyFsContents();
|
||||
emptyImages();
|
||||
|
||||
//stop workers
|
||||
|
||||
if (fsContentIngester != null) {
|
||||
boolean cancelled = fsContentIngester.cancel(true);
|
||||
if (!cancelled) {
|
||||
logger.log(Level.WARNING, "Unable to cancel file ingest worker");
|
||||
} else {
|
||||
fsContentIngester = null;
|
||||
}
|
||||
}
|
||||
|
||||
List<IngestImageThread> toStop = new ArrayList<IngestImageThread>();
|
||||
synchronized (this) {
|
||||
toStop.addAll(imageIngesters);
|
||||
}
|
||||
|
||||
for (IngestImageThread imageWorker : toStop) {
|
||||
boolean cancelled = imageWorker.cancel(true);
|
||||
if (!cancelled) {
|
||||
logger.log(Level.WARNING, "Unable to cancel image ingest worker for service: " + imageWorker.getService().getName() + " img: " + imageWorker.getImage().getName());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -153,6 +251,13 @@ public class IngestManager {
|
||||
*/
|
||||
public synchronized void postMessage(final IngestMessage message) {
|
||||
|
||||
if (stats != null) {
|
||||
//record the error for stats, if stats are running
|
||||
if (message.getMessageType() == MessageType.ERROR) {
|
||||
stats.addError(message.getSource());
|
||||
}
|
||||
}
|
||||
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
|
||||
@Override
|
||||
@@ -177,24 +282,19 @@ public class IngestManager {
|
||||
}
|
||||
|
||||
private void addImage(IngestServiceImage service, Image image) {
|
||||
|
||||
synchronized (queueLock) {
|
||||
synchronized (queuesLock) {
|
||||
imageQueue.enqueue(image, service);
|
||||
//queueLock.notifyAll();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void addFsContent(IngestServiceFsContent service, Image image) {
|
||||
Collection<FsContent> fsContents = new GetAllFilesContentVisitor().visit(image);
|
||||
synchronized (queueLock) {
|
||||
|
||||
synchronized (queuesLock) {
|
||||
for (FsContent fsContent : fsContents) {
|
||||
fsContentQueue.enqueue(fsContent, service);
|
||||
}
|
||||
//queueLock.notifyAll();
|
||||
}
|
||||
//logger.log(Level.INFO, fsContentQueue.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -204,16 +304,15 @@ public class IngestManager {
|
||||
*/
|
||||
private QueueUnit<FsContent, IngestServiceFsContent> getNextFsContent() {
|
||||
QueueUnit<FsContent, IngestServiceFsContent> ret = null;
|
||||
synchronized (queueLock) {
|
||||
synchronized (queuesLock) {
|
||||
ret = fsContentQueue.dequeue();
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private boolean hasNextFsContent() {
|
||||
boolean ret = false;
|
||||
synchronized (queueLock) {
|
||||
synchronized (queuesLock) {
|
||||
ret = fsContentQueue.hasNext();
|
||||
}
|
||||
return ret;
|
||||
@@ -221,20 +320,20 @@ public class IngestManager {
|
||||
|
||||
private int getNumFsContents() {
|
||||
int ret = 0;
|
||||
synchronized (queueLock) {
|
||||
synchronized (queuesLock) {
|
||||
ret = fsContentQueue.getCount();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private void emptyFsContents() {
|
||||
synchronized (queueLock) {
|
||||
synchronized (queuesLock) {
|
||||
fsContentQueue.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private void emptyImages() {
|
||||
synchronized (queueLock) {
|
||||
synchronized (queuesLock) {
|
||||
imageQueue.empty();
|
||||
}
|
||||
}
|
||||
@@ -246,7 +345,7 @@ public class IngestManager {
|
||||
*/
|
||||
private QueueUnit<Image, IngestServiceImage> getNextImage() {
|
||||
QueueUnit<Image, IngestServiceImage> ret = null;
|
||||
synchronized (queueLock) {
|
||||
synchronized (queuesLock) {
|
||||
ret = imageQueue.dequeue();
|
||||
}
|
||||
return ret;
|
||||
@@ -254,7 +353,7 @@ public class IngestManager {
|
||||
|
||||
private boolean hasNextImage() {
|
||||
boolean ret = false;
|
||||
synchronized (queueLock) {
|
||||
synchronized (queuesLock) {
|
||||
ret = imageQueue.hasNext();
|
||||
}
|
||||
return ret;
|
||||
@@ -262,12 +361,40 @@ public class IngestManager {
|
||||
|
||||
private int getNumImages() {
|
||||
int ret = 0;
|
||||
synchronized (queueLock) {
|
||||
synchronized (queuesLock) {
|
||||
ret = imageQueue.getCount();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private void initMainProgress(final int maximum) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
tc.initProgress(maximum);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void updateMainProgress(final int progress) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
tc.updateProgress(progress);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//image worker to remove itself when complete or interrupted
|
||||
void removeImageIngestWorker(IngestImageThread worker) {
|
||||
//remove worker
|
||||
synchronized (this) {
|
||||
imageIngesters.remove(worker);
|
||||
}
|
||||
}
|
||||
|
||||
//manages queue of pending FsContent and IngestServiceFsContent to use on that content
|
||||
//TODO in future content sort will be maintained based on priorities
|
||||
private class FsContentQueue {
|
||||
@@ -334,12 +461,12 @@ public class IngestManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
public synchronized String toString() {
|
||||
return "FsContentQueue, size: " + Integer.toString(fsContentUnits.size());
|
||||
}
|
||||
}
|
||||
|
||||
//manages queue of pending Images and IngestServiceImage to use on that image
|
||||
//manages queue of pending Images and IngestServiceImage to use on that image
|
||||
private class ImageQueue {
|
||||
|
||||
List<QueueUnit<Image, IngestServiceImage>> imageUnits = new ArrayList<QueueUnit<Image, IngestServiceImage>>();
|
||||
@@ -404,7 +531,7 @@ public class IngestManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
public synchronized String toString() {
|
||||
return "ImageQueue, size: " + Integer.toString(imageUnits.size());
|
||||
}
|
||||
}
|
||||
@@ -430,11 +557,14 @@ public class IngestManager {
|
||||
}
|
||||
|
||||
//merge services with the current collection of services per image
|
||||
//this assumes that there is one singleton instance of each type of service
|
||||
//this assumes singleton instances of every service type for correct merge
|
||||
//in case of multiple instances, they need to be handled correctly after dequeue()
|
||||
final void addAll(Collection<S> services) {
|
||||
this.services.addAll(services);
|
||||
}
|
||||
|
||||
//this assumes singleton instances of every service type for correct merge
|
||||
//in case of multiple instances, they need to be handled correctly after dequeue()
|
||||
final void add(S service) {
|
||||
this.services.add(service);
|
||||
}
|
||||
@@ -457,25 +587,48 @@ public class IngestManager {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final String EOL = System.getProperty("line.separator");
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (startTime != null) {
|
||||
sb.append("Start time: ").append(dateFormatter.format(startTime)).append("\n");
|
||||
sb.append("Start time: ").append(dateFormatter.format(startTime)).append(EOL);
|
||||
}
|
||||
if (endTime != null) {
|
||||
sb.append("End time: ").append(dateFormatter.format(endTime)).append("\n");
|
||||
sb.append("End time: ").append(dateFormatter.format(endTime)).append(EOL);
|
||||
}
|
||||
sb.append("Total ingest time: ").append(getTotalTimeString()).append("\n");
|
||||
sb.append("Total errors: ").append(errorsTotal).append("\n");
|
||||
sb.append("Total ingest time: ").append(getTotalTimeString()).append(EOL);
|
||||
sb.append("Total errors: ").append(errorsTotal).append(EOL);
|
||||
if (errorsTotal > 0) {
|
||||
sb.append("Errors per service:");
|
||||
for (IngestServiceAbstract service : errors.keySet()) {
|
||||
final int errorsService = errors.get(service);
|
||||
sb.append("\t").append(service.getName()).append(": ").append(errorsService).append("\n");
|
||||
sb.append("\t").append(service.getName()).append(": ").append(errorsService).append(EOL);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String toHtmlString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("<html>");
|
||||
if (startTime != null) {
|
||||
sb.append("Start time: ").append(dateFormatter.format(startTime)).append("<br />");
|
||||
}
|
||||
if (endTime != null) {
|
||||
sb.append("End time: ").append(dateFormatter.format(endTime)).append("<br />");
|
||||
}
|
||||
sb.append("Total ingest time: ").append(getTotalTimeString()).append("<br />");
|
||||
sb.append("Total errors: ").append(errorsTotal).append("<br />");
|
||||
if (errorsTotal > 0) {
|
||||
sb.append("Errors per service:");
|
||||
for (IngestServiceAbstract service : errors.keySet()) {
|
||||
final int errorsService = errors.get(service);
|
||||
sb.append("\t").append(service.getName()).append(": ").append(errorsService).append("<br />");
|
||||
}
|
||||
}
|
||||
sb.append("</html>");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
void start() {
|
||||
startTime = new Date();
|
||||
}
|
||||
@@ -491,6 +644,14 @@ public class IngestManager {
|
||||
return endTime.getTime() - startTime.getTime();
|
||||
}
|
||||
|
||||
String getStartTimeString() {
|
||||
return dateFormatter.format(startTime);
|
||||
}
|
||||
|
||||
String getEndTimeString() {
|
||||
return dateFormatter.format(endTime);
|
||||
}
|
||||
|
||||
String getTotalTimeString() {
|
||||
long ms = getTotalTime();
|
||||
long hours = TimeUnit.MILLISECONDS.toHours(ms);
|
||||
@@ -503,19 +664,19 @@ public class IngestManager {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
void addError(IngestServiceAbstract source) {
|
||||
synchronized void addError(IngestServiceAbstract source) {
|
||||
++errorsTotal;
|
||||
int curServiceError = errors.get(source);
|
||||
errors.put(source, curServiceError + 1);
|
||||
}
|
||||
}
|
||||
|
||||
//ingester worker doing work in background
|
||||
//in current design, worker runs until queues are consumed
|
||||
//and if needed, it is restarted when data arrives
|
||||
private class IngestThread extends SwingWorker {
|
||||
//ingester worker for fsContent queue
|
||||
//worker runs until fsContent queue is consumed
|
||||
//and if needed, new instance is created and started when data arrives
|
||||
private class IngestFsContentThread extends SwingWorker {
|
||||
|
||||
private Logger logger = Logger.getLogger(IngestThread.class.getName());
|
||||
private Logger logger = Logger.getLogger(IngestFsContentThread.class.getName());
|
||||
private ProgressHandle progress;
|
||||
|
||||
@Override
|
||||
@@ -524,52 +685,21 @@ public class IngestManager {
|
||||
logger.log(Level.INFO, "Starting background processing");
|
||||
stats.start();
|
||||
|
||||
progress = ProgressHandleFactory.createHandle("Ingesting", new Cancellable() {
|
||||
progress = ProgressHandleFactory.createHandle("File Ingest", new Cancellable() {
|
||||
|
||||
@Override
|
||||
public boolean cancel() {
|
||||
return IngestThread.this.cancel(true);
|
||||
return IngestFsContentThread.this.cancel(true);
|
||||
}
|
||||
});
|
||||
|
||||
progress.start();
|
||||
progress.switchToIndeterminate();
|
||||
int numImages = getNumImages();
|
||||
progress.switchToDeterminate(numImages);
|
||||
int processedImages = 0;
|
||||
//process image queue
|
||||
while (hasNextImage()) {
|
||||
QueueUnit<Image, IngestServiceImage> unit = getNextImage();
|
||||
for (IngestServiceImage service : unit.services) {
|
||||
if (isCancelled()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
service.process(unit.content);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.INFO, "Exception from service: " + service.getName(), e);
|
||||
stats.addError(service);
|
||||
}
|
||||
//check if new files enqueued
|
||||
int newImages = getNumImages();
|
||||
if (newImages > numImages) {
|
||||
numImages = newImages + processedImages + 1;
|
||||
progress.switchToIndeterminate();
|
||||
progress.switchToDeterminate(numImages);
|
||||
|
||||
}
|
||||
progress.progress("Images (" + service.getName() + ")", ++processedImages);
|
||||
--numImages;
|
||||
}
|
||||
}
|
||||
|
||||
progress.switchToIndeterminate();
|
||||
int numFsContents = getNumFsContents();
|
||||
progress.switchToDeterminate(numFsContents);
|
||||
int processedFiles = 0;
|
||||
initMainProgress(numFsContents);
|
||||
//process fscontents queue
|
||||
progress.progress("Running file ingest services.");
|
||||
while (hasNextFsContent()) {
|
||||
QueueUnit<FsContent, IngestServiceFsContent> unit = getNextFsContent();
|
||||
for (IngestServiceFsContent service : unit.services) {
|
||||
@@ -589,9 +719,11 @@ public class IngestManager {
|
||||
numFsContents = newFsContents + processedFiles + 1;
|
||||
progress.switchToIndeterminate();
|
||||
progress.switchToDeterminate(numFsContents);
|
||||
initMainProgress(numFsContents);
|
||||
|
||||
}
|
||||
progress.progress("Files", ++processedFiles);
|
||||
progress.progress(unit.content.getName(), ++processedFiles);
|
||||
updateMainProgress(processedFiles);
|
||||
--numFsContents;
|
||||
}
|
||||
logger.log(Level.INFO, "Done background processing");
|
||||
@@ -604,10 +736,6 @@ public class IngestManager {
|
||||
super.get(); //block and get all exceptions thrown while doInBackground()
|
||||
//notify services of completion
|
||||
if (!this.isCancelled()) {
|
||||
for (IngestServiceImage s : imageServices) {
|
||||
s.complete();
|
||||
}
|
||||
|
||||
for (IngestServiceFsContent s : fsContentServices) {
|
||||
s.complete();
|
||||
}
|
||||
@@ -630,28 +758,23 @@ public class IngestManager {
|
||||
stats.end();
|
||||
progress.finish();
|
||||
|
||||
//TODO display report
|
||||
logger.log(Level.INFO, "STATS: " + stats.toString());
|
||||
if (!this.isCancelled()) {
|
||||
logger.log(Level.INFO, "Summary Report: " + stats.toString());
|
||||
tc.displayReport(stats.toHtmlString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void process(List chunks) {
|
||||
super.process(chunks);
|
||||
}
|
||||
|
||||
private void handleInterruption() {
|
||||
for (IngestServiceImage s : imageServices) {
|
||||
s.stop();
|
||||
}
|
||||
|
||||
for (IngestServiceFsContent s : fsContentServices) {
|
||||
s.stop();
|
||||
}
|
||||
//empty queues
|
||||
emptyFsContents();
|
||||
emptyImages();
|
||||
|
||||
//reset main progress bar
|
||||
initMainProgress(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -691,7 +814,6 @@ public class IngestManager {
|
||||
} catch (CancellationException e) {
|
||||
//task was cancelled
|
||||
handleInterruption();
|
||||
|
||||
} catch (InterruptedException ex) {
|
||||
handleInterruption();
|
||||
} catch (ExecutionException ex) {
|
||||
@@ -705,13 +827,11 @@ public class IngestManager {
|
||||
//queing end
|
||||
if (this.isCancelled()) {
|
||||
//empty queues
|
||||
emptyFsContents();
|
||||
emptyImages();
|
||||
handleInterruption();
|
||||
} else {
|
||||
//start ingest workers
|
||||
startAll();
|
||||
}
|
||||
|
||||
progress.finish();
|
||||
tc.enableStartButton(true);
|
||||
}
|
||||
@@ -722,13 +842,29 @@ public class IngestManager {
|
||||
for (Image image : images) {
|
||||
final String imageName = image.getName();
|
||||
for (IngestServiceAbstract service : services) {
|
||||
if (isCancelled()) {
|
||||
return;
|
||||
}
|
||||
final String serviceName = service.getName();
|
||||
progress.progress(serviceName + " " + imageName, processed);
|
||||
switch (service.getType()) {
|
||||
case Image:
|
||||
addImage((IngestServiceImage) service, image);
|
||||
//enqueue a new instance of image service
|
||||
//Class serviceClass = service.getClass();
|
||||
//serviceClass.
|
||||
try {
|
||||
final IngestServiceImage newServiceInstance = (IngestServiceImage) (service.getClass()).newInstance();
|
||||
addImage(newServiceInstance, image);
|
||||
} catch (InstantiationException e) {
|
||||
logger.log(Level.SEVERE, "Cannot instantiate service: " + service.getName(), e);
|
||||
} catch (IllegalAccessException e) {
|
||||
logger.log(Level.SEVERE, "Cannot instantiate service: " + service.getName(), e);
|
||||
}
|
||||
|
||||
//addImage((IngestServiceImage) service, image);
|
||||
break;
|
||||
case FsContent:
|
||||
//enqueue the same singleton fscontent service
|
||||
addFsContent((IngestServiceFsContent) service, image);
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -20,7 +20,6 @@ package org.sleuthkit.autopsy.ingest;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import javax.swing.text.DateFormatter;
|
||||
import org.sleuthkit.autopsy.datamodel.KeyValueThing;
|
||||
|
||||
/**
|
||||
@@ -82,13 +81,15 @@ public class IngestMessage {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(Long.toString(ID)).append(": ");
|
||||
sb.append("type: ").append(messageType.name());
|
||||
sb.append(" source: ").append(source.getName());
|
||||
if (source != null) //can be null for manager messages
|
||||
sb.append(" source: ").append(source.getName());
|
||||
sb.append(" date: ").append(dateFormat.format(datePosted));
|
||||
sb.append(" text: ").append(text);
|
||||
if (data != null)
|
||||
sb.append(" data: ").append(data.toString()).append(' ');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
@@ -152,4 +153,9 @@ public class IngestMessage {
|
||||
return im;
|
||||
}
|
||||
|
||||
static IngestMessage createManagerMessage(String message) {
|
||||
IngestMessage im = new IngestMessage(0, MessageType.INFO, null, message);
|
||||
return im;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -52,7 +52,6 @@
|
||||
</Property>
|
||||
<Property name="autoResizeMode" type="int" value="3"/>
|
||||
<Property name="autoscrolls" type="boolean" value="false"/>
|
||||
<Property name="columnSelectionAllowed" type="boolean" value="false"/>
|
||||
<Property name="gridColor" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||
<Color blue="cc" green="cc" red="cc" type="rgb"/>
|
||||
</Property>
|
||||
|
||||
@@ -135,6 +135,10 @@ public class IngestMessagePanel extends javax.swing.JPanel {
|
||||
//autoscroll
|
||||
messageTable.scrollRectToVisible(messageTable.getCellRect(messageTable.getRowCount() - 1, messageTable.getColumnCount(), true));
|
||||
}
|
||||
|
||||
public void clearMessages() {
|
||||
tableModel.clearMessages();
|
||||
}
|
||||
|
||||
private void setVisited(int rowNumber) {
|
||||
tableModel.setVisited(rowNumber);
|
||||
@@ -182,7 +186,13 @@ public class IngestMessagePanel extends javax.swing.JPanel {
|
||||
|
||||
switch (columnIndex) {
|
||||
case 0:
|
||||
ret = (Object) entry.message.getSource().getName();
|
||||
Object service = entry.message.getSource();
|
||||
if (service == null) {
|
||||
ret = "";
|
||||
}
|
||||
else {
|
||||
ret = (Object) entry.message.getSource().getName();
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
ret = (Object) entry.message.getText();
|
||||
@@ -207,7 +217,12 @@ public class IngestMessagePanel extends javax.swing.JPanel {
|
||||
public void addMessage(IngestMessage m) {
|
||||
messageData.add(new TableEntry(m));
|
||||
int size = messageData.size();
|
||||
this.fireTableRowsInserted(size - 1, size); //TODO check
|
||||
this.fireTableRowsInserted(size - 1, size);
|
||||
}
|
||||
|
||||
public void clearMessages() {
|
||||
messageData.clear();
|
||||
fireTableDataChanged();
|
||||
}
|
||||
|
||||
public void setVisited(int rowNumber) {
|
||||
|
||||
@@ -30,6 +30,9 @@ public interface IngestServiceImage extends IngestServiceAbstract {
|
||||
* notification from manager to process image
|
||||
* The service notifies viewers via IngestManager.postMessage()
|
||||
* and may also write results to the black-board as it is processing.
|
||||
*
|
||||
* @param image image to process
|
||||
* @param controller controller to the worker, to update progress (if determinate) and check if cancelled
|
||||
*/
|
||||
public void process(Image image);
|
||||
public void process(Image image, IngestImageWorkerController controller);
|
||||
}
|
||||
@@ -16,12 +16,12 @@
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="mainScrollPane" alignment="0" pref="322" max="32767" attributes="0"/>
|
||||
<Component id="mainScrollPane" alignment="0" pref="340" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="mainScrollPane" alignment="0" pref="732" max="32767" attributes="0"/>
|
||||
<Component id="mainScrollPane" alignment="0" pref="771" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
@@ -29,7 +29,7 @@
|
||||
<Container class="javax.swing.JScrollPane" name="mainScrollPane">
|
||||
<Properties>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[322, 732]"/>
|
||||
<Dimension value="[322, 749]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
<Container class="javax.swing.JPanel" name="mainPanel">
|
||||
<Properties>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[322, 732]"/>
|
||||
<Dimension value="[322, 749]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
@@ -48,13 +48,13 @@
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="controlPanel" min="-2" max="-2" attributes="1"/>
|
||||
<EmptySpace pref="71" max="32767" attributes="0"/>
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<Component id="controlPanel" max="32767" attributes="1"/>
|
||||
<EmptySpace min="-2" pref="71" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="messageFrame" pref="241" max="32767" attributes="1"/>
|
||||
<EmptySpace min="-2" pref="71" max="-2" attributes="0"/>
|
||||
<Component id="messageFrame" min="-2" max="-2" attributes="1"/>
|
||||
<EmptySpace min="-2" pref="48" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
@@ -64,10 +64,10 @@
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="controlPanel" min="-2" pref="297" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="40" max="-2" attributes="0"/>
|
||||
<Component id="messageFrame" max="32767" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="129" max="-2" attributes="0"/>
|
||||
<Component id="controlPanel" min="-2" pref="357" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="30" max="-2" attributes="0"/>
|
||||
<Component id="messageFrame" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="127" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
@@ -76,10 +76,10 @@
|
||||
<Container class="javax.swing.JInternalFrame" name="messageFrame">
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.MatteColorBorderInfo">
|
||||
<MatteColorBorder bottom="2" left="2" right="2" top="2">
|
||||
<Color PropertyName="color" blue="ff" green="cc" red="cc" type="rgb"/>
|
||||
</MatteColorBorder>
|
||||
<Border info="org.netbeans.modules.form.compat2.border.LineBorderInfo">
|
||||
<LineBorder roundedCorners="true" thickness="3">
|
||||
<Color PropertyName="color" blue="db" green="cd" id="InternalFrame.inactiveTitleBackground" palette="3" red="bf" type="palette"/>
|
||||
</LineBorder>
|
||||
</Border>
|
||||
</Property>
|
||||
<Property name="maximizable" type="boolean" value="true"/>
|
||||
@@ -93,18 +93,22 @@
|
||||
<Property name="frameIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
<Image iconType="0" name="null"/>
|
||||
</Property>
|
||||
<Property name="opaque" type="boolean" value="true"/>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[280, 260]"/>
|
||||
</Property>
|
||||
<Property name="visible" type="boolean" value="true"/>
|
||||
</Properties>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<EmptySpace min="0" pref="237" max="32767" attributes="0"/>
|
||||
<EmptySpace min="0" pref="274" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<EmptySpace min="0" pref="227" max="32767" attributes="0"/>
|
||||
<EmptySpace min="0" pref="231" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
@@ -115,31 +119,35 @@
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="topLable" min="-2" max="-2" attributes="1"/>
|
||||
<EmptySpace pref="114" max="32767" attributes="0"/>
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="topLable" alignment="0" min="-2" max="-2" attributes="1"/>
|
||||
<Component id="servicesPanel" alignment="0" min="-2" max="-2" attributes="1"/>
|
||||
<Component id="startButton" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="103" alignment="0" groupAlignment="1" max="-2" attributes="0">
|
||||
<Component id="mainProgressBar" alignment="0" max="32767" attributes="1"/>
|
||||
<Component id="freqSlider" alignment="0" max="32767" attributes="1"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="servicesPanel" max="32767" attributes="1"/>
|
||||
<EmptySpace min="-2" pref="31" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="59" max="-2" attributes="0"/>
|
||||
<Component id="refreshFrequencyLabel" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="startButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="174" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="freqSlider" min="-2" max="-2" attributes="1"/>
|
||||
<EmptySpace pref="31" max="32767" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="59" max="-2" attributes="0"/>
|
||||
<Component id="ingestProgressLabel" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace pref="47" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="74" max="-2" attributes="0"/>
|
||||
<Component id="refreshFreqLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="77" max="32767" attributes="0"/>
|
||||
<EmptySpace pref="93" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
@@ -155,7 +163,13 @@
|
||||
<Component id="startButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="freqSlider" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="288" max="32767" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="refreshFrequencyLabel" min="-2" pref="14" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="mainProgressBar" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="ingestProgressLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="228" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
@@ -236,6 +250,22 @@
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="startButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="refreshFrequencyLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/ingest/Bundle.properties" key="IngestTopComponent.refreshFrequencyLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JProgressBar" name="mainProgressBar">
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="ingestProgressLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/ingest/Bundle.properties" key="IngestTopComponent.ingestProgressLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
|
||||
@@ -21,7 +21,10 @@ package org.sleuthkit.autopsy.ingest;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.ComponentAdapter;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@@ -32,7 +35,7 @@ import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JSlider;
|
||||
import org.openide.util.NbBundle;
|
||||
@@ -47,7 +50,7 @@ import org.sleuthkit.datamodel.TskException;
|
||||
* Top component explorer for the Ingest module.
|
||||
*/
|
||||
public final class IngestTopComponent extends TopComponent implements DataExplorer {
|
||||
|
||||
|
||||
private static IngestTopComponent instance;
|
||||
private static final Logger logger = Logger.getLogger(IngestTopComponent.class.getName());
|
||||
private IngestManager manager = null;
|
||||
@@ -55,14 +58,14 @@ public final class IngestTopComponent extends TopComponent implements DataExplor
|
||||
private Map<String, Boolean> serviceStates;
|
||||
private IngestMessagePanel messagePanel;
|
||||
private ActionListener serviceSelListener = new ActionListener() {
|
||||
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent ev) {
|
||||
JCheckBox box = (JCheckBox) ev.getSource();
|
||||
serviceStates.put(box.getName(), box.isSelected());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private IngestTopComponent() {
|
||||
services = new ArrayList<IngestServiceAbstract>();
|
||||
serviceStates = new HashMap<String, Boolean>();
|
||||
@@ -72,41 +75,41 @@ public final class IngestTopComponent extends TopComponent implements DataExplor
|
||||
setToolTipText(NbBundle.getMessage(IngestTopComponent.class, "HINT_IngestTopComponent"));
|
||||
//putClientProperty(TopComponent.PROP_UNDOCKING_DISABLED, Boolean.TRUE);
|
||||
putClientProperty(TopComponent.PROP_CLOSING_DISABLED, Boolean.TRUE);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static synchronized IngestTopComponent getDefault() {
|
||||
if (instance == null) {
|
||||
instance = new IngestTopComponent();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TopComponent getTopComponent() {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
logger.log(Level.INFO, "Unhandled property change: " + evt.getPropertyName());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getPersistenceType() {
|
||||
return TopComponent.PERSISTENCE_NEVER;
|
||||
}
|
||||
|
||||
|
||||
private void customizeComponents() {
|
||||
//custom GUI setup not done by builder
|
||||
freqSlider.setToolTipText("Lower update frequency can optimize performance of certain ingest services, but also reduce real time status feedback");
|
||||
|
||||
|
||||
JScrollPane scrollPane = new JScrollPane(servicesPanel);
|
||||
scrollPane.setPreferredSize(this.getSize());
|
||||
this.add(scrollPane, BorderLayout.CENTER);
|
||||
|
||||
|
||||
servicesPanel.setLayout(new BoxLayout(servicesPanel, BoxLayout.Y_AXIS));
|
||||
|
||||
|
||||
|
||||
freqSlider.setEnabled(false);
|
||||
|
||||
@@ -114,13 +117,41 @@ public final class IngestTopComponent extends TopComponent implements DataExplor
|
||||
|
||||
messagePanel.setOpaque(false);
|
||||
messageFrame.setOpaque(false);
|
||||
//this.setComponentZOrder(messageFrame, 0);
|
||||
messageFrame.addComponentListener(new ComponentAdapter() {
|
||||
|
||||
@Override
|
||||
public void componentResized(ComponentEvent e) {
|
||||
|
||||
super.componentResized(e);
|
||||
messageFrame.setPreferredSize(messageFrame.getSize());
|
||||
}
|
||||
});
|
||||
|
||||
//make messageframe on top
|
||||
this.setComponentZOrder(controlPanel, 2);
|
||||
messageFrame.setContentPane(messagePanel);
|
||||
messageFrame.pack();
|
||||
messageFrame.setVisible(true);
|
||||
|
||||
|
||||
//handle case change
|
||||
Case.addPropertyChangeListener(new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
if (evt.getPropertyName().equals(Case.CASE_CURRENT_CASE)) {
|
||||
Case oldCase = (Case) evt.getOldValue();
|
||||
if (oldCase == null)
|
||||
//nothing to do, not case had been opened
|
||||
return;
|
||||
//stop workers if running
|
||||
if (manager != null)
|
||||
manager.stopAll();
|
||||
//clear inbox
|
||||
messagePanel.clearMessages();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
Collection<IngestServiceImage> imageServices = IngestManager.enumerateImageServices();
|
||||
for (IngestServiceImage service : imageServices) {
|
||||
@@ -132,7 +163,7 @@ public final class IngestTopComponent extends TopComponent implements DataExplor
|
||||
servicesPanel.add(checkbox);
|
||||
serviceStates.put(serviceName, true);
|
||||
}
|
||||
|
||||
|
||||
Collection<IngestServiceFsContent> fsServices = IngestManager.enumerateFsContentServices();
|
||||
for (IngestServiceFsContent service : fsServices) {
|
||||
final String serviceName = service.getName();
|
||||
@@ -163,31 +194,36 @@ public final class IngestTopComponent extends TopComponent implements DataExplor
|
||||
freqSlider = new javax.swing.JSlider();
|
||||
refreshFreqLabel = new javax.swing.JLabel();
|
||||
startButton = new javax.swing.JButton();
|
||||
refreshFrequencyLabel = new javax.swing.JLabel();
|
||||
mainProgressBar = new javax.swing.JProgressBar();
|
||||
ingestProgressLabel = new javax.swing.JLabel();
|
||||
|
||||
mainScrollPane.setPreferredSize(new java.awt.Dimension(322, 732));
|
||||
mainScrollPane.setPreferredSize(new java.awt.Dimension(322, 749));
|
||||
|
||||
mainPanel.setPreferredSize(new java.awt.Dimension(322, 732));
|
||||
mainPanel.setPreferredSize(new java.awt.Dimension(322, 749));
|
||||
|
||||
messageFrame.setBorder(javax.swing.BorderFactory.createMatteBorder(2, 2, 2, 2, new java.awt.Color(204, 204, 255)));
|
||||
messageFrame.setBorder(new javax.swing.border.LineBorder(javax.swing.UIManager.getDefaults().getColor("InternalFrame.inactiveTitleBackground"), 3, true));
|
||||
messageFrame.setMaximizable(true);
|
||||
messageFrame.setResizable(true);
|
||||
messageFrame.setTitle(org.openide.util.NbBundle.getMessage(IngestTopComponent.class, "IngestTopComponent.messageFrame.title")); // NOI18N
|
||||
messageFrame.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
|
||||
messageFrame.setFrameIcon(null);
|
||||
messageFrame.setOpaque(true);
|
||||
messageFrame.setPreferredSize(new java.awt.Dimension(280, 260));
|
||||
messageFrame.setVisible(true);
|
||||
|
||||
javax.swing.GroupLayout messageFrameLayout = new javax.swing.GroupLayout(messageFrame.getContentPane());
|
||||
messageFrame.getContentPane().setLayout(messageFrameLayout);
|
||||
messageFrameLayout.setHorizontalGroup(
|
||||
messageFrameLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGap(0, 237, Short.MAX_VALUE)
|
||||
.addGap(0, 274, Short.MAX_VALUE)
|
||||
);
|
||||
messageFrameLayout.setVerticalGroup(
|
||||
messageFrameLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGap(0, 227, Short.MAX_VALUE)
|
||||
.addGap(0, 231, Short.MAX_VALUE)
|
||||
);
|
||||
|
||||
topLable.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
|
||||
topLable.setFont(new java.awt.Font("Tahoma", 0, 12));
|
||||
org.openide.awt.Mnemonics.setLocalizedText(topLable, org.openide.util.NbBundle.getMessage(IngestTopComponent.class, "IngestTopComponent.topLable.text")); // NOI18N
|
||||
|
||||
servicesPanel.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
|
||||
@@ -226,6 +262,10 @@ public final class IngestTopComponent extends TopComponent implements DataExplor
|
||||
}
|
||||
});
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(refreshFrequencyLabel, org.openide.util.NbBundle.getMessage(IngestTopComponent.class, "IngestTopComponent.refreshFrequencyLabel.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(ingestProgressLabel, org.openide.util.NbBundle.getMessage(IngestTopComponent.class, "IngestTopComponent.ingestProgressLabel.text")); // NOI18N
|
||||
|
||||
javax.swing.GroupLayout controlPanelLayout = new javax.swing.GroupLayout(controlPanel);
|
||||
controlPanel.setLayout(controlPanelLayout);
|
||||
controlPanelLayout.setHorizontalGroup(
|
||||
@@ -235,21 +275,31 @@ public final class IngestTopComponent extends TopComponent implements DataExplor
|
||||
.addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(controlPanelLayout.createSequentialGroup()
|
||||
.addComponent(topLable)
|
||||
.addContainerGap(114, Short.MAX_VALUE))
|
||||
.addContainerGap(198, Short.MAX_VALUE))
|
||||
.addGroup(controlPanelLayout.createSequentialGroup()
|
||||
.addComponent(servicesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addGap(31, 31, 31))
|
||||
.addComponent(servicesPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(115, 115, 115))
|
||||
.addGroup(controlPanelLayout.createSequentialGroup()
|
||||
.addComponent(startButton)
|
||||
.addContainerGap(174, Short.MAX_VALUE))
|
||||
.addContainerGap(258, Short.MAX_VALUE))
|
||||
.addGroup(controlPanelLayout.createSequentialGroup()
|
||||
.addComponent(freqSlider, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap(31, Short.MAX_VALUE))))
|
||||
.addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
|
||||
.addComponent(mainProgressBar, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(freqSlider, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.addContainerGap(115, Short.MAX_VALUE))))
|
||||
.addGroup(controlPanelLayout.createSequentialGroup()
|
||||
.addGap(59, 59, 59)
|
||||
.addComponent(refreshFrequencyLabel)
|
||||
.addContainerGap(174, Short.MAX_VALUE))
|
||||
.addGroup(controlPanelLayout.createSequentialGroup()
|
||||
.addGap(59, 59, 59)
|
||||
.addComponent(ingestProgressLabel)
|
||||
.addContainerGap(171, Short.MAX_VALUE))
|
||||
.addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(controlPanelLayout.createSequentialGroup()
|
||||
.addGap(74, 74, 74)
|
||||
.addComponent(refreshFreqLabel)
|
||||
.addContainerGap(77, Short.MAX_VALUE)))
|
||||
.addContainerGap(161, Short.MAX_VALUE)))
|
||||
);
|
||||
controlPanelLayout.setVerticalGroup(
|
||||
controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
@@ -262,7 +312,13 @@ public final class IngestTopComponent extends TopComponent implements DataExplor
|
||||
.addComponent(startButton)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(freqSlider, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap(288, Short.MAX_VALUE))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(refreshFrequencyLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(mainProgressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(ingestProgressLabel)
|
||||
.addContainerGap(228, Short.MAX_VALUE))
|
||||
.addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(controlPanelLayout.createSequentialGroup()
|
||||
.addGap(555, 555, 555)
|
||||
@@ -277,21 +333,21 @@ public final class IngestTopComponent extends TopComponent implements DataExplor
|
||||
.addGroup(mainPanelLayout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, mainPanelLayout.createSequentialGroup()
|
||||
.addComponent(controlPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addGap(71, 71, 71))
|
||||
.addGroup(mainPanelLayout.createSequentialGroup()
|
||||
.addComponent(controlPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap(71, Short.MAX_VALUE))
|
||||
.addGroup(mainPanelLayout.createSequentialGroup()
|
||||
.addComponent(messageFrame, javax.swing.GroupLayout.DEFAULT_SIZE, 241, Short.MAX_VALUE)
|
||||
.addGap(71, 71, 71))))
|
||||
.addComponent(messageFrame, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(48, 48, 48))))
|
||||
);
|
||||
mainPanelLayout.setVerticalGroup(
|
||||
mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(mainPanelLayout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(controlPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 297, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(40, 40, 40)
|
||||
.addComponent(messageFrame)
|
||||
.addGap(129, 129, 129))
|
||||
.addComponent(controlPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 357, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(30, 30, 30)
|
||||
.addComponent(messageFrame, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(127, 127, 127))
|
||||
);
|
||||
|
||||
mainScrollPane.setViewportView(mainPanel);
|
||||
@@ -300,19 +356,20 @@ public final class IngestTopComponent extends TopComponent implements DataExplor
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(mainScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 322, Short.MAX_VALUE)
|
||||
.addComponent(mainScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 340, Short.MAX_VALUE)
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(mainScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 732, Short.MAX_VALUE)
|
||||
.addComponent(mainScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 771, Short.MAX_VALUE)
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void startButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_startButtonActionPerformed
|
||||
|
||||
if (manager == null)
|
||||
if (manager == null) {
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
//pick the services
|
||||
List<IngestServiceAbstract> servicesToStart = new ArrayList<IngestServiceAbstract>();
|
||||
for (IngestServiceAbstract service : services) {
|
||||
@@ -335,30 +392,34 @@ public final class IngestTopComponent extends TopComponent implements DataExplor
|
||||
images.add(image);
|
||||
} catch (TskException e) {
|
||||
logger.log(Level.SEVERE, "Error ingesting image, can't retrieve image id: " + Integer.toString(imageId), e);
|
||||
|
||||
|
||||
} catch (SQLException e) {
|
||||
logger.log(Level.SEVERE, "Error ingesting image, can't retrieve image id: " + Integer.toString(imageId), e);
|
||||
}
|
||||
}
|
||||
|
||||
manager.execute(servicesToStart, images);
|
||||
if (! services.isEmpty() && ! images.isEmpty())
|
||||
manager.execute(servicesToStart, images);
|
||||
}//GEN-LAST:event_startButtonActionPerformed
|
||||
|
||||
|
||||
private void freqSliderStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_freqSliderStateChanged
|
||||
JSlider source = (JSlider) evt.getSource();
|
||||
if (!source.getValueIsAdjusting()) {
|
||||
final int refresh = (int) source.getValue();
|
||||
manager.setUpdateFrequency(refresh);
|
||||
|
||||
|
||||
}
|
||||
}//GEN-LAST:event_freqSliderStateChanged
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JPanel controlPanel;
|
||||
private javax.swing.JSlider freqSlider;
|
||||
private javax.swing.JLabel ingestProgressLabel;
|
||||
private javax.swing.JPanel mainPanel;
|
||||
private javax.swing.JProgressBar mainProgressBar;
|
||||
private javax.swing.JScrollPane mainScrollPane;
|
||||
private javax.swing.JInternalFrame messageFrame;
|
||||
private javax.swing.JLabel refreshFreqLabel;
|
||||
private javax.swing.JLabel refreshFrequencyLabel;
|
||||
private javax.swing.JPanel servicesPanel;
|
||||
private javax.swing.JButton startButton;
|
||||
private javax.swing.JLabel topLable;
|
||||
@@ -369,7 +430,7 @@ public final class IngestTopComponent extends TopComponent implements DataExplor
|
||||
logger.log(Level.INFO, "IngestTopComponent opened()");
|
||||
manager = new IngestManager(this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void componentClosed() {
|
||||
logger.log(Level.INFO, "IngestTopComponent closed()");
|
||||
@@ -378,33 +439,42 @@ public final class IngestTopComponent extends TopComponent implements DataExplor
|
||||
void enableStartButton(boolean enable) {
|
||||
startButton.setEnabled(enable);
|
||||
}
|
||||
|
||||
|
||||
void writeProperties(java.util.Properties p) {
|
||||
// better to version settings since initial version as advocated at
|
||||
// http://wiki.apidesign.org/wiki/PropertyFiles
|
||||
p.setProperty("version", "1.0");
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
void readProperties(java.util.Properties p) {
|
||||
String version = p.getProperty("version");
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Display ingest summary report in some dialog
|
||||
*/
|
||||
void displayReport(String ingestReport) {
|
||||
//TODO widget
|
||||
logger.log(Level.INFO, "INGEST REPORT: " + ingestReport);
|
||||
JOptionPane.showMessageDialog(
|
||||
null,
|
||||
ingestReport,
|
||||
"File Ingest Summary",
|
||||
JOptionPane.INFORMATION_MESSAGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display IngestMessage from service (forwarded by IngestManager)
|
||||
*/
|
||||
void displayMessage(IngestMessage ingestMessage) {
|
||||
//TODO widget
|
||||
logger.log(Level.INFO, "INGEST MESSAGE: " + ingestMessage.toString());
|
||||
messagePanel.addMessage(ingestMessage);
|
||||
}
|
||||
|
||||
void initProgress(int maximum) {
|
||||
this.mainProgressBar.setMaximum(maximum);
|
||||
}
|
||||
|
||||
void updateProgress(int progress) {
|
||||
this.mainProgressBar.setValue(progress);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.ingest.example;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.sleuthkit.autopsy.ingest.IngestImageWorkerController;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.autopsy.ingest.IngestMessage;
|
||||
import org.sleuthkit.autopsy.ingest.IngestMessage.MessageType;
|
||||
@@ -33,26 +34,53 @@ import org.sleuthkit.datamodel.Image;
|
||||
public final class ExampleImageIngestService implements IngestServiceImage {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ExampleImageIngestService.class.getName());
|
||||
private static ExampleImageIngestService instance = null;
|
||||
private static ExampleImageIngestService defaultInstance = null;
|
||||
private IngestManager manager;
|
||||
|
||||
private static int messageId = 0;
|
||||
|
||||
//public constructor is required
|
||||
//as multiple instances are created for processing multiple images simultenously
|
||||
public ExampleImageIngestService() {
|
||||
}
|
||||
|
||||
//default instance used for service registration
|
||||
public static synchronized ExampleImageIngestService getDefault() {
|
||||
if (instance == null) {
|
||||
instance = new ExampleImageIngestService();
|
||||
if (defaultInstance == null) {
|
||||
defaultInstance = new ExampleImageIngestService();
|
||||
}
|
||||
return instance;
|
||||
return defaultInstance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(Image image) {
|
||||
public void process(Image image, IngestImageWorkerController controller) {
|
||||
logger.log(Level.INFO, "process() " + this.toString());
|
||||
|
||||
manager.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, this, "Processing " + image.getName()));
|
||||
|
||||
//service specific Image processing code here
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
} catch (InterruptedException e) {
|
||||
//example:
|
||||
|
||||
//if we know amount of work units, we can switch to determinate and update progress bar
|
||||
int filesToProcess = 100;
|
||||
controller.switchToDeterminate(filesToProcess);
|
||||
int processedFiles = 0;
|
||||
|
||||
while (filesToProcess-- > 0) {
|
||||
|
||||
//check if should terminate on every loop iteration
|
||||
if (controller.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
//do the work
|
||||
Thread.sleep(500);
|
||||
//post message to user if found something interesting
|
||||
manager.postMessage(IngestMessage.createMessage(processedFiles, MessageType.INFO, this, "Processed " + image.getName() + ": " + Integer.toString(processedFiles)));
|
||||
|
||||
//update progress
|
||||
controller.progress(++processedFiles);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,10 +88,12 @@ public final class ExampleImageIngestService implements IngestServiceImage {
|
||||
|
||||
@Override
|
||||
public void complete() {
|
||||
logger.log(Level.INFO, "complete()");
|
||||
manager.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, this, "COMPLETE"));
|
||||
|
||||
//service specific cleanup due completion here
|
||||
logger.log(Level.INFO, "complete() " + this.toString());
|
||||
|
||||
final IngestMessage msg = IngestMessage.createMessage(++messageId, MessageType.INFO, this, "completed image processing");
|
||||
manager.postMessage(msg);
|
||||
|
||||
//service specific cleanup due to completion here
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -73,18 +103,18 @@ public final class ExampleImageIngestService implements IngestServiceImage {
|
||||
|
||||
@Override
|
||||
public void init(IngestManager manager) {
|
||||
logger.log(Level.INFO, "init()");
|
||||
logger.log(Level.INFO, "init() " + this.toString());
|
||||
this.manager = manager;
|
||||
|
||||
//service specific initialization here
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
logger.log(Level.INFO, "stop()");
|
||||
|
||||
//service specific cleanup due interruption here
|
||||
|
||||
//service specific cleanup due to interruption here
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -8,17 +8,18 @@
|
||||
<attr name="position" intvalue="300"/>
|
||||
</file>
|
||||
<!-- example services -->
|
||||
<!--
|
||||
|
||||
<file name="org-sleuthkit-autopsy-ingest-example-ExampleImageIngestService.instance">
|
||||
<attr name="instanceOf" stringvalue="org.sleuthkit.autopsy.ingest.IngestServiceImage"/>
|
||||
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.ingest.example.ExampleImageIngestService.getDefault"/>
|
||||
<attr name="position" intvalue="1000"/>
|
||||
</file>
|
||||
|
||||
<file name="org-sleuthkit-autopsy-ingest-example-ExampleFsContentIngestService.instance">
|
||||
<attr name="instanceOf" stringvalue="org.sleuthkit.autopsy.ingest.IngestServiceFsContent"/>
|
||||
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.ingest.example.ExampleFsContentIngestService.getDefault"/>
|
||||
<attr name="position" intvalue="1100"/>
|
||||
</file>
|
||||
-->
|
||||
|
||||
</folder>
|
||||
</filesystem>
|
||||
|
||||
@@ -49,7 +49,7 @@ public final class KeywordSearchIngestService implements IngestServiceFsContent
|
||||
Thread.sleep(100);
|
||||
}
|
||||
catch (InterruptedException e) {}
|
||||
manager.postMessage(IngestMessage.createMessage(1, MessageType.INFO, this, "Processing " + fsContent.getName()));
|
||||
//manager.postMessage(IngestMessage.createMessage(1, MessageType.INFO, this, "Processing " + fsContent.getName()));
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user