I like to have dxl script which lets me list out the dead inlinks, i.e list out links leading to a deleted object.
i tried if any option is there in doors but could not find it.
Can you please help in this.
Thanks
I have been investigating this issue for a long time and I have not been able to identify the cause of this issue and neither has IBM. Standard practice should be to always delete outlinks before softDeleting objects and make sure not to use the adminisitrative remove lock function while a user has a Module Opened in share edit with a lock on a section while an object modification or link modifications is being made. Doing so will help to eliminate this issue but not entirely since it happens allot and I have not been able to replicate this issue entirely.
The best way to find the Deadlinks is to use targetAbsNo and sourceAbsNo and check the source/target object for that incoming/outgoing matching AbsNo and module. If you try to set the outlink target to an object, DOORS will ignore this object and it will not find the DeadLink I.E(Object targetobj = target(lnk)).
If the objects have not been purged you can still remove the deadlinks by using the link analysis wizzard on the source object, creating a new link to the object with the deadlink and then deleting this link and saving your changes. If the object with deadlinks has been purged your are out of luck, I have not found a way of removing this types of links to and from objects that don't exist. Also you will want to know the non deleted objects with deadlinks so that this aren't softDeleted/purged and create issues with outlinks to non existent objects.
I did this code out of the back of my head so it has not been tested and it will not work, but you should get an idea of how to look for the DeadLinks. The object() and the Source and Target Module naming is incorrect, I don't remember exactly the syntax used for opening the Target Modules and I don't have access to the documentation at the moment, my apologies.
Copy paste the results into excel and you will get a nice spreadsheet.
Object objSrc
Link lnkTargetLink
Module modMain = read("/Project/YourModule", true, true)
modMain = current
filtering off
showDeletedObjects true
Buffer bufDeadObjects = create
bufDeadObjects = "Error\tSource Object\tTarget Module\tTarget Object\n"
for objSrc in modMain do {
for lnkTargetLink in all(objSrc -> "*") do {
Module targetMod = target module lnkTargetLink //Incorrect syntax
int intTargetAbs = targetAbsNo lnkTargetLink
showDeletedObjects (true)
filtering off
Object objTarget = object(intTargetAbs, targetMod)
if(null objTarget) {
bufDeadObjects += "Target Object Does not Exist\t"sourceAbsNo lnkTargetLink "\t" fullName targetMod "\t" intTargetAbs"\n"
} else {
Link lnkSourceLink
bool boolFoundLink = false
for lnkSourceLink in all(objTarget <- "*") do {
if(sourceAbsNo lnkSourceLink != intTargetAbs) continue
Module modSourceMod = source module lnkSourceLink //Incorrect syntax
if(fullName modSourceMod != fullName targetMod ) continue
boolFoundLink = true
}
if(!boolFoundLink and isDeleted(objTarget)) {
bufDeadObjects += "DeadInlink on a Deleted Object\t"sourceAbsNo lnkTargetLink "\t" fullName targetMod "\t" intTargetAbs"\n"
} else if (boolFoundLink and isDeleted(objTarget)){
bufDeadObjects += "Outlink to a Deleted Object\t"sourceAbsNo lnkTargetLink "\t" fullName targetMod "\t" intTargetAbs"\n"
} else {
bufDeadObjects += "DeadOutlink\t"sourceAbsNo lnkTargetLink "\t" fullName targetMod "\t" intTargetAbs"\n"
}
}
}
}
print stringOf (bufDeadObjects)
I did not run the following code, and this isn't optimally efficient, but it will get you started:
Link lnk ; for lnk in all obj->"*" do
{
ModuleVersion targetmv = targetVersion(lnk)
Module targetmod = load(mv,false)
Object targetobj = target(lnk)
if((null targetobj) || (isDeleted targetobj)) { /*dead link*/ }
close(targetmod)
delete(targetmv)
}
Edit > Purge all will purge/remove all deleted objects including all their dead links!
Observe that un-delete is not possible after this action.
Related
I‘m new to this so I hope I get it right.
I‘m not exactly new to writing DXL but currently have a performance issue with calling getProperties from a Layout dxl column that is supposed to display outgoing links depending on a module attribute value of type Enum of the linked module.
The code basically works but takes extremely long to complete. Commenting out the getProperties call makes it as fast as it could be.
Yes, the call is written exactly as shown in DXL Ref manual.
Calling the attribute directly, using a module object and dot operator does not work either as it always returns the enums default value but not the actual.
Any ideas welcome...
EDIT added example code below
// couple of declarations snipped
string cond = "Enum selection here" // this is modified from actual code, to show the idea
string linkModName = "*"
ModuleProperties mp
for l in all(o->linkModName) do
{
otherVersion = targetVersion l
otherMod = module(otherVersion)
if (null otherMod || isDeleted otherMod) continue
othero = target l
if (null othero)
{
load(otherVersion,false)
}
getProperties(otherVersion, mp)
sTemp = mp.myAttr
if (sTemp == cond) continue
// further code snipped
}
I'm not 100% sure but I think there is/was a performance issue with module properties in some DOORS versions.
You might want to try the following, i.e. directly get the attribute from the loaded Module
[...]
othero = target l
Module m
if (null othero)
{
m = load(otherVersion,false)
} else {
m = module othero
}
sTemp = m.myAttr
[...]
Caution, I did not test this snippet.
I'm new on DXL and working on something that is probably quite simple.
I would like to parse the current module, and get the following data for each object that has a given ID (calling IDNUM below) not empty:
IDNUM - Object text - all text with a lower hierarchic level and the same thing for all objects liked to this one.
It will probably be easier to understand with the code. So far, it looks like that:
Object o
Object ol
Link l
Module m = current Module
For o in entire(m) do{
if (o."IDNUM" != ""){
print o."IDNUM" ""
print o."text" ""
//HERE I WOULD LIKE TO ALSO PRINT EVERY TEXT IN OBJECT "LOWER" THAN o
for l in o --> "*" do{
ol = target(l)
print ol."text" ""
//HERE I WOULD LIKE TO ALSO PRINT EVERY TEXT IN OBJECT "LOWER" THAN ol
}
}
}
Basically, I have the ID and title of both an object and the one liked to it, but not the text below. In other words, my code will "mimic" the function right click>copy>copy with hierarchy
How can I do that? Unfortunately I didn't find anything very helpful.
Thanks a lot in advance,
Here is the sketch code you outlined:
Object o
Object ol
Link l
Module m = current Module
For o in entire(m) do{
if (o."IDNUM" != ""){
print o."IDNUM" ""
print o."text" ""
//HERE I WOULD LIKE TO ALSO PRINT EVERY TEXT IN OBJECT "LOWER" THAN o
for l in o --> "*" do{
ol = target(l)
print ol."text" ""
//HERE I WOULD LIKE TO ALSO PRINT EVERY TEXT IN OBJECT "LOWER" THAN ol
}
}
}
There are a few little syntax things that need to be changed here, but the big change is how you are handling linked items. Links 'live' in the source module, but they only store a limited amount of information, mostly the modules that are the source and target of the link, and the absolute numbers of the objects they touch. So you need to check if the module on the other side is open before you try and read text from it.
And since you are trying to go through the entire link structure, you'll need a recursive element to this.
I would probably end up with something like this:
//turn off run limit timer- this might take a bit
pragma runLim , 0
Object o
Module m = current Module
// Recursive function- assumes each object has a text attribute- will error otherwise
void link_print(Object obj) {
print obj."text" "\n"
Link out_link
Object next_obj = null
for out_link in obj -> "*" do {
// Set the next object in the chain
next_obj = target ( out_link )
// This might return null if the module is not loaded
if ( null next_obj ) {
// Load the module in read-only mode, displayed and in standard view
read ( fullName ( ModName_ target ( out_link ) ) , true , true )
// Try and resolve out 'target' again
next_obj = target ( out_link )
// If it doesn't work, print a message so we can figure it out
if ( null next_obj ) {
print "Error Accessing Object " ( targetAbsNo ( out_link ) )""
} else {
//Iterate down structure
link_print ( next_obj )
}
} else {
//Iterate down structure
link_print ( next_obj )
}
}
}
for o in entire(m) do {
// Note that I cast the result of o."IDNUM" to a string type by appending ""
if (o."IDNUM" "" != ""){
print o."IDNUM" "\n"
// Recurse
link_print(o)
print "\n"
}
}
Note! Depending on the size of your link structure, i.e. how many levels you have (and if there are any circular link patterns), this could be a pretty resource intensive task, and would be better solved using something other than "print" commands (like appending it to a word file, for example, so you know how far it got before it errored out)
Good luck!
EDIT:
Rather than head down recursively, this script will now go a single level but should report child objects.
//turn off run limit timer- this might take a bit
pragma runLim , 0
Object o
Module m = current Module
// Recursive function- assumes each object has a text attribute- will error otherwise
void link_print(Object obj) {
print obj."text" "\n"
Link out_link
Object next_obj = null
Object child_obj = null
for out_link in obj -> "*" do {
// Set the next object in the chain
next_obj = target ( out_link )
// This might return null if the module is not loaded
if ( null next_obj ) {
// Load the module in read-only mode, displayed and in standard view
read ( fullName ( ModName_ target ( out_link ) ) , true , true )
// Try and resolve out 'target' again
next_obj = target ( out_link )
// If it doesn't work, print a message so we can figure it out
if ( null next_obj ) {
print "Error Accessing Object " ( targetAbsNo ( out_link ) )""
} else {
// Loop and report on child objects
for child_obj in next_obj do {
print child_obj."text" "\n"
}
}
} else {
// Loop and report on child objects
for child_obj in next_obj do {
print child_obj."text" "\n"
}
}
}
}
for o in entire(m) do {
// Note that I cast the result of o."IDNUM" to a string type by appending ""
if (o."IDNUM" "" != ""){
print o."IDNUM" "\n"
// Recurse
link_print(o)
print "\n"
}
}
Dear Russell (and everyone else)
I've just went through the piece of code you provided me and it works.... but not for what I'm looking for. It seems my explanation wasn't very clear. I'm sorry (I'm not a native speaker).
I'm not looking to get all links, but just the Object text that is written just below the object pointed by the current link.
Here is what my files look like
object1 (with IDNUM) : "Title_doc_1" --> (link) objectA "Title_doc_2"
object2 : "some_text" objectB : "some_text"
object3 : "some_text" objectC : "some_text"
(object1 can point to many other objectA but I already deal with that.)
The code I provided above parses the "doc_1", and print "IDNUM" "Title_doc_1" "Title_doc_2"
What I'm looking for is to get, not only objectA but also objectB and objectC which are hierarchically below objectA (and object2 and object3 too but it will ve the same process).
Hopping I made myself understood...
I have the following situation.
I want to count in Module 1, how many objects are having links in links from Module 3.
example:
Module 1 Obj1 <- Module 2 Obj1 <- Module 3.Obj1
Module 1 Obj2 <- Module 2 Obj1 <- Module 3.Obj1
Module 1 Obj3 <- Module 2 Obj1 <- Module 3.Obj1
Module 1 Obj4 <- Module 2 Obj1
Module 1 Obj5 <- Module 2 Obj1
The count should return 3, in the above case.
Is it possible via DXL to follow a link, and then follow another link?
(not using the Wizard or DXL attributes)
Most important for me: knowing if somebody else did this and it's possible to do.
Please try the following DXL from within the module that has the incoming links. Before running the code:
make sure that you open the 'Edit DXL' window from the relevant module
set the string values assigned to global constant STR_LINK_MOD_FULLNAME (line 17) to the full pathname of the link module whose links you are interested in
set the string values assigned to global constant STR_SRC_MOD_FULLNAME (line 18) to the full pathname of the source formal module (Module 3, in your example) whose links you are interested in
You shouldn't need to change anything else to make it work.
N.B. I have not considered the implications of analysing links in all link modules by using the string "*" in place of a specific link module name in line 17 (see point 2, above).
I also haven't gone out of my way to explain the code, though I have tried to be nice and tidy up after myself where DOORS and DXL require it. Please feel free to reply with any questions on what I have done.
Kind regards,
Richard
//<CheckObjectInNestedLink.dxl>
/*
*/
///////////////
// Sanity check
if (null (current Module))
{
print "ERROR: this script must be run from a Formal Module."
}
///////////////////
// Global Constants
const string STR_LINK_MOD_FULLNAME = "/New Family Car Project/Admin/Satisfies" // the fullName of a single link module - results of using "*" have not been considered/tested
const string STR_SRC_MOD_FULLNAME = "/New Family Car Project/Architecture/Architectural Design" // The fullName of the desired source Formal Module
///////////////////
// Global Variables
Module modSource = null
Object objTarget = null
Object objSource = null
Link lkIn = null
Skip skLinkedMods = create()
Skip skObjsWithDesiredSource = create()
int intNoOfLinked = 0
//////////////////////
// Auxiliary Functions
void closeSourceMods ()
{
Module srcMod
for srcMod in skLinkedMods do
{
close(srcMod)
}
}
void openSourceMods (Object objWithLinks)
{
ModName_ srcModRef
Module srcMod
for srcModRef in (objWithLinks <- STR_LINK_MOD_FULLNAME) do
{
srcMod = read(fullName(srcModRef), false)
put(skLinkedMods, srcMod, srcMod)
}
}
void recurseFollowInLinks (Object objWithLinks)
{
openSourceMods(objWithLinks)
for lkIn in objWithLinks <- STR_LINK_MOD_FULLNAME do
{
openSourceMods(objWithLinks)
objSource = source(lkIn)
string strSrcModName = fullName(module(objSource))
if (strSrcModName == STR_SRC_MOD_FULLNAME)
{
bool blNewEntry = put(skObjsWithDesiredSource, objTarget, objTarget)
if (blNewEntry)
{
intNoOfLinked++
}
//print "put(skObjsWithDesiredSource, " identifier(objTarget) ", " identifier(objTarget) ")\n"
}
recurseFollowInLinks(objSource)
}
}
void checkObjectInNestedLink (Module modThis, string strSourceModuleFullname, string strLinkModuleFullName)
{
intNoOfLinked = 0
for objTarget in modThis do
{
recurseFollowInLinks(objTarget)
}
print "The following " intNoOfLinked " objects have direct or indirect links of type " STR_LINK_MOD_FULLNAME " from formal module " STR_SRC_MOD_FULLNAME ":\n"
for objTarget in skObjsWithDesiredSource do
{
print identifier(objTarget)
print "\n"
}
}
///////////////
// Main Program
checkObjectInNestedLink ((current Module), STR_SRC_MOD_FULLNAME, STR_LINK_MOD_FULLNAME)
closeSourceMods()
delete(skLinkedMods)
delete(skObjsWithDesiredSource)
I have a fairly simple nested table Aurora64.Chat containing a couple of functions (where the main Aurora64 class is initialized elsewhere but I inserted it here for completeness):
Aurora64 = {};
Aurora64.Chat = {
entityId = 0;
Init = function()
local entity; --Big long table here.
if (g_gameRules.class == "InstantAction") then
g_gameRules.game:SetTeam(3, entity.id); --Spectator, aka neutral.
end
entityId = Entity.id;
self:LogToSystem("Created chat entity '" .. entity.name .. "' with ID '" .. entity.id .. "'. It is now available for use.");
end
LogToSystem = function(msg)
System.LogAlways("$1[Aurora 64]$2 " .. msg);
end
}
The above code fails (checked with the Lua Demo) with the following:
input:14: '}' expected (to close '{' at line 3) near 'LogToSystem'
I have tracked it down to the LogToSystem function and its usage (if I remove the function and the one time it is used, the code compiles perfectly), and I thought it was to do with my use of use of concatenation (it wasn't).
I'm thinking I might have missed something simple, but I checked the documentation on functions and the function & its call seem to be written properly.
What exactly am I doing wrong here?
You are missing a comma before LogToSystem and you need to define it a bit differently (by adding self as an explicit parameter):
end,
LogToSystem = function(self, msg)
System.LogAlways("$1[Aurora 64]$2 " .. msg);
end
}
It's not possible to use the form obj:method with anonymous functions assigned to table fields; you can only use it with function obj:method syntax.
I'm having a huge problem when I've added content to a table (Lua), where all content in the table suddenly disappears.
The table in question holds the data for a banlist (608 entries at present) and is placed within the table by using table.insert, however the lead entry for the user is done as Umbra.Banlist[profileId] = {};. The Umbra.Banlist[profileId] = {}; table alone should mean that there's content within the Umbra.Banlist table.
I get no errors when running the code, and when using
if (#Umbra.Banlist == 0) then
System.LogAlways(Umbra.Tag.." The Banlist seems to be empty. It seems that some part of loading has failed.");
end
I get this:
I've looked on the web and on this site but there doesn't seem to be any related questions, so I'm posting it here.
This code is part of a server mod for Crysis Wars (see the whole function below), but has the entire Lua library at hand (so don't worry if you don't think your answer won't solve the problem).
The Code:
Umbra.ReadBans = function()
self = Umbra;
System.LogAlways(Umbra.Tag.." Starting banlist read.");
FileHnd, err = io.open(Root().."Mods/Infinity/System/Read/Banlst.lua", "r");
if (not FileHnd) then
System.LogAlways(Umbra.Tag.." Unable to find file 'Banlst.lua'.");
return;
end
for line in FileHnd:lines() do
local name, profile, ip, domain, reason, date, bannedby = line:match([[Umbra.BanSystem:Add%('(.-)', '(.+)', '(.+)', '(.+)', '(.+)', '(.+)', '(.-)'%);]]);
if (not name) then
System.LogAlways(Umbra.Tag.." Failed to read the banlist at line "..count or 0);
break;
end
System.LogAlways(Umbra.Tag.." Banlist; Name: [ "..name.." ], For: [ "..reason.." ], By: [ "..bannedby.." ]");
--local Msg, Date, Reason, Type, Domain = line:match([[User:Read%( "(.-)", { Date="(.+)"; Reason="(.+)"; Typ="(.+)"; Info="(.+)"; } %);]]);
--User:Read( "Banned", { Date="31.03.2011"; Reason="WEBSTREAM"; Typ="Inetnum"; Info="COMPUTER.SED.gg"; } );
--Umbra.BanSystem:Add('patryk', '258132298', '178.183.243.163', '178.183.243.163.dsl.dynamic.t-mobile.pl', 'flyhack', '08/11/2012 | 21:39:53', 'Anti-Noob');
Umbra.Banlist[profile] = {};
table.insert(Umbra.Banlist[profile], name);
table.insert(Umbra.Banlist[profile], ip);
table.insert(Umbra.Banlist[profile], domain);
table.insert(Umbra.Banlist[profile], reason);
table.insert(Umbra.Banlist[profile], date);
table.insert(Umbra.Banlist[profile], bannedby);
--[[Umbra.Banlist[profile].name = name;
Umbra.Banlist[profile].ip = ip;
Umbra.Banlist[profile].domain = domain;
Umbra.Banlist[profile].reason = reason;
Umbra.Banlist[profile].date = date;
Umbra.Banlist[profile].bannedby = bannedby;--]]
if not count then count = 0; end
count = count + 1;
end
Umbra.Bans = {};
Umbra.Bans.cnt = count;
System.LogAlways(Umbra.Tag.." Read "..count.." banned players (added into the Umbra Global Banlist)");
if (#Umbra.Banlist == 0) then
System.LogAlways(Umbra.Tag.." The Banlist seems to be empty. It seems that some part of loading has failed.");
end
count = nil; --Purge this one as well, again!
end
Edit:
I don't get the message that the code below should print if their profile doesn't exist in the table, so their profile does actually exist.
if (not Umbra.Banlist[profile]) then
System.LogAlways(Umbra.Tag.." Error in 'Umbra.Banlist': The profile does not exist.)");
break;
end
Another Edit:
Proof that the system can in fact get the 'ID' variable:
Near the end of your code you have #Umbra.Banlist == 0 but I don't see any item insertions into it by numeric keys. Here are some things to check to see if you're assumptions matches up with reality.
Check that profile isn't nil. It looks like in your use-case you're assuming it's a number. You can check this easily with:
assert(profile)
assert(type(profile) == 'number')
If profile is actually not a number type then checking Umbra.Banlist with # operator is faulty. Note # does not count the associative part of the table. If you only care whether Umbra.Banlist is empty or not you can use if next(Umbra.Banlist) then to check for it.
Just try to use this function to get count of items in table:
function count(t)
local c=0;
for i in pairs(t) do c=c+1; end
return c;
end
--...
if(count(Umbra.Banlist)==0)then
--...
end
The thing is, that # counts an array/table with number indexes, but you have table with string indexes. # is same like when you would replace "pairs" with "ipairs" in that count function. So and when you do #Umbra.Banlist, where all indexes are strings, it returns 0, because there are 0 integer indexes, but it does not mean, that table is empty.