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:
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.
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 }
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.
Then to run the program type the following command, but filling in the appropriate parameter values.
Running the program will generate two files. One is the primary export file:
The source file and the two resulting reports are included in the following downloadable zip file: