/*
* 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.host.impl;
import com.sun.tools.visualvm.host.HostsSupport;
import com.sun.tools.visualvm.host.RemoteHostsContainer;
import com.sun.tools.visualvm.core.datasource.DataSource;
import com.sun.tools.visualvm.core.datasource.DataSourceContainer;
import com.sun.tools.visualvm.core.datasource.DataSourceRepository;
import com.sun.tools.visualvm.host.Host;
import com.sun.tools.visualvm.core.datasupport.DataChangeEvent;
import com.sun.tools.visualvm.core.datasupport.DataChangeListener;
import com.sun.tools.visualvm.core.datasource.Storage;
import com.sun.tools.visualvm.core.datasupport.Utils;
import com.sun.tools.visualvm.core.explorer.ExplorerSupport;
import com.sun.tools.visualvm.core.datasource.descriptor.DataSourceDescriptor;
import com.sun.tools.visualvm.core.datasource.descriptor.DataSourceDescriptorFactory;
import com.sun.tools.visualvm.core.options.GlobalPreferences;
import java.awt.BorderLayout;
import java.io.File;
import java.io.FilenameFilter;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.Semaphore;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
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.awt.Mnemonics;
import org.openide.util.NbBundle;
import org.openide.util.RequestProcessor;
import org.openide.windows.WindowManager;
/**
*
* @author Jiri Sedlacek
*/
// A provider for Hosts
public class HostProvider {
private static final Logger LOGGER = Logger.getLogger(HostProvider.class.getName());
private static final String SNAPSHOT_VERSION = "snapshot_version"; // NOI18N
private static final String SNAPSHOT_VERSION_DIVIDER = ".";
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 PROPERTY_HOSTNAME = "prop_hostname"; // NOI18N
private static final String DNSA_KEY = "HostProvider_NotifyUnresolved"; // NOI18N
private static InetAddress localhostAddress2;
private Semaphore hostsLockedSemaphore = new Semaphore(1);
public Host createHost(final HostProperties hostDescriptor, final boolean createOnly, final boolean interactive) {
try {
lockHosts();
final String hostName = hostDescriptor.getHostName();
InetAddress inetAddress = null;
ProgressHandle pHandle = null;
try {
pHandle = ProgressHandleFactory.createHandle(NbBundle.getMessage(HostProvider.class, "LBL_Searching_for_host") + hostName); // NOI18N
pHandle.setInitialDelay(0);
pHandle.start();
try {
inetAddress = InetAddress.getByName(hostName);
} catch (UnknownHostException e) {
if (interactive) {
DialogDisplayer.getDefault().notifyLater(new NotifyDescriptor.
Message(NbBundle.getMessage(HostProvider.class,
"MSG_Wrong_Host", hostName), NotifyDescriptor. // NOI18N
ERROR_MESSAGE));
}
}
} finally {
final ProgressHandle pHandleF = pHandle;
SwingUtilities.invokeLater(new Runnable() {
public void run() { if (pHandleF != null) pHandleF.finish(); }
});
}
if (inetAddress != null) {
final Host knownHost = getHostByAddressImpl(inetAddress);
if (knownHost != null) {
if (interactive && createOnly) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
ExplorerSupport.sharedInstance().selectDataSource(knownHost);
DialogDisplayer.getDefault().notifyLater(new NotifyDescriptor.
Message(NbBundle.getMessage(HostProvider.class,
"MSG_Already_Monitored",new Object[] // NOI18N
{hostName,DataSourceDescriptorFactory.
getDescriptor(knownHost).getName()}),
NotifyDescriptor.WARNING_MESSAGE));
}
});
}
return knownHost;
} else {
String ipString = inetAddress.getHostAddress();
String[] propNames = new String[] {
SNAPSHOT_VERSION,
PROPERTY_HOSTNAME,
DataSourceDescriptor.PROPERTY_NAME };
String[] propValues = new String[] {
CURRENT_SNAPSHOT_VERSION,
hostName,
hostDescriptor.getDisplayName() };
File customPropertiesStorage = Utils.getUniqueFile(HostsSupport.getStorageDirectory(), ipString, Storage.DEFAULT_PROPERTIES_EXT);
Storage storage = new Storage(customPropertiesStorage.getParentFile(), customPropertiesStorage.getName());
storage.setCustomProperties(propNames, propValues);
Host newHost = null;
try {
newHost = new RemoteHostImpl(hostName, storage);
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "Error creating host", e); // Should never happen // NOI18N
}
if (newHost != null) {
DataSourceContainer remoteHosts = RemoteHostsContainer.sharedInstance().getRepository();
Set<Host> remoteHostsSet = remoteHosts.getDataSources(Host.class);
if (!createOnly && remoteHostsSet.contains(newHost)) {
storage.deleteCustomPropertiesStorage();
Iterator<Host> existingHosts = remoteHostsSet.iterator();
while (existingHosts.hasNext()) {
Host existingHost = existingHosts.next();
if (existingHost.equals(newHost)) {
newHost = existingHost;
break;
}
}
} else {
if (hostDescriptor.getPropertiesCustomizer() != null)
hostDescriptor.getPropertiesCustomizer().propertiesDefined(newHost);
remoteHosts.addDataSource(newHost);
}
}
return newHost;
}
}
return null;
} catch (InterruptedException ex) {
LOGGER.throwing(HostProvider.class.getName(), "createHost", ex); // NOI18N
return null;
} finally {
unlockHosts();
}
}
void removeHost(RemoteHostImpl host, boolean interactive) {
try {
lockHosts();
// TODO: if interactive, show a Do-Not-Show-Again confirmation dialog
DataSource owner = host.getOwner();
if (owner != null) owner.getRepository().removeDataSource(host);
} catch (InterruptedException ex) {
LOGGER.throwing(HostProvider.class.getName(), "removeHost", ex); // NOI18N
} finally {
unlockHosts();
}
}
public Host getHostByAddress(InetAddress inetAddress) {
try {
lockHosts();
return getHostByAddressImpl(inetAddress);
} catch (InterruptedException ex) {
LOGGER.throwing(HostProvider.class.getName(), "getHostByAddress", ex); // NOI18N
return null;
} finally {
unlockHosts();
}
}
private Host getHostByAddressImpl(InetAddress inetAddress) {
Set<RemoteHostImpl> knownHosts = DataSourceRepository.sharedInstance().getDataSources(RemoteHostImpl.class);
for (RemoteHostImpl knownHost : knownHosts)
if (knownHost.getInetAddress().equals(inetAddress)) return knownHost;
if (inetAddress.equals(Host.LOCALHOST.getInetAddress())) return Host.LOCALHOST;
if (inetAddress.equals(localhostAddress2)) return Host.LOCALHOST;
if (inetAddress.isLoopbackAddress()) return Host.LOCALHOST;
return null;
}
public Host createLocalHost() {
try {
return new LocalHostImpl();
} catch (UnknownHostException e) {
LOGGER.severe("Critical failure: cannot resolve localhost"); // NOI18N
return null;
}
}
public Host createUnknownHost() {
try {
return new Host("unknown", InetAddress.getByAddress(new byte[] { 0, 0, 0, 0 })) {}; // NOI18N
} catch (UnknownHostException e) {
LOGGER.severe("Failure: cannot resolve <unknown> host"); // NOI18N
return null;
}
}
private void initLocalHost() {
try {
localhostAddress2 = InetAddress.getLocalHost();
} catch (java.net.UnknownHostException e) {}
if (Host.LOCALHOST != null)
DataSource.ROOT.getRepository().addDataSource(Host.LOCALHOST);
}
private void initUnknownHost() {
final Host unknownhost = Host.UNKNOWN_HOST;
if (unknownhost != null) {
unknownhost.getRepository().addDataChangeListener(new DataChangeListener() {
public void dataChanged(DataChangeEvent event) {
unknownhost.setVisible(!event.getCurrent().isEmpty());
}
}, DataSource.class);
RemoteHostsContainer.sharedInstance().getRepository().addDataSource(unknownhost);
}
}
private void initPersistedHosts() {
if (HostsSupport.storageDirectoryExists()) {
File storageDir = HostsSupport.getStorageDirectory();
File[] files = storageDir.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.endsWith(Storage.DEFAULT_PROPERTIES_EXT);
}
});
Set<File> unresolvedHostsF = new HashSet();
Set<String> unresolvedHostsS = new HashSet();
Set<RemoteHostImpl> hosts = new HashSet();
for (File file : files) {
if (HostsSupportImpl.LOCALHOST_PROPERTIES_FILENAME.equals(file.getName()))
continue;
Storage storage = new Storage(storageDir, file.getName());
String hostName = storage.getCustomProperty(PROPERTY_HOSTNAME);
RemoteHostImpl persistedHost = null;
try {
persistedHost = new RemoteHostImpl(hostName, storage);
} catch (Exception e) {
LOGGER.throwing(HostProvider.class.getName(), "initPersistedHosts", e); // NOI18N
unresolvedHostsF.add(file);
unresolvedHostsS.add(hostName);
}
if (persistedHost != null) hosts.add(persistedHost);
}
if (!unresolvedHostsF.isEmpty()) notifyUnresolvedHosts(unresolvedHostsF, unresolvedHostsS);
RemoteHostsContainer.sharedInstance().getRepository().addDataSources(hosts);
}
}
private static void notifyUnresolvedHosts(final Set<File> unresolvedHostsF, final Set<String> unresolvedHostsS) {
RequestProcessor.getDefault().post(new Runnable() {
public void run() {
String s = GlobalPreferences.sharedInstance().getDoNotShowAgain(DNSA_KEY);
Boolean b = s == null ? null : Boolean.parseBoolean(s);
if (b == null) {
JPanel messagePanel = new JPanel(new BorderLayout(5, 5));
messagePanel.add(new JLabel(NbBundle.getMessage(HostProvider.class, "MSG_Unresolved_Hosts")), BorderLayout.NORTH); // NOI18N
JList list = new JList(unresolvedHostsS.toArray());
list.setVisibleRowCount(4);
messagePanel.add(new JScrollPane(list), BorderLayout.CENTER);
JCheckBox dnsa = new JCheckBox();
Mnemonics.setLocalizedText(dnsa, NbBundle.getMessage(HostProvider.class, "LBL_RememberAction")); // NOI18N
dnsa.setToolTipText(NbBundle.getMessage(HostProvider.class, "TTP_RememberAction")); // NOI18N
JPanel p = new JPanel(new BorderLayout());
p.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 20));
p.add(dnsa, BorderLayout.WEST);
messagePanel.add(p, BorderLayout.SOUTH);
NotifyDescriptor dd = new NotifyDescriptor(
messagePanel, NbBundle.getMessage(HostProvider.class, "Title_Unresolved_Hosts"), // NOI18N
NotifyDescriptor.YES_NO_OPTION, NotifyDescriptor.ERROR_MESSAGE,
null, NotifyDescriptor.YES_OPTION);
Object ret = DialogDisplayer.getDefault().notify(dd);
if (ret == NotifyDescriptor.NO_OPTION) b = Boolean.FALSE;
else if (ret == NotifyDescriptor.YES_OPTION) b = Boolean.TRUE;
if (dnsa.isSelected() && b != null) GlobalPreferences.sharedInstance().setDoNotShowAgain(DNSA_KEY, b.toString());
}
if (Boolean.FALSE.equals(b))
for (File file : unresolvedHostsF) Utils.delete(file, true);
unresolvedHostsF.clear();
unresolvedHostsS.clear();
}
}, 1000);
}
private void lockHosts() throws InterruptedException {
hostsLockedSemaphore.acquire();
}
private void unlockHosts() {
DataSource.EVENT_QUEUE.post(new Runnable() {
public void run() {
hostsLockedSemaphore.release();
}
});
}
public void initialize() {
WindowManager.getDefault().invokeWhenUIReady(new Runnable() {
public void run() {
RequestProcessor.getDefault().post(new Runnable() {
public void run() {
initLocalHost();
initUnknownHost();
initPersistedHosts();
unlockHosts();
}
});
}
});
}
public HostProvider() {
try {
lockHosts(); // Immediately lock the hosts, will be released after initialize()
} catch (InterruptedException ex) {
LOGGER.throwing(HostProvider.class.getName(), "<init>", ex); // NOI18N
}
}
}