ij-16.png   inspectorJ -- JavaTM Profiler
sf project site browse source checkout source
SourceForge.net Logo



src/inspectorj/client/connectionmanager.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   inspectorJ - java profiler                                            *
00003  *   Copyright (C) 2007 by $AUTHOR$
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU General Public License as published by  *
00007  *   the Free Software Foundation; either version 2 of the License, or     *
00008  *   (at your option) any later version.                                   *
00009  *                                                                         *
00010  *   This program is distributed in the hope that it will be useful,       *
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00013  *   GNU General Public License for more details.                          *
00014  *                                                                         *
00015  *   You should have received a copy of the GNU General Public License     *
00016  *   along with this program; if not, write to the                         *
00017  *   Free Software Foundation, Inc.,                                       *
00018  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00019  ***************************************************************************/
00020 
00027 #include "inspectorj/client/connectionmanager.h"
00028         
00029 using namespace inspectorj::client;
00030 using namespace inspectorj::jdwp;        
00031  
00036 ConnectionManager::ConnectionManager(QObject *prnt, QMap<QString, SessionProfile> &profiles, QProcess &process)
00037     : parent(prnt), profiles(profiles), javaAppProcess(process), handler(tcpSocket), attached(false)
00038 {
00039     this->setParent(parent);
00040     connect(&tcpSocket, SIGNAL(connected()), this, SLOT(sendHandshake()));
00041     connect(&tcpSocket, SIGNAL(delayedCloseFinished()),
00042              this, SLOT(connectionClosedByServer()));
00043     connect(&tcpSocket, SIGNAL(readyRead()), this, SLOT(readPacket()));
00044     connect(&tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),
00045              this, SLOT(error(QAbstractSocket::SocketError)));    
00046 }
00047 
00051 bool ConnectionManager::isAttached()
00052 {
00053     return attached;
00054 }
00055 
00062 void ConnectionManager::sendRequest(JDWPCommand *cmd, QList<JDWPAction*> &actions) {
00063     handler.sendJDWPCommand(cmd, actions);
00064 }
00065 
00066 
00073 void ConnectionManager::sendRequest(JDWPCommand *cmd, JDWPAction* action) {
00074     QList<JDWPAction*> actions;
00075     actions << action;
00076     sendRequest(cmd, actions);
00077 }
00078 
00079 
00084 void ConnectionManager::readPacket()
00085 {
00086     if (attached)
00087     {
00088         handler.readJDWPPacket();
00089     }
00090     else
00091     {
00092         receiveHandshake();
00093     }
00094 }
00095 
00099 bool ConnectionManager::okToLaunch()
00100 {
00101     QProcess::ProcessState state = javaAppProcess.state();
00102     if (state == QProcess::Starting || state == QProcess::Running) {
00103         QString peerName = tcpSocket.peerName();
00104         QString peerPort;
00105         peerPort.setNum(tcpSocket.peerPort());
00106         QString msg = "You are currently connected to a running process on ";
00107         msg.append(peerName).append(":").append(peerPort);
00108         msg.append("\nDo you want to disconnect and terminate this process?");
00109 
00110         int result = QMessageBox::information(dynamic_cast<QWidget*>(parent), "inspectorJ Launch", msg,
00111                 QMessageBox::Yes | QMessageBox::Default, QMessageBox::No);
00112         if (result == QMessageBox::Yes) {
00113             closeConnection();
00114             javaAppProcess.terminate();
00115             while (javaAppProcess.state() != QProcess::NotRunning) {
00116                 javaAppProcess.waitForFinished(500);
00117             }
00118             return true;
00119         } else {
00120             return false;
00121         }
00122     } else {    
00123         return okToConnect();
00124     }
00125         
00126 }
00127 
00131 bool ConnectionManager::okToConnect()
00132 {   
00133     // See if we're already connected
00134     if (tcpSocket.state() == QAbstractSocket::ConnectedState) {
00135         QString peerName = tcpSocket.peerName();
00136         QString peerPort;
00137         peerPort.setNum(tcpSocket.peerPort());
00138         QString msg = "You are currently connected to ";
00139         msg.append(peerName).append(":").append(peerPort);
00140         msg.append("\nDo you want to disconnect?");
00141 
00142         int result = QMessageBox::information(dynamic_cast<QWidget*>(parent), "inspectorJ Connection", msg,
00143                 QMessageBox::Yes | QMessageBox::Default, QMessageBox::No);
00144         if (result == QMessageBox::Yes) {
00145             closeConnection();
00146             return true;
00147         } else {
00148             return false;
00149         }
00150     } else {    
00151         return true;
00152     }
00153 }
00154 
00158 bool ConnectionManager::attachToServer()
00159 {
00160     // Get the action that was triggered. The action contains the
00161     // connection information.
00162     QAction *action = qobject_cast<QAction *>(sender());
00163     if (action) {
00164                 
00165         // See if we're already connected
00166         if ( !okToConnect()) {
00167             return false;
00168         }
00169         
00170         QStringList actionData = action->data().toStringList();
00171         QString profileName;
00172         QString host;
00173         QString port;
00174         profileName = actionData[0];
00175         host = actionData[1];
00176         port = actionData[2]; 
00177         bool ok;
00178         int portNum = port.toInt(&ok, 10); 
00179         tcpSocket.connectToHost(host, portNum);
00180         return true;
00181     }
00182     return false;
00183 }
00184 
00188 void ConnectionManager::attachToLaunchedServer()
00189 {
00190     bool ok;
00191     int portNum = connection.port.toInt(&ok, 10); 
00192     tcpSocket.connectToHost(connection.host, portNum);    
00193 }
00194 
00201 bool ConnectionManager::startAttachTimer(int mills, ijConnection conn)
00202 {
00203     // See if we're already connected
00204     if ( !okToConnect()) {
00205         return false;
00206     }
00207         
00208     this->connection = conn;
00209     QTimer::singleShot(mills, this, SLOT(attachToLaunchedServer()));
00210     return true; 
00211 }
00212 
00213 
00217 void ConnectionManager::launchJavaApp()
00218 {
00219     // Get the action that was triggered. The action contains the
00220     // profile information.
00221     QAction *action = qobject_cast<QAction *>(sender());
00222     if (action) {
00223                         
00224         // See if we're already connected
00225         if ( !okToLaunch()) {
00226             return;
00227         }
00228         
00229         QStringList actionData = action->data().toStringList();
00230         QString profileName;
00231         profileName = actionData[0];
00232         
00233         QString profileDir;
00234         profileDir = actionData[1];
00235         QString cmd = buildCmdString(profiles[profileName], profileDir);
00236         
00237         javaAppProcess.setWorkingDirectory(QDir::currentPath());
00238         javaAppProcess.start(cmd);
00239     }
00240 }
00241 
00242 bool isWindows()
00243 {
00244     return QDir::separator().toAscii() == '\\';
00245 }
00246 
00254 QString ConnectionManager::buildCmdString(SessionProfile &profile, QString& 
00255 profileDir)
00256 {
00257     // Get the native separator for the host os
00258     QChar sep = QDir::separator();
00259     
00260     // Path separator
00261     QChar pathSep;
00262     
00263     if (isWindows()) {
00264         pathSep = QChar(';');
00265     } else {
00266         pathSep = QChar(':');
00267     }
00268     
00269     // Get the inspectorj client's current path
00270     QString path = QDir::currentPath();
00271     QString javaExec;
00272     
00273     // build the java executable string
00274     if (profile.isTomcatApp()) {
00275         javaExec = profile.getApplicationEntry();
00276         if (!javaExec.endsWith(sep)) {
00277             javaExec += sep;
00278         }
00279         javaExec.append("bin").append(sep).append("catalina.");
00280         if (isWindows()) {
00281             javaExec.prepend("\"");
00282             javaExec.append("bat\"");
00283         } else {
00284             javaExec.append("sh");
00285         }
00286         javaExec.append(" run");
00287     } else {
00288         javaExec = profile.getJreHome();
00289         if (!javaExec.endsWith(sep)) {
00290             javaExec += sep;
00291         }   
00292         javaExec.append("bin").append(sep).append("java");
00293         if (isWindows()) {
00294             javaExec.prepend("\"");
00295             javaExec.append(".exe\"");
00296         }
00297     }
00298     
00299     // append the args to be passed to the java command
00300     QString args;
00301     QString javaOptions = profile.getJavaOptions();
00302     if (!javaOptions.isEmpty()) {
00303         args.append(javaOptions);
00304     }
00305 
00306     args.append(" -Xbootclasspath/a:\"");
00307     args.append(path).append(sep).append("mtrace.jar\" ");
00308     
00309     // append classpath entries
00310     QStringList classpaths = profile.getClassPath();
00311     if (classpaths.size() > 0) {
00312         args.append("-classpath ");
00313         for (int i = 0; i < classpaths.size(); i++) {
00314             args.append(classpaths.at(i));
00315             // add the path separator
00316             if (i < classpaths.size() - 1) {
00317                 args.append(pathSep);
00318             }
00319         }
00320     }
00321     
00322     QString agentLibOption(" -agentpath:\"");
00323     agentLibOption.append(path).append(sep);
00324     if (!isWindows()) {
00325         agentLibOption.append("lib");
00326     }
00327     agentLibOption.append("ij_agent.");
00328     
00329     // add the correct file ext (.so or .dll)
00330     if (isWindows()) {
00331         agentLibOption.append("dll");
00332     } else {
00333         agentLibOption.append("so");
00334     }
00335     agentLibOption.append("\"=profile=\"");
00336     agentLibOption.append(profileDir);
00337     if (!profileDir.endsWith(sep)) {
00338         agentLibOption += sep;
00339     }       
00340     agentLibOption.append(profile.getFileName()).append("\"");
00341     agentLibOption.append(",loglevel=99 ");
00342     args.append(agentLibOption);
00343     
00344     if (profile.isJarFile()) {
00345         if (javaOptions.isEmpty() || !javaOptions.contains("-jar")) {
00346             args.append(" -jar ");
00347         }
00348     }
00349     
00350     if (profile.isTomcatApp()) {
00351         QStringList env = QProcess::systemEnvironment();
00352         QString javaOpts ("JAVA_OPTS=");
00353         javaOpts.append(args);
00354         env << javaOpts;
00355         QString catalinaHome("CATALINA_HOME=");
00356         catalinaHome.append(profile.getApplicationEntry());
00357         env << catalinaHome;
00358         if (!profile.getJreHome().isEmpty()) {
00359             QString javaHome("JAVA_HOME=");
00360             javaHome.append(profile.getJreHome());
00361             env << javaHome;
00362         }
00363         javaAppProcess.setEnvironment(env);        
00364     } else {
00365         if (profile.isJarFile()) {
00366             args.append("\"");
00367         }
00368         args.append(profile.getApplicationEntry());
00369         if (profile.isJarFile()) {
00370             args.append("\"");
00371         }
00372         args.append(" ");
00373         
00374         QString appArgs = profile.getApplicationArgs();
00375         if (!appArgs.isEmpty()) {
00376             args.append(appArgs);
00377         }
00378         
00379         javaExec.append(args);
00380     }
00381     return javaExec;
00382 }
00383 
00384 void ConnectionManager::setExiting(bool exit)
00385 {
00386     this->exiting = exit;
00387 }
00388 
00389 
00393 void ConnectionManager::sendHandshake()
00394 {
00395     tcpSocket.write(JDWP_HANDSHAKE, (qint64)14);
00396 }
00397 
00401 void ConnectionManager::receiveHandshake()
00402 {
00403     QString msg;
00404     handler.getHandshake(attached, msg);
00405     if (!msg.isEmpty()) {
00406         if (attached) {
00407             emit connected(attached, msg);
00408         } else { 
00409             // Handshake failed ;-[             
00410             QMessageBox::warning( dynamic_cast<QWidget*>(parent), "inspectorJ Connection",
00411                                   msg, QMessageBox::Ok | QMessageBox::Default);
00412         }
00413     } else {
00414         // msg String shouldn't be empty. If so something bad has happened
00415         QMessageBox::warning( dynamic_cast<QWidget*>(parent), "inspectorJ Connection",
00416                               "An unexpected error has occurred!",
00417                               QMessageBox::Ok | QMessageBox::Default);
00418     }
00419 }
00420 
00424 void ConnectionManager::connectionClosedByServer()
00425 {
00426     closeConnection();  
00427 }
00428 
00432 void ConnectionManager::closeConnection()
00433 {
00434     QAction *action = qobject_cast<QAction *>(sender());
00435     if (action && action->text() == "&Disconnect") {
00436         QString msg = "Are you sure you want to disconnect?";
00437         int result = QMessageBox::information(dynamic_cast<QWidget*>(parent), 
00438                             "inspectorJ Connection", msg,
00439                             QMessageBox::Yes | QMessageBox::Default, 
00440                             QMessageBox::No);
00441         
00442         if (result != QMessageBox::Yes) {
00443             return;
00444         }
00445     }
00446     
00447     if (!attached) {
00448         return;
00449     }
00450     QAbstractSocket::SocketState state = tcpSocket.state();
00451     if (state != QAbstractSocket::ClosingState && state != QAbstractSocket::UnconnectedState) {
00452         JDWPCommand *cmd = JDWPCommand::newCommand(IJ_DISCONNECT);    
00453         sendRequest(cmd,  NULL);
00454         tcpSocket.close();
00455     }
00456     attached = false;
00457     QString msg = "Disconnected";
00458     emit connected(attached, msg);
00459 }
00460 
00461 void ConnectionManager::stopJavaApp()
00462 {
00463     QString msg = "Are you sure you want to terminate the launched process?";
00464     int result = QMessageBox::information(dynamic_cast<QWidget*>(parent), 
00465                         "inspectorJ - Stop Java Application", msg,
00466                         QMessageBox::Yes | QMessageBox::Default, 
00467                         QMessageBox::No);
00468     
00469     if (result != QMessageBox::Yes) {
00470         return;
00471     }
00472     
00473     QAbstractSocket::SocketState state = tcpSocket.state();
00474     if (state != QAbstractSocket::ClosingState && state != QAbstractSocket::UnconnectedState) {
00475         JDWPCommand *cmd = JDWPCommand::newCommand(IJ_EXIT);    
00476         sendRequest(cmd,  NULL);        
00477         tcpSocket.close();
00478     }
00479     attached = false;
00480     msg = "Disconnected";
00481     emit connected(attached, msg);
00482         
00483     javaAppProcess.kill();
00484 }
00485 
00492 void ConnectionManager::getJDWPError(int errCode, QString &s)
00493 {
00494     ClientPacketHandler::getJDWPError(errCode, s);
00495 }
00496 
00501 void ConnectionManager::error(QAbstractSocket::SocketError error)
00502 {
00503     if (!exiting) {
00504         closeConnection();
00505         QString errMsg;
00506         handler.getSocketError(error, errMsg);
00507         QMessageBox::warning( dynamic_cast<QWidget*>(parent), "inspectorJ Connection", errMsg,
00508                               QMessageBox::Ok | QMessageBox::Default);  
00509     }
00510 }

Generated on Sun Aug 19 17:07:53 2007 for inspectorJ by  doxygen 1.5.1