Archiv der Kategorie: DXL

IBM Doors DXL: Iterate over Linkmodule

Problem

The links in a link module should be iterated

Approach

Link Modules can be read with the appropriate method like formal modules.

Solution

nSatisfiesLinkModule = "/NDS/90 Administration/Satisfies"; 
Object o = null; 
string src   = ""; 
string tgt   = ""; 
SatisfiesLinkModule = read(nSatisfiesLinkModule, false); 
for o in SatisfiesLinkModule do 
{ 
                // get names of source and target modules 
                src = o."source" "" 
                tgt = o."target" "" 
                print src " -> " tgt "\n" 
} 

IBM Doors DXL: Helpful Trigger Functions for persistent Triggers to block a module

Problem

The modification (Edit Mode / Edit Share) of a module shall be prevented.
Das Editieren eine Doors Modules (Edit Mode / Share Mode) soll verhindert werden.

Approach

Defining a library and using the existence of a trigger as condition for allowed modifications can be used to block the formal Module for edit/share mode.
Durch das definieren eine Triggers und der zugehörigen Trigger_Library kann man die Existenz eines Triggers als Bedingung für das Erlauben des Edit/Share Modes nehmen.

Solution

void listAllTriggerForMod (Module mod) 
{
	Trigger t;
	for t in mod do 
	{
		print name(t) "\n";	
	}
}

bool checkTriggerIfExistForMod (Module mod, string triggername) 
{
	Trigger t;
	for t in mod do 
	{
		if(name(t) "" == triggername)	
		{
			return true;
		}
	}
	
	return false;
}

string getDXLCodeForModWithTrigger (Module mod, string triggername) 
{
	Trigger t;
	for t in mod do 
	{
		if(name(t) "" == triggername)	
		{
			return dxl(t);
		}
	}
	
	return "not found";
}

void removeTriggerForModWithName(Module mod, string triggername) {

	Trigger t;
	string errorMsg;
	
	// first delete _all possible trigger_
	for t in mod do {
		if (name (t) "" == triggername) {
			errorMsg = delete(t);
		   	if(!null(errorMsg)) {
			  errorBox("Error occurred:\n" errorMsg"");
			  break;
		   }
		}
	}
}

void installTriggerForMod (Module mod) 
{
	string dxlCode = "Module cm = current Module;\n" //-
					"if ((isEdit(cm)||isShare(cm))){\n" //-
					"ack(\"During Wings LDT modifications it is not allowed to modify texts in the UIT/ALM Module.\");\n" //-
					"downgrade(cm)\n" //-
					"}\n";
	 
	string errors = checkDXL(dxlCode)
	
	if(null(errors)) 
	{
		string moduleName = name(mod)
		if(!checkTriggerIfExistForMod(mod, "Text_Tool_Block_Trigger"))
		{
			Trigger t = trigger("Text_Tool_Block_Trigger", project->module->moduleName, post, open, 15, dxlCode);
		}
		else ack "Trigger already exist!";
	}
	
	save(mod);
}

Module uitModule = read("/NDS/20 System/DS/UIT-User Interface Texts", false);
print "Vor der Installation...\n";
print "=======================\n";
listAllTriggerForMod(uitModule);
installTriggerForMod(uitModule);
print "\n\nNach der Installation...\n";
print "=======================\n";
listAllTriggerForMod(uitModule);
removeTriggerForModWithName(uitModule, "Text_Tool_Block_Trigger");
print "\n\nNach dem Entfernen...\n";
print "=======================\n";
listAllTriggerForMod(uitModule);

IBM Doors DXL: Die fehlenden Stringfunktionen / The missing String functions

Problem

DXL besitzt leider nur sehr wenige Stringfunktionen. Man muss sich für einfache Stringmanipulationen eine eigene Bibliothek bauen.
DXL consists only of a very less number of string functions. For this purpose you have to implement your own library.

Ansatz – Approach

Ich habe die wichtigsten Stringfunktionen aus JAVA/PHP in eine Bibliothek ausgelagert, die ich im Kopf meiner DXL Skripte einbinde…
I have implemented a library with the most important string function from JAVA/PHP, which can be included in the head of DXL scripts…

Lösung – Solution

Das Einbinden erfolgt z.B. mit

#include "\\\\der\\netzwerk\\pfad\\strings.inc";

wobei oben ein Netzwerkpfad genutzt wird. Ohne Pfadangebe muss die Datei direkt im dxl-Verzeichnis der Installation des Doors-Clients liegen.


/******************************
 * String funktionen
 * @Author: Bjoern Karpenstein 
 * @Datum:  2012-11-06 
 ******************************/
// Zweistellige Ganzzahl mit fuehrender Null
string getZeroPrefixedInt(int i)
{
	string s = i "";
	if (i < 10) s = "0" s "";
	return s;
}
 
// Gib datum und Uhrzeit als String
string getDateTime()
{
	string dateTimeString = "";
	int now = intOf(dateAndTime(today));
	Date d = dateOnly(today);
	int day = intOf(date(stringOf(d)));
	int diff = now-day;
	int hours = diff / 3600;
	int mins = (diff - (3600 * hours)) / 60;
	int secs = diff - (hours * 3600) - (mins * 60);

	return "<td>" stringOf(today, "yyyy-MM-dd") "</td><td>" getZeroPrefixedInt(hours) ":" getZeroPrefixedInt(mins) ":" getZeroPrefixedInt(secs) "</td>";
} 

// Gib datum und Uhrzeit als String für Dateien
string getFileTimestamp()
{
	string dateTimeString = "";
	int now = intOf(dateAndTime(today));
	Date d = dateOnly(today);
	int day = intOf(date(stringOf(d)));
	int diff = now-day;
	int hours = diff / 3600;
	int mins = (diff - (3600 * hours)) / 60;
	int secs = diff - (hours * 3600) - (mins * 60);

	return stringOf(today, "yyyy-MM-dd") "_" getZeroPrefixedInt(hours) "_" getZeroPrefixedInt(mins) "_" getZeroPrefixedInt(secs) "";
} 

// Gib datum und Uhrzeit als String für Dateien
string getAvitumTimestamp()
{
	string dateTimeString = "";
	int now = intOf(dateAndTime(today));
	Date d = dateOnly(today);
	int day = intOf(date(stringOf(d)));
	int diff = now-day;
	int hours = diff / 3600;
	int mins = (diff - (3600 * hours)) / 60;
	int secs = diff - (hours * 3600) - (mins * 60);

	return stringOf(today, "yyyy-MM-dd") " " getZeroPrefixedInt(hours) ":" getZeroPrefixedInt(mins) ":" getZeroPrefixedInt(secs) "";
} 

// Gib datum und Uhrzeit als String für Dateien
string getAvitumDate(Date d)
{
	return stringOf(d, "yyyy-MM-dd");
} 
 
// Gibt die Groesse eines Arrays zurück
int getArraySize(Array a){
    int size = 0;
    while( !null(get(a, size, 0) ) )
        size++;
    return size;
}

// Fuegt einen String in ein Array hinzu
void addArrayString(Array a, string str)
{
    int array_index = getArraySize(a);

    put(a, str, array_index, 0);
}

// Gibt den String im Array zurueck
string getArrayString(Array a, int index)
{
    return (string get(a, index, 0));
}

// Setze String für vorhandene Array-Position
void setArrayString(Array a, int change_index, string newString)
{
	put(a, newString, change_index, 0);
}

// Der notorische Sortieralgorithmus für Arme
void bubbleSort(Array a, bool asc)
{
	int size=getArraySize(a);

	int i=0;
	int j=0;
	for(i=0; i<size; i++)
	{
		for(j=0;j<size; j++)
		{
			bool sortierKriterium=asc?getArrayString(a,i)<getArrayString(a,j):getArrayString(a,i)>getArrayString(a,j);
			if(sortierKriterium)
			{
				// Tauschen
				string swapRAM=getArrayString(a,j);
				setArrayString(a, j, getArrayString(a,i));
				setArrayString(a, i, swapRAM);
				
			}
		}
	}	
}


// Zum analysieren eines Strings auf seine Ascii Zeichen
string giveMeAscii(string withoutAscii)
{
	string myAsciiString = "";
	for (i=0; i<length(withoutAscii); i++)
	{  
   		char c = withoutAscii[i];            // <<<--- here you go, get the char
   		int ascii = intOf(c);        // <<<--- convert char to Ascii Code
   		myAsciiString = myAsciiString "" c "[" ascii "]";
	}
	
	return myAsciiString;
}

// Erstellt z.B. einen CSV String 
string joinString(string joiner, Array str_array)
{
    Buffer joined = create;
    int array_index = 0;

    joined += "";

    for(array_index = 0; array_index < getArraySize(str_array); array_index++)
    {
        joined += getArrayString(str_array, array_index);
        if( array_index + 1 < getArraySize(str_array) )
            joined += joiner;
    }

    return stringOf(joined)
}

// Zerhackt einen String nach einem definierten Zeichen und gibt ihn als Array zurueck
Array split(string splitter, string str)
{
    Array tokens = create(1, 1);
    Buffer buf = create;
    int str_index;

    buf = "";

    for(str_index = 0; str_index < length(str); str_index++){
        if( str[str_index:str_index] == splitter ){
            addArrayString(tokens, stringOf(buf));
            buf = "";
        }else{
            buf += str[str_index:str_index];
        }
    }
    addArrayString(tokens, stringOf(buf));

    delete buf;
    return tokens;
}

// If the string starts with another string
bool startsWith(string theString, string startsWithWhat)
{
	if(length(theString)<length(startsWithWhat))
	{
		return false;
	}
	return theString[0:length(startsWithWhat)-1]==startsWithWhat
}

// Zaehlt wie oft Skip-Listen-Keys mit einem Teilstring anfangen
int countKeysThatStartWith(string prefixPfad, Skip skipListeToLookForStart)
{
	int countedKeys=0;
	for myIterator in skipListeToLookForStart do 
  	{
    	string keyValue = (string key(skipListeToLookForStart));
    	
    	string currentPfad = "";
    	if(find(skipListeToLookForStart, keyValue, currentPfad))
    	{
	    	if(startsWith( keyValue, prefixPfad))
	    	{
		    		countedKeys++;
	    	}
  		}
  	}
  	
  	return countedKeys;
}

// A String Replace function because there is nothing in the standard
string replace (string sSource, string sSearch, string sReplace) 
{
    int iLen = length sSource
    if (iLen == 0) return ""
    
    int iLenSearch = length(sSearch)
    
    if (iLenSearch == 0) 
    { 
        print "Parameter error", "in strings.inc/replace: search string must not be empty"
        return "" 
    }
    
    // read the first char for latter comparison -> speed optimization
    char firstChar = sSearch[0]
    
    Buffer s = create() 
    int pos = 0, d1,d2;    
    int i
    
    while (pos < iLen) { 
        char ch = sSource[pos]; 
        bool found = true
        
        if (ch != firstChar) {pos ++; s+= ch; continue}
        for (i = 1; i < iLenSearch; i++) 
           if (sSource[pos+i] != sSearch[i]) { found = false; break }
        if (!found) {pos++; s+= ch; continue}
        s += sReplace
        pos += iLenSearch
    }
    
    string result = stringOf s
    delete s
    return result
}

// Backslashes maskieren und LF durch <br> ersetzen
string mask(string toMask)
{
	string backslashStrip   = replace(toMask, "\\", "\\\\");
	string doubleQuoteStrip = replace(backslashStrip, "\"", "\\\"");
	string replaceLFWithBRs = replace(doubleQuoteStrip,"\n","<br/>");		
	// string replaceLFWithBRs = replace(doubleQuoteStrip,"\012","<br/>");		
	//return replace(replaceLFWithBRs, "\015", "");
	return replaceLFWithBRs;
}

// Backslashes maskieren und LF durch <br> ersetzen
string unmask(string toUnMask)
{
	string backslashStrip = replace(toUnMask, "\\\\","\\");
	string doubleQuoteStrip = replace(backslashStrip, "\\\"","\"");
	
	// wenn da <br/> drinne sind ignoriere 13 oder 10 
	
	string machLFWeg = replace(doubleQuoteStrip,"<br/>","\n");
	
	// string machLFWeg = replace(doubleQuoteStrip,"<br/>","\012") <- 10 wech;
	// return replace(machLFWeg, "\015", "") <- 13 wech;
	
	return machLFWeg;
}

// LTRIM gibts wohl nicht
string leftTrim(string einString)
{
   int dieLetztePosition=-1;
   for (x=0; x<length(einString); x++)
   {
      if( einString[x:x] != " " )
      {
        dieLetztePosition=x;
         break;
      }
   }

   return einString[dieLetztePosition:];
}

// RTRIM gibts wohl nicht
string rightTrim(string einString)
{
   int dieLetztePosition=-1;
   for (x=length(einString)-1; x>=0; x--)
   {
      if( einString[x:x] != " " )
      {
        dieLetztePosition=x;
         break;
      }
   }

   return einString[0:dieLetztePosition];
}

// Gibt die erste Position eines Strings zurück
int indexOf(string testString, string part)
{
	Buffer buf = create()
	buf = testString
	int index = 0
	while(true)
	{
	    index = contains(buf, part, index)
	    if(0 <= index)
	    {
	        return index;
	        index += length(part)
	    }
	    else { return -1; break }
	}
	delete(buf)
}

// Gibt die erste Position eines zeichens zurueck
int indexOfChar(string derString, string dasZeichen)
{
   int dieLetztePosition=-1;
   
   for (x=0; x<length(derString)-1;x++)
   {
      if( derString[x:x] "" == dasZeichen "")
      {
        dieLetztePosition=x;
         break;
      }
   }

   return dieLetztePosition;
}

// Gibt die Auftretens-Haeufigkeit eines Characters zurueck
int getCharOccurrence(string characterChain, string charToCheckFor)
{
   int countChars=0;

   for (x=0; x<length(characterChain);x++)
   {
      if( characterChain[x:x] "" == charToCheckFor"")
      {
		countChars++;
      }
   }
   return countChars;
}

// Gibt die erste Position eines zeichens zurueck
int indexOfFrom(string derString, string dasZeichen, int n)
{
   int dieLetztePosition=-1;
   int zeichenCount=0;
   
   for (x=0; x<length(derString)-1;x++)
   {
      if( derString[x:x] "" == dasZeichen "")
      {
      	zeichenCount++;
      	
      	if(zeichenCount!=n)
      	{
      		continue;
      	}
      	
        dieLetztePosition=x;
        break;
      }
   }

   return dieLetztePosition;
}

// Gibt die letzte Position eines zeichens zurueck
int lastIndexOf(string derString, string dasZeichen)
{
   int dieLetztePosition=-1;
   
   for (x=length(derString)-1; x>=0; x--)
   {
      if( derString[x:x] "" == dasZeichen "")
      {
        dieLetztePosition=x;
         break;
      }
   }

   return dieLetztePosition;
}

// Alle Zeichen links und rechts abschneiden
string trim(string einString)
{
	return leftTrim(rightTrim(einString)) "";
}

// Ersetze Zeilen in einem String
string replaceLines(string content, int startLine, int targetLine, string toReplace)
{
	string newContent="";
	Array stringLines = split("\n", content);
	int stringLineCount=getArraySize(stringLines);
	
	if(startLine>targetLine)
	{
		return "replaceLines: the start index is bigger than the target index";
	}
	
	if(startLine==-1||targetLine==-1)
	{
		return "replaceLines: Select start and target index bigger or equal to zero";
	}
	
	int i=0;
	for(i=0;i<stringLineCount;i++)
	{
		string stringZeile=getArrayString(stringLines,i);	
		
		if(i>=startLine&&i<=targetLine)
		{
			if(i==startLine)
			{
				newContent=newContent "" toReplace "\n";
			}
		}
		else
		{
			newContent=newContent "" stringZeile "\n";
		}

	}
	
	return newContent;
}

IBM Doors DXL: Excel Dateien einlesen mit OLE Automation

Problem

IBM Doors besitzt keine direkte Import-Option für Excel Files. Man geht hier den Umweg über das konvertieren in andere Formate. Manchmal sind mehrere Tools bei einem Import beteiligt.

Ansatz

Durch das direkte Einlesen von Excel Dateien in DXL über OLE Automation kann auf Zellenwerte zugegriffen werden.

Lösung

// Global settings
//pragma encoding,"UTF-8";
pragma runLim, 0;

int findLastRow (OleAutoObj objExcelSheet)
{
	OleAutoObj objUsedRange, objRows;
      int iRow = 0;
	oleGet(objExcelSheet,"UsedRange",objUsedRange);
	oleGet(objUsedRange,"Rows",objRows);
	oleGet(objRows,"Count",iRow);
 
      return iRow+1;
}

int findLastColumn (OleAutoObj objExcelSheet)
{
	OleAutoObj objUsedRange, objColumns;
      int iColumn = 0;
	oleGet(objExcelSheet,"UsedRange",objUsedRange);
	oleGet(objUsedRange,"Columns",objColumns);
	oleGet(objColumns,"Count",iColumn );
 
      return iColumn +1;
}

string getCellContent(OleAutoObj objSheet, int x, int y)
{
	// Das hier brauchen wir, um Parameter an OLE-Objekte zu übergeben
             //  - immer leer machen!
	OleAutoArgs objArgBlock = create;

	OleAutoObj objCell;  // Das Zellen-Objekt nach Übermittlung 
                                        // der Koordinaten (1,1)
	string zellenInhalt;	// Der Inhalt aus der Zelle als String
	clear( objArgBlock );   // Parameter leeren
	put( objArgBlock, x );  // Parameter 1
	put( objArgBlock, y );  // Parameter 2
             // Das Zellenobjekt nimmt Koordinaten an
	oleGet(objSheet, "Cells", objArgBlock,objCell); 

	if (!null objCell)
		// Ewig rumprobiert... Value liefert Schrott bei Zahlen (manchmal nix...) 
		// oleGet(objCell,"Value",zellenInhalt);	{

		// Get the value
		oleGet(objCell,"FormulaR1C1",zellenInhalt);
	}
	else return "";

	return zellenInhalt "";
}
 
 
 
void main(void)
{
	// Wenn Excel lokal installiert ist gibt es dieses OLE Objekt im 
            // System.. suchs Hasso!!!
	OleAutoObj objExcel = oleCreateAutoObject( "Excel.Application" );

	// Das hier brauchen wir, um Parameter an OLE-Objekte zu 
             // übergeben - immer leer machen!
	OleAutoArgs objArgBlock = create;

	// Was steht in Application.isVisible?
	bool isVisible;	// Auslesen 1
	oleGet(objExcel, "Visible", isVisible);	// Auslesen 2
	print "Die Anwendung ist momentan " (isVisible?"sichtbar":"unsichtbar") "\n";

	// Mache die Anwendung sichtbar Application.isVisible=true;
	olePut(objExcel, "Visible", true);		// Reinschreiben

	// Ein Woorkbook ist eine Excel-Datei. Excel kann mehrere Dateien 
             // öffnen daher die Collection. Die Collection selbst hat die Open 
             // Methode zum einlesen von XLS-Files
	OleAutoObj objWorkbooks;
	oleGet(objExcel, "Workbooks", objWorkbooks);	// Hole Workbooks Collection

	// Öffne Excel application
	string xlsWorkbook="N:\\doorsattachments\\alarms.xls";	// Öffne Workbook
	clear( objArgBlock );
	put( objArgBlock, xlsWorkbook);
	OleAutoObj objWorkbook = null;
              // Reinschreiben Datei zu öffnen und Auslesen 
	oleGet(objWorkbooks, "Open",objArgBlock, objWorkbook ); 
	// Hole das erste Sheet
	clear( objArgBlock )
	put( objArgBlock, 1 )
	oleGet( objWorkbook, "Sheets", objArgBlock, objSheet);

	// Gib den Namen des ersten Sheets aus
	string sheetName;
	oleGet(objSheet, "Name", sheetName);
	print sheetName "\n";

	// Hole das Sheet mit dem Namen sheet1
	clear( objArgBlock );
	put( objArgBlock, "sheet1" ); 
	oleGet( objWorkbook, "Sheets", objArgBlock, objSheet);	

	// Gib den Index des "sheet1" Sheets aus
	int sheetIndex;
	oleGet(objSheet, "Index", sheetIndex);
	print sheetIndex"\n";

	// Hole das Cells(1,1) Objekt um auf die Excel Zellen zuzugreifen
	print "Zelleninhalt  : " getCellContent(objSheet,1,1) "\n";
	print "Zelleninhalt  : " getCellContent(objSheet,2,2) "\n";
	print "Letzte Zeile  : " findLastRow(objSheet) "\n";
	print "Letzte Spalte :"  findLastColumn(objSheet) "\n";

	// Iteration durch das Excel Sheet 
	int spaltenCount = findLastColumn(objSheet);
	int zeilenCount  = findLastRow(objSheet);
	int currentZeile, currentSpalte;
	string zeilenString="";

	for (currentZeile=1;currentZeile&lt;zeilenCount;currentZeile++)
	{
		
		for (currentSpalte=1;currentSpalte&lt;spaltenCount;currentSpalte++)
		{
			zeilenString = zeilenString "" getCellContent(objSheet, //-
                                                      currentSpalte, currentZeile) "\t";	
		}
		print zeilenString "\n";
		zeilenString="";
	}

	// Speicher aufräumen
	oleCloseAutoObject( objExcel );
}

main();

IBM Doors DXL: Line Feed w/o carriage return on stream write.

Problem

Die normale write methode eines Stream-Objektes erzeugt beim schreiben bei den folgenden Operationen stets ein Carriage Return am Zeilenende:

  • \n – erzeugt line feed mit carriage return
  • \012 – Explizites ausgeben oktal 12 (erzeugt line feed inkl. carriage return)
  • \r – erzeugt ledigtlich ein Carriage Return

Ansatz – Approach

Änderung der Stream write Methode

Lösung – Solution

Nutzt man die Methode mit dem Parameter binary, gibt es künftig mit \012 ausschließlich line feeds ohne carriage returns.

Stream theStream = write binary (dirPath "afile.txt" "");

IBM Doors DXL: Ist ein Filter gesetzt? Test if a filter is active / has been set

Aufgabenstellung – Problem

In einem DXL Skript wird geprüft, ob ein Filter aktiviert ist. Diese Funktion ist nicht in der Referenz dokumentiert!

In a DXL Skript the activation of a filter should be tested. This is not documented in the reference!

Ansatz – Approach

Use the filtering method.

Lösung – Solution

Module m = current; 
bool filterIsActive = filtering(m);

Danke an Johannes R. 🙂

IBM Doors DXL: How-to access Microsoft SQL Server & Microsoft Access from DXL (eine Bibliothek für SQL Statements / a library to perform sql statements)

Aufgabenstellung — Problem

Es wird eine einfache Bibliothek benötigt um SELECT Statements auf eine Microsoft SQL Server Datenbank abzusetzen und diese in einem DXL Programm zu verwenden

A library is needed for easily creating SQL Statements with result sets. This library should be embeddable in a DXL Skript.

Ansatz — Approach

Die Bibliothek wird von Capri-Soft (Björn Karpenstein) ständig weiterentwickelt und an dieser Stelle mit regelmäßigen Updates zur Verfügung gestellt.

The library will be provided on this site with frequently updates and can be downloaded at this site.

Lösung — Solution

Implemented Functions

Skip selectStatement(string sql, string dbServer, string dbName, string dbUsername, string dbPassword)
Skip selectStatementOnMDB(string sql, string mdbFile) [since Version 0.3]
Array selectStatement(string sql, string dbServer, string dbName, string dbUsername, string dbPassword)
Array selectStatementOnMDB(string sql, string mdbFile)  [since Version 0.3]
int executeQuery(string sql, string dbServer, string dbName, string dbUsername, string dbPassword)
int executeQueryOnMDB(string sql, string mdbFile)  [since Version 0.3]
OleAutoObj openDatabase(string dbServer, string dbName, string dbUsername, string dbPassword)
OleAutoObj openDatabaseOnMDB(string mdbFile)  [since Version 0.3]

Download

First download the DXL-Library here…

sqllibrary.dxl — Version 0.3 [match filename the includes of the examples!!!]
sqlserverlibrary.dxl — Version 0.2
sqlserverlibrary.dxl — Version 0.1

Create your DXL Skript in Doors

Recommendation: When you are writing your SQL Statements, use the CAST-Method every time you define a Field in the SELECT-Clause.

Eample for Version 0.3 with MS Access Support

In this example (only works since version 0.3) you can access .mdb Files like in the following example:

#include "C:\\dev\\dxl\\client\\sqllibrary.dxl";


Skip result = selectStatementOnMDB("SELECT [Connector_ID], [Connector_Type], [Btm_Mid_Label], [Stereotype]  FROM q_connector", "\\\\bbmag295\\ProcessModellingPrototypeAdvanced\\mdb\\modell.eap");
				
// Iteration through the SkipList
for myIterator in result do 
{
   string keyValue = (string key(result));
   DxlObject currentObject = null;

   if(find(result, keyValue, currentObject))
   {
       // Just put the column names here.. it will work
       print (string currentObject->"Connector_ID") "\t";
       print (string currentObject->"Connector_Type") "\t";
       print (string currentObject->"Btm_Mid_Label") "\t";
       print (string currentObject->"Stereotype") "\n";
   }
}

delete result;

Example:

string customFieldSQL= "" //-
" SELECT  CAST(pk.PROJECT_KEY+'-'+CAST(ji.issuenum as VARCHAR(7)) as varchar(10)) as pkey,  " //-
"	     CAST(convert(char, cg.created, 120) as varchar(30)) as on_date, " //-
"		 CAST(ci.field as varchar(50)), " //-
"		 CAST(cg.author as varchar(10)) as changed_by, " //-
"		 CAST(ISNULL(ci.oldstring,'') as varchar(4096)) as changed_from,  " //-
"		 CAST(ISNULL(ci.newstring,'') as varchar(4096)) as changed_to " //-
" FROM jiraissue ji, changegroup cg, changeitem ci, project_key pk " //-
" WHERE ci.groupid = cg.id " //-
" AND cg.issueid = ji.id  " //-
" AND pk.PROJECT_ID=ji.PROJECT " //-
" AND ci.field = '" customField "' " 

Examples for Version 0.2

#include "sqlserverlibrary.dxl"; // renamed to sqllibrary since version 0.3

// Here you can define your connection setting
string dbServer="IPorSERVERNAME";
string dbName="Databasename";
string dbUsername="databaseuser";
string dbPassword="databasepasswort";

// Reduce methods only to get SQL 
Skip selectStatement(string sql) 
{	return selectStatement(sql,dbServer,dbName,dbUsername,dbPassword); }
Array selectStatement(string sql) 
{	return selectStatement(sql,dbServer,dbName,dbUsername,dbPassword); }
int executeQuery(string sql) 
{ return executeQuery(sql,dbServer,dbName,dbUsername,dbPassword); }

// A manipulation like INSERT/UPDATE/DELETE
executeQuery("INSERT INTO table(col1) VALUES('TEST')");

// SKIPLIST: SELECT statement will return a SKIP-List with 
//           dynamic attributes (KEY is first column) 
Skip result = //-
selectStatement("SELECT [id], [col1], [col2], [col3], " //-
			    "[col4], [col5], [col6] " //-
				"FROM table " //-
				"WHERE col1<>'TEST' ORDER BY id ASC");
				
// Iteration through the SkipList
for myIterator in result do 
{
   string keyValue = (string key(result));
   DxlObject currentObject = null;

   if(find(result, keyValue, currentObject))
   {
       // Just put the column names here.. it will work
       print (string currentObject->"id") "\t";
       print (string currentObject->"col1") "\t";
       print (string currentObject->"col2") "\t";
       print (string currentObject->"col3") "\t";
       print (string currentObject->"col4") "\t";
       print (string currentObject->"col5") "\t";
       print (string currentObject->"col6") "\n";
   }
}

delete result;

// Array: SELECT statement will return an  Array 
Array result2 = selectStatement("SELECT [id], [col1], [col2], " //-
				"[col3], [col4], [col5], [col6] " //-
				"FROM table " //-
				"WHERE col1<>'TEST' ORDER BY id ASC");

int i;
for (i=0; i<resultCount; i++)
{
   DxlObject currentObject2 = (DxlObject get(result2,i,1));
   
   if(!null(currentObject2))
   {
       // Just put the column names here.. it will work
       print (string currentObject2->"id") "\t";
       print (string currentObject2->"col1") "\t";
       print (string currentObject2->"col2") "\t";
       print (string currentObject2->"col3") "\t";
       print (string currentObject2->"col4") "\t";
       print (string currentObject2->"col5") "\t";
       print (string currentObject2->"col6") "\n";
   }
}

delete result2;

Example for Version 0.1

#include "sqlserverlibrary.dxl"; // renamed to sqllibrary since version 0.3

// Here you can define your connection setting
Skip selectStatement(string sql)
{
	// Connection details for test
	string dbServer="DATABASE_SERVER_OR_IP";
	string dbName="DATABASE_NAME";
	string dbUsername="DATABASE_USER";
	string dbPassword="DATABASE_PASSWORD";

	return selectStatement(sql,dbServer,dbName,dbUsername,dbPassword);
}

// selectStatement will return a SKIP-List with dynamic attributes
Skip result = //-
selectStatement( //-
"SELECT col1,col2,col3,col4,col5,col6 " //-
			"FROM table " //-
			"WHERE col1 " //-
			" NOT IN ( " //-
			"	SELECT col1 " //-
			"	FROM table " //-
			" 	WHERE LTRIM(RTRIM(col1))<>'---' " //-
			"   GROUP BY alarm_id " //-
			"	HAVING COUNT(*)>1 " //-
			"	) ")
				
// Iteration durch SkipList
for myIterator in result do 
{
   string keyValue = (string key(result));
   DxlObject currentObject = null;

   if(find(result, keyValue, currentObject))
   {
       // Just put the column names here.. it will work
       print (string currentObject->"col1") " ";
       print (string currentObject->"col2") " ";
       print (string currentObject->"col3") " ";
       print (string currentObject->"col4") " ";
       print (string currentObject->"col5") " ";
       print (string currentObject->"col6") "\n";
   }
}

delete result;

Comment

Don’t forget to leave some improvement comments here!!!

IBM Doors DXL: Zugriff auf MS SQL Server

Aufgabenstellung

In der Programmiersprache DXL von IBM Doors soll auf Daten eines Microsoft SQL Servers zugegriffen werden.

Ansatz

Die Verwendung der COM-Schnittstelle erlaubt Zugriff auf die ADODB.Connection. Hierbei handelt es sich um eine Microsoft Bibliothek für den Zugriff auf SQL Server.

Lösung 1

Das folgende Skript erlaubt Zugriff auf den Microsoft SQL Server und führt eine SELECT-Anweisung durch:

// Connection details
string dbServer=“SERVER“;
string dbName=“DATABASE“;
string dbUsername=“USER“;
string dbPassword=“PASS“;

string connectionString = „Data Source='“ dbServer „‚;
Initial Catalog='“ dbName „‚;User Id='“ dbUsername „‚;Password='“ dbPassword „‚;“;

OleAutoArgs oleAutoArgs=create;
OleAutoObj adodbConnection, adodbRecordset, objFields, objField;

string fieldName, result, err;
int numFields, index;

// Instantiate a new ADODB Connection object
adodbConnection = oleCreateAutoObject „ADODB.Connection“;

if (null adodbConnection)
{
print „Unable to instantiate database connection\n“;
halt;
}

// Instantiate a new ADODB Recordset object
adodbRecordset = oleCreateAutoObject „ADODB.Recordset“;

if(null adodbRecordset)
{
print „Unable to create Recordset object\n“;
halt;
}

// Connection details

// Set the provider and data source of the connection
// based on information from connectionstrings.com
olePut(adodbConnection, „Provider“, „sqloledb“);
clear oleAutoArgs;
put(oleAutoArgs, connectionString );
// „Password=“ dataPass „;“)
// Open the connection to the database
err=oleMethod(adodbConnection, „Open“, oleAutoArgs);

if(!null err „“)
{
print „Error opening database: “ err „\n“;
halt;
}

// SQL Command: Open a cursor to return all columns and rows of ‚tableName‘
clear oleAutoArgs

put(oleAutoArgs, „select * from [alarms] order by 1“) // SQL Command
put(oleAutoArgs, adodbConnection) // ACTIVE CONNECTION
put(oleAutoArgs, 1) // CURSOR TYPE – ‚adOpenKeyset‘
put(oleAutoArgs, 1) // LOCK TYPE – ‚adLockReadOnly‘
put(oleAutoArgs, 1) // OPTIONS – ‚adCmdText‘

err=oleMethod(adodbRecordset, „Open“, oleAutoArgs);

if(!null err „“)
{
print „Error opening table: “ err „\n“;
halt;
}

// From the Recordset object, list each field name (defined in database)
oleGet(adodbRecordset, „Fields“, objFields);
oleGet(objFields, „Count“, numFields);

for(index=0; index0?“\“,“:““) „\““ fieldName;
}

print „\“\n“;

// From the Recordset object cursor, loop through and print each row
while(true)
{
result=““;
clear oleAutoArgs;
put(oleAutoArgs, 2); // StringFormat – ‚adClipString‘
put(oleAutoArgs, 1); // NumRows
put(oleAutoArgs, „\“,\““); // ColumnDelimiter
put(oleAutoArgs, „\““); // RowDelimiter
put(oleAutoArgs, „“); // NullExpr
oleMethod(adodbRecordset, „GetString“, oleAutoArgs, result);
if(length(result)<=0) break else print "\"" result "\n"; } [/javascript]

Lösung 2

Das untere Beispiel zeigt die Kapselung in eine Funktion und den Zugriff auf Einzelwerte, bzw. auf einzelne Zellen eines Recordsets. Dieses Beispiel lässt sich ausgezeichnet in andere Bibliotheken auslagern:

OleAutoArgs args = null;

void cleanup (OleAutoObj &obj)
{
if (!null obj)
{
oleCloseAutoObject obj;
obj = null;
}
}

// some syntax helpers for arguments (from DXL standard library) …
void checkNull (string s)
{
if (!null s)
{
print „Error: “ s „\n“ dxlHere();
halt;
}
}

OleAutoArgs createArgs ()
{
if (!null args) delete args;
args = create();
return args
}

OleAutoArgs ::<-(OleAutoArgs x, int a) { put(x, a); return x } OleAutoArgs ::<-(OleAutoArgs x, string a) { put(x, a); return x } OleAutoArgs ::<-(OleAutoArgs x, bool a) { put(x, a); return x } // Hier bekommt man eine Spalte des aktuellen Records als String string stringProperty (OleAutoObj obj, string s) { string result = null; checkNull oleGet (obj, s, result); return result } void selectStatement(string sql, string dbServer, string dbName, string dbUsername, string dbPassword) { string connectionString = "Data Source='" dbServer "';Initial Catalog='" dbName "';User Id='" dbUsername "';Password='" dbPassword "';"; OleAutoArgs oleAutoArgs=create; OleAutoObj adodbConnection, adodbRecordset, objFields, objField; string fieldName, result, err; int numFields, index; // Instantiate a new ADODB Connection object adodbConnection = oleCreateAutoObject "ADODB.Connection"; if (null adodbConnection) { print "Unable to instantiate database connection\n"; halt; } // Instantiate a new ADODB Recordset object adodbRecordset = oleCreateAutoObject "ADODB.Recordset"; if(null adodbRecordset) { print "Unable to create Recordset object\n"; halt; } // Connection details // Set the provider and data source of the connection // based on information from connectionstrings.com olePut(adodbConnection, "Provider", "sqloledb"); clear oleAutoArgs; put(oleAutoArgs, connectionString ); // "Password=" dataPass ";") // Open the connection to the database err=oleMethod(adodbConnection, "Open", oleAutoArgs); if(!null err "") { print "Error opening database: " err "\n"; halt; } // SQL Command: Open a cursor to return all columns and rows of 'tableName' clear oleAutoArgs put(oleAutoArgs, sql) // SQL Command put(oleAutoArgs, adodbConnection) // ACTIVE CONNECTION put(oleAutoArgs, 1) // CURSOR TYPE - 'adOpenKeyset' put(oleAutoArgs, 1) // LOCK TYPE - 'adLockReadOnly' put(oleAutoArgs, 1) // OPTIONS - 'adCmdText' err=oleMethod(adodbRecordset, "Open", oleAutoArgs); if(!null err "") { print "Error opening table: " err "\n"; halt; } // From the Recordset object, list each field name (defined in database) oleGet(adodbRecordset, "Fields", objFields); oleGet(objFields, "Count", numFields); for(index=0; index0?“\“,“:““) „\““ fieldName;
}

print „\“\n“;

// From the Recordset object cursor, loop through and print each row
while(true)
{
// Break when we are still at the end
bool bEOF = false;
checkNull oleGet(adodbRecordset, „EOF“, bEOF);
if (bEOF) break;

oleGet(adodbRecordset, „Fields“, objFields);

// Hier werden die Einzelfelder ausgelesen
oleGet(objFields, „Item“, createArgs <- 0 , objField); string feld1 = stringProperty(objField, "Value"); oleGet(objFields, "Item", createArgs <- 1 , objField); string feld2 = stringProperty(objField, "Value"); oleGet(objFields, "Item", createArgs <- 2 , objField); string feld3 = stringProperty(objField, "Value"); print feld3 " " feld1 " " feld2 "\n"; checkNull oleMethod (adodbRecordset, "MoveNext"); } cleanup adodbConnection; cleanup adodbRecordset; cleanup objFields; cleanup objField; } // Connection details string sql="select [alarm_id], [subsystem], [bitnumber] from [alarms] order by 1"; string dbServer="SERVER"; string dbName="DATENBANK"; string dbUsername="USER"; string dbPassword="PASS"; selectStatement(sql,dbServer,dbName,dbUsername,dbPassword); [/javascript]

IBM Doors DXL Skript: Eingeloggte User und blockierte Module / current logged in users and modules blocked or in edit

Problembeschreibung – Problem description

Aufgrund von Lizenzeinschränkungen (z.B. durch die floating Licence) ist es manchmal nötig die Liste der momentan eingeloggten DOORS-User herauszufinden. Darüberhinaus möchte man oft wissen, wer welches Modul gerade editiert.

Because of licence restrictions in IBM DOORS it is sometimes necessary to find out which users are currently logged in. Further it is helpful to know which users are currently editing or blocking one module.

Ansatz – Approach

Das folgende DXL Skript gibt eine Liste der eingeloggten User und der Module aus, die gerade editiert werden.

The following DXL Skript creates a list of logged in users an blocked modules.

Lösung – Solution

Das DXL Skript kann als Menüpunkt in Doors eingebunden werden (hierzu gibt es genug IBM Beispiele).

Please follow IBM examples to embed the DXL script as menu in your DOORS client.

Download DXL Skript

Achtung! Dieses Skript funktioniert nur mit Administratorrechten.
Please note: You will need admin rights to show the Dialogs.