Toolboxcategory cloud |
ViewsPersonal toolsSDK NetBeans TutorialFrom Seapine LabsWorks with TestTrack 2008.1 Works with NetBeans 6.1 If you would like to take advantage of the TestTrack SOAP SOAP based SDK, you have at your disposal several options as to which language to use. Using Java can be tricky since you first must find an IDE that allows you to work with web services and can build Java classes from the WSDL file.
This is meant as an example only and Seapine does not offer support for this.
[edit] Don't want to use NetBeans?If you do not want to work with NetBeans, you can just download the Generated Java Classes. Simply import the needed Jar files into your project using your favorite IDE. [edit] The environmentThe following example uses TestTrack 2008.1.2 and NetBeans IDE 6.1 (Build 200805300101). Older versions of TestTrack or NetBeans should also work. Screenshots included in this article are of NetBeans or TestTrack in a Windows environment. [edit] Creating the projectCreating the project is very straight forward. In NetBeans, select File > New Project.... The New Project dialog appears. The New Project dialog consists of two sections:
[edit] Setting up the web service interfaceThe next major step is to step up an interface with the TestTrack SOAP server. NetBeans can create a web service client based on a WSDL file. While this works for the most part, there are a couple of things you must do to get it to work properly. NOTE: You can always just download the Generated Java Classes. [edit] Handling a known issueThe main issue is with the Web Service Client in NetBeans not handling dashes in the WSDL properly and creating variables in Java with those dashes in the name which causes compile errors.
Here is a list of these variables: CSCCFileRecord m-strFileName m-strFixedRevision m-dateFixedTimestamp m-strType m-scriptOrder m-pFileData
m-strArchiveName m-strType m-scriptOrder m-strScriptState
By far the easiest is to go with option #1 and that is what will be done in this example.
[edit] Editing the WSDL fileNOTE: Make a backup copy of the ttsoapcgi.wsdl file before making any changes. Open the ttsoapcgi.wsdl file with your favorite XML editor. Search for any "-" characters and either replace them with an underscore or just remove them from the variables listed above. The first section you will see these variables in is:
<complexType name="CSCCFileRecord">
<complexContent>
<extension base="ttns:CItemWithDBRecordId">
<sequence>
<element name="m-strFileName" type="xsd:string" minOccurs="1" maxOccurs="1" nillable="false"/>
<element name="m-strFixedRevision" type="xsd:string" minOccurs="0" maxOccurs="1" nillable="true"/>
<element name="m-dateFixedTimestamp" type="xsd:dateTime" minOccurs="0" maxOccurs="1" nillable="true"/>
<element name="m-strType" type="xsd:string" minOccurs="0" maxOccurs="1" nillable="true"/>
<element name="m-scriptOrder" type="xsd:long" minOccurs="0" maxOccurs="1"/>
<element name="m-strScriptState" type="xsd:string" minOccurs="0" maxOccurs="1" nillable="true"/>
</sequence>
</extension>
</complexContent>
</complexType>
<complexType name="CSCCFileRecord">
<complexContent>
<extension base="ttns:CItemWithDBRecordId">
<sequence>
<element name="mstrFileName" type="xsd:string" minOccurs="1" maxOccurs="1" nillable="false"/>
<element name="mstrFixedRevision" type="xsd:string" minOccurs="0" maxOccurs="1" nillable="true"/>
<element name="mdateFixedTimestamp" type="xsd:dateTime" minOccurs="0" maxOccurs="1" nillable="true"/>
<element name="mstrType" type="xsd:string" minOccurs="0" maxOccurs="1" nillable="true"/>
<element name="mscriptOrder" type="xsd:long" minOccurs="0" maxOccurs="1"/>
<element name="mstrScriptState" type="xsd:string" minOccurs="0" maxOccurs="1" nillable="true"/>
</sequence>
</extension>
</complexContent>
</complexType>
The next section where you will find the variables is here:
<complexType name="CFileAttachment">
<sequence>
<element name="m-pFileData" type="xsd:base64Binary" minOccurs="0" maxOccurs="1" nillable="true"/>
<element name="m-strFileName" type="xsd:string" minOccurs="0" maxOccurs="1" nillable="true"/>
<element name="m-strArchiveName" type="xsd:string" minOccurs="0" maxOccurs="1" nillable="true"/>
<element name="m-strType" type="xsd:string" minOccurs="0" maxOccurs="1" nillable="true"/>
<element name="m-scriptOrder" type="xsd:long" minOccurs="0" maxOccurs="1"/>
<element name="m-strScriptState" type="xsd:string" minOccurs="0" maxOccurs="1" nillable="true"/>
</sequence>
</complexType>
After doing the same with these variables, the section now looks like this:
</complexType>
<complexType name="CFileAttachment">
<sequence>
<element name="mpFileData" type="xsd:base64Binary" minOccurs="0" maxOccurs="1" nillable="true"/>
<element name="mstrFileName" type="xsd:string" minOccurs="0" maxOccurs="1" nillable="true"/>
<element name="mstrArchiveName" type="xsd:string" minOccurs="0" maxOccurs="1" nillable="true"/>
<element name="mstrType" type="xsd:string" minOccurs="0" maxOccurs="1" nillable="true"/>
<element name="mscriptOrder" type="xsd:long" minOccurs="0" maxOccurs="1"/>
<element name="mstrScriptState" type="xsd:string" minOccurs="0" maxOccurs="1" nillable="true"/>
</sequence>
</complexType>
[edit] Handling a requirementThe WSDL is rpc encoded and you will need to download the JAX-RPC Web Service plug-in for NetBeans. [edit] Creating the web service clientSince we are going to need to edit some of the java files, we need to include them in the project. It is recommended that you create a separate package to hold these files. In this example, the package is named "testtrack_Interface" under the Source Packages folder. While the project is selected, select File > New File. The New File dialog appears. Under Categories select Web Services and then under File Types select Web Service Client.
[edit] Getting the files in the packageYou will notice that if you now go into the testtrack_Interface package, it is still empty, eventhough you specified to place the files in there and also the ttsoapcgi-config.xml file in the META-INF.wsdl package also references the testtrack_Interface package.
The package in NetBeans now shows all of the Java classes created by the Web Service Client.
[edit] Editing the classesAs mentioned earlier, the last thing we need to do is edit two files: CSCCFileRecord_SOAPSerializer.java
In each file you will find a section where it builds the section of the XML file for the file attachments and source code files.
public class CFileAttachment_SOAPSerializer extends ObjectSerializerBase implements Initializable {
private static final javax.xml.namespace.QName ns1_m_pFileData_QNAME = new QName("", "mpFileData");
private static final javax.xml.namespace.QName ns3_base64Binary_TYPE_QNAME = SchemaConstants.QNAME_TYPE_BASE64_BINARY;
private CombinedSerializer ns3_myns3_base64Binary__byte_Base64Binary_Serializer;
private static final javax.xml.namespace.QName ns1_m_strFileName_QNAME = new QName("", "mstrFileName");
private static final javax.xml.namespace.QName ns3_string_TYPE_QNAME = SchemaConstants.QNAME_TYPE_STRING;
private CombinedSerializer ns3_myns3_string__java_lang_String_String_Serializer;
private static final javax.xml.namespace.QName ns1_m_strArchiveName_QNAME = new QName("", "mstrArchiveName");
private static final javax.xml.namespace.QName ns1_m_strType_QNAME = new QName("", "mstrType");
private static final javax.xml.namespace.QName ns1_m_scriptOrder_QNAME = new QName("", "mscriptOrder");
private static final javax.xml.namespace.QName ns3_long_TYPE_QNAME = SchemaConstants.QNAME_TYPE_LONG;
private CombinedSerializer ns3_myns3__long__java_lang_Long_Long_Serializer;
private static final javax.xml.namespace.QName ns1_m_strScriptState_QNAME = new QName("", "mstrScriptState");
public class CFileAttachment_SOAPSerializer extends ObjectSerializerBase implements Initializable {
private static final javax.xml.namespace.QName ns1_m_pFileData_QNAME = new QName("", "m-pFileData");
private static final javax.xml.namespace.QName ns3_base64Binary_TYPE_QNAME = SchemaConstants.QNAME_TYPE_BASE64_BINARY;
private CombinedSerializer ns3_myns3_base64Binary__byte_Base64Binary_Serializer;
private static final javax.xml.namespace.QName ns1_m_strFileName_QNAME = new QName("", "m-strFileName");
private static final javax.xml.namespace.QName ns3_string_TYPE_QNAME = SchemaConstants.QNAME_TYPE_STRING;
private CombinedSerializer ns3_myns3_string__java_lang_String_String_Serializer;
private static final javax.xml.namespace.QName ns1_m_strArchiveName_QNAME = new QName("", "m-strArchiveName");
private static final javax.xml.namespace.QName ns1_m_strType_QNAME = new QName("", "m-strType");
private static final javax.xml.namespace.QName ns1_m_scriptOrder_QNAME = new QName("", "m-scriptOrder");
private static final javax.xml.namespace.QName ns3_long_TYPE_QNAME = SchemaConstants.QNAME_TYPE_LONG;
private CombinedSerializer ns3_myns3__long__java_lang_Long_Long_Serializer;
private static final javax.xml.namespace.QName ns1_m_strScriptState_QNAME = new QName("", "m-strScriptState");
public class CSCCFileRecord_SOAPSerializer extends ObjectSerializerBase implements Initializable {
private static final javax.xml.namespace.QName ns1_recordid_QNAME = new QName("", "recordid");
private static final javax.xml.namespace.QName ns3_long_TYPE_QNAME = SchemaConstants.QNAME_TYPE_LONG;
private CombinedSerializer ns3_myns3__long__long_Long_Serializer;
private static final javax.xml.namespace.QName ns1_m_strFileName_QNAME = new QName("", "mstrFileName");
private static final javax.xml.namespace.QName ns3_string_TYPE_QNAME = SchemaConstants.QNAME_TYPE_STRING;
private CombinedSerializer ns3_myns3_string__java_lang_String_String_Serializer;
private static final javax.xml.namespace.QName ns1_m_strFixedRevision_QNAME = new QName("", "mstrFixedRevision");
private static final javax.xml.namespace.QName ns1_m_dateFixedTimestamp_QNAME = new QName("", "mdateFixedTimestamp");
private static final javax.xml.namespace.QName ns3_dateTime_TYPE_QNAME = SchemaConstants.QNAME_TYPE_DATE_TIME;
private CombinedSerializer ns3_myns3_dateTime__java_util_Calendar_DateTimeCalendar_Serializer;
private static final javax.xml.namespace.QName ns1_m_strType_QNAME = new QName("", "mstrType");
private static final javax.xml.namespace.QName ns1_m_scriptOrder_QNAME = new QName("", "mscriptOrder");
private static final javax.xml.namespace.QName ns1_m_strScriptState_QNAME = new QName("", "mstrScriptState");
After making the changes, the same section now looks like:
public class CSCCFileRecord_SOAPSerializer extends ObjectSerializerBase implements Initializable {
private static final javax.xml.namespace.QName ns1_recordid_QNAME = new QName("", "recordid");
private static final javax.xml.namespace.QName ns3_long_TYPE_QNAME = SchemaConstants.QNAME_TYPE_LONG;
private CombinedSerializer ns3_myns3__long__long_Long_Serializer;
private static final javax.xml.namespace.QName ns1_m_strFileName_QNAME = new QName("", "m-strFileName");
private static final javax.xml.namespace.QName ns3_string_TYPE_QNAME = SchemaConstants.QNAME_TYPE_STRING;
private CombinedSerializer ns3_myns3_string__java_lang_String_String_Serializer;
private static final javax.xml.namespace.QName ns1_m_strFixedRevision_QNAME = new QName("", "m-strFixedRevision");
private static final javax.xml.namespace.QName ns1_m_dateFixedTimestamp_QNAME = new QName("", "m-dateFixedTimestamp");
private static final javax.xml.namespace.QName ns3_dateTime_TYPE_QNAME = SchemaConstants.QNAME_TYPE_DATE_TIME;
private CombinedSerializer ns3_myns3_dateTime__java_util_Calendar_DateTimeCalendar_Serializer;
private static final javax.xml.namespace.QName ns1_m_strType_QNAME = new QName("", "m-strType");
private static final javax.xml.namespace.QName ns1_m_scriptOrder_QNAME = new QName("", "m-scriptOrder");
private static final javax.xml.namespace.QName ns1_m_strScriptState_QNAME = new QName("", "m-strScriptState");
Now you are ready to code! [edit] Writing CodeNow the real fun begins, we are ready to actually start writing code. [edit] Invoking a web service operationNetBeans offers a really neat tool that can help you get started. You can call a web service operation and have NetBeans place actual code in your java class. It is not complete code (it does not fill out paramters, for example), but for your first time it can be of great help. Once you become more familiar with the TestTrack SOAP interface you may find yourself using this less and less.
For this example, we'll select the getProjectList and click OK. The following code now appears in the Main.java file:
try { // This code block invokes the Ttsoapcgi:getProjectList operation on web service
testtrack_Interface.Ttsoapcgi ttsoapcgi = new testtrack_Interface.Ttsoapcgi_Impl();
testtrack_Interface.TtsoapcgiPortType _ttsoapcgi = ttsoapcgi.getTtsoapcgi();
_ttsoapcgi.getProjectList(/* TODO enter operation arguments*/);
} catch(javax.xml.rpc.ServiceException ex) {
java.util.logging.Logger.getLogger(testtrack_Interface.Ttsoapcgi.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch(java.rmi.RemoteException ex) {
java.util.logging.Logger.getLogger(testtrack_Interface.Ttsoapcgi.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch(Exception ex) {
java.util.logging.Logger.getLogger(testtrack_Interface.Ttsoapcgi.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
All you have to do now is fill out the parameters where the comments /* TODO enter operation arguments*/ appear. However, after you get the list of projects you may want to do something with them, so other code may also be necsessary.
- Passes username and password to the getProjecList method. - Loops through each project and prints out each name.
package ttsoapsample;
import testtrack_Interface.*;
/**
*
* @author cremerf
*/
public class Main {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic
try
{ // This code block invokes the Ttsoapcgi:getProjectList operation on web service
Ttsoapcgi ttsoapcgi = new Ttsoapcgi_Impl();
TtsoapcgiPortType _ttsoapcgi = ttsoapcgi.getTtsoapcgi();
CProject[] projectList = _ttsoapcgi.getProjectList("Administrator","password");
for (int i =0; i < projectList.length;i++)
{
System.out.println(projectList[i].getDatabase().getName());
}
}
catch(javax.xml.rpc.ServiceException ex)
{
java.util.logging.Logger.getLogger(testtrack_Interface.Ttsoapcgi.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
catch(java.rmi.RemoteException ex)
{
java.util.logging.Logger.getLogger(testtrack_Interface.Ttsoapcgi.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
catch(Exception ex)
{
java.util.logging.Logger.getLogger(testtrack_Interface.Ttsoapcgi.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
}
}
[edit] Setting the ttsoapcgi urlIn the methods shown above the URL to the SOAP cgi is already set. The URL was obtained from the WSDL file and the URL in the WSDL file was set during the installaion of the SOAP components. To change the URL programatically, invoke the ttsoapcgi object and change the URL as follows:
//Define soap cgi object
TtsoapcgiPortType_Stub _ttsoapcgi = (TtsoapcgiPortType_Stub)(new Ttsoapcgi_Impl().getTtsoapcgi());
//Set the soap cgi URL
_ttsoapcgi._setProperty(javax.xml.rpc.Stub.ENDPOINT_ADDRESS_PROPERTY, "http://yourserver/ttsoapcgi.exe");
[edit] Sample MethodsThe following are excerpts from a class created to handle all calls made to the web service. The TtsoapcgiPortType object (_ttsoapcgi) is generated when the class is instantiated and therefore can be reused each time the same instance of the _ttsoapcgi object is used. NOTE: The following variables are declared as public and therefore are accessible to all of the methods: ttCookie(long) ttUsername(String) ttPassword(String) ttProjectName(String) _ttsoapcgi(TtsoapcgiPortType) [edit] Logging into a projectLogging into a project requires a CProject object. You can either get the list of projects and go through the array until you find the one you want to log into, or you can create a CProject object from scratch. The example above shows you how to loop through a CProject[] array already, so the method below shows how to build a CProject object from scratch and then log in. If the process fails it returns false.
public boolean Login()
{
boolean result = false;
//First we need to build the project object
//Create the database object and set its name
CDatabase ttDatabase = new CDatabase();
ttDatabase.setName(ttProjectName);
//Create the project options object
CProjectDataOption[] ttProjOps = new CProjectDataOption[2];
//Allow TestTrack Pro access
ttProjOps[0].setName("TestTrack Pro");
//Allow TestTrack TCM access
ttProjOps[1].setName("TestTrack TCM");
//Now create the project object
CProject ttProj = new CProject();
ttProj.setDatabase(ttDatabase);
ttProj.setOptions(ttProjOps);
//Now we can try to log in
try
{ // This code block invokes the Ttsoapcgi:projectLogon operation on web service
ttCookie = _ttsoapcgi.projectLogon(ttProj, ttUsername, ttPassword);
if (ttCookie > 0)
{
result = true;
}
}
catch(Exception ex)
{
java.util.logging.Logger.getLogger(testtrack_Interface.Ttsoapcgi.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
return result;
}
[edit] Getting a defect list array (CRecordListSoap)This method can be used get a defects list. You must pass it a string array containing the columns to retrieve. The column names are those that are displayed in the defect list window.
public CRecordListSoap getDefects(String[] m_ColList)
{
//We do not want to get every single column, so we first must build our CTableColumn[] object
//We initialize the size of the array to 3 since that is how many columns we are interested in
CTableColumn[] m_Columns = new CTableColumn[m_ColList.length];
for (int i = 0; i < m_ColList.length; i++)
{
//We need to instantiate each column (you'll get a null exception if you don't)
m_Columns[i] = new CTableColumn();
//After you instantiate the column, then give it the name
m_Columns[i].setName(m_ColList[i]);
}
//Define our variable that will hold the defects
//I am defining it here because I will use it outside of the
//embedded try catch below
CRecordListSoap m_Records = new CRecordListSoap();
try
{
//Get defect table name
CDatabaseTable[] m_Tables = _ttsoapcgi.getTableList(ttCookie);
//Populate the crl variable
m_Records = _ttsoapcgi.getRecordListForTable(ttCookie, m_Tables[0].getName(), "",m_Columns );
}
catch (Exception fcc)
{
java.util.logging.Logger.getLogger(Ttsoapcgi.class.getName()).log(java.util.logging.Level.SEVERE, null, fcc);
}
return m_Records;
}
[edit] Get defect for edit
public CDefect GetDefectForEdit(long defNum)
{
CDefect m_Defect = new CDefect();
try
{
m_Defect = _ttsoapcgi.editDefect(ttCookie,defNum,"",false);
}
catch(java.rmi.RemoteException ex)
{
java.util.logging.Logger.getLogger(Ttsoapcgi.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
return m_Defect;
}
[edit] Save Defect
public boolean SaveDefect(CDefect m_Defect)
{
boolean result = false;
int s_result = -1;
try
{
s_result = _ttsoapcgi.saveDefect(ttCookie, m_Defect);
}
catch(java.rmi.RemoteException ex)
{
java.util.logging.Logger.getLogger(Ttsoapcgi.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
if (s_result == 0)
{
result = true;
}
return result;
}
[edit] DownloadI have posted below a project I created following the steps in this article. It includes everything, including the .class files created by NetBeans. Note that this example does not employ the method that allows you to change the URL prgramatically. It does contain the .java and .class files created from the WSDL. |
|


