/**
* DataCleaner (community edition)
* Copyright (C) 2014 Neopost - Customer Information Management
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.datacleaner.actions;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import javax.inject.Inject;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemException;
import org.apache.commons.vfs2.provider.DelegateFileObject;
import org.apache.metamodel.util.FileHelper;
import org.datacleaner.Version;
import org.datacleaner.configuration.DataCleanerConfiguration;
import org.datacleaner.job.AnalysisJob;
import org.datacleaner.job.AnalysisJobMetadata;
import org.datacleaner.job.JaxbJobMetadataFactoryImpl;
import org.datacleaner.job.JaxbJobWriter;
import org.datacleaner.job.builder.AnalysisJobBuilder;
import org.datacleaner.job.builder.NoResultProducingComponentsException;
import org.datacleaner.user.MonitorConnection;
import org.datacleaner.user.UserPreferences;
import org.datacleaner.util.FileFilters;
import org.datacleaner.util.VFSUtils;
import org.datacleaner.util.WidgetUtils;
import org.datacleaner.widgets.DCFileChooser;
import org.datacleaner.windows.AnalysisJobBuilderWindow;
import org.datacleaner.windows.MonitorConnectionDialog;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Strings;
/**
* ActionListener for saving an analysis job
*/
public final class SaveAnalysisJobActionListener implements ActionListener {
public static final String ACTION_COMMAND_SAVE_AS = "SAVE_AS";
private static final String LABEL_TEXT_SAVING_JOB = "Saving job...";
private static final Logger logger = LoggerFactory.getLogger(SaveAnalysisJobActionListener.class);
private final AnalysisJobBuilder _analysisJobBuilder;
private final AnalysisJobBuilderWindow _window;
private final UserPreferences _userPreferences;
private final DataCleanerConfiguration _configuration;
public boolean _saved;
@Inject
protected SaveAnalysisJobActionListener(final AnalysisJobBuilderWindow window,
final AnalysisJobBuilder analysisJobBuilder, final UserPreferences userPreferences,
final DataCleanerConfiguration configuration) {
_window = window;
_analysisJobBuilder = analysisJobBuilder;
_userPreferences = userPreferences;
_configuration = configuration;
}
@Override
public void actionPerformed(final ActionEvent event) {
_saved = false;
final String actionCommand = event.getActionCommand();
_window.setStatusLabelNotice();
_window.setStatusLabelText(LABEL_TEXT_SAVING_JOB);
AnalysisJob analysisJob;
try {
_window.applyPropertyValues();
analysisJob = _analysisJobBuilder.toAnalysisJob();
} catch (final Exception e) {
if (e instanceof NoResultProducingComponentsException) {
final int result = JOptionPane.showConfirmDialog(_window.toComponent(),
"You job does not have any result-producing components in it, and is thus 'incomplete'. "
+ "Do you want to save it anyway?", "No result producing components in job",
JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
if (result == JOptionPane.YES_OPTION) {
analysisJob = _analysisJobBuilder.toAnalysisJob(false);
} else {
return;
}
} else {
String detail = _window.getStatusLabelText();
if (LABEL_TEXT_SAVING_JOB.equals(detail)) {
detail = e.getMessage();
}
WidgetUtils.showErrorMessage("Errors in job",
"Please fix the errors that exist in the job before saving it:\n\n" + detail, e);
return;
}
}
final FileObject existingFile = _window.getJobFile();
final FileObject file;
if (existingFile == null || ACTION_COMMAND_SAVE_AS.equals(actionCommand)) {
// ask the user to select a file to save to ("Save as" scenario)
final DCFileChooser fileChooser = new DCFileChooser(_userPreferences.getAnalysisJobDirectory());
fileChooser.setFileFilter(FileFilters.ANALYSIS_XML);
final int result = fileChooser.showSaveDialog(_window.toComponent());
if (result != JFileChooser.APPROVE_OPTION) {
return;
}
final FileObject candidate = fileChooser.getSelectedFileObject();
final boolean exists;
try {
final String baseName = candidate.getName().getBaseName();
if (!baseName.endsWith(".xml")) {
final FileObject parent = candidate.getParent();
file = parent.resolveFile(baseName + FileFilters.ANALYSIS_XML.getExtension());
} else {
file = candidate;
}
exists = file.exists();
} catch (final FileSystemException e) {
throw new IllegalStateException("Failed to prepare file for saving", e);
}
if (exists) {
final int overwrite = JOptionPane.showConfirmDialog(_window.toComponent(),
"Are you sure you want to overwrite the file '" + file.getName() + "'?",
"Overwrite existing file?", JOptionPane.YES_NO_OPTION);
if (overwrite != JOptionPane.YES_OPTION) {
return;
}
}
} else {
// overwrite existing file ("Save" scenario).
file = existingFile;
}
try {
final FileObject parent = file.getParent();
final File parentFile = VFSUtils.toFile(parent);
if (parentFile != null) {
_userPreferences.setAnalysisJobDirectory(parentFile);
}
} catch (final FileSystemException e) {
logger.warn("Failed to determine parent of {}: {}", file, e.getMessage());
}
final AnalysisJobMetadata existingMetadata = analysisJob.getMetadata();
final String jobName = existingMetadata.getJobName();
final String jobVersion = existingMetadata.getJobVersion();
final String author;
if (Strings.isNullOrEmpty(existingMetadata.getAuthor())) {
author = System.getProperty("user.name");
} else {
author = existingMetadata.getAuthor();
}
final String jobDescription;
if (Strings.isNullOrEmpty(existingMetadata.getJobDescription())) {
jobDescription = "Created with DataCleaner " + Version.getEdition() + " " + Version.getVersion();
} else {
jobDescription = existingMetadata.getJobDescription();
}
final JaxbJobWriter writer = new JaxbJobWriter(_configuration,
new JaxbJobMetadataFactoryImpl(author, jobName, jobDescription, jobVersion));
OutputStream outputStream = null;
try {
outputStream = file.getContent().getOutputStream();
writer.write(analysisJob, outputStream);
} catch (final IOException e) {
throw new IllegalStateException(e);
} finally {
FileHelper.safeClose(outputStream);
}
if (file instanceof DelegateFileObject) {
// this "file" is probably a HTTP URL resource (often provided by DC
// monitor)
final DelegateFileObject delegateFileObject = (DelegateFileObject) file;
final String scheme = file.getName().getScheme();
if ("http".equalsIgnoreCase(scheme) || "https".equalsIgnoreCase(scheme)) {
final String uri = delegateFileObject.getName().getURI();
final MonitorConnection monitorConnection = _userPreferences.getMonitorConnection();
if (monitorConnection.matchesURI(uri) && monitorConnection.isAuthenticationEnabled()
&& monitorConnection.getEncodedPassword() == null) {
// password is not configured, ask for it.
final MonitorConnectionDialog dialog =
new MonitorConnectionDialog(_window.getWindowContext(), _userPreferences);
dialog.openBlocking();
}
final PublishJobToMonitorActionListener publisher =
new PublishJobToMonitorActionListener(delegateFileObject, _window.getWindowContext(),
_userPreferences);
publisher.actionPerformed(event);
} else {
throw new UnsupportedOperationException(
"Unexpected delegate file object: " + delegateFileObject + " (delegate: " + delegateFileObject
.getDelegateFile() + ")");
}
} else {
_userPreferences.addRecentJobFile(file);
}
_window.setJobFile(file);
_window.setStatusLabelNotice();
_window.setStatusLabelText("Saved job to file " + file.getName().getBaseName());
_saved = true;
}
public boolean isSaved() {
return _saved;
}
}