| 1 | = !HowTo: Concept Diagrams and Ontology Generation with FS Concepts = |
| 2 | |
| 3 | This document explains the purpose and handling of the ''Concept Daigrams'' provided by the plugins: ''Feature Structures'' (Renew plugin FS) and ''Feature |
| 4 | Structure Ontology Generator'' (Mulan plugin |
| 5 | ''FSOntologyGenerator''). |
| 6 | |
| 7 | == (1) Introduction == |
| 8 | |
| 9 | The FSOntologyGenerator plugin is used to build the ontology for a |
| 10 | Mulan project from simple Renew drawings. Hereby, it replaces the |
| 11 | Protégé-based !OntologyGenerator plugin. The generated classes then |
| 12 | encapsulate a FIPA-compatible ontology with convenient constructors |
| 13 | and accessors and the build-in functionality to parse or generate ACL |
| 14 | message strings with SL representations for the concepts. |
| 15 | |
| 16 | As a reference, the Mulan plugin FSOntologyTestPlugin is a complete |
| 17 | example project showing how the generator could be used. |
| 18 | |
| 19 | == (2) Embedment in the PAOSE Development Process == |
| 20 | |
| 21 | The following figure shows how the !FSOntologyGenerator plugin fits |
| 22 | into the overall PAOSE development process. |
| 23 | |
| 24 | [[Image(paose-detailed-fsonto.png)]] |
| 25 | |
| 26 | There are two development areas where the ontology plays a role: |
| 27 | * The ontology design, which is done using concept diagrams |
| 28 | * The implementation of nets which make use of the generated |
| 29 | classes, especially protocol nets. |
| 30 | |
| 31 | == (3) Creating Ontology Diagrams == |
| 32 | [[Image(example_prodstorecons.png)]] |
| 33 | |
| 34 | An ontology is defined by a concept diagrams, which is very similar to |
| 35 | UML class diagrams. They are simply stored as .rnw files. |
| 36 | |
| 37 | === (3.1) XFS Toolbar components === |
| 38 | |
| 39 | Ontology diagrams are built using the Renew XFS toolbar (you get it |
| 40 | through Simulation -> Formalisms -> XFS Net Compiler). |
| 41 | |
| 42 | [[Image(xfs_toolbar.png)]] |
| 43 | |
| 44 | Actually, just |
| 45 | two of its tools are really needed: |
| 46 | * Concept Tool: Used to add new concepts to the |
| 47 | diagram. After clicking on the drawing pane, you get a text box |
| 48 | where you can enter the concept name and its slots (if it has some) |
| 49 | * Disjunctive Is-A Tool: Relates a concept to a |
| 50 | superconcept. Slots will be inherited. |
| 51 | |
| 52 | '''Don't use the other Is-A tool''', as its semantics cannot |
| 53 | be translated to class hierarchies, thus edges drawn with this will |
| 54 | yield a compiler error. |
| 55 | |
| 56 | === (3.2) Declaring Slots === |
| 57 | |
| 58 | Usually, slot definitions for a concept are put into the concept box |
| 59 | after the concept name (be sure to put two line breaks in |
| 60 | between). The syntax is name:type, where type may be any Java type |
| 61 | (primitive or class) or any concept name (in the same ontology or one |
| 62 | that is imported or accessed (see 3.6). The type may optionally be |
| 63 | followed by a Kleene star (*) to indicate a multi-valued slot |
| 64 | which will be represented as a list of values. |
| 65 | |
| 66 | Example: |
| 67 | {{{ |
| 68 | my-concept |
| 69 | |
| 70 | one-slot:int |
| 71 | another-slot:some-concept |
| 72 | all-strings:String* |
| 73 | }}} |
| 74 | |
| 75 | This defines a concept named my-concept with three slots: |
| 76 | * one-slot has the type int |
| 77 | * another-slot with type some-concept |
| 78 | * all-strings with the type "list of strings" |
| 79 | |
| 80 | Optionally, the feature tool could be used for slot declarations, |
| 81 | instead, similar to UML diagram - although the "inline" way seems more |
| 82 | readable and is therefore recommended. |
| 83 | |
| 84 | === (3.3) Documenting Concepts and Slots === |
| 85 | |
| 86 | For documentation of the generated classes, Javadoc-style comments may |
| 87 | be written before the concept (the comment should also precede a |
| 88 | stereotype if present - see 3.4) as well as before each slot. |
| 89 | |
| 90 | Example: |
| 91 | {{{ |
| 92 | /** This is the doc for my concept. */ |
| 93 | my-concept |
| 94 | |
| 95 | /** Doc for one slot. */ |
| 96 | one-slot:int |
| 97 | another-slot:some-concept |
| 98 | /** Doc for all strings */ |
| 99 | all-strings:string* |
| 100 | }}} |
| 101 | |
| 102 | The slot called "another-slot" has no comment in this example. |
| 103 | |
| 104 | If you get any compilation errors with documented concepts, check the |
| 105 | syntax: For example, currently, there must be a line break directly |
| 106 | after "*/". |
| 107 | |
| 108 | === (3.4) Abstract and Concrete Classes === |
| 109 | |
| 110 | Due to Capa restrictions, all concepts that are superconcepts have to |
| 111 | be abstract (the generated class cannot be instantiated). The |
| 112 | generator will therefore treat all concepts with subconcepts as |
| 113 | abstract and those without subconcepts (in the same ontology) as |
| 114 | concrete. For forcing a concept to be abstract, the <<abstract>> |
| 115 | stereotype is used, for example: |
| 116 | {{{ |
| 117 | <<abstract>> |
| 118 | my-concept |
| 119 | |
| 120 | my-slot:int |
| 121 | }}} |
| 122 | |
| 123 | This is useful for cross-ontology references (see 3.5). |
| 124 | |
| 125 | === (3.5) Cross-Ontology-References === |
| 126 | |
| 127 | It is possible to inherit from concepts that are in other ontologies |
| 128 | by drawing a "reference concept" named |
| 129 | "referencedOntology::conceptName" (there is no need to repeat the |
| 130 | slots or stereotype in the reference) and inherit from this "reference |
| 131 | concept". There must be an access declaration for the referenced |
| 132 | ontology (see 3.6). |
| 133 | |
| 134 | When inheriting from a foreign concept that has no "local subconcepts" |
| 135 | (i.e. in the same ontology), the concept must be declared abstract |
| 136 | (see 3.4). |
| 137 | |
| 138 | === (3.6) The Declaration Node === |
| 139 | |
| 140 | The declaration node holds ontology-level information like package, |
| 141 | imports and accesses. |
| 142 | |
| 143 | ==== Package ==== |
| 144 | |
| 145 | The first line must declare the Java package of the ontology, just |
| 146 | like in a Java source file. |
| 147 | |
| 148 | ==== Access Declarations ==== |
| 149 | |
| 150 | The next (zero to n) lines can be access declarations for referencing |
| 151 | external ontologies. Be sure to configure the ant task right (see 4.2) |
| 152 | so that the net holding the referenced ontology can be found. An |
| 153 | access declaration consists of the "access" keyword as well as the |
| 154 | name of the referenced ontology (but without the package). After |
| 155 | accessing an ontology, all of its concepts can be used as slot types |
| 156 | and for inheritence (see 3.5). |
| 157 | |
| 158 | ==== Import Declarations ==== |
| 159 | |
| 160 | Following the access declarations, there can be any number of normal |
| 161 | java imports. All imported classes can be used as slot types (but not |
| 162 | for inheritence). |
| 163 | |
| 164 | |
| 165 | '''Be sure to put package, accesses and imports in the order given |
| 166 | here''' - otherwise a parser error will occur. |
| 167 | |
| 168 | Example: |
| 169 | {{{ |
| 170 | package de.renew.agent.settler.ontology; |
| 171 | access Basic; |
| 172 | access GameConcepts; |
| 173 | import java.net.URI; |
| 174 | import java.util.*; |
| 175 | }}} |
| 176 | |
| 177 | == (4) Configuration of the Ant Target == |
| 178 | |
| 179 | General information about ant can be found at |
| 180 | http://ant.apache.org/manual/. The basics are axplained pretty well at |
| 181 | http://ant.apache.org/manual/using.html. |
| 182 | |
| 183 | To call the ontology generator from ant, there is the createfsontology |
| 184 | task. |
| 185 | |
| 186 | === (4.1) Basic Functionality === |
| 187 | |
| 188 | In the simple case, it takes a destination directory as (mandatory) |
| 189 | parameter. A fileset of ontology-sns-files belongs in the body - all |
| 190 | those ontologies will be generated. |
| 191 | |
| 192 | Simple example: |
| 193 | {{{ |
| 194 | <createfsontology destdir="build/gensrc"> |
| 195 | <fileset dir="build/classes/ontology"> |
| 196 | <include name="*.sns"/> |
| 197 | </fileset> |
| 198 | </createfsontology> |
| 199 | }}} |
| 200 | |
| 201 | Note that using explicit paths like here is considered bad style - |
| 202 | usually, it is a better idea to use properties for directory |
| 203 | references, which will be done in the following examples. |
| 204 | |
| 205 | === (4.2) The Netpath === |
| 206 | |
| 207 | The netpath is needed in order to find ontologies referenced by access |
| 208 | declarations (see 3.6). All ontologies in the body-fileset will |
| 209 | automatically be added to the netpath, so it is no problem to access |
| 210 | one generated ontology from another. |
| 211 | |
| 212 | But sometimes, there are ontologies in other plugins or target folders |
| 213 | that we would like to refererence. In this case, we need to use a |
| 214 | reference to a netpath: |
| 215 | {{{ |
| 216 | <createfsontology destdir="${dir.build.gensrc}" netpathref="ref.ontology.netpath"> |
| 217 | <fileset dir="${dir.build.classes}"> |
| 218 | <include name="ontology/ProdStoreCons.sns"/> |
| 219 | </fileset> |
| 220 | </createfsontology> |
| 221 | }}} |
| 222 | |
| 223 | Now, all references from the !ProdStoreCons ontology to ontologies |
| 224 | found in ref.ontology.netpath will be correctly resolved. The netpath |
| 225 | could have been configured like this: |
| 226 | {{{ |
| 227 | <path id="ref.ontology.netpath"> |
| 228 | <pathelement location="${dir.build.classes}/ontology"/> |
| 229 | </path> |
| 230 | }}} |
| 231 | |
| 232 | === (4.3) Where the Shadows Come From === |
| 233 | |
| 234 | Shadow nets are usually built from the .rnw source using the createsns |
| 235 | task. You should use a seperate targets for building the ontology sns |
| 236 | files and the reference net sns files, instead of trying to do all in |
| 237 | the same target. This is because for syntax check, the createsns task |
| 238 | should be set up to compile the nets. Then, we should use the |
| 239 | XFSNetCompiler instead of the !JavaNetCompiler. Also, there would be |
| 240 | cyclic references: The ontology generator needs the sns target, while |
| 241 | the reference nets need the generated ontologies to compile. |
| 242 | |
| 243 | The ontology sns target might look like this: |
| 244 | {{{ |
| 245 | <target name="ontology.sns.app" depends="init"> |
| 246 | <path id="ref.classpath.sns"> |
| 247 | <path refid="ref.classpath"/> |
| 248 | <pathelement location="${dir.build.classes}"/> |
| 249 | </path> |
| 250 | |
| 251 | <!-- creates separate sns for each rnw --> |
| 252 | <createsns destdir="${dir.build.classes}" |
| 253 | classpathref="ref.classpath.sns" |
| 254 | compilername="de.renew.formalism.fsnet.XFSNetCompiler" |
| 255 | compile="true"> |
| 256 | <fileset dir="${dir.src}"> |
| 257 | <include name="ontology/**/*.rnw"/> |
| 258 | </fileset> |
| 259 | </createsns> |
| 260 | </target> |
| 261 | }}} |
| 262 | |
| 263 | === (4.4) Full example from FSOntologyTestPlugin === |
| 264 | |
| 265 | This example shows the complete ontology.app target from |
| 266 | FSOntologyTestPlugin. There are two ontologies: Basic and |
| 267 | !ProdStoreCons. They will be built in two phases for demonstration, |
| 268 | although they are in the same plugin and folder - usually, of course, |
| 269 | one would just do both at once. |
| 270 | {{{ |
| 271 | <target name="ontology.app" depends="init.mulantasks,ontology.sns.app"> |
| 272 | <!-- Build the ontology in two phases just to demonstrate how it works --> |
| 273 | <!-- First, just the "Basic" ontology, no netpath is needed here --> |
| 274 | <createfsontology destdir="${dir.build.gensrc}"> |
| 275 | <fileset dir="${dir.build.classes}"> |
| 276 | <include name="ontology/Basic.sns"/> |
| 277 | </fileset> |
| 278 | </createfsontology> |
| 279 | |
| 280 | <!-- Configure the netpath to look for referenced ontology sns's --> |
| 281 | <path id="ref.ontology.netpath"> |
| 282 | <pathelement location="${dir.build.classes}/ontology"/> |
| 283 | </path> |
| 284 | |
| 285 | <!-- Second, the ProdStoreCons ontology which references Basic. |
| 286 | As Basic is not in the fileset, we need the netpath here --> |
| 287 | <createfsontology destdir="${dir.build.gensrc}" netpathref="ref.ontology.netpath"> |
| 288 | <fileset dir="${dir.build.classes}"> |
| 289 | <include name="ontology/ProdStoreCons.sns"/> |
| 290 | </fileset> |
| 291 | </createfsontology> |
| 292 | </target> |
| 293 | }}} |
| 294 | |
| 295 | == (5) About the Generated Classes == |
| 296 | |
| 297 | For each ontology concept, a Java class is being generated. Abstract/concrete concepts will have |
| 298 | abstract/concrete classes, respectively. |
| 299 | |
| 300 | === (5.1) Class Hierarchy === |
| 301 | The generated class hierarchy normaly reflects the concept hierarchy - |
| 302 | with a few exceptions: |
| 303 | |
| 304 | * The superconcept of all concepts is "concept", theoretically - but this has no |
| 305 | semantic meaning, so a concept with this name will just be ignored |
| 306 | for the generation process. |
| 307 | * Concepts with name "agent-action" or "predicate" will not be |
| 308 | generated, either, but concepts inheriting from them will be |
| 309 | regarded agent actions or predicate, respectively. Classes |
| 310 | generated from agent actions and predicates will have special |
| 311 | methods (see 5.5). |
| 312 | * Concepts directly inheriting from "predicate" are mapped to |
| 313 | classes inheriting from GenericVT, while all other concepts with |
| 314 | no superconcepts besides "concept" or "agent action" inherit from |
| 315 | GenericKVT. This is due to FIPA specifications, where predicated |
| 316 | are regarded as value-tuples, while other concepts are usually |
| 317 | key-value-tuples. |
| 318 | * Sometimes people feel happy to draw the concept agent-identifier - |
| 319 | although the corresponding class is already implemented in |
| 320 | Capa. Therefore, this concept will also be ignore by the generator. |
| 321 | |
| 322 | === (5.1) Automatic Name Conversion === |
| 323 | |
| 324 | All concept names, slot types and slot names will be converted to Java |
| 325 | conventions using the following two rules: |
| 326 | * Hyphens will be replaced by camelCase. |
| 327 | * Concept names and non-primitive slot types will be capitalized to |
| 328 | yield legal class names. |
| 329 | |
| 330 | For example, the concept defined by |
| 331 | {{{ |
| 332 | my-nice-concept |
| 333 | |
| 334 | first-slot:int |
| 335 | second-slot:String |
| 336 | third-slot:neighbour-concept |
| 337 | }}} |
| 338 | |
| 339 | generates a class of name !MyNiceConcept with three slots: |
| 340 | * firstSlot of type int |
| 341 | * secondSlot of type String |
| 342 | * thirdSlot of type !NeighbourConcept |
| 343 | |
| 344 | === (5.2) Constructors === |
| 345 | |
| 346 | Concrete classes have two visible constructors: |
| 347 | * A basic constructor without any parameters - all slots will be |
| 348 | null unless explicitly set later |
| 349 | * A conveniance constructor with a parameter for each |
| 350 | slot. If null is given instead of any parameter, the corresponding |
| 351 | slot will not be set. Multi-valued slots have parameter type |
| 352 | VTSequence. Primitive types slots have the boxed type as parameter |
| 353 | (e.g. int has Integer), so null can also be used here. |
| 354 | |
| 355 | Also, the static methods fromString and fromAclMessage(for predicates, |
| 356 | this is called predicateFromAclMessage) are generated, which take a string |
| 357 | in SL1 and Acl format, respectively, which will be parsed. They then return an instance of the |
| 358 | concept class. (It was not possible to make this a constructor, as a |
| 359 | concept with exactly one slot of type String already has a conveniance |
| 360 | constructor with this signature.) |
| 361 | |
| 362 | === (5.3) Accessors for Simple Slots === |
| 363 | |
| 364 | Simple (that is, not multi-valued) slots have simply a getter and a |
| 365 | setter using the types given in the slot definition. This also holds |
| 366 | for primitive Java types like int, although slots of this kind are |
| 367 | internally stored using the boxed types - the conversion is done |
| 368 | automatically by the accessors. |
| 369 | |
| 370 | === (5.4) Accessors for Multi-Valued Slots === |
| 371 | |
| 372 | For multi-valued slots or list slots, several methods will be |
| 373 | generated. For example, the slot defined by |
| 374 | {{{ |
| 375 | village:String* |
| 376 | }}} |
| 377 | produces the following methods: |
| 378 | * void setVillage(VTSequence vals) |
| 379 | Sets the slot to the given list. |
| 380 | * VTSequence getAllVillage() |
| 381 | Gets all villages stored in the list slot. |
| 382 | * Iterator getAllVillageAsIterator() |
| 383 | Gives an iterator over all villages. |
| 384 | * void addVillage(String val) |
| 385 | Adds a village to the list. |
| 386 | * void removeVillage(String val) |
| 387 | Removes the given village from the list. |
| 388 | * void addAllVillage(VTSequence vals) |
| 389 | Appends the given list of villages. |
| 390 | * void removeAllVillage(VTSequence vals) |
| 391 | Removes all villages in the given list. |
| 392 | |
| 393 | Automatic boxing is also done for list slots, so a slot of type int* |
| 394 | will have add- and remove-methods with type int as parameter. |
| 395 | |
| 396 | === (5.5) Other Generated Methods === |
| 397 | |
| 398 | As mentioned in 5.1, agent actions and predicates will get a few extra |
| 399 | methods generated. |
| 400 | |
| 401 | Methods for agent actions: |
| 402 | * toActionRequest(!AgentIdentifier receiver) |
| 403 | Generates an Acl message which asks the receiver to perform this |
| 404 | action. |
| 405 | * Depricated: |
| 406 | * toAclMessage(!AgentIdentifier receiver) |
| 407 | Alias for toActionRequest. |
| 408 | * toAclInform(!AgentIdentifier receiver) |
| 409 | Wraps an inform around the action. This construct should rather |
| 410 | be avoided, as it is semantically unclear who is performing the |
| 411 | action. |
| 412 | |
| 413 | Methods for predicates: |
| 414 | * toSimpleInform(!AgentIdentifier receiver) |
| 415 | Wraps an inform message around this predicate. |
| 416 | * toQueryIf(!AgentIdentifier receiver) |
| 417 | Wraps a query-if message around this predicate. |