Implemented and tested the XRY DSP

This commit is contained in:
U-BASIS\dsmyda 2019-11-14 14:14:14 -05:00
parent 875b789abb
commit aa88bc69b5
7 changed files with 588 additions and 1 deletions

View File

@ -0,0 +1,3 @@
XRYDataSourceProcessorConfigPanel.fileBrowserButton.text=Browse
XRYDataSourceProcessorConfigPanel.filePathTextField.text=
XRYDataSourceProcessorConfigPanel.xrySelectFolderLabel.text=Select an XRY Folder

View File

@ -0,0 +1,12 @@
XRYDataSourceProcessor.dataSourceType=Import Tool Report
XRYDataSourceProcessor.fileAdded=Added %s to the case database
XRYDataSourceProcessor.ioError=I/O error occured trying to test the XRY report folder
XRYDataSourceProcessor.notReadable=Could not read from the selected folder
XRYDataSourceProcessor.notXRYFolder=Selected folder did not contain any XRY files
XRYDataSourceProcessor.preppingFiles=Preparing to add files to the case database
XRYDataSourceProcessor.processingFiles=Processing all XRY files...
XRYDataSourceProcessor.testingFolder=Testing input folder...
XRYDataSourceProcessor.unexpectedError=Internal error occurred while processing XRY report
XRYDataSourceProcessorConfigPanel.fileBrowserButton.text=Browse
XRYDataSourceProcessorConfigPanel.filePathTextField.text=
XRYDataSourceProcessorConfigPanel.xrySelectFolderLabel.text=Select an XRY Folder

View File

@ -0,0 +1,242 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 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.datasourceprocessors.xry;
import com.google.common.collect.Lists;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.stream.Collectors;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
import org.openide.util.NbBundle;
import org.openide.util.lookup.ServiceProvider;
import org.openide.util.lookup.ServiceProviders;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.casemodule.services.FileManager;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.LocalFilesDataSource;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskDataException;
/**
* An XRY Report data source processor.
*/
@ServiceProviders(value = {
@ServiceProvider(service = DataSourceProcessor.class)}
)
public class XRYDataSourceProcessor implements DataSourceProcessor {
private final XRYDataSourceProcessorConfigPanel configPanel;
//Background processor to relieve the EDT from adding files to the case
//database and parsing the report files.
private XRYReportProcessorSwingWorker swingWorker;
private static final Logger logger = Logger.getLogger(XRYDataSourceProcessor.class.getName());
public XRYDataSourceProcessor() {
configPanel = XRYDataSourceProcessorConfigPanel.getInstance();
}
@Override
@NbBundle.Messages({
"XRYDataSourceProcessor.dataSourceType=Import Tool Report"
})
public String getDataSourceType() {
return Bundle.XRYDataSourceProcessor_dataSourceType();
}
@Override
public JPanel getPanel() {
return configPanel;
}
@Override
public boolean isPanelValid() {
return true;
}
/**
* Processes the XRY folder the examiner selected. The heavy lifting
* is handed off to a dedicated thread. This function will
* test the minimum requirements needed to successfully process the input.
*/
@Override
@NbBundle.Messages({
"XRYDataSourceProcessor.testingFolder=Testing input folder...",
"XRYDataSourceProcessor.notReadable=Could not read from the selected folder",
"XRYDataSourceProcessor.notXRYFolder=Selected folder did not contain any XRY files",
"XRYDataSourceProcessor.ioError=I/O error occured trying to test the XRY report folder"
})
public void run(DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
progressMonitor.setProgressText(Bundle.XRYDataSourceProcessor_testingFolder());
String selectedFilePath = configPanel.getSelectedFilePath();
File selectedFile = new File(selectedFilePath);
Path selectedPath = selectedFile.toPath();
//Test permissions
if (!Files.isReadable(selectedPath)) {
callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS,
Lists.newArrayList(Bundle.XRYDataSourceProcessor_notReadable()),
Lists.newArrayList());
return;
}
try {
//Validate the folder.
if (!XRYFolder.isXRYFolder(selectedPath)) {
callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS,
Lists.newArrayList(Bundle.XRYDataSourceProcessor_notXRYFolder()),
Lists.newArrayList());
return;
}
} catch (IOException ex) {
logger.log(Level.WARNING, "[XRY DSP] I/O exception encountered trying to test the XRY folder.", ex);
callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS,
Lists.newArrayList(Bundle.XRYDataSourceProcessor_ioError(), ex.toString()), Lists.newArrayList());
return;
}
try {
XRYFolder xryFolder = new XRYFolder(selectedPath);
FileManager fileManager = Case.getCurrentCaseThrows()
.getServices().getFileManager();
//Move heavy lifting to a dedicated thread.
swingWorker = new XRYReportProcessorSwingWorker(xryFolder, progressMonitor,
callback, fileManager);
swingWorker.execute();
} catch (NoCurrentCaseException ex) {
logger.log(Level.WARNING, "[XRY DSP] No case is currently open.", ex);
}
}
@Override
public void cancel() {
if (swingWorker != null) {
swingWorker.cancel(true);
}
}
@Override
public void reset() {
//Clear the current selected file path.
configPanel.clearSelectedFilePath();
}
/**
* Relieves the EDT from add images to the case database and processing the
* XRY report files.
*/
private class XRYReportProcessorSwingWorker extends SwingWorker<LocalFilesDataSource, Void> {
private final DataSourceProcessorProgressMonitor progressMonitor;
private final DataSourceProcessorCallback callback;
private final FileManager fileManager;
private final XRYFolder xryFolder;
public XRYReportProcessorSwingWorker(XRYFolder folder, DataSourceProcessorProgressMonitor progressMonitor,
DataSourceProcessorCallback callback, FileManager fileManager) {
this.xryFolder = folder;
this.progressMonitor = progressMonitor;
this.callback = callback;
this.fileManager = fileManager;
}
@Override
@NbBundle.Messages({
"XRYDataSourceProcessor.preppingFiles=Preparing to add files to the case database",
"XRYDataSourceProcessor.processingFiles=Processing all XRY files..."
})
protected LocalFilesDataSource doInBackground() throws TskCoreException,
TskDataException, IOException {
progressMonitor.setProgressText(Bundle.XRYDataSourceProcessor_preppingFiles());
List<Path> nonXRYFiles = xryFolder.getNonXRYFiles();
List<String> filePaths = nonXRYFiles.stream()
//Map paths to string representations.
.map(Path::toString)
.collect(Collectors.toList());
String uniqueUUID = UUID.randomUUID().toString();
LocalFilesDataSource dataSource = fileManager.addLocalFilesDataSource(
uniqueUUID,
"XRY Report", //Name
"", //Timezone
filePaths,
new ProgressMonitorAdapter(progressMonitor));
//Process the report files.
progressMonitor.setProgressText(Bundle.XRYDataSourceProcessor_processingFiles());
XRYReportProcessor.process(xryFolder, dataSource);
return dataSource;
}
@Override
@NbBundle.Messages({
"XRYDataSourceProcessor.unexpectedError=Internal error occurred while processing XRY report"
})
public void done() {
try {
LocalFilesDataSource newDataSource = get();
callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.NO_ERRORS,
Lists.newArrayList(), Lists.newArrayList(newDataSource));
} catch (InterruptedException ex) {
//DSP was cancelled. Not an error.
} catch (ExecutionException ex) {
logger.log(Level.SEVERE, "[XRY DSP] Unexpected internal error while processing XRY report.", ex);
callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS,
Lists.newArrayList(Bundle.XRYDataSourceProcessor_unexpectedError(),
ex.toString()), Lists.newArrayList());
}
}
/**
* Makes the DSP progress monitor compatible with the File Manager
* progress updater.
*/
private class ProgressMonitorAdapter implements FileManager.FileAddProgressUpdater {
private final DataSourceProcessorProgressMonitor progressMonitor;
ProgressMonitorAdapter(DataSourceProcessorProgressMonitor progressMonitor) {
this.progressMonitor = progressMonitor;
}
@Override
@NbBundle.Messages({
"XRYDataSourceProcessor.fileAdded=Added %s to the case database"
})
public void fileAdded(AbstractFile newFile) {
progressMonitor.setProgressText(String.format(Bundle.XRYDataSourceProcessor_fileAdded(), newFile.getName()));
}
}
}
}

View File

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="xrySelectFolderLabel" pref="380" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Component id="filePathTextField" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="fileBrowserButton" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="xrySelectFolderLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="filePathTextField" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="fileBrowserButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace pref="246" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JTextField" name="filePathTextField">
<Properties>
<Property name="editable" type="boolean" value="false"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/datasourceprocessors/xry/Bundle.properties" key="XRYDataSourceProcessorConfigPanel.filePathTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="fileBrowserButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/datasourceprocessors/xry/Bundle.properties" key="XRYDataSourceProcessorConfigPanel.fileBrowserButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="fileBrowserButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="xrySelectFolderLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/datasourceprocessors/xry/Bundle.properties" key="XRYDataSourceProcessorConfigPanel.xrySelectFolderLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,136 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 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.datasourceprocessors.xry;
import java.io.File;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
/**
* Allows an examiner to configure the XRY Data source processor.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class XRYDataSourceProcessorConfigPanel extends JPanel {
private static final XRYDataSourceProcessorConfigPanel INSTANCE =
new XRYDataSourceProcessorConfigPanel();
/**
* Creates new form XRYDataSourceConfigPanel.
* Prevent direct instantiation.
*/
private XRYDataSourceProcessorConfigPanel() {
initComponents();
}
/**
* Gets the singleton XRYDataSourceProcessorConfigPanel.
*/
static XRYDataSourceProcessorConfigPanel getInstance() {
return INSTANCE;
}
/**
* Clears the selected file path.
*/
void clearSelectedFilePath() {
filePathTextField.setText(null);
}
/**
* Gets the file path selected by the examiner.
*/
String getSelectedFilePath() {
return filePathTextField.getText();
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
filePathTextField = new javax.swing.JTextField();
fileBrowserButton = new javax.swing.JButton();
xrySelectFolderLabel = new javax.swing.JLabel();
filePathTextField.setEditable(false);
filePathTextField.setText(org.openide.util.NbBundle.getMessage(XRYDataSourceProcessorConfigPanel.class, "XRYDataSourceProcessorConfigPanel.filePathTextField.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(fileBrowserButton, org.openide.util.NbBundle.getMessage(XRYDataSourceProcessorConfigPanel.class, "XRYDataSourceProcessorConfigPanel.fileBrowserButton.text")); // NOI18N
fileBrowserButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
fileBrowserButtonActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(xrySelectFolderLabel, org.openide.util.NbBundle.getMessage(XRYDataSourceProcessorConfigPanel.class, "XRYDataSourceProcessorConfigPanel.xrySelectFolderLabel.text")); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(xrySelectFolderLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 380, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addComponent(filePathTextField)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(fileBrowserButton)))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(xrySelectFolderLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(filePathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(fileBrowserButton))
.addContainerGap(246, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
/**
* Opens a JFileChooser instance so that the examiner can select a XRY
* report folder.
*/
private void fileBrowserButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fileBrowserButtonActionPerformed
JFileChooser fileChooser = new JFileChooser();
fileChooser.setMultiSelectionEnabled(false);
fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
int returnVal = fileChooser.showOpenDialog(this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
File selection = fileChooser.getSelectedFile();
filePathTextField.setText(selection.getAbsolutePath());
}
}//GEN-LAST:event_fileBrowserButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton fileBrowserButton;
private javax.swing.JTextField filePathTextField;
private javax.swing.JLabel xrySelectFolderLabel;
// End of variables declaration//GEN-END:variables
}

View File

@ -24,7 +24,9 @@ import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Stream;
/**
@ -36,6 +38,62 @@ final class XRYFolder {
//children of their parent folder.
private static final int XRY_FILES_DEPTH = 1;
//Raw path to the XRY folder.
private final Path xryFolder;
public XRYFolder(Path folder) {
xryFolder = folder;
}
/**
* Finds all paths in the XRY report folder which are not XRY files. Only
* the first directory level is searched. As a result, some paths may point
* to directories.
*
* @return A non-null collection of paths
* @throws IOException If an I/O error occurs.
*/
public List<Path> getNonXRYFiles() throws IOException {
try (Stream<Path> allFiles = Files.walk(xryFolder, XRY_FILES_DEPTH)) {
List<Path> otherFiles = new ArrayList<>();
Iterator<Path> allFilesIterator = allFiles.iterator();
while (allFilesIterator.hasNext()) {
Path currentPath = allFilesIterator.next();
if (!currentPath.equals(xryFolder)
&& !XRYFileReader.isXRYFile(currentPath)) {
otherFiles.add(currentPath);
}
}
return otherFiles;
} catch (UncheckedIOException ex) {
throw ex.getCause();
}
}
/**
* Creates XRYFileReader instances for all XRY files found in the top level
* of the folder.
*
* @return A non-null collection of file readers.
* @throws IOException If an I/O error occurs.
*/
public List<XRYFileReader> getXRYFileReaders() throws IOException {
try (Stream<Path> allFiles = Files.walk(xryFolder, XRY_FILES_DEPTH)) {
List<XRYFileReader> fileReaders = new ArrayList<>();
Iterator<Path> allFilesIterator = allFiles.iterator();
while (allFilesIterator.hasNext()) {
Path currentFile = allFilesIterator.next();
if (XRYFileReader.isXRYFile(currentFile)) {
fileReaders.add(new XRYFileReader(currentFile));
}
}
return fileReaders;
} catch (UncheckedIOException ex) {
throw ex.getCause();
}
}
/**
* Searches for XRY files at the top level of a given folder. If at least
* one file matches, the entire directory is assumed to be an XRY report.
@ -48,7 +106,7 @@ final class XRYFolder {
* @return Indicates whether the Path is an XRY report.
*
* @throws IOException Error occurred during File I/O.
* @throws SecurityException If the security manager denies access any of
* @throws SecurityException If the security manager denies access to any of
* the files.
*/
public static boolean isXRYFolder(Path folder) throws IOException {

View File

@ -0,0 +1,61 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 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.datasourceprocessors.xry;
import java.io.IOException;
import java.util.List;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Processes all XRY files in an XRY folder.
*/
class XRYReportProcessor {
private static final Logger logger = Logger.getLogger(XRYReportProcessor.class.getName());
/**
* Processes all XRY Files and creates artifacts on the given Content
* instance.
*
* @param folder XRY folder to process
* @param parent Content instance to hold newly created artifacts.
* @throws IOException If an I/O exception occurs.
* @throws TskCoreException If an error occurs adding artifacts.
*/
static void process(XRYFolder folder, Content parent) throws IOException, TskCoreException {
//Get all XRY file readers from this folder.
List<XRYFileReader> xryFileReaders = folder.getXRYFileReaders();
for (XRYFileReader xryFileReader : xryFileReaders) {
String reportType = xryFileReader.getReportType();
if (XRYFileParserFactory.supports(reportType)) {
XRYFileParser parser = XRYFileParserFactory.get(reportType);
parser.parse(xryFileReader, parent);
} else {
logger.log(Level.SEVERE, String.format("[XRY DSP] XRY File (in brackets) "
+ "[ %s ] was found, but no parser to support its report type exists. "
+ "Report type is (in brackets) [ %s ]", xryFileReader.getReportPath().toString(), reportType));
}
xryFileReader.close();
}
}
}