package org.limewire.core.impl.support;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.management.ManagementFactory;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.limewire.core.api.support.LocalClientInfo;
import org.limewire.core.api.support.SessionInfo;
import org.limewire.core.settings.LimeProps;
import org.limewire.core.settings.SharingSettings;
import org.limewire.mojito.settings.MojitoProps;
import org.limewire.setting.Setting;
import org.limewire.setting.SettingsFactory;
import org.limewire.util.CommonUtils;
import org.limewire.util.OSUtils;
import org.limewire.util.VersionUtils;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.internal.Nullable;
import com.limegroup.gnutella.util.LimeWireUtils;
/**
* This class encapsulates all of the data for an individual client machine for
* an individual bug report.
* <p>
*
* This class collects all of the data for the local machine and provides access
* to that data in url-encoded form.
*/
// 2345678|012345678|012345678|012345678|012345678|012345678|012345678|012345678|
public final class LocalClientInfoImpl extends LocalAbstractInfo implements LocalClientInfo {
/**
* Creates information about this bug from the bug, thread, and detail.
*/
@Inject
public LocalClientInfoImpl(@Assisted Throwable bug,
@Nullable @Assisted("threadName") String threadName,
@Nullable @Assisted("detail") String detail, @Assisted boolean fatal,
SessionInfo sessionInfo) {
// Store the basic information ...
_limewireVersion = LimeWireUtils.getLimeWireVersion();
_javaVersion = VersionUtils.getJavaVersion();
_javaVendor = System.getProperty("java.vendor", "?");
_os = OSUtils.getOS();
_osVersion = System.getProperty("os.version", "?");
_architecture = System.getProperty("os.arch", "?");
_freeMemory = "" + Runtime.getRuntime().freeMemory();
_totalMemory = "" + Runtime.getRuntime().totalMemory();
_peakThreads = "" + ManagementFactory.getThreadMXBean().getPeakThreadCount();
_loadAverage = "" + ManagementFactory.getOperatingSystemMXBean().getSystemLoadAverage();
_pendingObjects = ""
+ ManagementFactory.getMemoryMXBean().getObjectPendingFinalizationCount();
_heapUsage = "" + ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();
_nonHeapUsage = "" + ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage();
_settingsFreeSpace = "" + CommonUtils.getUserSettingsDir().getUsableSpace();
_incompleteFreeSpace = "" + SharingSettings.INCOMPLETE_DIRECTORY.get().getUsableSpace();
_downloadFreeSpace = "" + SharingSettings.getSaveDirectory().getUsableSpace();
// Store information about the bug and the current thread.
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
bug.printStackTrace(pw);
pw.flush();
_bug = sw.toString();
_currentThread = threadName;
_bugName = bug.getClass().getName();
_fatalError = "" + fatal;
// Store the properties.
sw = new StringWriter();
pw = new PrintWriter(sw);
Properties props = new Properties();
// Load the properties from SettingsFactory, excluding
// FileSettings and FileArraySettings.
SettingsFactory sf = LimeProps.instance().getFactory();
synchronized (sf) {
for (Setting set : sf) {
if (!set.isPrivate() && !set.isDefault())
props.put(set.getKey(), set.getValueAsString());
}
}
sf = MojitoProps.instance().getFactory();
synchronized (sf) {
for (Setting set : sf) {
if (!set.isPrivate() && !set.isDefault())
props.put(set.getKey(), set.getValueAsString());
}
}
// list the properties in the PrintWriter.
props.list(pw);
pw.flush();
_props = sw.toString();
// Store extra debugging information. We removed an old call to
// AppFrame.isStarted() because it is no longer useful.
if (sessionInfo.isLifecycleLoaded()) {
_upTime = CommonUtils.seconds2time(sessionInfo.getCurrentUptime() / 1000);
_connected = "" + sessionInfo.isConnected();
_upToUp = "" + sessionInfo.getNumUltrapeerToUltrapeerConnections();
_upToLeaf = "" + sessionInfo.getNumUltrapeerToLeafConnections();
_leafToUp = "" + sessionInfo.getNumLeafToUltrapeerConnections();
_oldConnections = "" + sessionInfo.getNumOldConnections();
_ultrapeer = "" + sessionInfo.isSupernode();
_leaf = "" + sessionInfo.isShieldedLeaf();
_activeUploads = "" + sessionInfo.getNumActiveUploads();
_queuedUploads = "" + sessionInfo.getNumQueuedUploads();
_activeDownloads = "" + sessionInfo.getNumActiveDownloads();
_httpDownloaders = "" + sessionInfo.getNumIndividualDownloaders();
_waitingDownloaders = "" + sessionInfo.getNumWaitingDownloads();
_acceptedIncoming = "" + sessionInfo.acceptedIncomingConnection();
_sharedFiles = "" + sessionInfo.getSharedFileListSize();
_managedFiles = "" + sessionInfo.getManagedFileListSize();
_friendFiles = "" + sessionInfo.getAllFriendsFileListSize();
_guessCapable = "" + sessionInfo.isGUESSCapable();
_solicitedCapable = "" + sessionInfo.canReceiveSolicited();
_latestSIMPP = "" + sessionInfo.getSimppVersion();
_portStable = "" + sessionInfo.isUdpPortStable();
_canDoFWT = "" + sessionInfo.canDoFWT();
_lastReportedPort = "" + sessionInfo.lastReportedUdpPort();
_externalPort = "" + sessionInfo.getPort();
_receivedIpPong = "" + sessionInfo.receivedIpPong();
_responseSize = "" + sessionInfo.getContentResponsesSize();
_creationCacheSize = "" + sessionInfo.getCreationCacheSize();
_vfByteSize = "" + sessionInfo.getDiskControllerByteCacheSize();
_vfVerifyingSize = "" + sessionInfo.getDiskControllerVerifyingCacheSize();
_bbSize = "" + sessionInfo.getByteBufferCacheSize();
_vfQueueSize = "" + sessionInfo.getDiskControllerQueueSize();
_waitingSockets = "" + sessionInfo.getNumberOfWaitingSockets();
_pendingTimeouts = "" + sessionInfo.getNumberOfPendingTimeouts();
_sp2Workarounds = "" + sessionInfo.getNumConnectionCheckerWorkarounds();
_slotManager = "" + sessionInfo.getUploadSlotManagerInfo();
long[] selectStats = sessionInfo.getSelectStats();
if (selectStats != null) {
_numSelects = "" + selectStats[0];
_numImmediateSelects = "" + selectStats[1];
_avgSelectTime = "" + selectStats[2];
}
}
// Store the detail, thread counts, and other information.
_detail = detail;
Thread[] allThreads = new Thread[Thread.activeCount()];
int copied = Thread.enumerate(allThreads);
_threadCount = "" + copied;
Map<String, Integer> threads = new HashMap<String, Integer>();
for (int i = 0; i < copied; i++) {
String name = allThreads[i].getName();
Integer val = threads.get(name);
if (val == null)
threads.put(name, new Integer(1));
else {
int num = val.intValue() + 1;
threads.put(name, new Integer(num));
}
}
sw = new StringWriter();
pw = new PrintWriter(sw);
for (Map.Entry<String, Integer> info : threads.entrySet())
pw.println(info.getKey() + ": " + info.getValue());
pw.flush();
_otherThreads = sw.toString();
}
/**
* Returns an array of map entries in this info.
*/
public final Map.Entry[] getPostRequestParams() {
List<Map.Entry> params = new LinkedList<Map.Entry>();
append(params, LIMEWIRE_VERSION, _limewireVersion);
append(params, JAVA_VERSION, _javaVersion);
append(params, OS, _os);
append(params, OS_VERSION, _osVersion);
append(params, ARCHITECTURE, _architecture);
append(params, FREE_MEMORY, _freeMemory);
append(params, TOTAL_MEMORY, _totalMemory);
append(params, BUG, _bug);
append(params, CURRENT_THREAD, _currentThread);
append(params, PROPS, _props);
append(params, UPTIME, _upTime);
append(params, CONNECTED, _connected);
append(params, UP_TO_UP, _upToUp);
append(params, UP_TO_LEAF, _upToLeaf);
append(params, LEAF_TO_UP, _leafToUp);
append(params, OLD_CONNECTIONS, _oldConnections);
append(params, ULTRAPEER, _ultrapeer);
append(params, LEAF, _leaf);
append(params, ACTIVE_UPLOADS, _activeUploads);
append(params, QUEUED_UPLOADS, _queuedUploads);
append(params, ACTIVE_DOWNLOADS, _activeDownloads);
append(params, HTTP_DOWNLOADERS, _httpDownloaders);
append(params, WAITING_DOWNLOADERS, _waitingDownloaders);
append(params, ACCEPTED_INCOMING, _acceptedIncoming);
append(params, SHARED_FILES, _sharedFiles);
append(params, OTHER_THREADS, _otherThreads);
append(params, DETAIL, _detail);
append(params, OTHER_BUG, _otherBug);
append(params, JAVA_VENDOR, _javaVendor);
append(params, THREAD_COUNT, _threadCount);
append(params, BUG_NAME, _bugName);
append(params, GUESS_CAPABLE, _guessCapable);
append(params, SOLICITED_CAPABLE, _solicitedCapable);
append(params, LATEST_SIMPP, _latestSIMPP);
// append(params, IP_STABLE,_ipStable);
append(params, PORT_STABLE, _portStable);
append(params, CAN_DO_FWT, _canDoFWT);
append(params, LAST_REPORTED_PORT, _lastReportedPort);
append(params, EXTERNAL_PORT, _externalPort);
append(params, RECEIVED_IP_PONG, _receivedIpPong);
append(params, FATAL_ERROR, _fatalError);
append(params, RESPONSE_SIZE, _responseSize);
append(params, CT_SIZE, _creationCacheSize);
append(params, VF_BYTE_SIZE, _vfByteSize);
append(params, VF_VERIFY_SIZE, _vfVerifyingSize);
append(params, BB_BYTE_SIZE, _bbSize);
append(params, VF_QUEUE_SIZE, _vfQueueSize);
append(params, WAITING_SOCKETS, _waitingSockets);
append(params, PENDING_TIMEOUTS, _pendingTimeouts);
append(params, PEAK_THREADS, _peakThreads);
append(params, SP2_WORKAROUNDS, _sp2Workarounds);
append(params, LOAD_AVERAGE, _loadAverage);
append(params, PENDING_GCOBJ, _pendingObjects);
append(params, SETTINGS_FREE_SPACE, _settingsFreeSpace);
append(params, INCOMPLETES_FREE_SPACE, _incompleteFreeSpace);
append(params, DOWNLOAD_FREE_SPACE, _downloadFreeSpace);
append(params, HEAP_USAGE, _heapUsage);
append(params, NON_HEAP_USAGE, _nonHeapUsage);
append(params, SLOT_MANAGER, _slotManager);
append(params, NUM_SELECTS, _numSelects);
append(params, NUM_IMMEDIATE_SELECTS, _numImmediateSelects);
append(params, AVG_SELECT_TIME, _avgSelectTime);
if (!_userComments.equals("")) {
append(params, USER_COMMENTS, _userComments);
}
append(params, MANAGED_FILES, _managedFiles);
append(params, FRIEND_FILES, _friendFiles);
// APPEND OTHER PARAMETERS HERE.
return params.toArray(new Map.Entry[params.size()]);
}
/**
* @return compact printout of the list of parameters
*/
public String getShortParamList() {
StringBuilder sb = new StringBuilder(2000);
for (Map.Entry entry : getPostRequestParams()) {
sb.append(entry.getKey()).append("=").append(entry.getValue()).append("\n");
}
return sb.toString();
}
/**
* Appends a map entry to the specified list using the specified key and
* value. If the value is null, then the entry is not added.
*/
private final void append(List<Map.Entry> list, String key, String value) {
if (value != null) {
list.add(new AbstractMap.SimpleEntry<String, String>(key, value));
}
}
}