home *** CD-ROM | disk | FTP | other *** search
/ PC World 2000 December / PCWorld_2000-12_cd.bin / Komunikace / Comanche / docs / developer / programmer.sgml < prev    next >
SGML Document  |  2000-11-02  |  61KB

  1.  
  2. <!doctype linuxdoc system>
  3.  
  4. <article>
  5.  
  6. <!-- Title Information -->
  7.  
  8. <title>Comanche Programmers Guide
  9. <author>Daniel Lopez Ridruejo, <tt/ridruejo@apache.org/
  10. <date>v0.15, 30 November1999
  11.  
  12. <!-- Abstract -->
  13. <abstract>
  14. This paper is a work in progress that documents Comanche internals and the
  15. design philosophy behind it. It will help you get started if you want to
  16. write your own plugins or want to help develop the existing ones.
  17. </abstract>
  18.  
  19. <!-- Table of Contents -->
  20. <toc>
  21.  
  22.  
  23. <sect> Introduction
  24.  
  25. <p>
  26. The main issue that Comanche wants to address was the lack of appropriate
  27. management tools for popular internet software. The Apache web server and
  28. derivatives runs on more than 60% of all internet servers (acording to <url
  29. name="Netcraft" url="http://www.netcraft.com/survey">). Sendmail runs in
  30. approximately 75% of all mail servers on the internet (<url name="Sendmail
  31. website" url="http://www.sendmail.org">). (<url name="Bind"
  32. url="http://www.isc.org">  has a virtual monopoly for internet DNS servers.
  33. Big organizations running SMB networks (windows file and printer services
  34. protocol) often turn to a Unix Operating System running <url name="Samba"
  35. url="http://www.samba.org">  for their mission critical file servers..
  36. <p>
  37. These programs are free. Their source code is available for inspection and
  38. customization. However, although they are often technically superior to
  39. their commercial counterparts, they usually lack good management software.
  40. This steep learning curve often hinders their adoption both by the casual
  41. user and large corporations who want to keep down their administrative costs.
  42. <p>
  43. The purpose of this project is to implement a management system, code named
  44. Comanche, geared toward improving the usability and widespread adoption of
  45. Internet related Open Source software.
  46. <p>
  47. Design goals:
  48. <p>
  49. <itemize>
  50. <item>Avoid focusing on a single product. Create a framework for easily
  51. developing management programs
  52. <item>Provide the ability to easily develop simple modules yet still make it
  53. possible to architect complicated ones. 
  54. <item>Build an intuitive GUI to hide complex tasks from casual users while
  55. providing full flexibility to advanced users.
  56. <item>Enable remote administration
  57. <item>Possibility to extend the framework in arbitrary programming languages
  58. <item>Support localization of both Help files and interface
  59. </itemize>
  60. The following sections give an overview of the architecture of Comanche.
  61. Later on we introduce XML usage in Comanche and we conclude with a step by
  62. step implementation of a simple module.
  63.  
  64. <sect1> Design principles
  65. <p>
  66. After downloading, compiling and using many configuration programs and
  67. management frameworks, it was felt that there was room for improvement, and
  68. thus the idea of writing Comanche was born. Some of the key points that
  69. motivated that decision follow. To describe them, some thoughts are borrowed
  70. from the author of <url name="Perl" url="http://www.perl.org">, <url
  71. name="Larry Wall" url="http://kiev.wall.org/~larry/">.
  72. <p>
  73. <sect2>"Easy things should be easy and hard thing should be possible" 
  74. <p>
  75. Comanche, as any other open source project can benefit greatly if other
  76. people were able to contribute to it. The idea is to develop a framework that
  77. encourages other programmers to contribute. Successful open
  78. source projects have a modular architecture. To become productive, a
  79. developer only has to deal with the module API and a few concepts of the
  80. overall architecture. The learning curve is much higher for one piece
  81. monolithic programs. 
  82. <p>
  83. Existing frameworks usually aim to be comprehensive solutions, providing
  84. special functions for registring and accessing configuration files,
  85. starting/stopping programs, etc. This increases the amount of knowledge
  86. required to build even the simplest of the modules. One of the goals of
  87. Comanche is to make it easy to develop plug-ins. The API should be kept
  88. simple. A developer should be able to write a simple module for Comanche in
  89. a very short amount of time, without precluding the development of more
  90. complex modules. 
  91. <p>
  92. <sect2>"There's more than one way to do it"
  93. <p>
  94. Some of the existing frameworks restrict the developer to the use of only
  95. certain extension languages, like C++ or Java. The design of the framework
  96. should not restrict the developer to the use of only certain languages. 
  97.  
  98. <sect2>"Laziness is one of the virtues of a good programmer"
  99. <p>
  100. Configuring complex programs can be a daunting task. Hard-coded interfaces
  101. make painful to maintain the program when new versions of the application
  102. are released and that requires changes to the syntax of directives, redesign
  103. of existing dialogs or creation of new ones. Usually all this requires changing
  104. the source code and recompiling with existing frameworks. It will be
  105. desirable to clearly separate the interface and directive description from
  106. the configurated engine itself, so interfaces can be generated dynamically.
  107. <p>
  108. <sect2>"Many acceptable levels of competence"
  109. <p>
  110. If this separation of content from presentation can be achieved, then it
  111. would be possible to maintain different versions of the interface.
  112. New users would be presented with the minimum set of information required to
  113. configure the program, while experts would be presented with an advanced
  114. view, that exposes the more obscure details.
  115.  
  116. <sect2>"There are probably better ways to do that, but it would make the parser
  117. more complex. I do, occasionally, struggle feebly against complexity..." 
  118. <p>
  119. The design of the program should be kept as simple as possible while
  120. covering the most common cases and uses. This may involve some functionality
  121. tradeoff.
  122.  
  123. <sect2>"Historically speaking, the presence of wheels in Unix has never
  124. precluded their reinvention." 
  125. <p>
  126. In this case it is believed that it will be a better, faster, rounder wheel.
  127.   
  128. <p>  
  129. Now that it has been stated what the ideal configuration framework, it
  130. should be analyzed which problem it should/would solve for different target
  131. groups:
  132.  
  133. <sect2>End users
  134. <p>
  135. It should help them set up and manage popular open source applications like
  136. Apache and Samba. It should make the process easy by hiding the complexity and
  137. guiding them through the different options using wizards. When they feel
  138. confident, they should be able to switch to expert mode and be able to
  139. configure the more obscure parameters. 
  140.  
  141. <sect2>Experienced administrators
  142. <p>
  143. Usually experienced administrators set up an infrastructure to automate
  144. repetitive tasks (like adding users, creating mail aliases, etc.). This is
  145. usually accomplished using Perl or shell scripts. This kind of
  146. infrastructure is often poorly documented and the know-how is difficult to
  147. transmit. Comanche can make it really easy to create administration scripts and
  148. provide a graphical interface to them that can be then used by junior
  149. administrators.
  150.  
  151. <sect2>Developers
  152. <p>
  153. It should help them providing a simple API, so they can concentrate on their
  154. original purpose: configure the application. The framework should take care
  155. of presenting an unified interface and interacting with the user.
  156.  
  157.  
  158.  
  159. <sect> Architecture
  160.  
  161.  
  162. This section is an introduction to the Comanche architecture. 
  163. <p>
  164. Comanche is designed around a modular architecture and has the following
  165. characteristics:
  166. <p>
  167. Even the most complex configuration programs can be reduced to follow these
  168. principles: 
  169. <itemize>
  170.  <item>Present information to the user and ask him for input.
  171.  <item>Receive input from the user. 
  172.  <item>Act upon that input.
  173. </itemize>
  174. <p>
  175. <img src="images/dia-1.gif">
  176. <p> 
  177.  Comanche takes care of the first two items and leaves the 
  178.  third to the module author. It can optionally provide libraries to help 
  179.  with this step, but it gives him absolute freedom. The module author, not 
  180.  the framework is who knows better how to parse configuration files or take 
  181.  certain actions (like execute a external program or check environment 
  182.  variables). As stated before, the goal is to provide as much freedom 
  183.  as possible to the module authors and present them with a small, 
  184.  simple API.
  185. <p>
  186.  To present information to the user, instead of having to hard-code
  187.  interface and dialogs in the program itself, they are described in a mark up
  188.  language based on <url name="XML" url="http://www.w3.org/xml"> (XML is a
  189. mark up language to represent structured data).
  190.  The interface can be easily manipulated or even generated on the fly. The 
  191.  XML representation is platform independent, it can be rendered using a 
  192.  traditional UI toolkit or in a web based interface. 
  193.  
  194. <sect1>Simple API for developers
  195. <p>  A lot of time was spent in designing a simple API. The plug-in or
  196. management module has to know how to:
  197. <itemize>
  198.   <item> Deliver the XML description of the configuration options. This
  199. information will be rendered and presented to the user, who will manipulate
  200. it.
  201.   <item> Receive the results from the user (also encoded in XML format).
  202.   <item> Extract the results and act upon them.
  203. </itemize>
  204. <p>
  205.   This can be reduced to the following APIs calls:
  206.   <itemize>
  207.   <item>RequestDocument
  208.   <item>ReceiveDocument
  209.   </itemize>
  210.  <p> There are some others API calls for initializing the plugIn, etc. but
  211. these two are the main ones. The dialogs, if fixed, can be stored in text
  212. files or alternatively can be generated on the fly. In a way the plug-in
  213. acts like a traditional cgi-bin application. But instead of generating HTML
  214. , it generates user interface data encoded in XML, and instead of accepting
  215. form variables, it accepts XML encoded data.
  216.  
  217. <sect1>Support for multiple extension languages
  218. <p>
  219.   Comanche is developed mainly in Tcl, but that does not preclude future use of
  220. other languages for building extension modules (plugins). Since the
  221. interface is well defined, small and-text based it is possible to
  222. encapsulate the protocol into HTTP or <url name="Fast cgi"
  223. url="http://www.fastcgi.com">. Most programming languages support these
  224. interfaces, including Tcl, Perl, Java, Python, C, C++, etc.
  225. This is still not implemented, but the basics are there.
  226.  
  227. <sect1>Easy addition and maintenance of configuration files
  228. <p>
  229.   XML is not only used for exchange of information. It is also used for
  230. describing the interfaces and the configuration directives. Since XML is
  231. a text based language, it is easy to change the definition of directives or
  232. rearrange user interfaces without need to recompile.
  233.   
  234. <sect1> Easy maintenance of different interfaces (and languages)
  235. <p>
  236.   Since the information can be separated from the presentation it is
  237. possible to maintain several versions of the interface, based on the mother
  238. tongue and/or skill level of the end user.
  239.  
  240. <p>
  241. The architecture of Comanche gravitates around three blocks:
  242. <itemize>
  243. <item> Namespace. Can be thought of as a hierarchical database or a directory
  244. server. 
  245. <item> Plugins. They provide the configuration functionality. They register 
  246. themselves with the namespace, and populate it creating nodes. 
  247. <item> The console. It is the graphical tool used by the user to connect to
  248. the different namespaces (represented by computer icons in the tree) 
  249. </itemize>
  250. <p>
  251. These elements are usually part of the same program, but the system has been
  252. designed such it should be relatively easy to have them running in separate
  253. machines or processes. They could be tied together using simple protocols
  254. like HTTP + SSL, thus someone running a console in one machine can
  255. securely administer remote boxes. The protocol is designed to work well over 
  256. moderately slow links. Alternatively, the console instead of being a 
  257. traditional application can be a web server module that renders the 
  258. interface and interacts with the user. All of this is transparent to the 
  259. module developer, which still sees the same simple interface described above.
  260. <p>  
  261.   
  262. <sect2>Namespace 
  263. <p>  
  264. The namespace is the "central switch" of the
  265. Comanche architecture. It acts as a broker between the plugins and the
  266. console. It helps organize information about the plug-ins in a hierarchical
  267. manner, and to arbitrate communication between users and plugins (so an
  268. user can configure several plugins at the same time or several users
  269. can communicate with one plug in simultaneously). plugins register with the
  270. namespace and they create new nodes under existing categories (like network
  271. services or system).
  272. <p>
  273. Plugins can also extend other plugins. To do so, plugins inform the
  274. namespace which nodes they are interested in. For example, there may be a
  275. need to add SSL (Secure Sockets Layer, necessary for secure communications
  276. between the browser and the server) configuration
  277. support to Apache. Instead of rewriting the existing Apache plug in, an
  278. extension SSL plugin is created. It tells the namespace its interest in all
  279. nodes created by Apache. Whenever the namespace receives a request for the
  280. property pages for a given node, the SSL plugin is also given an opportunity
  281. to contribute to the answer, so it can add new property pages. In case the
  282. SSL module is not installed or enabled, no new pages appear.
  283.  
  284. <sect2>Console 
  285. <p>
  286. The console is the end user interface. The console UI is divided in several 
  287. areas, the main two are:
  288. <itemize>
  289. <item><bf>A tree structure on the left</bf>.
  290. It allows the user to connect to the different managed machines, and 
  291. navigate them by clicking and expanding nodes 
  292. <item><bf>A right pane</bf>.
  293. It visualizes information related to the currently selected node. 
  294. </itemize>
  295. <p>
  296. The user navigates the tree on the left and configures the properties of the 
  297. nodes by right-clicking on them and selecting the properties entry in the 
  298. pop-up menu.
  299. <p>
  300. <img src="images/ug-console-general.gif" >
  301.   
  302. <sect2>Plugins 
  303. <p>  
  304. Plugins are modules that implement the specific management behaviour. They
  305. are the ones that populate the namespace that is browsed by the console. 
  306. They produce the content of the property pages that are delivered to the
  307. user and they act upon the received changes. 
  308.  
  309. <p><img src="images/dia-2.gif">
  310.  
  311. <sect> XML based configuration
  312. <p>
  313. This section explains introduces a configuration language based in XML.
  314. Traditionally different applications have stored their configuration
  315. settings in a variety of formats ranging from databases to text files, from
  316. the Windows registry to directory services like LDAP.
  317. <p>
  318. The most common configuration format employed by Unix applications is plain
  319. text files. The exact syntax employed inside the text file varies greatly
  320. from application to application: Samba uses a simple pair key/value Windows
  321. .INI format, Apache allows sections and nested subsections,
  322. Bind also structures information with sections delimited by curly braces, etc.
  323. There are advantages/disadvantages of having a text based configuration as
  324. opossed to a GUI, such as easy automation with scripts, remote
  325. administration, etc. 
  326. <p>
  327. A XML based configuration language was designed with the following goals:
  328. <itemize>   
  329. <item><bf>Simple</bf>. An human should be able to read, modify or write from
  330. scratch the XML documents. Parsers for the configuration parser should be
  331. easy to write. 
  332. <item><bf>Universal</bf>. The language should be general enough that it can
  333. be applied to describe the configuration settings of a variety of programs.
  334. <item><bf>Extensible</bf>. The language should admit easy generation of new
  335. configuration parameters.
  336. <item><bf>Multilingual</bf>. It should be possible to localize (translate) the
  337. information about the directives, help text, etc
  338. <item><bf>Comprehensive</bf>. By combining simple basic blocks it is
  339. possible to describe complex configuration directives.
  340. <item><bf>Verbose</bf>. The description of the directive should include
  341. information about the class of the directive (string, number, ...), range of
  342. values accepted, etc. This metadata helps the user interface and the parser
  343. when validating or displaying the data.
  344. </itemize>
  345. <p>
  346. The XML configuration language is built on top of basic building blocks.
  347. These blocks represent parameters from a semantic point of view, for what
  348. they mean, not how they are represented. That is, if there is a directive
  349. "userName" that can accept the name of a person as its value, the directive is
  350. thought as being a directive of class string rather than thinking about the
  351. directive in terms of how would it be represented in a GUI (in an entry
  352. form). This decoupling between the meaning of the directive and the
  353. user interface representation is of great importance as it will become clear
  354. in the section about XML User Interface.
  355. <p>
  356. The current basic blocks are the following:
  357. <itemize>
  358. <item>string
  359. <item>number
  360. <item>boolean
  361. <item>choice 
  362. <item>label
  363. <item>structure
  364. <item>list
  365. <item>alternate
  366. </itemize>
  367.  
  368. To understand the following sections, it is important that there are two
  369. components to consider:
  370. <itemize>
  371. <item>Configuration file: This is the actual configuration information of the
  372. program being manipulated. If it is a mail server it will have mail aliases,
  373. mailing list information, etc.
  374. <item>Directive description: This describes what the tags found in the
  375. configuration file actually mean and how they can be nested, etc. If it is
  376. the mail server mentioned above, it will explain how the mail aliases are
  377. described or how to store the members of the mailing lists.
  378. </itemize>
  379.  
  380. A simple XML configuration file of a fictitious server could be:
  381. <p>
  382. <verb>
  383. <server>
  384.    <name>Mike's server&etago;name>
  385.    <ipAddress>10.0.0.1&etago;ipAddress>
  386.    <port>80&etago;port>
  387. &etago;server>
  388. </verb>
  389. <p>
  390.    But how it is possible to know, when a server tag is found, which
  391. elements are allowed inside, and which are the ranges of accepted values? We
  392. need a configuration directives metalanguage. The server directive could be
  393. described as follows: 
  394. <verb>
  395. <structure name="server" label="Server">
  396.      &etago;syntax>
  397.          <string name="name" label="Server Name"/>
  398.          <string name="ipAddress" label="IP address"/>
  399.          <number name="Port" label="Port"/>
  400.     &etago;syntax>
  401. &etago;structure>
  402. </verb>
  403. <p>
  404. The syntax above will be explained in the following sections. It is important
  405. to note that although
  406. the XML standard has a similar mechanism for defining the structure of a
  407. document, called DTDs (Document Type Definitions) they are not suitable for
  408. this purpose. If only because DTDs define the structure of a document (which
  409. tag can appear where) but do not offer any information about the data hold
  410. by those elements. Other XML standards, like XML Schemas aim to solve this
  411. problem, but they were only early drafts at the time Comanche was written.
  412. As the standards mature a move to them will be considered.
  413.  
  414. <sect1>String
  415. <p>
  416. A string element represents text values and has the following XML
  417. definition.
  418. <p>
  419. <verb>
  420. <string name="stringName" label="This briefly describes the directive">
  421.    <default>Some default value&etago;default>
  422. &etago;string>
  423. </verb>
  424. <p>
  425. This directive will be represented in the XML configuration file as:
  426. <verb>
  427. <stringName>This is some value&etago;stringName>
  428. </verb>
  429. <p>
  430. If the directive stringName does not appear in the configuration file, it
  431. will be assumed to have the value "Some default value".
  432. <p>
  433. The default value and tags are optional.
  434. A graphical representation could be the following:
  435. <p><img src="images/guistring.gif">
  436. <sect1>Number
  437. <p>
  438. A number elemenet represents numbers and has the following XML definition.
  439. <p>
  440. <verb>
  441. <number name="numberName" label="This briefly describes the directive">
  442.    <default>123456&etago;default>
  443. &etago;number>
  444. </verb>
  445. <p>
  446. This directive will be represented in the XML configuration file as:
  447. <verb>
  448. <numberName>123456&etago;numberName>
  449. </verb>
  450. <p>
  451. If the directive numberName does not appear in the configuration file, it
  452. will be assumed to have the value "123456".
  453. <p>
  454. The default value and tags are optional
  455. A graphical representation could be the following:
  456. <p><img src="images/guinumber.gif">
  457. <sect1>Boolean
  458. <p>
  459. A boolean element can only hold two values, true or false.
  460. <p>
  461. <verb>
  462. <boolean name="booleanName" label="Boolean label">
  463.    <default>1&etago;default>
  464. &etago;boolean>
  465. </verb>
  466. <p>
  467. In the XML configuration, it will appear the following
  468. <p>
  469. <verb>
  470. <booleanName>1&etago;booleanName>
  471. </verb>
  472. A graphical representation could be the following:
  473. <p><img src="images/guiboolean.gif">
  474. <sect1>Choice
  475. <p>
  476. The values can be one of a collection of fixed ones
  477. <verb>
  478. <choice name="choiceName" label="Choose a fruit">
  479.    <syntax>
  480.      <option name="orange" value="Juicy orange" />
  481.      <option name="lemon" value="Acid lemon" />
  482.    &etago;syntax>
  483.    <default>orange&etago;default>
  484. &etago;choice>
  485. </verb>
  486. <p>
  487. This directive will be represented in the configuration file as:
  488. <verb>
  489. <choiceName>lemon&etago;choiceName>
  490. </verb>
  491. <p>
  492. If the directive choiceName does not appear in the configuration file, it
  493. will be assumed to have the value "orange".
  494. <p>
  495. The default value and tags are optional
  496. A graphical representation could be the following:
  497. <p><img src="images/guichoice.gif">
  498. <sect1>Label
  499. <p>
  500. This element represents a fixed value. It will be used in other composite
  501. elements.
  502. <verb>
  503. <label name="labelName" label="This is the value of the label" >
  504. &etago;label>
  505. </verb>
  506. <p>
  507. The directive will be represented as:
  508. <p>
  509. <verb>
  510. <labelName>This is the value of the label&etago;labelName>
  511. </verb>
  512. A graphical representation could be the following:
  513. <p><img src="images/guilabel.gif">
  514.  
  515. <sect1>Structure
  516.  
  517. <p>
  518. This is an element that is a composite of others. The directive is composed
  519. of other directives. The general XMl description of the directive is as
  520. follows:
  521. <verb>
  522. <structure name="structureName" label="Description of the structure">
  523.    <syntax>
  524.       (... Here comes the XMl description of the structure
  525.       components ..)
  526.    &etago;syntax>
  527. &etago;structure>
  528. </verb>
  529. <p>
  530. This is better explained through an example. Let's assume a directive
  531. "person", which is composed of three other directives: a name (string), a
  532. surname (string) and an age (number)
  533. <p>
  534. The description would be:
  535. <verb>
  536. <structure name="person" label="Description of a person" >
  537.    <syntax>
  538.       <string name="name" label="Name" />
  539.       <string name="surname" label="Family name" />
  540.       <number name="age" label="Age">
  541.          <default>21&etago;default>
  542.       &etago;number>
  543.    &etago;syntax>
  544. &etago;structure>
  545. </verb>
  546. <p>
  547. A representation of an instance of this directive in the configuration file
  548. would be:
  549. <verb>
  550. <person>
  551.   <name>John&etago;name>
  552.   <surname>Smith&etago;surname>
  553.   <age>30&etago;age>
  554. &etago;person>
  555. </verb>
  556. <p>
  557. There is no default for the directive itself, but rather each one of the
  558. elements defines its own default.
  559. <p>
  560. A possible graphical representation:<p>
  561. <img src="images/guistructure.gif">
  562.  
  563. <sect1>List
  564.  
  565. <p>
  566. A list is a collection of elements of the same type. The list element definition
  567. (the part inside the syntax tags) can be itself be described in terms of other basic
  568. building blocks.  
  569. <verb>
  570. <list name="listName" label="Comment about the list">
  571.    <syntax>
  572.       (... XML description of the list elements  ...)
  573.    &etago;syntax>
  574.    <default> (... depends on the list element ...) &etago;default>
  575. &etago;list>
  576. </verb>
  577. <p>
  578. The following example illustrates the use of the list element:
  579. <verb>
  580. <list name="userNames" label="Names of users">
  581.    <syntax>
  582.       <string name="user" label="Name of the user" >
  583.          <default>nobody&etago;default>
  584.       &etago;string>
  585.    &etago;syntax>
  586.    <default>
  587.       <item>dani&etago;item>
  588.       <item>&etago;item>
  589.    &etago;default>
  590. &etago;list>
  591. </verb>          
  592.  
  593. <p>
  594. An entry io the XML conf file that uses this list would be:
  595. <verb>
  596. <userNames>
  597.    <user>user1&etago;user>
  598.    <user>user2&etago;user>
  599. &etago;userNames>
  600. </verb>
  601.  
  602. A possible graphical representation:<p>
  603. <img src="images/guilist1.gif">
  604. When the user adds an element:
  605. <p>
  606. <img src="images/guilist2.gif">
  607.  
  608. <sect1>Alternate
  609. <p>
  610. This element is similar to the structure element, but in this case instead
  611. of being a collection of elements, it is one (and only one) of the elements.
  612. <verb>
  613. <alternate name="alternateName" label="some text describing the alternate" >
  614.    <syntax>
  615.       (... XML description of the possible elements  ...)    
  616.    <syntax>
  617.    <default>
  618.      (... XML description of the element and value   ...)    
  619.    &etago;default>
  620. &etago;alternate>
  621. </verb>
  622. As an example, the Apache bind directive is implementated as an alternate
  623. <verb>
  624. <alternate name="bindAddress" label="Address to bind the server" >
  625.    <syntax>
  626.       <label name="allAddresses" label="All available addresses" />
  627.       <string name="specific" label="Specific address/domain-name" >
  628.       &etago;string>
  629.    &etago;syntax>
  630. <default><specific>127.0.0.1&etago;specific>&etago;default>
  631. &etago;alternate>
  632. </verb>
  633. <p>
  634. A possible graphical representation:
  635. <p><img src="images/guialternate.gif">
  636. <p>
  637. In the XML configuration file, a bindAddress directive would look like:
  638. <verb>
  639. <bindAddress>
  640.    <specific>10.0.0.1&etago;specific>
  641. <bindAddress>
  642. </verb>
  643. <p>
  644. or if the web server is going to listen to all addresses available:
  645. <verb>
  646. <bindAddress>
  647.    <allAddresses/>
  648. &etago;bindAddress>
  649. </verb>
  650. <p>
  651. These are the basic building blocks that, combined, can be used to create
  652. arbitrarily complex directives. Yet the rules are very simple.<p>
  653. These XML elements are manipulated in Tcl in a special way, that isolates
  654. the XML syntax details (that may change in the future) and allows similar
  655. elements to be accessed in a similar way (i.e reading a string or numeric
  656. value is done in a similar way)<p>
  657. The process is the following: a XML document containing the directives is
  658. parsed using a XML parser. This XML parser's callbacks are used to construct
  659. a Document Object Model representation of the XML document. A DOM
  660. representation of a XML document is a tree like structure of the document
  661. that can be accessed programtically. For example, the following XML document:
  662. <verb>
  663. <server>
  664.     <name>Daniel&etago;name>
  665.     <surname>Lopez&etago;surname>
  666. &etago;server>
  667. </verb>
  668. Its DOM
  669. representation would be:
  670. <verb>
  671. server (element)
  672. |
  673. |---name (element)
  674. |    |
  675. |    \_ text node (value="Daniel")
  676. |
  677. |---surname (element)
  678. |
  679.  \_text node (value="Lopez")
  680. </verb>
  681.  
  682.  The DOM implementation allows navigation of the document. To get the value
  683.  "Daniel" the steps are as follows:
  684.  <itemize>
  685. <item> ╖ Ask for the first node. It returns as a reference to "server"
  686. <item> ╖ Ask for the children of "server", get a reference to "name"
  687. <item> ╖ Ask for the children of "name", get reference to the text node
  688. <item> ╖ Get the value of the text node: "Daniel"
  689. </itemize>
  690.  Manipulating XML documents this way can be cumbersome. A new method was
  691.  devised to transition from XML documents to a DOM tree and from a DOM tree
  692.  to xuiObjects. What is a xuiObject? It stands for XML User Interface Object.
  693.  It is a Tcl object that encapsulates the functionality of its corresponding
  694.  XML element. After those objects are created, it is possible to manipulate
  695.  them easily, combine them and serialize them back to XML.
  696. <p>
  697.    That is, a xuiString encapsulates the functionality of a XML string
  698. element. This functionality can be accessed invoking different methods:
  699. <p>
  700. If the variable xuiStr contains the name of an object instance of a
  701. xuiString class it is possible to do the following in the Tcl programming
  702. language:
  703.  
  704. <verb>
  705.  $xuiStr getValue
  706. </verb> 
  707.  The previous Tcl code invokes the method getValue on the object referenced
  708.  by the xuiStr variable. The result of the invocation will be the return of
  709.  the value of the string. If the string was defined as:
  710. <verb>
  711.     <someString>Some value<&etago;someString>
  712. </verb>
  713.    And xuiStr contained a reference to an object that represents that
  714.    someString XML code, getValue would return "Some value".<p>
  715.    Similarly,
  716. <verb> 
  717.  $xuiStr setValue "Another value"
  718. </verb> 
  719.   Will set the new value for the string. If the object is serialized back to
  720.   XML, the result would be:
  721.   <verb>
  722.   <someString>Another value&etago;someString>
  723.   </verb>
  724. <p> 
  725.  If the xuiObject is a xuiList, it has methods available to create, add,
  726. remove certain elements, etc.
  727. <p>If the xuiObject is a xuiList, it has methods available to create, add,
  728. remove certain elements, etc.
  729. Assuming $myList is a xuiList of strings defined by the following XML
  730. declaration:
  731.  
  732.  
  733. <verb>
  734. <list name="myListName" label="Some comentary">
  735.    <syntax>
  736.       <string name="someStringName" label="some label" />
  737.    &etago;syntax>
  738.    <default>
  739.       <item>bla&etago;item>
  740.    &etago;default>
  741. &etago;list>
  742. </verb>
  743. <p>
  744.  If $MyList has just been created it has a default content
  745.  of one children with the value "bla", which XML representation would be:
  746. <verb>
  747. <myListName>
  748.    <item>bla&etago;item>
  749. &etago;myListName>
  750.  
  751.  
  752. set childList [$myList getChildren]
  753.  
  754. # In Tcl, code in brackets [] is executed and the result is substituted.
  755. # The previous statement works as follows:
  756. # - Invokes the method getChildren on the $myList object
  757. # - Store the result on the childList variable
  758. # Now childList contains all the children of $myList, in this case only one,
  759. # a xuiString element with value "bla"
  760.  
  761. puts [$childList getValue]
  762.  
  763. # puts is the Tcl command for printing a value to the standard output
  764. # The code inside the brackets gets the value of the list element, in this
  765. # case it will print "bla" since we have a single element, which has that
  766. # value.
  767.  
  768. set newChild [$myList newChild]
  769.  
  770. # The newChild method invocation creates a new list element and the
  771. # reference is stored in the newChild variable
  772.  
  773. $newChild setValue "foo"
  774.  
  775. # This new child, which is of the type xuiString, is asigned the value "foo"
  776.  
  777. $myList insertChild $newChild
  778.  
  779. # Finally, the child is inserted at the end of the xuilist.
  780. # In summary: A new children has been created and inserted in the list.
  781. # If the object was serialized, the result would be the following:
  782.  
  783. <myListName>
  784.     <item>bla&etago;item>
  785.     <item>foo&etago;item>
  786. &etago;myListName>
  787.            
  788. </verb>
  789. <p>
  790. This distinction between the XML representation of the object and
  791. the object itself is very important for a number of reasons:
  792. <itemize>
  793. <item>The XML document description specifics may change in the future. The XML
  794. objects are used widely through Comanche. Small changes on the syntax of the
  795. XML document would have wide impact and would require a multitude of other
  796. changes. The encapsulation on Tcl objects provides a level of abstraction
  797. that isolates most of these changes from the rest of programs.
  798. <item>Similar objects can be manipulated in a similar way (string, number,
  799. etc.). From the point of view of the programmer, it is assigning a value to
  800. an object via methods, with no required knowledge of how the XML output will
  801. look.
  802. <item>Objects can be easily manipulated and then rendered back to XML (or to
  803. some other format, like HTML). The rendering logic is separated from the
  804. object logic. The same object (a xuiString object) can be rendered in
  805. different GUI controls. This is the topic of the next section.
  806. </itemize>
  807.  
  808. <sect>XML User Interface
  809. <p>
  810. Tcl, together with the graphical toolkit extension Tk was chosen to provide
  811. a Graphical User Interface for Comanche. As seen in previous sections, the
  812. interface can be described in terms of a mark up language based on XML. The
  813. interface description can be parsed and abstracted into [incr tcl] objects
  814. (see Glossary on Tcl and [incr tcl]). This intermediate abstraction layer
  815. allows for different rendering engines. The rendering can transform the
  816. objects into DHTML (Dynamic HTML) that can be rendered by a
  817. web browser or into a traditional GUI representation. It is possible for the
  818. front ends to issue callbacks and manipulate the Tcl object. If XUI objects
  819. share the same interface (like string, number), the same GUI object class
  820. can manipulate them. Conversely, the same xui object can be rendered
  821. differently by different GUI object class: an element of the type structure
  822. can be rendered like a collection of property pages or as several groups of
  823. directives.
  824. <p>
  825. <img src="images/ch6-property-page.gif">
  826. <p>
  827. Examples of guiInterfaces are :
  828.  
  829. <sect1>guiString
  830. <p>
  831. Can render xuiString and xuiNumber elements.
  832. <p><img src="images/guistring.gif">
  833. <p><img src="images/guinumber.gif">
  834. <sect1>guiLabel
  835. <p>
  836. It is used to represent elements of the type label
  837. <p><img src="images/guilabel.gif">
  838. <sect1>guiLabeled
  839. <p>All the elements that have a label inherit from this guiObject class. It
  840. provides for text alignment of the labels so the interface looks nice.
  841.  
  842. <sect1>guiBoolean
  843. <p>
  844. It is used to represent elements of the type guiBoolean
  845. <p><img src="images/guiboolean.gif">
  846.  
  847. <sect1>guiImage
  848. <p>
  849. It is used to represent images
  850.  
  851. <sect1>guiChoice
  852. <p>
  853. It is used to manipulate xui elements of the type choice.
  854. It is generally represented as a combobox. It could easily be represented as
  855. a collection of radiobuttons.
  856. <p><img src="images/guichoice.gif">
  857.  
  858. <sect1>guiList
  859. <p>
  860. It is used to manipulate list objects
  861. <p><img src="images/guilist2.gif">
  862.  
  863. <sect1>guiStructure
  864. <p>
  865. Is is used to manipulate xuiStructure elements. xuiStructure elements can
  866. represent compound directives or groups of other xuiElements. Depending on
  867. certain attributes being present (style) groups of directives can be
  868. represented in different ways: horizontally or vertically, surrounded by a
  869. labeled frame or with no decoration.
  870. <p><img src="images/ch6-gui-struct1.gif">
  871. <p><img src="images/ch6-gui-struct2.gif">
  872.  
  873. <sect1>guiAlternate
  874. <p>Is is used to manipulate xuiAlternate elements.
  875. <p><img src="images/ch6-gui-alternate.gif">
  876. <sect1>guiPropertyPage
  877. <p>
  878. This gui element manipulates xuiStructures interpreting them as property
  879. pages:
  880. <p><img src="images/ch6-guiPropertyPage.gif">
  881.  
  882. <sect1>How it works
  883. <p>
  884. This section describes how the process works from the instant that the user
  885. requests some information to the point that the user is presented with a
  886. property page that he can fill and return the information to the plugin.
  887. <p><img src="images/ch6-everything.gif">
  888. <p>
  889. <itemize>
  890. <item>User selects to view the properties of a given node, by right clicking
  891. on the node and selecting the "Configure node" entry from the menu.
  892. <item>The message is sent to the namespace, which contacts the appropriate
  893. plugins and generates the property pages document, which it is a XML
  894. description of the property pages.
  895. <item>The console receives the document, transforming it into a xuiObject of
  896. the type xuiPropertyPages (the XML definition is transformed into Tcl code).
  897. <item>The console needs to allow the end user to manipulate the
  898. xuiPropertyPages object and for that purpose creates a guiPropertyPages
  899. (presentation) object and connects it to the xuiPropertyPages object (data).
  900. <item>The guiPropertyPages object is passed the frame where it has to display
  901. its information, the propertyPages object and a reference to an object
  902. factory. It creates a listbox menu on the left and a notebook on the right.
  903. For each one of the property pages (elements of the xuiStructure), it
  904. creates an entry in the listbox (with an additional image if the attribute
  905. icon is present) and uses the guiObject factory to render the property page
  906. on the notebook. 
  907. <item>When an element is selected on the listbox, the appropriate property page
  908. is displayed on the right notebook.
  909. <item>When the user is done, it can press the Ok button. The GUI representation
  910. can be destroyed then, but the xuiPropertyPages object will have the
  911. modifications performed by the user.
  912. <item>The xuiObject is then passed to the namespace, which will select the
  913. appropriate property pages and deliver it to the plug ins so they can act
  914. upon it.
  915. </itemize>
  916.  
  917. <sect>Distributed architecture
  918.  
  919. <p>The architecture of the system has being designed with distributed operation
  920. in mind. This translates into the following ideas:
  921. <itemize>
  922. <item>Few, well defined API calls. The idea is to reduce the traffic over the
  923. net and to simplify the implementation of different front end clients.
  924. <item>The inter process protocol is based on XML, which in turn is based in text
  925. and can be easily transported over other protocols and manipulated by other
  926. languages.
  927. <item>There is no notion of a single user. Requests can be server concurrently
  928. in a web server like fashion. Little or no state is kept.
  929. </itemize>
  930. <p>
  931. There are still issues that need to be addressed like delegation of
  932. authority and how to prevent administrators working concurrently on a
  933. configuration from interfering with each other
  934.  
  935.  
  936. <sect1>Different models for distributed operation
  937. <p>
  938. At least two models have been considered for developing an architecture that
  939. would allow for remote administration of machines
  940.  
  941. <sect2> Web based approach
  942. <p> 
  943. Namespace and plugins would reside in the remote machine. A web front end
  944. would also reside in the same machine and would accept requests from client
  945. browsers. 
  946. <p>
  947. <sect2>Distributed application approach
  948. <p>
  949. The other approach is to encapsulate the protocol between the console client
  950. and the namespace over HTTP and have them reside in different servers. This
  951. would require installation of a Tcl client in the administrator machine, but
  952. would allow centralized administration from a single machine (the web based
  953. approach would require connecting to each machine that requires
  954. administration)
  955. <p>
  956. <sect1>Few, well defined API calls
  957. <p>
  958. The API calls between the three architectural blocks are few and well
  959. defined, as explained in the following sections:
  960.  
  961. <sect2>Namespace / Plug-in
  962. <p>
  963. The communication that takes place requires the following information to be
  964. exchanged.
  965.  
  966. <p>The plugins need to register with the namespace and explain which nodes it
  967. is interested in extending, etc.
  968. <p>
  969. <verb>
  970. registerPlugInInterests
  971.         The information that the plug in would provide would be
  972.     name
  973.     version
  974.     description
  975.     node types that it provides
  976.     node types that it extends
  977.     category the plug in belongs to: network services, user management,
  978.     system management
  979. </verb>
  980. <p>The plugIns needs to query the tree structure, add and remove nodes, etc
  981. The API functions to perform that are:
  982. <verb>
  983.     getRootNode
  984.     addNode
  985.     configureNode 
  986.     removeNode
  987.     getChildren
  988. </verb>
  989. <p>The namespace needs to request and deliver information from the plug in
  990. <itemize>
  991. <item>deleteNodeRequest  (When the user wants to delete a node)
  992. <item>requestXuiDocument    (The user requests a document. it can be a property
  993.                        page, a wizard or a right pane content)
  994. <item>answerXuiDocument (the user has filled some information and it has to be
  995.                        returned to the plug in for processing)
  996. <item>populateNodeRequest (The user is exploring a node and double-clicks on
  997. it, the namespace takes note and urges the plugin to add nodes. This
  998. allows for dynamically generating trees (useful for navigating a server's
  999. filesystem, for example.)
  1000. </itemize>
  1001.     
  1002. <sect2>Namespace / View
  1003. <p>
  1004. Similarly, the view needs to access the namespace, basically for the same
  1005. purpose: query the tree structure, request information for display to the
  1006. user and deliver back the user feedback. For those purposes it uses the
  1007. previously detailed functions. In addition, the namespace informs the view
  1008. when certain events occur: a node has been added or modified, etc
  1009. <p>
  1010.    Also the namespace keeps track of which view has browsed which nodes and
  1011. thus avoid informing the views of event regarding nodes the user has not yet
  1012. browsed.
  1013. <p>
  1014.    A future option may to request not to be notified of updates, and have
  1015. the user refresh the display when necessary. This may be useful for slow
  1016. links or the web based interface.
  1017.  
  1018. <sect1>Inter process protocol based on XML
  1019. <p>
  1020. The interprocess communication that takes places is based on XML. The data
  1021. ,object and method invoked are encoded in XML.
  1022. <p>
  1023. The interprocess communication is hidden in the infrastructure. The API
  1024. offered to the module author is identical, no matter if the plug in is being
  1025. used locally or remotely. When a component of the system talks to another
  1026. component, it does so using xui objects. The system keeps track if the
  1027. component that is being called is remote or local, if it is local, it
  1028. directly passes the xuiObject to the called entity. If the entity is remote,
  1029. it performs a remote call and serializes the object into XML. At the other
  1030. end, the serialized object is transformed again into a xui Object.
  1031. <p>
  1032.    How does the system know if the object called is remote or local? First,
  1033. objects must register themselves before being able to invoke / receive any
  1034. methods. If the object is accessible locally (for example, namespace and
  1035. plug ins are living in the same Tcl interpreter) nothing is done and
  1036. future communication takes place directly. If the object being registered is
  1037. accessing the system remotely, a "fake object" will be created that will
  1038. remember how to access the remote object. This fake object will then be
  1039. accessed normally as a local object by the rest of the system. When a method
  1040. is invoked in this fake object, it will in turn take the arguments, the
  1041. method and the identity of the caller, serialize them and sends it to the
  1042. remote object. This also involves timeouts (that can be tuned depending on
  1043. the situation) so if the remote end becomes unavailable the application will
  1044. get informed and the object will get deleted.
  1045. <p>
  1046.    All this process is greatly simplified by the fact that arguments are
  1047. passed as xuiObjects, which are composed of only a few building blocks. Thus
  1048. arbitrary functions can be called with arbitrary arguments, since the system
  1049. knows how to serialize them. This allows for greater flexibility, since this
  1050. generic mechanism avoids:
  1051. <itemize>
  1052.    <item>having to declare each one of the possible functions.
  1053.    <item>having to explicitily distinguish between remote and local operations.
  1054. </itemize>   
  1055.  
  1056. The XML protocol can be encapsualted in a variety of transport protocols:
  1057. <itemize>
  1058. <item>Over HTTP, both directly (using GET and POST methods) or over XMl-RPC
  1059. <item>Plug-In communication with the namespace could also be done using a
  1060. Fast-CGI approach.
  1061. </itemize>
  1062. Note: none of the above is yet implemented. Comanche can only run as a local
  1063. application right now.
  1064.  
  1065. <sect1>Concurrency handling
  1066. <p>
  1067. The namespace server will act in a similar fashion to a web server, in the
  1068. sense that it can serve requests simultaneously. In fact, initial
  1069. feasibility tests where performed using the tclhttpd web server.
  1070. In both cases, XML-RPC was used as the underlying communication mechanism.
  1071. Requests are served in a first come first served basis. There is a single
  1072. process running and speed is not likely to be an issue (the network part is
  1073. usually the bottleneck. Because of that network transmission is done using
  1074. fileevents (fileevents is a Tcl feature that allows serving of multiple
  1075. requests using callbacks to detect when a socket has received new data or
  1076. the data scheduled to send has been effectively transmitted).
  1077. <p>
  1078.     Concurency means several problems need to be addressed: what happens when two
  1079. different users are configuring the same application or where the same user
  1080. configures the application using different windows (in the case of the web
  1081. interface, opening several browser windows). There is the potential for the
  1082. following scenarion to happen: Administrator A selects property pages for
  1083. virtualhost v1. Administrator B selects property pages for the same virtual
  1084. host. Administrator B presses OK and commits the changes. Administrator A
  1085. presses OK and commits the changes.
  1086. <p>
  1087. The following can happen:
  1088. <itemize>
  1089. <item>Administrator A will overwrite administrator B changes. Administrator B
  1090. does not even know that. This is Bad
  1091. <item>Changes could be merged a la CVS style. But the concept of merging
  1092. changes is more ambiguous here. Merging could also lead to inconsistencies.
  1093. </itemize>
  1094. Alternative, more desirable solutions are the following:
  1095. <itemize>
  1096. <item>Only one admin can be editing a node/service at a given time. Users
  1097. with enough rights should be able to kick out other admins to avoid deadlock
  1098. situations (the administrator browser crashed, but the admin appears to the
  1099. system as still logged, preventing anyone else from administering the
  1100. machine). Some schema of auto-logout after a period of inactivity could also
  1101. be implemented. 
  1102. <item>More than one admin can be logged and editing the same node. If the 
  1103. previously described situation with admin A and admin B occurs, the solution
  1104. is to prevent Admin A to commit its changes, informing it that the node has
  1105. been modified in the mean time and the information is no longer valid.
  1106. </itemize>
  1107.  
  1108. <sect1>Delegation of authority
  1109. <p>
  1110.    Currently there is no concept of users or privileges in Comanche.
  1111. It needs to run with the privileges required to edit by hand the
  1112. configuration files of the programs it is configuring. It would however, be
  1113. interesting to have some authentication and delegation schema for certain
  1114. situations: an ISP may be hosting hundreds of web sites as virtual hosts for
  1115. their customers. In the current situation, the customer must explain what
  1116. changes it needs to make to the configuration files and the ISP staff
  1117. performs that for them. This has an obvious administrative overhead and slow
  1118. turn around time. This problem is partially solved currently :
  1119.  
  1120. <itemize>
  1121. <item><bf>Using Frontpage server extensions</bf>. This allows customers to use
  1122. proprietary Ms tools to configure and maintain their web servers. This
  1123. extensions have a track record of security problems and messy code, so they
  1124. are not very popular with ISPs, which however have to install them due to
  1125. customer demand.
  1126. <item><bf>Use .htaccess files</bf>. These files allow per directory configuration files
  1127. If its used is enable, Apache will look for every one of these files and
  1128. apply the parameters that it finds. They are used for example to allow users
  1129. to specify password protected pages and directories. .htaccess files are
  1130. however, a serious performance hit for highly loaded servers
  1131. </itemize>
  1132. <p>
  1133. In summary, delegation of authority is an interesting feature, but poses a
  1134. series of challenges that are out of the scope of a first implementation of
  1135. Comanche. The architecture, however, if flexible enough to implement such
  1136. hooks for authentication and delegation. These controls could be placed when
  1137. views register with the namespace, when xuiRequests and xuiAnswers are
  1138. requested, etc.
  1139.  
  1140.  
  1141. <sect>Programmer tutorial
  1142. <p>
  1143. This section guides a programmer in the process of writing a simple plugin
  1144. for Comanche. The purpose is to describe the APIs that module authors should
  1145. know and give examples of how they can be used. Although the module is
  1146. written in Tcl, knowledge of Tcl is not strictly necessary or assumed. The
  1147. code is extensively commented and explained to guide the reader.
  1148. <p>
  1149.  
  1150. <sect1>Creating a module.
  1151. <p>
  1152. The main tasks that a Comanche module has to carry out are:
  1153.  
  1154. <itemize>
  1155.  <item>Read any internal configuration and initialize itself
  1156.  <item>Answer requests for information
  1157.  <item>Accept answers from the client
  1158. </itemize> 
  1159. <p> 
  1160. We will develop a simple module. This module queries the hostname
  1161. of the machine and allows the user to change it. To do so, the plugin will
  1162. rely on the "hostname" system command. In certain operating systems, like
  1163. Red Hat Linux, changing the hostname permanently involves changing some text
  1164. files that get read at startup. Since this is just a demonstration of how to
  1165. write a simple module for Comanche, we will not worry about that. This
  1166. simple plugIn will add a node to the Comanche console. When the user clicks
  1167. on the node, a page on the right will appear that gives the current
  1168. hostname. When the user right clicks on the node, a menu will appear that
  1169. allows the user to pop up  a property page to change the hostname value.
  1170. <p>
  1171. Every Comanche module should be designed as a [incr tcl] module (this is not
  1172. necessary if it is done via the remote plugin interface, which is not
  1173. implemented in this version and that allows plugins to be written in a
  1174. variety of languages)
  1175. <p>
  1176. [incr Tcl] is an object oriented extension of Tcl. It allows you to create
  1177. classes which define objects. Objects have functions that can be called on
  1178. the object and that are called methods. We could define a class dog, which
  1179. represents dogs in abstract. We could define a method, bark, that when
  1180. invoked would print "Barf!" on the screen. In [incr tcl] this is done in the
  1181. following fashion:
  1182. <verb>
  1183. class dog {
  1184.  
  1185.    method barf {} {
  1186.        puts "Barf!"
  1187.    }    
  1188.  
  1189. }
  1190. </verb>
  1191. <p>
  1192. We can create an object called scooby, which is an instance of the class dog.
  1193. <p>
  1194. <verb>
  1195. dog scooby
  1196. </verb>
  1197. <p>
  1198. Now we can tell scooby to bark:<p>
  1199. <verb>
  1200. scooby bark
  1201. </verb>
  1202. <p>
  1203. and we get:<p>
  1204. <verb>
  1205. Barf!
  1206. </verb>
  1207. <p>
  1208.  
  1209. The skeleton of the plug in looks something similar to the following:
  1210. <verb>
  1211. class hostnamePlugIn {
  1212.     inherit plugIn
  1213. }
  1214. </verb>
  1215. <p>
  1216. In a similar fashion to the above, we are going to be creating an object of
  1217. the class plugin. When we have a plugin, we can tell it to do certain things
  1218. for us: we can tell it to add nodes to the namespace, we can ask it
  1219. information about nodes that belong to it, etc.<p>
  1220. The kind of information that we ask is usually property pages for
  1221. displaying/modifying the plugin settings. Most of the work in a plugin
  1222. resides on the design of these property pages.
  1223. <p>
  1224. We are inheritting from the plugIn class, which implements the following
  1225. methods:
  1226. <verb>
  1227.   method init { args }
  1228.   method requestXuiDocument { xuiData }
  1229.   method answerXuiDocument  { xuiData }
  1230.   method deleteNodeRequest  { xuiData }
  1231.   method populateNodeRequest { xuiData }
  1232. </verb>
  1233. <p>
  1234.  
  1235. From all these, the only ones that we need to implement are the first three
  1236. ones, since we only have one node (populateNodeRequest is the way the
  1237. namespace tell us to add nodes that are children of another) and we do not
  1238. want to delete it. The remaining three functions (init, requestXuiDocument,
  1239. answerXuiDocument), deal with initialization routines, and passing/getting 
  1240. information to/from the user.
  1241.  
  1242. <sect1>init
  1243. <p>
  1244.    This function will get called at initialization time. It gives our
  1245. plugin a chance to initialize internal data structures, read external files,
  1246. etc. and finally add nodes to the namespace if necessary. There are several
  1247. helper objects that can be used when managing many nodes. Since we are adding
  1248. a single node, it is easier to add it directly and keep track of where we
  1249. added it in a variable.
  1250. <p>
  1251. <verb>
  1252. # args contains the options that are passed to the plugIn at initialization
  1253. # time.
  1254. #
  1255. #  -namespace    contains the name of the name space server
  1256.  
  1257.  
  1258. method init { args } {
  1259.  
  1260.     # args is a list of pair/value options
  1261.     # The following is to convert the list to an array, called options
  1262.  
  1263.     array set options $args
  1264.     
  1265.     # This is the way Tcl assigns a variable value
  1266.     # Now namespace contains the value of the element -namespace
  1267.     # of the array options
  1268.     
  1269.     set namespace $options(-namespace)
  1270.     
  1271.     # The [] tell Tcl to treat the text contained in the brackets as a
  1272.     # command, execute it and substitute the result. So the sequence of
  1273.     # events is as follows:
  1274.     # - Ask the namespace for the root node (will return a xuiNode object)
  1275.     # - Get the unique id number for that node
  1276.     # - Assign that value to the hostnameNode variable
  1277.     #
  1278.     
  1279.     set parentNode [[ $namespace getRootNode] getId]
  1280.     
  1281.     # Add a node to the namespace, we need to tell the namespace:
  1282.     # - Who we are: $this
  1283.     # - Which namespace we want to hook up under: $namespace
  1284.     # - Which node we want to hook the new node under: $parentNode
  1285.     # - Several icons for open and closed
  1286.     # - Classes: List with node classes. Leaf means that it cannot have
  1287.     #            children. Hostname means that it belongs to our plugin.
  1288.     # - Label: Text that will be displayed next to the icon
  1289.     
  1290.     set hostnameNode [::plugInUtils::addNode $this $namespace $parentNode \
  1291.         -classes {hostname leaf} \
  1292.         -openIcon networkComputer \
  1293.         -closedIcon networkComputer \
  1294.         -label {Hostname settings}]
  1295.     
  1296.     # We remember the Id of the node that we just added
  1297.     
  1298.     set hostnameNodeId [$hostNameNode getId]            
  1299. }
  1300. </verb>
  1301. <p>
  1302.  We add a couple of variables to the plugIn, to also store the id for the
  1303.  node just added and the name of the namespace
  1304.  <p>
  1305.  With just the above, the plugin will add the node to the namespace:
  1306.  <p><img src="images/pg-hostname.gif">
  1307. <verb> 
  1308.  class hostnamePlugIn {
  1309.      inherit plugIn
  1310.      variable namespace
  1311.      variable hostnameNodeId
  1312.  }   
  1313. </verb>
  1314. <p>
  1315. By declaring the variables in the plugin class, we make sure that they are
  1316. persistent and accessible when other methods are called.
  1317. <p>
  1318. Next step is to implement the rest of the functions required for displaying
  1319. menus, right pane contents and a pop up property page. When we receive/send
  1320. a XML document using <verb>requestXuiDocument</verb> or
  1321. <verb>answerXuiDocument</verb>  we have to specify the kind of document we
  1322. are receiving/transmitting (menu, property page, etc)
  1323. <p>
  1324. This involves processing xuiStructures for storing the answer, etc. We can
  1325. save ourselves a lot of trouble if we directly inherit from the basePlugIn
  1326. class, which already takes care of many of those details. 
  1327. <p>
  1328. The basePlugin class defines the following methods:
  1329. <verb>
  1330.  method _inquiryForPropertyPages  { node }
  1331.  method _inquiryForMenu { node }
  1332.  method _inquiryForWizard { type node }
  1333.  method _receivedWizard { type node }
  1334.  method _inquiryForRightPaneContent { node }
  1335.  method _receivedPropertyPages { node xuiPropertyPages }
  1336.  method _receivedCommand { node command } 
  1337. </verb>
  1338. <p>
  1339.  
  1340. We are going to provide content now for each one of the functions and we
  1341. will be one step ahead in building our plugin
  1342. <verb>
  1343. _inquiryForRightPaneContent 
  1344. </verb>
  1345. <p>
  1346. This function takes as an argument the node for what the content is being
  1347. requested. It must return the HTML-like text to be displayed in the right
  1348. pane portion of the interface. Since our plugin only has one node, it is
  1349. safe to assume that when the function is called the node is the right one,
  1350. so we do not need to double-check it. If a plugin had more than one node, it
  1351. would be necessary to distinguish between them.
  1352. <p>
  1353. The function is then, simply:
  1354. <verb>
  1355. body hostnamePlugIn::_inquiryForRightPaneContent { node } {
  1356.     
  1357.     # Set the variable result to a snippet of HTMl-like code
  1358.     # The link, instead of a normal HTML link is a command directed
  1359.     # to the console. In this case it tells the console to show
  1360.     # the property pages for the selected node when clicked.
  1361.     
  1362.     set result {
  1363.         <h1>Hostname Settings<h1>
  1364.     <br> This is a small plug in that allows to display and
  1365.     <a href="command propertyPages"> change&etago;a>the hostname value.<br>
  1366.     The current value is }
  1367.     
  1368.     # Current value is given by executing the system command hostname
  1369.     
  1370.     append result [exec hostname]
  1371.     return $result
  1372. }
  1373. </verb>
  1374. The previous addition will show in the console as follows:
  1375. <p>
  1376. <img src="images/pg-hostname-right.gif">
  1377. <p>
  1378. Menu generation is still not implemented, there is a generic menu in place.
  1379. When the user clicks on the menu entries, nothing will happen except when
  1380. the user selects "Configure node". This will trigger the
  1381. <verb>_inquiryForPropertyPages</verb> method
  1382. <p>
  1383. For returning property pages, instead of creating a new property page object
  1384. per request, we will keep a property page and update it every time it is
  1385. requested.
  1386. <p>
  1387. We add the following to the plug in definition
  1388. <p>
  1389. <verb>
  1390. variable hostnameXuiPP
  1391. variable hostnameEntry
  1392.  
  1393. constructor {} {
  1394.  
  1395.    # We create a global  object of type xuiPropertyPage
  1396.    # the #auto keyword will assign an arbitrary name.
  1397.    # This is necessary because if we hardcode the name, this would
  1398.    # prevent having two instances of the same plugin
  1399.  
  1400.    set hostnameXuiPP [xuiPropertyPage ::#auto]
  1401.    
  1402.    # Set default icon, title and name of the property page
  1403.    
  1404.    $hostnameXuiPP configure -icon network
  1405.    $hostnameXuiPP setLabel {Configuring hostname}
  1406.    $hostnameXuiPP setName hostnamePP
  1407.    
  1408.    # Create the xuiString object that will hold the hostname value for the
  1409.    # user to modify ...
  1410.    
  1411.    set hostnameEntry [xuiString ::#auto]
  1412.    $hostnameEntry setLabel "Hostname"
  1413.    $hostnameEntry setName hostname
  1414.    
  1415.    # ..and add it to the property page
  1416.    
  1417.    $hostnameXuiPP addComponent $hostnameEntry
  1418. }
  1419. </verb>
  1420. <p>
  1421. The constructor method is called everytime a hostnamePlugIn object is
  1422. created. It set ups a XUI property page object. Every time they ask us for
  1423. a property page, we fill the current hostname and we return the property
  1424. page back. When it comes back, it will contain the data, probably modified
  1425. by the user.
  1426. <p>
  1427. The following methods perform just that:
  1428. <p>
  1429. <verb>
  1430. body hostnamePlugIn::_inquiryForPropertyPages  { node } {
  1431.     
  1432.     # User is asking for a property page to display for this node 
  1433.     # We set the current hostname in the entry
  1434.     
  1435.     $hostnameEntry setValue [exec hostname]
  1436.     
  1437.     # We return the property page
  1438.     
  1439.     return $hostnameXuiPP
  1440. }
  1441.  
  1442. body hostnamePlugIn::_receivedPropertyPages { node xuiPropertyPages } {
  1443.  
  1444.     # We extract the appropriate property page from the xuiStructure
  1445.     # containing the property pages.
  1446.     # (there is only one page, but we ask it by name)
  1447.     
  1448.     set pp [$xuiPropertyPages getComponentByName hostnamePP]
  1449.     
  1450.     # From that property page, we get to the string containing the hostname
  1451.     # and get its value
  1452.     
  1453.     set newHostname [[$pp getComponentByName hostname] getValue]
  1454.     
  1455.     # Change the hostname to the one supplied by the user
  1456.     
  1457.     catch {exec hostname $newHostname}
  1458. }
  1459. </verb>
  1460. <p>
  1461. And that is all, the plugIn is completed, we do not care about the rest of
  1462. available functions by now (asking for wizards, etc...), since the plugIn is
  1463. a simple one. We need now to package the plugIn in a certain way so Comanche
  1464. can discover it and load it at start up. Comanche stores modules under the
  1465. subdirectory modules/ Under modules, each directory contains a plugIn. For
  1466. each plugIn, a special file called init.tcl will get sourced.
  1467. <p>
  1468. The module needs to define certain functions that will get called at the
  1469. appropriate time:
  1470. <verb>
  1471. modulename_init 
  1472. modulename_restart  
  1473. modulename_info 
  1474. modulename_unload
  1475. </verb>
  1476. <p>
  1477. Using the module name is a convention. It will probably be replaced by use
  1478. of Tcl namespace facility, just not yet.
  1479. <p>
  1480. By now we only define the modulename_init function, in this case
  1481. hostname_init, that will get called with the following arguments
  1482. -namespace   namespaceObject
  1483. <verb>
  1484.  
  1485. # This file will get sourced when Comanche starts to load the module
  1486. #  and declare the hostname_* functions
  1487.  
  1488. # Determine my current directory
  1489.  
  1490. set currentDir [file dirname [file join [pwd] [info script]]]
  1491.  
  1492. # Load the file containing the class definition
  1493.  
  1494. source [file join $currentDir hostname.tcl]
  1495.  
  1496. # Will get called each time we want to add a plugin. In this case, we are
  1497. # only adding one
  1498.  
  1499. proc hostname_init { args } {
  1500.     array set options $args
  1501.     set hostnameInstance [hostnamePlugIn ::#auto]
  1502.     
  1503.     # Hook up the plugin to the namespace
  1504.     
  1505.     $hostnamePlugIn init -namespace $options(-namespace)
  1506. }
  1507.  
  1508. # This function is used to provide information about the installed plugins
  1509.  
  1510. proc hostname_info {} {
  1511.     array set info {description {Example module that changes hostname}}
  1512.     array set info {name {hostname}}
  1513.     array set info {version {1.0}}
  1514.     array set info {icon network}
  1515.     return [array get info]
  1516. }
  1517. </verb>
  1518.  
  1519. Where do you go from here? Have a look at the other documents at the docs/
  1520. subdirectory and at the source code for the modules at plugins/.
  1521. Writing a XML definition to support an apache module (such as PHP)
  1522. is really easy. have a look at plugins/apache/modules
  1523.  
  1524. </article>
  1525.