/*
* Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.visualvm.application.snapshot;
import com.sun.tools.visualvm.application.Application;
import com.sun.tools.visualvm.core.snapshot.Snapshot;
import com.sun.tools.visualvm.core.datasource.Storage;
import com.sun.tools.visualvm.core.datasupport.Utils;
import com.sun.tools.visualvm.core.datasource.descriptor.DataSourceDescriptor;
import com.sun.tools.visualvm.core.datasource.descriptor.DataSourceDescriptorFactory;
import com.sun.tools.visualvm.core.explorer.ExplorerSupport;
import com.sun.tools.visualvm.core.snapshot.SnapshotsContainer;
import com.sun.tools.visualvm.core.snapshot.SnapshotsSupport;
import com.sun.tools.visualvm.core.ui.DataSourceViewsManager;
import com.sun.tools.visualvm.core.ui.DataSourceWindowManager;
import java.io.File;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.SwingUtilities;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.util.NbBundle;
import org.openide.util.RequestProcessor;
/**
*
* @author Jiri Sedlacek
*/
class ApplicationSnapshotProvider {
private static final String SNAPSHOT_VERSION = "snapshot_version"; // NOI18N
private static final String SNAPSHOT_VERSION_DIVIDER = "."; // NOI18N
private static final String CURRENT_SNAPSHOT_VERSION_MAJOR = "1"; // NOI18N
private static final String CURRENT_SNAPSHOT_VERSION_MINOR = "0"; // NOI18N
private static final String CURRENT_SNAPSHOT_VERSION = CURRENT_SNAPSHOT_VERSION_MAJOR + SNAPSHOT_VERSION_DIVIDER + CURRENT_SNAPSHOT_VERSION_MINOR;
private static final String PROPERTIES_FILENAME = "application_snapshot" + Storage.DEFAULT_PROPERTIES_EXT; // NOI18N
private static final Logger LOGGER = Logger.getLogger(ApplicationSnapshotProvider.class.getName());
private static ApplicationSnapshotProvider sharedInstance;
synchronized static ApplicationSnapshotProvider sharedInstance() {
if (sharedInstance == null) sharedInstance = new ApplicationSnapshotProvider();
return sharedInstance;
}
private ApplicationSnapshotProvider() {
}
void createSnapshot(final Application application, final boolean openSnapshot) {
RequestProcessor.getDefault().post(new Runnable() {
public void run() {
ProgressHandle pHandle = null;
try {
pHandle = ProgressHandleFactory.createHandle(NbBundle.getMessage(ApplicationSnapshotProvider.class, "MSG_Saving_snapshot", DataSourceDescriptorFactory.getDescriptor(application).getName())); // NOI18N
pHandle.setInitialDelay(0);
pHandle.start();
createSnapshotImpl(application, openSnapshot);
} finally {
final ProgressHandle pHandleF = pHandle;
SwingUtilities.invokeLater(new Runnable() {
public void run() { if (pHandleF != null) pHandleF.finish(); }
});
}
}
});
}
private void createSnapshotImpl(final Application application, final boolean openSnapshot) {
Set<Snapshot> snapshots = application.getRepository().getDataSources(Snapshot.class);
if (snapshots.isEmpty() && !DataSourceViewsManager.sharedInstance().canSaveViewsFor(application, ApplicationSnapshot.class)) return;
File snapshotDirectory = null;
synchronized (ApplicationSnapshotProvider.this) {
snapshotDirectory = Utils.getUniqueFile(ApplicationSnapshotsSupport.getStorageDirectory(),
ApplicationSnapshotsSupport.getInstance().
getCategory().createFileName());
if (!Utils.prepareDirectory(snapshotDirectory))
throw new IllegalStateException("Cannot save datasource snapshot " + snapshotDirectory); // NOI18N
}
for (Snapshot snapshot : snapshots) {
try {
Storage storage = snapshot.getStorage();
String prop = DataSourceDescriptor.PROPERTY_PREFERRED_POSITION;
boolean customPos = storage.getCustomProperty(prop) != null;
if (!customPos) {
int pos = ExplorerSupport.sharedInstance().getDataSourcePosition(snapshot);
storage.setCustomProperty(prop, Integer.toString(pos));
}
snapshot.save(snapshotDirectory);
if (!customPos) {
storage.clearCustomProperty(prop);
if (!storage.hasCustomProperties()) storage.deleteCustomPropertiesStorage();
}
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "Error saving snapshot to application snapshot", e); // NOI18N
}
}
// See #299
// ApplicationType applicationType = ApplicationTypeFactory.getApplicationTypeFor(application);
DataSourceDescriptor descriptor = DataSourceDescriptorFactory.getDescriptor(application);
String[] propNames = new String[] {
SNAPSHOT_VERSION,
DataSourceDescriptor.PROPERTY_NAME,
DataSourceDescriptor.PROPERTY_ICON
};
String[] propValues = new String[] {
CURRENT_SNAPSHOT_VERSION,
descriptor.getName() + getDisplayNameSuffix(application),
Utils.imageToString(descriptor.getIcon(), "png") // NOI18N
};
Storage storage = new Storage(snapshotDirectory, PROPERTIES_FILENAME);
storage.setCustomProperties(propNames, propValues);
ApplicationSnapshot snapshot = new ApplicationSnapshot(snapshotDirectory, storage);
DataSourceViewsManager.sharedInstance().saveViewsFor(application, snapshot);
SnapshotsContainer.sharedInstance().getRepository().addDataSource(snapshot);
if (openSnapshot && DataSourceWindowManager.sharedInstance().canOpenDataSource(snapshot))
DataSourceWindowManager.sharedInstance().openDataSource(snapshot); // TODO: check #VISUALVM-636
}
private static String getDisplayNameSuffix(Application application) {
return ", " + SnapshotsSupport.getInstance().getTimeStamp(System.currentTimeMillis()); // NOI18N
// See #299
// StringBuilder builder = new StringBuilder(" ("); // NOI18N
// int pid = application.getPid();
// if (pid != Application.UNKNOWN_PID) builder.append("pid " + pid + ", ");
// builder.append(SnapshotsSupport.getInstance().getTimeStamp(System.currentTimeMillis()));
// builder.append(")"); // NOI18N
// return builder.toString();
}
void addSnapshotArchive(File archive, boolean deleteArchive) {
processApplicationSnapshotImpl(archive, deleteArchive, true, NbBundle.
getMessage(ApplicationSnapshotProvider.class, "MSG_Adding", // NOI18N
archive.getName()), false);
}
void loadSnapshotArchive(File archive) {
processApplicationSnapshotImpl(archive, false, false, NbBundle.
getMessage(ApplicationSnapshotProvider.class, "MSG_Loading", // NOI18N
archive.getName()), true);
}
private void processApplicationSnapshotImpl(final File archive, final boolean deleteArchive,
final boolean persistent, final String progressMsg,
final boolean openSnapshot) {
// TODO: check if the same snapshot isn't already imported
RequestProcessor.getDefault().post(new Runnable() {
public void run() {
ProgressHandle pHandle = null;
try {
pHandle = ProgressHandleFactory.createHandle(progressMsg);
pHandle.setInitialDelay(0);
pHandle.start();
File storageDirectory = persistent ? ApplicationSnapshotsSupport.getStorageDirectory() :
Storage.getTemporaryStorageDirectory();
File snapshotDirectory = Utils.extractArchive(archive, storageDirectory);
if (snapshotDirectory != null) {
Storage storage = new Storage(snapshotDirectory, PROPERTIES_FILENAME);
ApplicationSnapshot snapshot = new ApplicationSnapshot(snapshotDirectory, storage);
if (persistent) SnapshotsContainer.sharedInstance().getRepository().addDataSource(snapshot);
if (openSnapshot) {
if (DataSourceWindowManager.sharedInstance().canOpenDataSource(snapshot)) {
DataSourceWindowManager.sharedInstance().openDataSource(snapshot); // TODO: check #VISUALVM-636
} else {
DialogDisplayer.getDefault().notifyLater(
new NotifyDescriptor.Message(NbBundle.
getMessage(ApplicationSnapshotProvider.class,
"MSG_Opening_snapshot_failed", archive. // NOI18N
getName()), NotifyDescriptor.ERROR_MESSAGE));
}
}
if (deleteArchive) if (!archive.delete()) archive.deleteOnExit();
} else {
DialogDisplayer.getDefault().notifyLater(
new NotifyDescriptor.Message(NbBundle.
getMessage(ApplicationSnapshotProvider.class,
"MSG_Adding_snapshot_failed", archive. // NOI18N
getName()), NotifyDescriptor.ERROR_MESSAGE));
}
} finally {
final ProgressHandle pHandleF = pHandle;
SwingUtilities.invokeLater(new Runnable() {
public void run() { if (pHandleF != null) pHandleF.finish(); }
});
}
}
});
}
private void loadSnapshots() {
if (!ApplicationSnapshotsSupport.storageDirectoryExists()) return;
File[] files = ApplicationSnapshotsSupport.getStorageDirectory().listFiles(
ApplicationSnapshotsSupport.getInstance().getCategory().getFilenameFilter());
Set<ApplicationSnapshot> snapshots = new HashSet();
for (File file : files) {
if (file.isDirectory()) { // NOTE: once archived snapshots are implemented, this is not necessary
Storage storage = new Storage(file, PROPERTIES_FILENAME);
snapshots.add(new ApplicationSnapshot(file, storage));
}
}
if (!snapshots.isEmpty())
SnapshotsContainer.sharedInstance().getRepository().addDataSources(snapshots);
}
void initialize() {
RequestProcessor.getDefault().post(new Runnable() {
public void run() { loadSnapshots(); }
});
}
}