diff --git a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessor.java b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessor.java index e150e871ac..f76f6b29a1 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessor.java @@ -21,69 +21,70 @@ package org.sleuthkit.autopsy.corecomponentinterfaces; import javax.swing.JPanel; -/* - * Defines an interface used by the Add DataSource wizard to discover different - * Data SourceProcessors. +/** + * Interface used by the Add DataSource wizard to allow different + * types of data sources to be added to a case. Examples of data + * sources include disk images, local files, etc. * - * Each data source may have its unique attributes and may need to be processed - * differently. - * - * The DataSourceProcessor interface defines a uniform mechanism for the Autopsy UI + * The interface provides a uniform mechanism for the Autopsy UI * to: - * - collect details for the data source to be processed. - * - Process the data source in the background - * - Be notified when the processing is complete + * - Collect details from the user about the data source to be processed. + * - Process the data source in the background and add data to the database + * - Provides progress feedback to the user / UI. */ public interface DataSourceProcessor { - /* + /** * The DSP Panel may fire Property change events * The caller must enure to add itself as a listener and * then react appropriately to the events */ enum DSP_PANEL_EVENT { - - UPDATE_UI, // the content of JPanel has changed that MAY warrant updates to the caller UI - FOCUS_NEXT // the caller UI may move focus the the next UI element, following the panel. + UPDATE_UI, ///< the content of JPanel has changed that MAY warrant updates to the caller UI + FOCUS_NEXT ///< the caller UI may move focus the the next UI element, following the panel. }; /** * Returns the type of Data Source it handles. * This name gets displayed in the drop-down listbox - **/ + */ String getDataSourceType(); /** * Returns the picker panel to be displayed along with any other - * runtime options supported by the data source handler. - **/ + * runtime options supported by the data source handler. The + * DSP is responsible for storing the settings so that a later + * call to run() will have the user-specified settings. + * + * Should be less than 544 pixels wide and 173 pixels high. + */ JPanel getPanel(); /** * Called to validate the input data in the panel. * Returns true if no errors, or * Returns false if there is an error. - **/ + */ boolean isPanelValid(); /** - * Called to invoke the handling of Data source in the background. - * Returns after starting the background thread - * @param settings wizard settings to read/store properties - * @param progressPanel progress panel to be updated while processing + * Called to invoke the handling of data source in the background. + * Returns after starting the background thread. * - **/ + * @param progressPanel progress panel to be updated while processing + * @param dspCallback Contains the callback method DataSourceProcessorCallback.done() that the DSP must call when the background thread finishes with errors and status. + */ void run(DataSourceProcessorProgressMonitor progressPanel, DataSourceProcessorCallback dspCallback); /** * Called to cancel the background processing. - **/ + */ void cancel(); /** * Called to reset/reinitialize the DSP. - **/ + */ void reset(); } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessorCallback.java b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessorCallback.java index 1b69c03c17..76acfd2efc 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessorCallback.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessorCallback.java @@ -16,7 +16,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.corecomponentinterfaces; import java.awt.EventQueue; @@ -25,42 +24,52 @@ import org.sleuthkit.datamodel.Content; /** * Abstract class for a callback for a DataSourceProcessor. - * - * Ensures that DSP invokes the caller overridden method, doneEDT(), - * in the EDT thread. - * + * + * Ensures that DSP invokes the caller overridden method, doneEDT(), in the EDT + * thread. + * */ public abstract class DataSourceProcessorCallback { - - public enum DataSourceProcessorResult - { - NO_ERRORS, - CRITICAL_ERRORS, - NONCRITICAL_ERRORS, + + public enum DataSourceProcessorResult { + NO_ERRORS, ///< No errors were encountered while ading the data source + CRITICAL_ERRORS, ///< No data was added to the database. There were fundamental errors processing the data (such as no data or system failure). + NONCRITICAL_ERRORS, ///< There was data added to the database, but there were errors from data corruption or a small number of minor issues. }; + - /* - * Invoke the caller supplied callback function on the EDT thread + /** + * Called by a DSP implementation when it is done adding a data source + * to the database. Users of the DSP can override this method if they do + * not want to be notified on the EDT. Otherwise, this method will call + * doneEDT() with the same arguments. + * @param result Code for status + * @param errList List of error strings + * @param newContents List of root Content objects that were added to database. Typically only one is given. */ - public void done(DataSourceProcessorResult result, List errList, List newContents) - { - + public void done(DataSourceProcessorResult result, List errList, List newContents) { + final DataSourceProcessorResult resultf = result; final List errListf = errList; final List newContentsf = newContents; - - // Invoke doneEDT() that runs on the EDT . - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - doneEDT(resultf, errListf, newContentsf ); - - } - }); + + // Invoke doneEDT() that runs on the EDT . + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + doneEDT(resultf, errListf, newContentsf); + } + }); } - - /* - * calling code overrides to provide its own calllback - */ - public abstract void doneEDT(DataSourceProcessorResult result, List errList, List newContents); + + /** + * Called by done() if the default implementation is used. Users of DSPs + * that have UI updates to do after the DSP is finished adding the DS can + * implement this method to receive the updates on the EDT. + * + * @param result Code for status + * @param errList List of error strings + * @param newContents List of root Content objects that were added to database. Typically only one is given. + */ + public abstract void doneEDT(DataSourceProcessorResult result, List errList, List newContents); }; diff --git a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessorProgressMonitor.java b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessorProgressMonitor.java index 7495979d71..28001a9d62 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessorProgressMonitor.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessorProgressMonitor.java @@ -18,10 +18,10 @@ */ package org.sleuthkit.autopsy.corecomponentinterfaces; -/* +/** * An GUI agnostic DataSourceProcessorProgressMonitor interface for DataSourceProcesssors to * indicate progress. - * It models after a JProgressbar though it could use any underlying implementation + * It models after a JProgressbar though it could use any underlying implementation (or NoOps) */ public interface DataSourceProcessorProgressMonitor { diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/FXVideoPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/FXVideoPanel.java index 809be1da89..728749ccf6 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/FXVideoPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/FXVideoPanel.java @@ -78,8 +78,10 @@ import org.sleuthkit.datamodel.TskData; @ServiceProvider(service = FrameCapture.class) }) public class FXVideoPanel extends MediaViewVideoPanel { - - private static final String[] EXTENSIONS = new String[]{".mov", ".m4v", ".flv", ".mp4", ".mpg", ".mpeg"}; //NON-NLS + + // Refer to https://docs.oracle.com/javafx/2/api/javafx/scene/media/package-summary.html + // for Javafx supported formats + private static final String[] EXTENSIONS = new String[]{".m4v", ".fxm", ".flv", ".m3u8", ".mp4", ".aif", ".aiff", ".mp3", "m4a", ".wav"}; //NON-NLS private static final List MIMETYPES = Arrays.asList("audio/x-aiff", "video/x-javafx", "video/x-flv", "application/vnd.apple.mpegurl", " audio/mpegurl", "audio/mpeg", "video/mp4", "audio/x-m4a", "video/x-m4v", "audio/x-wav"); //NON-NLS private static final Logger logger = Logger.getLogger(MediaViewVideoPanel.class.getName()); @@ -478,6 +480,10 @@ public class FXVideoPanel extends MediaViewVideoPanel { pauseButton.setOnAction(new EventHandler() { @Override public void handle(ActionEvent e) { + if (mediaPlayer == null) { + return; + } + Status status = mediaPlayer.getStatus(); switch (status) { @@ -496,7 +502,7 @@ public class FXVideoPanel extends MediaViewVideoPanel { // If the MediaPlayer is in an unexpected state, stop playback. mediaPlayer.stop(); setInfoLabelText(NbBundle.getMessage(this.getClass(), - "FXVideoPanel.pauseButton.infoLabel.playbackErr")); + "FXVideoPanel.pauseButton.infoLabel.playbackErr")); break; } } @@ -505,6 +511,10 @@ public class FXVideoPanel extends MediaViewVideoPanel { stopButton.setOnAction(new EventHandler() { @Override public void handle(ActionEvent e) { + if (mediaPlayer == null) { + return; + } + mediaPlayer.stop(); } }); @@ -512,6 +522,10 @@ public class FXVideoPanel extends MediaViewVideoPanel { progressSlider.valueProperty().addListener(new InvalidationListener() { @Override public void invalidated(Observable o) { + if (mediaPlayer == null) { + return; + } + if (progressSlider.isValueChanging()) { mediaPlayer.seek(duration.multiply(progressSlider.getValue() / 100.0)); } @@ -559,6 +573,9 @@ public class FXVideoPanel extends MediaViewVideoPanel { * media. */ private void updateProgress() { + if (mediaPlayer == null) { + return; + } Duration currentTime = mediaPlayer.getCurrentTime(); updateSlider(currentTime); updateTime(currentTime); @@ -634,6 +651,10 @@ public class FXVideoPanel extends MediaViewVideoPanel { @Override public void run() { + if (mediaPlayer == null) { + return; + } + duration = mediaPlayer.getMedia().getDuration(); long durationInMillis = (long) mediaPlayer.getMedia().getDuration().toMillis(); @@ -657,6 +678,10 @@ public class FXVideoPanel extends MediaViewVideoPanel { @Override public void run() { + if (mediaPlayer == null) { + return; + } + Duration beginning = mediaPlayer.getStartTime(); mediaPlayer.stop(); mediaPlayer.pause(); diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java index b5944cd2b4..2bbb74d823 100755 --- a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java @@ -33,11 +33,9 @@ import java.util.List; import java.util.logging.Level; import javax.imageio.ImageIO; import javax.swing.ImageIcon; -import org.openide.util.Exceptions; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.corelibs.ScalrWrapper; import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.Content; @@ -55,7 +53,11 @@ public class ImageUtils { private static final Logger logger = Logger.getLogger(ImageUtils.class.getName()); private static final Image DEFAULT_ICON = new ImageIcon("/org/sleuthkit/autopsy/images/file-icon.png").getImage(); //NON-NLS private static final List SUPP_EXTENSIONS = Arrays.asList(ImageIO.getReaderFileSuffixes()); - private static final List SUPP_MIME_TYPES = Arrays.asList(ImageIO.getReaderMIMETypes()); + private static final List SUPP_MIME_TYPES = new ArrayList(Arrays.asList(ImageIO.getReaderMIMETypes())); + static { + SUPP_MIME_TYPES.add("image/x-ms-bmp"); + } + /** * Get the default Icon, which is the icon for a file. * @return @@ -88,14 +90,17 @@ public class ImageUtils { return true; } } + // if the file type is known and we don't support it, bail + if (attributes.size() > 0) { + return false; + } } catch (TskCoreException ex) { logger.log(Level.WARNING, "Error while getting file signature from blackboard.", ex); //NON-NLS } - final String extension = f.getNameExtension(); - // if we have an extension, check it + final String extension = f.getNameExtension(); if (extension.equals("") == false) { // Note: thumbnail generator only supports JPG, GIF, and PNG for now if (SUPP_EXTENSIONS.contains(extension)) { @@ -109,7 +114,8 @@ public class ImageUtils { /** - * Get an icon of a specified size. + * Get a thumbnail of a specified size. Generates the image if it is + * not already cached. * * @param content * @param iconSize @@ -118,6 +124,7 @@ public class ImageUtils { public static Image getIcon(Content content, int iconSize) { Image icon; // If a thumbnail file is already saved locally + // @@@ Bug here in that we do not refer to size in the cache. File file = getFile(content.getId()); if (file.exists()) { try { @@ -125,7 +132,7 @@ public class ImageUtils { if (bicon == null) { icon = DEFAULT_ICON; } else if (bicon.getWidth() != iconSize) { - icon = generateAndSaveIcon(content, iconSize); + icon = generateAndSaveIcon(content, iconSize, file); } else { icon = bicon; } @@ -134,18 +141,17 @@ public class ImageUtils { icon = DEFAULT_ICON; } } else { // Make a new icon - icon = generateAndSaveIcon(content, iconSize); + icon = generateAndSaveIcon(content, iconSize, file); } return icon; } /** - * Get the cached file of the icon. Generates the icon and its file if it - * doesn't already exist, so this method guarantees to return a file that - * exists. + * Get a thumbnail of a specified size. Generates the image if it is + * not already cached. * @param content * @param iconSize - * @return + * @return File object for cached image. Is guaranteed to exist. */ public static File getIconFile(Content content, int iconSize) { if (getIcon(content, iconSize) != null) { @@ -155,13 +161,12 @@ public class ImageUtils { } /** - * Get the cached file of the content object with the given id. - * - * The returned file may not exist. + * Get a file object for where the cached icon should exist. The returned file may not exist. * * @param id * @return */ + // TODO: This should be private and be renamed to something like getCachedThumbnailLocation(). public static File getFile(long id) { return new File(Case.getCurrentCase().getCacheDirectory() + File.separator + id + ".png"); } @@ -223,18 +228,24 @@ public class ImageUtils { } - private static Image generateAndSaveIcon(Content content, int iconSize) { + /** + * Generate an icon and save it to specified location. + * @param content File to generate icon for + * @param iconSize + * @param saveFile Location to save thumbnail to + * @return Generated icon or null on error + */ + private static Image generateAndSaveIcon(Content content, int iconSize, File saveFile) { Image icon = null; try { icon = generateIcon(content, iconSize); if (icon == null) { return DEFAULT_ICON; } else { - File f = getFile(content.getId()); - if (f.exists()) { - f.delete(); + if (saveFile.exists()) { + saveFile.delete(); } - ImageIO.write((BufferedImage) icon, "png", getFile(content.getId())); //NON-NLS + ImageIO.write((BufferedImage) icon, "png", saveFile); //NON-NLS } } catch (IOException ex) { logger.log(Level.WARNING, "Could not write cache thumbnail: " + content, ex); //NON-NLS @@ -243,7 +254,7 @@ public class ImageUtils { } /* - * Generate a scaled image + * Generate and return a scaled image */ private static BufferedImage generateIcon(Content content, int iconSize) { diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/CollapseAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/CollapseAction.java index d554f63e04..5ed8778618 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/CollapseAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/CollapseAction.java @@ -44,7 +44,14 @@ class CollapseAction extends AbstractAction { // Collapse all BeanTreeView tree = DirectoryTreeTopComponent.findInstance().getTree(); - collapseAll(tree, selectedNode[0]); + if(selectedNode.length != 0) { + collapseSelectedNode(tree, selectedNode[0]); + } else { + // If no node is selected, all the level-2 nodes (children of the + // root node) are collapsed. + for(Node childOfRoot: em.getRootContext().getChildren().getNodes()) + collapseSelectedNode(tree, childOfRoot); + } } /** @@ -53,13 +60,13 @@ class CollapseAction extends AbstractAction { * @param tree the given tree * @param currentNode the current selectedNode */ - private void collapseAll(BeanTreeView tree, Node currentNode) { + private void collapseSelectedNode(BeanTreeView tree, Node currentNode) { Children c = currentNode.getChildren(); for (Node next : c.getNodes()) { if (tree.isExpanded(next)) { - this.collapseAll(tree, next); + this.collapseSelectedNode(tree, next); } } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java index 15da98c0b7..dbbb906a4e 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java @@ -39,6 +39,7 @@ import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Directory; import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.VirtualDirectory; /** * This class sets the actions for the nodes in the directory tree and creates @@ -106,22 +107,35 @@ class DirectoryTreeFilterNode extends FilterNode { actions.add(ExtractAction.getInstance()); } - // file search action final Image img = this.getLookup().lookup(Image.class); - if (img != null) { - actions.add(new FileSearchAction( - NbBundle.getMessage(this.getClass(), "DirectoryTreeFilterNode.action.openFileSrcByAttr.text"))); + + VirtualDirectory virtualDirectory = this.getLookup().lookup(VirtualDirectory.class); + // determine if the virtualDireory is at root-level (Logical File Set). + boolean isRootVD = false; + if (virtualDirectory != null) { + try { + if (virtualDirectory.getParent() == null) { + isRootVD = true; + } + } catch (TskCoreException ex) { + logger.log(Level.WARNING, "Error determining the parent of the virtual directory", ex); // NON-NLS + } } - //ingest action - actions.add(new AbstractAction( - NbBundle.getMessage(this.getClass(), "DirectoryTreeFilterNode.action.runIngestMods.text")) { - @Override - public void actionPerformed(ActionEvent e) { - final RunIngestModulesDialog ingestDialog = new RunIngestModulesDialog(Collections.singletonList(content)); - ingestDialog.display(); - } - }); + // 'run ingest' action and 'file search' action are added only if the + // selected node is img node or a root level virtual directory. + if (img != null || isRootVD) { + actions.add(new FileSearchAction( + NbBundle.getMessage(this.getClass(), "DirectoryTreeFilterNode.action.openFileSrcByAttr.text"))); + actions.add(new AbstractAction( + NbBundle.getMessage(this.getClass(), "DirectoryTreeFilterNode.action.runIngestMods.text")) { + @Override + public void actionPerformed(ActionEvent e) { + final RunIngestModulesDialog ingestDialog = new RunIngestModulesDialog(Collections.singletonList(content)); + ingestDialog.display(); + } + }); + } } //check if delete actions should be added diff --git a/Core/src/org/sleuthkit/autopsy/examples/SampleFileIngestModule.java b/Core/src/org/sleuthkit/autopsy/examples/SampleFileIngestModule.java index a6dc6af76b..e3420e0468 100755 --- a/Core/src/org/sleuthkit/autopsy/examples/SampleFileIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/examples/SampleFileIngestModule.java @@ -98,7 +98,7 @@ class SampleFileIngestModule implements FileIngestModule { @Override public IngestModule.ProcessResult process(AbstractFile file) { - if (attrId != -1) { + if (attrId == -1) { return IngestModule.ProcessResult.ERROR; } diff --git a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverFileIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverFileIngestModule.java index da78665e73..8a35a4edbf 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverFileIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverFileIngestModule.java @@ -248,7 +248,7 @@ final class PhotoRecCarverFileIngestModule implements FileIngestModule { */ @Override public void shutDown() { - if (refCounter.decrementAndGet(this.context.getJobId()) == 0) { + if (this.context != null && refCounter.decrementAndGet(this.context.getJobId()) == 0) { try { // The last instance of this module for an ingest job cleans out // the working paths map entry for the job and deletes the temp dir. diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ThumbnailCache.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ThumbnailCache.java index ee7c74e981..e22eb75488 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ThumbnailCache.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ThumbnailCache.java @@ -153,6 +153,7 @@ public enum ThumbnailCache { } private static File getCacheFile(long id) { + // @@@ should use ImageUtils.getFile(); return new File(Case.getCurrentCase().getCacheDirectory() + File.separator + id + ".png"); } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LuceneQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LuceneQuery.java index 72e564c11b..aef452b7d5 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LuceneQuery.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LuceneQuery.java @@ -340,7 +340,6 @@ class LuceneQuery implements KeywordSearchQuery { List snippetList = highlightResponse.get(docId).get(Server.Schema.TEXT.toString()); // list is null if there wasn't a snippet if (snippetList != null) { - snippetList.sort(null); snippet = EscapeUtil.unEscapeHtml(snippetList.get(0)).trim(); } } @@ -440,7 +439,6 @@ class LuceneQuery implements KeywordSearchQuery { //docs says makes sense for the original Highlighter only, but not really //analyze all content SLOW! consider lowering q.setParam("hl.maxAnalyzedChars", Server.HL_ANALYZE_CHARS_UNLIMITED); //NON-NLS - q.setParam("hl.preserveMulti", true); //NON-NLS try { QueryResponse response = solrServer.query(q, METHOD.POST); @@ -453,8 +451,6 @@ class LuceneQuery implements KeywordSearchQuery { if (contentHighlights == null) { return ""; } else { - // Sort contentHighlights in order to get consistently same snippet. - contentHighlights.sort(null); // extracted content is HTML-escaped, but snippet goes in a plain text field return EscapeUtil.unEscapeHtml(contentHighlights.get(0)).trim(); } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java index 131fb319c3..2f6997be76 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java @@ -1097,8 +1097,7 @@ public class Server { filterQuery = filterQuery + Server.ID_CHUNK_SEP + chunkID; } q.addFilterQuery(filterQuery); - // sort the TEXT field - q.setSortField(Schema.TEXT.toString(), SolrQuery.ORDER.asc); + q.setFields(Schema.TEXT.toString()); try { // Get the first result. SolrDocument solrDocument = solrCore.query(q).getResults().get(0); diff --git a/docs/doxygen/modIngest.dox b/docs/doxygen/modIngest.dox index 8bbcbd043b..ffea77385d 100755 --- a/docs/doxygen/modIngest.dox +++ b/docs/doxygen/modIngest.dox @@ -271,17 +271,22 @@ that the samples do not do anything particularly useful. Autopsy allows you to provide a graphical panel that will be displayed when the user decides to enable the ingest module. This panel is supposed to be for settings that the user may turn on or off for different data sources. + To provide options for each ingest job: - Update org.sleuthkit.autopsy.ingest.IngestModuleFactory.hasIngestJobSettingsPanel() in your factory class to return true. -- Update org.sleuthkit.autopsy.ingest.IngestModuleFactory.getIngestJobSettingsPanel() in your factory class to return a IngestModuleIngestJobSettingsPanel that displays the needed configuration options and returns a IngestModuleIngestJobSettings object based on the settings. This will get passed in the last configuration setting that was used, so that you can populate the panel accordlingly and the user doesn't have to choose new settings. -- Create a class based on org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings to store the settings. +- Update org.sleuthkit.autopsy.ingest.IngestModuleFactory.getIngestJobSettingsPanel() in your factory class to return a IngestModuleIngestJobSettingsPanel that displays the needed configuration options. The org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel.getSettings() method should return an instance of a org.sleutkit.autopsy.ingest.IngestModuleIngestJobSettings object based on the user-specified settings (see next bullet). +- Create a class that implements org.sleutkit.autopsy.ingest.IngestModuleIngestJobSettings. Your IngestModuleIngestJobSettingsPanel should store settings in here. This class needs to be Serializable, so keep all data types simple or mark them as transient with some custom deserialization code. You should also set the serialVersionUID (see http://stackoverflow.com/questions/285793/what-is-a-serialversionuid-and-why-should-i-use-it). +- If you decide to store settings internal to the module (NOT RECOMMENDED), the getSettings() method can return an instance of NoIngestModuleIngestJobSettings. +- Your instance of IngestModuleIngestJobSettings will be saved and passed to your panel the next time so that you can pre-populate it accordingly. + +Your panel should create the IngestModuleIngestJobSettings class to store the settings and that will be passed back into your factory with each call to createDataSourceIngestModule() or createFileIngestModule(). The way that we have implemented this in Autopsy modules is that the factory casts the IngestModuleINgestJobSettings object to the module-specific implementation and then passes it into the constructor of the ingest module. The ingest module can then call whatever getter methods that were defined based on the panel settings. -Your panel should create the IngestModuleIngestJobSettings class to store the settings and that will be passed back into your factory with each call to createDataSourceIngestModule() or createFileIngestModule(). The factory should cast it to its internal class that implements IngestModuleIngestJobSettings and pass that object into the constructor of its ingest module so that it can use the settings when it runs. You can also implement the getDefaultIngestJobSettings() method to return an instance of your IngestModuleIngestJobSettings class with default settings. Autopsy will call this when the module has not been run before. NOTE: We recommend storing simple data in the IngestModuleIngestJobSettings-based class. In the case of our hash lookup module, we store the string names of the hash databases to do lookups in. We then get the hash database handles in the call to startUp() using the global module settings. + NOTE: The main benefit of using the IngestModuleIngestJobSettings-based class to store settings (versus some static variables in your package) are: - When multiple jobs are running at the same time, each can have their own settings. - Autopsy persists them so that the last used settings get passed into the call to getIngestJobSettingsPanel() and you don't need to save them yoursevles to provide the user the benefit of re-using the last settings. diff --git a/docs/doxygen/platformConcepts.dox b/docs/doxygen/platformConcepts.dox index f567f4e747..8600b23aa5 100755 --- a/docs/doxygen/platformConcepts.dox +++ b/docs/doxygen/platformConcepts.dox @@ -44,12 +44,10 @@ The blackboard allows modules to communicate with each other and the UI. It has The blackboard is not unique to Autopsy. It is part of The Sleuth Kit datamodel and The Sleuth Kit Framework. In the name of reducing the amount of documentation that we need to maintain, we provide links here to those documentation sources. -- Details on the blackboard concepts (artifacts versus attributes) can be found at http://sleuthkit.org/sleuthkit/docs/framework-docs/mod_bbpage.html. These documents are about the C++ implementation of the blackboard, but it is the same concepts. -- Details of the Java classes can be found in \ref jni_blackboard section of the The Sleuth Kit JNI documents (http://sleuthkit.org/sleuthkit/docs/jni-docs/). +- \ref mod_bbpage (http://sleuthkit.org/sleuthkit/docs/jni-docs/mod_bbpage.html) - -\subsection mod_dev_other_services Framework Services and Utilities +\section mod_dev_other_services Framework Services and Utilities The following are basic services that are available to any module. They are provided here to be used as a reference. When you are developing your module and feel like something should be provided by the framework, then refer to this list to find out where it could be. If you don't find it, let us know and we'll talk about adding it for other writers to benefit.