Reflecting over ArchestrA Object Attributes

by Klaus Graefensteiner 7. December 2007 02:45

Have you ever read the children's book: "Have you seen my cat?" by Eric Carle? A little boy is searching for his cat and gets to see a bunch of different kinds of cats during his quest. The challenge of finding the Primitive that an ArchestrA Attribute belongs to reminded me of this story:

clip_image001

"Have you seen my Primitive ID?"

No sorry. I have not seen your Primitive ID, at least not yet, but listen carefully!

The GRAccess toolkit provides programmable access to ArchestrA objects and their meta data. In this article I introduce a utility that exports a list of all attributes of a given object instance or template into a text file. The program is written as a C# console application. Compiling the provided sample requires a reference to the ArchestrA.GRAccess.dll assembly . The assembly is usually located under the folder C:\Program Files\Common Files\ArchestrA.

Each attribute is uniquely defined by its PrimitiveID and AttributeID. The meta data of an individual attribute e.g. DataType, Category and Security Classification are defined by the Attribute Properties. Not all meta data is exposed directly by the toolkit. If you are interested in the actual ordinal values of each of the components like PrimitiveID, AttributeID and PropertyID then you are out of luck. These implementation details are not directly accessible. But fortunately there is a back door.

Setting the "GetAttribute" LogFlag of the "WWFSObject" LogFlag group will enable verbose debug logging during the export operation of our utility. With the help of the log file we then can map the ordinal values of PrimitiveID, AttributeID and PropertyID to their corresponding items in the export file. This way we can for example determine the Primitive that an Attribute belongs to. This export utility also demonstrates how to set a LogFlag automatically by directly writing the LogFlag value to the Registry.

Program Listing

    1 using System;

    2 using System.Collections.Generic;

    3 using System.Text;

    4 using System.IO;

    5 

    6 

    7 //Registry Related Stuff

    8 using Microsoft.Win32;

    9 using System.Security;

   10 using System.Security.Permissions;

   11 using System.Security.AccessControl;

   12 using System.Reflection;

   13 

   14 //GRAccess

   15 using ArchestrA.GRAccess;

   16 

   17 

   18 namespace DumpAttributes

   19 {

   20   class Program

   21   {

   22     static void Main(string[] args)

   23     {

   24 

   25       #region Command Line Argument Parsing

   26 

   27 

   28       //("DumpAttributes Usage:");

   29       //("+++++++++++++++++++++");

   30 

   31       //("  g=<Galaxy Name>");

   32       //("  gr=<GR Server Node>");

   33       //("  u=<User Name>");

   34       //("  pw=<Password>");

   35       //("  o=<Object or Template Name. Templates start with '$'!");

   36 

   37       //("  -> The order of the parameters doesn't matter!");

   38       //("  -> There must be 5 parameters!");

   39       //("  -> Use empty space characters to separate parameter=value pairs!");

   40       //("  -> Don't use commas or semi-colon to separate parameter=value pairs!");

   41       //("  -> The parameter=value pairs can't be longer than 254 characters!");

   42       //("  -> The parameter specifier can't be longer than 2 characters!");

   43 

   44       //("  Example:");

   45       //("  DumpAttributes o=$WatchDog gr=localhost g=PENGUINS u=Administrator pw=ww");

   46 

   47       //Initialize dictionary

   48       Dictionary<string, string> CmdParams = new Dictionary<string, string>(5);

   49 

   50       CmdParams.Add("gr", Environment.MachineName);

   51       CmdParams.Add("g", "");

   52       CmdParams.Add("o", "");

   53       CmdParams.Add("u", "");

   54       CmdParams.Add("pw", "");

   55 

   56       if (args.GetLength(0) != CmdParams.Count)

   57       {

   58         PrintHelp();

   59         return;

   60       }

   61       else

   62       {

   63         foreach (string s in args)

   64         {

   65           if (s.Length > 255)

   66           {

   67             PrintHelp();

   68             return;

   69           }

   70 

   71           if (s.IndexOf('=') > 2)

   72           {

   73             PrintHelp();

   74             return;

   75           }

   76 

   77           if (s.Split('=').GetLength(0) != 2)

   78           {

   79             PrintHelp();

   80             return;

   81           }

   82           else

   83           {

   84             try

   85             {

   86               string temp = CmdParams[(s.Split('='))[0]];

   87             }

   88             catch

   89             {

   90               PrintHelp();

   91               return;

   92             }

   93 

   94             CmdParams[(s.Split('='))[0]] = ((s.Split('='))[1]);

   95           }

   96         }

   97       }

   98 

   99       if (0 == String.Compare(CmdParams["gr"], "localhost", true))

  100       {

  101         CmdParams["gr"] = Environment.MachineName;

  102       }

  103 

  104       string GRMachineName = CmdParams["gr"];

  105       string GalaxyName = CmdParams["g"]; ;

  106       string UserName = CmdParams["u"]; ;

  107       string Password = CmdParams["pw"];

  108       string AAObjectName = CmdParams["o"];

  109 

  110       Boolean IsTemplate = false;

  111 

  112       //Parse Object Name

  113       if (AAObjectName[0] == '$')

  114       {

  115         IsTemplate = true;

  116       }

  117 

  118       #endregion

  119       #region GRAccess Login

  120       ICommandResult CR;

  121       IGalaxies Galaxies;

  122       IGalaxy G;

  123       IgObjects Objects;

  124       ITemplate T;

  125       IInstance I;

  126       IAttributes Attributes;

  127       GRAccessAppClass GR = new GRAccessAppClass();

  128 

  129       Galaxies = GR.QueryGalaxies(GRMachineName);

  130 

  131       if (Galaxies == null || GR.CommandResult.Successful == false)

  132       {

  133         System.Console.Out.WriteLine(GR.CommandResult.Text + " : " + GR.CommandResult.CustomMessage);

  134         return;

  135       }

  136 

  137       G = Galaxies[GalaxyName];

  138 

  139       if (G == null)

  140       {

  141         System.Console.Out.WriteLine("Galaxy {0} not found on server {1}!", GalaxyName, GRMachineName);

  142         return;

  143       }

  144 

  145       G.Login(UserName, Password);

  146       CR = GR.CommandResult;

  147       if (!CR.Successful)

  148       {

  149         System.Console.Out.WriteLine("Login Galaxy Failed: " + CR.Text + " : " + CR.CustomMessage);

  150         return;

  151       }

  152       else

  153       {

  154         System.Console.Out.WriteLine("Login Galaxy Successful!");

  155       }

  156 

  157 #endregion

  158       #region Query Object

  159       string[] Names = { "TestObject" };

  160       Names[0] = AAObjectName;

  161 

  162 

  163       if (IsTemplate)

  164       {

  165         Objects = G.QueryObjectsByName(EgObjectIsTemplateOrInstance.gObjectIsTemplate, ref Names);

  166 

  167         CR = G.CommandResult;

  168         if (!CR.Successful)

  169         {

  170           System.Console.Out.WriteLine("QueryObjectsByName Failed for {0} Template: " +

  171                           CR.Text + " : " +

  172                           CR.CustomMessage, AAObjectName);

  173           return;

  174         }

  175 

  176         if (Objects.count != 1)

  177         {

  178           System.Console.Out.WriteLine("Template {0} not valid!", AAObjectName);

  179           return;

  180         }

  181 

  182         T = (ITemplate)Objects[1];

  183 

  184         if (T == null)

  185         {

  186           System.Console.Out.WriteLine("Template {0} not valid!", AAObjectName);

  187           return;

  188         }

  189         Attributes = T.ConfigurableAttributes;

  190       }

  191       else

  192       {

  193         Objects = G.QueryObjectsByName(EgObjectIsTemplateOrInstance.gObjectIsInstance, ref Names);

  194 

  195         CR = G.CommandResult;

  196         if (!CR.Successful)

  197         {

  198           System.Console.Out.WriteLine("QueryObjectsByName Failed for {0} Instance: " +

  199                           CR.Text + " : " +

  200                           CR.CustomMessage, AAObjectName);

  201           return;

  202         }

  203 

  204         if (Objects.count != 1)

  205         {

  206           System.Console.Out.WriteLine("Instance {0} not valid!", AAObjectName);

  207           return;

  208         }

  209 

  210         I = (IInstance)Objects[1];

  211 

  212         if (I == null)

  213         {

  214           System.Console.Out.WriteLine("Instance {0} not valid!", AAObjectName);

  215           return;

  216         }

  217         Attributes = I.ConfigurableAttributes;

  218       }

  219 #endregion

  220       #region Prepare Export File

  221       StreamWriter outWriter;

  222       FileInfo outFile;

  223 

  224       //Prepare Export File

  225       try

  226       {

  227         string FileName = string.Format("{0}_AttributeProperties.txt", AAObjectName);

  228         if (IsTemplate)

  229         {

  230           FileName = FileName.Replace("$", "TEMPLATE_");

  231         }

  232 

  233         outFile = new FileInfo(FileName);

  234         outWriter = outFile.CreateText();

  235       }

  236       catch

  237       {

  238         System.Console.Out.WriteLine("Failed to open the export file");

  239         return;

  240       }

  241 

  242       System.Console.Out.WriteLine("Dumping attribute properties of {0} into {1}", AAObjectName, outFile.FullName);

  243 #endregion

  244       #region Setting LogFlag For Debug Output to AALogger

  245       //Prepare verbose logging in AALogger by activating a logflag via registry

  246 

  247       //Adding WWFSObject LogFlags

  248       string user = Environment.UserDomainName + "\\" + Environment.UserName;

  249       RegistrySecurity rs = new RegistrySecurity();

  250 

  251       //Allow the current user to read and delete the key.

  252       rs.AddAccessRule(new RegistryAccessRule(user, RegistryRights.FullControl,

  253           InheritanceFlags.None,

  254           PropagationFlags.None,

  255           AccessControlType.Allow));

  256 

  257       RegistryKey LogFlagRegistry = Registry.LocalMachine;

  258 

  259       LogFlagRegistry = LogFlagRegistry.OpenSubKey(@"SOFTWARE\ArchestrA\Framework\Logger\LogFlags", true);

  260       LogFlagRegistry.SetAccessControl(rs);

  261       LogFlagRegistry.SetValue("GetAttribute", 1, RegistryValueKind.DWord);

  262 #endregion

  263       #region Dump Attribute Properties to Export File

  264       //Writing header

  265       outWriter.WriteLine("Name" + "{0}" + "AttributeCategory" + "{0}" + "DataType" + "{0}" + "Locked" + "{0}" + "SecurityClassification" + "{0}" + "UpperBoundDim1" + "{0}" + "value", "^");

  266 

  267       //Exporting Attribute Properties

  268       foreach (IAttribute A in Attributes)

  269       {

  270         outWriter.WriteLine(A.Name + "{0}" + A.AttributeCategory + "{0}" + A.DataType + "{0}" + A.Locked + "{0}" + A.SecurityClassification + "{0}" + A.UpperBoundDim1 + "{0}" + A.value.GetString(), "^");

  271       }

  272 

  273       outWriter.Close();

  274 

  275       //Removing logflag

  276       LogFlagRegistry.DeleteValue("GetAttribute", false);

  277 #endregion

  278     }

  279     #region Helper Methods

  280     static void PrintHelp()

  281     {

  282       System.Console.Write("\n\n\n");

  283       System.Console.Out.WriteLine("DumpAttributes Usage:");

  284       System.Console.Out.WriteLine("+++++++++++++++++++++");

  285       System.Console.Write("\n\n");

  286       System.Console.Out.WriteLine("  g=<Galaxy Name>");

  287       System.Console.Out.WriteLine("  gr=<GR Server Node>");

  288       System.Console.Out.WriteLine("  u=<User Name>");

  289       System.Console.Out.WriteLine("  pw=<Password>");

  290       System.Console.Out.WriteLine("  o=<Object or Template Name. Templates start with '$'!");

  291       System.Console.Write("\n\n");

  292       System.Console.Out.WriteLine("  -> The order of the parameters doesn't matter!");

  293       System.Console.Out.WriteLine("  -> There must be 5 parameters!");

  294       System.Console.Out.WriteLine("  -> Use empty space characters to separate parameter=value pairs!");

  295       System.Console.Out.WriteLine("  -> Don't use commas or semi-colon to separate parameter=value pairs!");

  296       System.Console.Out.WriteLine("  -> The parameter=value pairs can't be longer than 254 characters!");

  297       System.Console.Out.WriteLine("  -> The parameter specifier can't be longer than 2 characters!");

  298 

  299       System.Console.Write("\n\n");

  300       System.Console.Out.WriteLine("  Example:");

  301       System.Console.Out.WriteLine("  DumpAttributes o=$WatchDog gr=localhost g=PENGUINS u=Administrator pw=ww");

  302     }

  303     #endregion

  304   }

  305 }

Compiling and Running DumpAttributes

To compile and run the sample on a machine that has the Industrial Application Server IDE 2.0 or higher installed. Save the code sample as program.cs file and open the Visual Studio 2005 command prompt.

clip_image002

Compile the file program.cs using the following command line:

csc /out:DumpAttributes.exe program.cs /r:"C:\Program Files\Common Files\ArchestrA\ArchestrA.GRAccess.dll"

Then to run the program type the following command, but filling in the appropriate parameter values.

DumpAttributes o=$WatchDog gr=localhost g=PENGUINS u=Administrator pw=ww

Running the program will generate two files. One is the primary export file:

clip_image003

And the second file is the logger file:

clip_image004

The source file and the two resulting reports are included in the following downloadable zip file:

Reflecting.zip (9.64 kb)

kick it on DotNetKicks.com

Tags: , , , ,

Wonderware | Toolkits | C# | GRAccess Toolkit

Comments

12/7/2007 3:18:25 AM #

trackback

Trackback from DotNetKicks.com

Reflecting over ArchestrA Object Attributes

DotNetKicks.com |

4/15/2008 12:08:59 AM #

pingback

Pingback from lucas.shopgoodnews.com

eric carle

lucas.shopgoodnews.com |

Comments are closed

About Klaus Graefensteiner

I like the programming of machines.

Add to Google Reader or Homepage

LinkedIn FacebookTwitter View Klaus Graefensteiner's profile on Technorati
Klaus Graefensteiner

Klaus Graefensteiner
works as Developer In Test and is founder of the PowerShell Unit Testing Framework PSUnit. More...

Open Source Projects

PSUnit is a Unit Testing framwork for PowerShell. It is designed for simplicity and hosted by Codeplex.
BlogShell is The tool for lazy developers who like to automate the composition of blog content during the writing of a blog post. It is hosted by CodePlex.

Administration

About

Powered by:
BlogEngine.Net
Version: 1.6.1.0

License:
Creative Commons License

Copyright:
© Copyright 2014, Klaus Graefensteiner.

Disclaimer:
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

Theme design:
This blog theme was designed and is copyrighted 2014 by Klaus Graefensteiner

Rendertime:
Page rendered at 7/23/2014 9:01:30 AM (PST Pacific Standard Time UTC DST -7)