-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
715 lines (504 loc) · 39.7 KB
/
index.html
File metadata and controls
715 lines (504 loc) · 39.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>JCategory User Guide</title>
<link rel="stylesheet" href="styles/publication/sc.tutorial.css" />
<script type="text/javascript" src="js/jquery.min.js" charset="utf-8"></script>
<script type="text/javascript" src="js/ace-builds/src-noconflict/ace.js" charset="utf-8"></script>
<script type="text/javascript" src="js/publication/jquery.tableofcontents.min.js" charset="utf-8"></script>
<script type="text/javascript" src="js/publication/jquery.sc.publication.js" charset="utf-8"></script>
<script type="text/javascript">//<![CDATA[
(function ($) {
$(document).ready(function(){
$('#table_of_content_entries').tableOfContents('#content', {startLevel:2, depth: 3});
$.prettifyCodeSnippets("eclipse");
//$.prettifyCodeSnippets("solarized_light");
$.configureFootnotes();
})
})(jQuery);
//]]></script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-45484809-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</head>
<body>
<h1>JCategory User Guide</h1>
<div id="table_of_content">
<strong>Contents</strong>
<ol id="table_of_content_entries"></ol>
</div>
<div id="content">
<h2>Overview</h2>
<p>
JCategory is a lightweight categorization framework for Java.
</p>
<p>
Since ancient times, conceptual grouping has been a natural human way to create abstract models of the world <sup> <a rel="footnote" href="#fn:aristo">1</a> </sup>.
In computer science, the notion of categories plays a major role in computer programming <sup> <a rel="footnote" href="#fn:classes-vs-prototypes">2</a> </sup>.
Particularly, different categorization mechanisms are often implicit in most programming languages (e.g., classes and packages).
However, for statically-typed languages it is often not trivial (or not possible at all) to modify at runtime the properties of existing categories, or creating new categories on the fly.
Furthermore, a programmer may intend to create or modify the properties of categories in a certain well-scoped context, isolating category properties, or the categories themselves, from the rest of the application.
</p>
JCategory provides support for defining complex taxonomies of categories into a particular context.
With JCategory, a programmer can define and manipulate ad hoc categorizations, as well as easily organize categories relying on existing Java categorization mechanisms, such as classes and packages.
<h2>Having Fun with Categories (or a Short Introduction to <a href="http://logging.apache.org/log4j/1.2/" title="Apache log4j">log4j</a>)</h2>
This section illustrates a typical usage of custom categories in everyday programming by means of reviewing common logging practices using a well known Java library.
<h3 id="log4j-named-hierarchies">Name Hierarchies</h3>
Popular logging libraries such as <a href="http://logging.apache.org/log4j/1.2/" title="Apache log4j">log4j</a> allow fine-grained control on which kind of logging message (e.g., warning or error) should be processed at runtime.
This control is enabled since programmers can easily categorize a <q>logging space</q> <sup> <a rel="footnote" href="#fn:apache-manual">3</a> </sup> according to some developer-chosen criteria.
Loggers are organized hierarchically following a naming rule. For example, a logger named <code>"org"</code> is the parent of a logger named <code>"org.jcategory"</code>, and the ancestor of a logger named <code>"org.jcategory.JCategory"</code>.
If a logger property (e.g., a logging <code>level</code>) is not defined for a given logger, it should be resolved according to the corresponding property value of its parent.
<p/>
Loggers are typically defined by means of configuration files. The following fragment of a log4j configuration file configures a logger named <code>org.jcategory</code> with the level <code>WARN</code>.
<p><pre data-editor="properties" data-show-gutter="true">
# Set the logger level to WARN for the "org.jcategory" logger
log4j.logger.org.jcategory=WARN</pre></p>
Although loggers can have any name, a practical convention is to name them according to the fully qualified name of the class where they are used.
For example, a logger used in the <code>org.jcategory.JCategory</code> class may be named <code>"org.jcategory.JCategory"</code>. Such logger can be instantiated with:
<p><pre data-editor="properties" data-show-gutter="true">Logger jcategoryLogger = Logger.getLogger(org.jcategory.JCategory.class); //instantiates a logger named "org.jcategory.JCategory"</pre></p>
Since this logger is a descendant from the <code>"org.jcategory"</code> logger defined in the configuration file, it inherits from its parent the <code>level</code> property, set to <code>WARN</code>.
This is illustrated by the figure below.
<div class="divImg">
<img src="img/log4j_packages.svg" alt="Name category properties." style="padding-bottom:0.5em;" width="268" height="233" />
<div id="imglabel:log4j_named_properties" >Fig 1. - A name categorization for loggers.</div>
</div>
<p>
Note that in order to keep our example simple some details of log4j have been omitted.
Particularly, the actual implementation of log4j defines <code>level</code> and other properties with default values in the root category.
For a detailed explanation on the semantic meaning of logger properties please refer to the <a href="http://logging.apache.org/log4j/1.2/manual.html">log4j manual</a>.
</p>
<p>
This section has illustrated how a popular logging library makes use of name hierarchies to create a categorization of loggers.
The core idea of a name based categorization is to infer hierarchical relationships between labeled categories based on a given naming convention.
As we will see, JCategory provides high level support for dealing with this categorization pattern.
</p>
<p>
The following section motivates another kind of categorization based on the existing type hierarchies of a programming language.
</p>
<h3 id="log4j-type-hierarchies">Type Hierarchies</h3>
<p>
Back to our logging example, this section illustrates how log4j renders objects in logging messages.
</p>
<p>
Since generating readable messages is a core objective of logging, log4j allows to associate custom renderers with certain classes.
The renderers are responsible to convert instances of such classes to a convenient string representation for logging purposes.
</p>
Quoting the <a href="http://logging.apache.org/log4j/1.2/manual.html">log4j manual</a>:
<q>Object rendering follows the class hierarchy. For example, assuming oranges are fruits, if you register a <code>FruitRenderer</code>, all fruits including oranges will be rendered by the <code>FruitRenderer</code>, unless of course you registered an orange specific OrangeRenderer </q>.
Following this example, we would like to associate a property (a renderer) with the category identified by the <code>Fruit</code> class. However, in this setting we require a different categorization heuristic: instead of categorizing a class according to its fully qualified name as in the previous section, we want to do it according to its position in a class hierarchy. This categorization is illustrated by the figure below.
<div class="divImg">
<img src="img/log4j_classes.svg" alt="Type category properties." style="padding-bottom:0.5em;" width="314" height="174" />
<div id="imglabel:log4j_type_properties">Fig 2. - A type categorization for renderers.</div>
</div>
Therefore, this categorization relies on an existing categorization already provided by the language (a hierarchy of classes).
As in the previous categorization based on name hierarchies, JCategory factorizes out this categorization pattern as a general mechanism to associate properties to classes and interfaces.
As before, this association is limited to the scope of a certain context.
<h2>The JCategory Context</h2>
JCategory allows to create and maintain categorizations associated with a context.
A JCategory context can be regarded as a register for categorizations and a store of preferences.
A default <a href="javadocs/org/jcategory/JCategory.html">JCategory context</a> can be instantiated as follows:
<p><pre data-editor="java" data-show-gutter="true">
JCategory context = new JCategory();</pre></p>
Categorizations can be registered and retrieved as follows:
<p><pre data-editor="java" data-show-gutter="true">
Categorization<CategoryClass> myCategorization = ...;
context.register("my-categorization", myCategorization); //registering a categorization under the identifier "my-categorization"
context.getCategorization("my-categorization"); //retrieving the categorization identified by "my-categorization"</pre></p>
<p>
This context also provides high-level methods to deal with name and type categorizations, as it will be illustrated in the next section.
</p>
<h2>JCategory Categories</h2>
The notion of category is a core aspect of the JCategory implementation.
A <a href="javadocs/org/jcategory/category/Category.html">JCategory category</a> is defined by a group of properties shared by the objects belonging to such a category.
Categories can also be defined in terms of other categories, in which case they inherit the properties of their ancestor categories.
Therefore, categories define parents-children relationships with other categories.
<p>JCategory categories may be associated with an identifying <a href="javadocs/org/jcategory/category/LabeledCategory.html">label</a>.
According to the chosen categorization, this label may determine the position of the category in a hierarchy (e.g., <a href="#log4j-named-hierarchies">named hierarchies</a>), or just serve as a human aid facilitating reasoning over the category and its extension <sup> <a rel="footnote" href="#fn:categories-matter">4</a> </sup>.
</p>
<p>
In addition to offer a framework for creating and maintaining custom hierarchies of categories, JCategory provides special classes and routines for dealing with two common categorization mechanisms.
The rest of this section overviews the JCategory support for name and type categorizations.
</p>
<h3>Name Categorizations</h3>
<p>
JCategory allows to define <a href="javadocs/org/jcategory/category/named/NameCategory.html">name categorizations</a> that structure their hierarchy according to the naming convention described in our <a rel="footnote" href="#log4j-named-hierarchies">loggers categorization example</a>.
This categorization approach can be used to associate properties with Java packages, classes (by means of their fully qualified name) or any artifact following a similar hierarchical naming convention.
</p>
<p>
The example below creates a name categorization with the same properties that our <a rel="footnote" href="#imglabel:log4j_named_properties">logging example</a>.
</p>
<p><pre data-editor="java" data-show-gutter="true">
final Object LEVEL = "level"; //the property identifier
JCategory context = new JCategory();
NameCategory parent = context.forPackage(JCategory.class.getPackage()); //name category for "org.jcategory"
NameCategory child = context.forName(JCategory.class.getName()); //name category for "org.jcategory.JCategory"
parent.setProperty(LEVEL, "WARN"); //"level" property set to "WARN" for "org.jcategory"
assertEquals("WARN", parent.getProperty(LEVEL).get()); //"level" property is "WARN" for "org.jcategory"
assertEquals("WARN", child.getProperty(LEVEL).get()); //"level" property is also "WARN" for "org.jcategory.JCategory"
assertFalse(context.forName("org").getProperty(LEVEL).isPresent()); //"level" property has not been set for "org"</pre></p>
<p>
First we obtain categories corresponding to the names <code>"org.jcategory"</code> (line 3) and <code>"org.jcategory.JCategory"</code> (line 4). We set the <code>level</code> property to <code>WARN</code> in the <code>"org.jcategory"</code> category (line 5). We verify that the property is set for both this category (line 6) and a child category that should inherit that property (line 7).
In line 8 we verify that the property is undefined for the category <code>"org"</code>, since it is before in the hierarchy of the only category defining this property.
</p>
<h3>Type Categorizations</h3>
JCategory facilitates the creation of <a href="javadocs/org/jcategory/category/type/TypeCategory.html">type categorizations</a> based on the Java class hierarchy.
Back to our <a rel="footnote" href="#log4j-type-hierarchies">renderers categorization example</a>, consider the classes <code>Fruit</code>, <code>Orange</code> and <code>FruitRenderer</code> as:
<p><pre data-editor="java" data-show-gutter="true">
public class Fruit {...}
public class Orange extends Fruit{...}
public class FruitRenderer implements ObjectRenderer {
@Override
public String doRender(Object fruit) {
...
}
}</pre></p>
The code below shows how the categorization illustrated in our <a rel="footnote" href="#imglabel:log4j_type_properties">rendering example</a> can be implemented in few lines of code.
<p><pre data-editor="java" data-show-gutter="true">
final Object OBJECT_RENDERER_KEY = ObjectRenderer.class; //the property identifier
JCategory context = new JCategory();
TypeCategory<Fruit> fruitCategory = context.forClass(Fruit.class); //type category for Fruit
TypeCategory<Orange> orangeCategory = context.forClass(Orange.class); //type category for Orange
fruitCategory.setProperty(OBJECT_RENDERER_KEY, FruitRenderer.class); //ObjectRenderer property set to FruitRenderer for Fruit
assertEquals(FruitRenderer.class, fruitCategory.getProperty(OBJECT_RENDERER_KEY).get()); //ObjectRenderer property is FruitRenderers for Fruit
assertEquals(FruitRenderer.class, orangeCategory.getProperty(OBJECT_RENDERER_KEY).get()); //ObjectRenderer property is also FruitRenderer for Orange
assertFalse(context.forClass(Object.class).getProperty(OBJECT_RENDERER_KEY).isPresent()); //ObjectRenderer property has not been set for Object</pre></p>
<p>
First we obtain categories corresponding to the classes <code>Fruit</code> (line 3) and <code>Orange</code> (line 4).
Note that a property identifier can be any object, in this case the property is identified by the <code>ObjectRenderer</code> class (line 1).
We set the <code>ObjectRenderer</code> property to <code>FruitRenderer</code> in the <code>Fruit</code> category (line 5). We verify that the property is set for both this category (line 6) and a child category that should inherit that property (line 7).
In line 8 we verify that the property is undefined for the category <code>Object</code>, since it is an ancestor of the only category defining this property.
</p>
<h2>Dealing with Multi-Inheritance</h2>
<p>
Previous examples showed categories inheriting the properties of a single parent category, creating tree-structured category hierarchies.
However, other categories may be better modelled as inheriting from more than one single parent.
Although powerful in expressiveness <sup> <a rel="footnote" href="#fn:meyer">5</a> </sup>, multi-inheritance introduces many conceptual and technical problems <sup> <a rel="footnote" href="#fn:inheritance">6</a> </sup>.
</p>
<p>
The following section illustrates this with one common problematic scenario in multi-inheritance categorizations.
</p>
<h3>The Diamond Inheritance Problem</h3>
The figure below illustrates a known problem referred to as <q>diamond inheritance</q> <sup> <a rel="footnote" href="#fn:diamond-inheritance">7</a> </sup> with a simple example.
Categories <code>B</code> and <code>C</code> inherit from <code>A</code>. They define different values for the property <code>p</code>.
If category <code>D</code> inherits from both <code>B</code> and <code>C</code>, the value of the property <code>p</code> is ambiguous in <code>D</code> .
<div class="divImg">
<img src="img/diamond_inheritance.svg" alt="Diamond inheritance." style="padding-bottom:0.5em;" width="369" height="208" />
<div id="imglabel:diamond_inheritance">Fig 3. - Diamond inheritance.</div>
</div>
Although there are many different alternatives to solve conflicts for ambiguous properties, unfortunately there is not a perfect one-fit-all solution <sup> <a rel="footnote" href="#fn:name-collision">8</a> </sup>.
The following section illustrates the approach followed by JCategory.
<h3>Linearization Functions</h3>
Linearization is a common approach for solving multi-inheritance conflicts <sup> <a rel="footnote" href="#fn:linearization">9</a> </sup>.
In order to illustrate this approach, let's consider the following classes and interfaces defining a taxonomy of animals (example adapted from a popular Scala book <sup> <a rel="footnote" href="#fn:scala-book">10</a> </sup>) :
<p><pre data-editor="java" data-show-gutter="true">
public class Animal {}
public interface HasLegs {}
public interface FourLegged extends HasLegs {}
public interface Furry {}
public class Cat extends Animal implements Furry, FourLegged {}
public class Fish extends Animal {}</pre></p>
<p>
Figure 4 illustrates a JCategory type categorization based on this class hierarchy.
</p>
<div class="divImg">
<img src="img/animal_hierarchy.svg" alt="Animal hierarchy example." style="padding-bottom:0.5em;" width="559" height="250" />
<div id="imglabel:animal_hierarchy" >Fig 4. - Animal hierarchy example.</div>
</div>
<p>
First note that JCategory adds the special class <code>Any</code> at the root of the hierarchy.
This design decision allows to have a common root for both <a href="javadocs/org/jcategory/category/type/ClassCategory.html">class</a> and <a href="javadocs/org/jcategory/category/type/InterfaceCategory.html">interface</a> type categories and this presents various advantages.
One of those is being able to set global properties that are inherited by both class and interface categories in the hierarchy.
</p>
<p>
The figure also illustrates a type-based categorization of renderers according to this class hierarchy (note the <code>renderer</code> property associated to certain classes).
Observe that JCategory considers, in many aspects, both classes and interfaces as same-level categorization units.
For example, one of the two renderers shown in the figure (<code>AnimalRenderer</code>) is a property of the <code>Animal</code> class.
The other (<code>HasLegsRenderer</code>) is a property of the <code>HasLegs</code> interface.
In order to associate those renderers with the categories <code>Animal</code> and <code>HasLegs</code>, we can write:
</p>
<p><pre data-editor="java" data-show-gutter="true">
final Object OBJECT_RENDERER_KEY = ObjectRenderer.class;
JCategory context = new JCategory();
TypeCategory<Animal> animalCategory = context.forClass(Animal.class); //type category for Animal
TypeCategory<HasLegs> hasLegsCategory = context.forClass(HasLegs.class); //type category for HasLegs
animalCategory.setProperty(OBJECT_RENDERER_KEY, AnimalRenderer.class); //setting property ObjectRenderer to AnimalRenderer in Animal
hasLegsCategory.setProperty(OBJECT_RENDERER_KEY, HasLegsRenderer.class); //setting property ObjectRenderer to HasLegsRenderer in HasLegs</pre></p>
This example provides for both non-conflictive and conflictive property resolution scenarios.
In the simplest case, let's consider we would like to query the render property for the <code>Fish</code> category.
Since there is only single inheritance in the category hierarchy of <code>Fish</code>, its renderer is trivially found from the first ancestor defining such a property (i.e., <code>Animal</code>), as the following test illustrates:
<p><pre data-editor="java" data-show-gutter="true">
...
TypeCategory<Fish> fishCategory = context.forClass(Fish.class); //type category for Fish
assertEquals(AnimalRenderer.class, fishCategory.getProperty(OBJECT_RENDERER_KEY).get()); //ObjectRenderer property is AnimalRenderer for Fish</pre></p>
<p>
However, if we ask which is the appropriate renderer for instances of <code>Cat</code>, different property resolution strategies may result in different values.
For example, some may think that categories from super interfaces should be looked up first. In this case <code>HasLegRenderer</code> should be returned.
Others may prefer to query first categories corresponding to the super class. In that case <code>AnimalRenderer</code> should be returned.
</p>
<p>
Linearization helps to solve this conflict unambiguously defining a lineal order in which (super-)categories should be visited when querying a property.
In JCategory, linearization is considered a function mapping a category to a list of categories creating a search path.
</p>
The default JCategory type linearization function is, to certain extent, inspired by the linearization function used by Scala <sup> <a rel="footnote" href="#fn:scala">11</a> </sup> when solving conflicts between classes and traits.
JCategory uses a left-first depth-first search, before eliminating all but the last occurrence of each category in the resulting list (the main difference with the Scala algorithm is that the later uses a right-first depth-first search).
Figure 5 illustrates the resolution order of a property starting from the category <code>Cat</code>.
<div class="divImg">
<img src="img/animal_hierarchy_linearization2.svg" alt="Linearization: traversing classes first." style="padding-bottom:0.5em;" width="559" height="250" />
<div id="imglabel:animal_hierarchy_linearization2" >Fig 5. - Linearization: Left to right (classes first).</div>
</div>
<p>
The linearization function first finds this resolution order (left-first depth-first search):
<code>[Cat, Animal, Object, Any, Furry, Any, FourLegged, HasLegs, Any]</code>
which is reduced down to:
<code>[Cat, Animal, Object, Furry, FourLegged, HasLegs, Any]</code> (eliminating all but the last occurrence of a redundant category).
As the figure shows, this algorithm has the particularity that an ancestor category will not be reached until all the descendants leading to it have been explored.
</p>
<p>
The following example verifies that the <code>ObjectRenderer</code> property is <code>AnimalRenderer</code> for <code>Cat</code>, according to our default linearization function:
</p>
<p><pre data-editor="java" data-show-gutter="true">
...
TypeCategory<Cat> catCategory = context.forClass(Cat.class); //type category for Cat
assertEquals(AnimalRenderer.class, catCategory.getProperty(OBJECT_RENDERER_KEY).get()); //ObjectRenderer property is AnimalRenderer for Cat</pre></p>
Given that a custom linearization function may be not that trivial to implement, JCategory provides simple abstractions for creating those functions from a set of parameters.
In order to associate a type linearization function with a JCategory context we can write:
<p><pre data-editor="java" data-show-gutter="true">
Function<TypeCategory<?>, List<TypeCategory<?>>> linearizationFunction =
new BottomUpTypeTraversalPolicy(
SearchStrategy.PRE_ORDER, //pre-order search
Priority.CLASSES_FIRST, //look first at classes, then interfaces
InterfaceOrder.DECLARATION, //traverse the interfaces from left to right (declaration order)
RedundancyCheck.KEEP_LAST); //if a category appears more than once in the linearization, keep the last found and discard the previous ones.
JCategory context = new JCategory(linearizationFunction);</pre></p>
The previous linearization function is the same as the default linearization function for type categories: left to right search, looking at classes first.
Alternatively, we could have configured a different linearization function, say a right to left search, looking at interfaces first:
<p><pre data-editor="java" data-show-gutter="true">
Function<TypeCategory<?>, List<TypeCategory<?>>> linearizationFunction =
new BottomUpTypeTraversalPolicy(
SearchStrategy.PRE_ORDER, //pre-order search
Priority.INTERFACES_FIRST, //look first at interfaces, then classes
InterfaceOrder.REVERSE, //traverse the interfaces from right to left (reverse declaration order)
RedundancyCheck.KEEP_LAST); //if a category appears more than once in the linearization, keep the last found and discard the previous ones.
JCategory context = new JCategory(linearizationFunction);</pre></p>
Figure 6 illustrates the alternative resolution order defined by our custom linearization function.
<div class="divImg">
<img src="img/animal_hierarchy_linearization1.svg" alt="Linearization: traversing interfaces first." style="padding-bottom:0.5em;" width="559" height="250" />
<div id="imglabel:animal_hierarchy_linearization1" >Fig 6. - Linearization: Right to left (interfaces first).</div>
</div>
This function first finds this resolution order:
<code>[Cat, FourLegged, HasLegs, Any, Furry, Any, Animal, Object, Any]</code>
which is reduced down to:
<code>[Cat, FourLegged, HasLegs, Furry, Animal, Object, Any]</code>.
In this setting, the renderer for instances of <code>Cat</code> is <code>HasLegsRenderer</code>, since it is found earlier in the list of categories returned by the linearization function.
<h2>Ad Hoc Categorizations</h2>
<p>
Of course, you can always create simple ad hoc categorizations if you do not care about name and type categorizations.
For ad hoc categorizations, the default linearization function makes use of a left-first depth-first search. Conflicts are solved keeping the last redundant category in the linearization and dropping the rest.
</p>
The example below implements a simple diamond inheritance hierarchy.
<p><pre data-editor="java" data-show-gutter="true">
//creating a simple hierarchy
Categorization mySimpleCategorization = new Categorization();
Category grandFather = new Category(mySimpleCategorization); //the root of the hierarchy
Category parent1 = new Category(asList(grandFather)); //parent1 inherits from grandFather
Category parent2 = new Category(asList(grandFather)); //parent2 also inherits from grandFather
Category child = new Category(asList(parent1, parent2)); //child inherits from both parent1 and parent2
//setting properties
Object p1 = new Object();
Object p2 = new Object();
grandFather.setProperty(p1, "x"); //setting property p1 to "x" in grandFather
parent1.setProperty(p1, "y"); //overriding property p1 as "y" in parent1
parent2.setProperty(p1, "z"); //overriding property p1 as "z" in parent2
parent2.setProperty(p2, "x"); //setting property p2 to "x" in parent2
//testing
assertEquals("y", child.getProperty(p1).get()); //p1 property found in parent1
assertEquals("x", child.getProperty(p2).get()); //p2 property found in parent2
//optionally registering the previous categorization in a JCategory context
JCategory context = new JCategory();
context.register("my-categorization", mySimpleCategorization);</pre></p>
<h2>Strategies</h2>
<p>
Categories may be associated with strategies.
A JCategory strategy is just an object which class implements one or more interfaces.
Multiple strategies can be located in a categorization, forming an implicit <a href="http://en.wikipedia.org/wiki/Chain-of-responsibility_pattern" title="Chain-of-responsibility pattern">chain of responsibility</a>.
</p>
<p>
In order to illustrate this, we come back to the animal renderers showed in a <a href="#imglabel:animal_hierarchy" title="Animal renderers">previous example</a>.
The following classes provide a simple implementation of such renderers:
</p>
<p><pre data-editor="java" data-show-gutter="true">
public class AnimalRenderer implements ObjectRenderer {
@Override
public String doRender(Object animal) {
return "animal";
}
}
public class HasLegsRenderer implements ObjectRenderer {
@Override
public String doRender(Object hasLegs) {
return "has-legs";
}
}</pre></p>
For this example, we will make use of type categories to associate classes with <em>instances</em> of our renderers, as it is showed in the example below:
<p><pre data-editor="java" data-show-gutter="true">
final Object OBJECT_RENDERER_KEY = ObjectRenderer.class;
JCategory context = new JCategory();
//instantiating categories
TypeCategory<Animal> animalCategory = context.forClass(Animal.class); //type category for Animal
TypeCategory<HasLegs> hasLegsCategory = context.forClass(HasLegs.class); //type category for HasLegs
TypeCategory<Cat> catCategory = context.forClass(Cat.class); //type category for Cat
//setting properties
animalCategory.setProperty(OBJECT_RENDERER_KEY, new AnimalRenderer()); //ObjectRenderer property is an instance of AnimalRenderer for Animal
hasLegsCategory.setProperty(OBJECT_RENDERER_KEY, new HasLegsRenderer()); //ObjectRenderer property is an instance of HasLegsRenderer for HasLegs</pre></p>
<p>
We can obtain an instance of a strategy by means of the <a href="javadocs/org/jcategory/category/Category.html#getStrategy(java.lang.Class)" title="getStrategy() method">getStrategy()</a> method in the <a href="javadocs/org/jcategory/category/Category.html" title="Category class">Category</a> class.
The returned strategy is in fact a composition of other strategies (specifically, a chain of responsibility) in the upper hierarchy of a category.
Note that the class of this strategy is generated at runtime (at the moment, by means of <a href="http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Proxy.html" title="Dynamic proxies">dynamic proxies</a>).
</p>
<p>
The code below verifies that the result of rendering a cat by means of the strategy <code>ObjectRenderer</code> at the <code>Cat</code> category is delegated to the first renderer found in the hierarchy (according to the default linearization function). This is the instance of <code>AnimalRenderer</code> found at the <code>Animal</code> class.
</p>
<p><pre data-editor="java" data-show-gutter="true">
...
ObjectRenderer renderer = catCategory.getStrategy(ObjectRenderer.class);
assertEquals("animal", renderer.doRender(new Cat()));</pre></p>
<p>
Finally, in case a strategy requires to delegate to the next strategy in the chain of responsibility, it just needs to throw a <a href="javadocs/org/jcategory/strategy/NoMyResponsibilityException.html" title="NoMyResponsibilityException class">NoMyResponsibilityException</a> exception.
If this happens, the next strategy in the chain will be employed. If all the strategies in the chain are exhausted, a <code>NoMyResponsibilityException</code> exception is thrown to the caller.
</p>
<p>
To illustrate this, let's consider the following alternative animal renderer:
</p>
<p><pre data-editor="java" data-show-gutter="true">
class DelegationAnimalRenderer implements ObjectRenderer {
@Override
public String doRender(Object animal) {
throw new NoMyResponsibilityException();
}
}</pre></p>
<p>
The code below verifies that the renderer of a cat is now the instance of <code>HasLegsRenderer</code> found at the <code>HasLegs</code> class, which is second in the hierarchy (again, according to the default linearization function). This is given to the fact that the renderer instance of <code>AnimalRenderer</code>, although found first in the hierarchy, throws a <code>NoMyResponsibilityException</code> exception.
</p>
<p><pre data-editor="java" data-show-gutter="true">
...
//overridding property
animalCategory.setProperty(OBJECT_RENDERER_KEY, new DelegationAnimalRenderer()); //ObjectRenderer property is an instance of DelegationAnimalRenderer for Animal
//testing
ObjectRenderer renderer = catCategory.getStrategy(ObjectRenderer.class);
assertEquals("has-legs", renderer.doRender(new Cat()));</pre></p>
<!--
<h2>Miscelaneous Features</h2>
<h3>Iterating on property values in a categorization</h3>
<h3>Category creation listeners</h3>
-->
<h2>Limitations and Future Work</h2>
This section highlights certain limitations of JCategory. In certain cases, future work directions to overcome these limitations are outlined.
<h3>Name Categorizations Limitations</h3>
<p>
JCategory provides support for only one pattern of name categorizations: hierarchies specified by means of category names implicitly containing a list of ancestors using dots as token separator.
However, many other alternatives are possible (e.g., structuring hierarchies based on a numeric pattern present in the name of a category).
The current mechanism was chosen because it is well known and understood. Other strategies should not be difficult to implement.
</p>
<h3>Type Categorizations Limitations</h3>
<p>
JCategory type categories currently do not take into consideration implicit reflective properties (e.g., fields and methods declarations) of the wrapped classes that define a type categorization.
Instead, existing classes are just considered category identifiers and provide a hierarchical organization for type categorizations.
This may change in the future if a good use-case appears.
</p>
<h3>Alternative Conflict Resolution Mechanisms</h3>
<p>
As mentioned before, linearization is only one mechanism to solve conflicts in multi-inheritance scenarios.
For example, an alternative mechanism allowing to rename one of the conflictive properties in a descendant type category may be implemented, or somehow given the possibility to the programmer to explicitly decide which inherited property to choose.
</p>
<p>
At the moment, there are no plans to implement any of these alternative conflict resolution mechanisms since they are not part of the requirements that motivated the implementation of JCategory.
</p>
<h3>Performance Issues</h3>
<p>
A potential performance issue may occur in scenarios with many categories deep in a hierarchy.
For example, if many of those categories do not contain properties (or only contain properties that are not queried often), the property look up algorithm has to continuously traverse a long list of non interesting nodes.
This may be solved by adding to each category references not only to its parents, but to the next ancestors actually containing properties.
In this line, it may also make sense to implement a sort of indexing based on certain frequently queried properties. In other words, a category may keep a reference to the next category with a particular often-queried property.
This optimization algorithms may make the querying of properties more efficient despite a small overhead in the addition of new properties.
</p>
<p>
Alternatively, for a rather static categorization that do not modify much its properties, it may also make sense to pre-process its categories, in such a way that a category has a local copy of all its inherited properties according to a linearization function.
</p>
<h2>Conclusions</h2>
This tutorial has described a lightweight Java library for creating different kinds of categorizations: 1) name, 2) type and 3) ad hoc categorizations.
<p>
Not all the JCategory features have been discussed here. Features such as top-down traversing of hierarchies, registration of listeners in categorizations and the description of utility classes facilitating common tasks have been left out for timing constraints.
</p>
Particularly, top-down search has interesting applications. For example, with JCategory it is easy to find, given a type categorization, the first implementor of an interface (say using breadth-first search) that has certain desired characteristics (e.g., it is associated with a particular JCategory property). This feature may be described in the next version of this tutorial.
<p>
If you are interested to learn more about such features, or would like to know how to extend JCategory to support other user-defined categorizations, please <a href="#contact" title="Contact the author">contact</a> the author.
</p>
<h2>License</h2>
JCategory is open source, distributed under the terms of this <a href="https://github.com/jcategory/jcategory/blob/master/LICENSE.txt" title="License">license</a>.
<h2>Try it !</h2>
<p>
JCategory sources are available at <a href="https://github.com/jcategory/jcategory" title="JCategory at GitHub">GitHub</a>.
</p>
<p>
In case you are using Maven, it is also available at the <a href="http://search.maven.org/#search%7Cga%7C1%jcategory" title="JCategory at the Maven Central repository">Maven Central repository</a>. Just add this dependency to your POM to include JCategory into your project.
</p>
<p><pre data-editor="xml" data-show-gutter="true">
<dependency>
<groupId>com.github.jcategory</groupId>
<artifactId>jcategory</artifactId>
<version>0.0.1</version>
</dependency></pre></p>
You may also find interesting taking a look at the <a href="javadocs/index.html">JCategory API documentation</a>.
<h2 id="contact">Contact</h2>
Constructive feedback and criticism, questions or a wish list can be sent to <em>[sergioc78 (that symbol for emails) gmail(dot)com]</em>.
Or just drop me a line if you want to say hello ! :-)
</div> <!-- end of content -->
<div id="footnotes">
<hr />
<h3>Footnotes</h3>
<ol>
<li id="fn:aristo">
The complete works of Aristotle. Barnes, J. (ed). Volume 1. (the revised Oxford translation), Princeton University Press. 1984.
</li>
<li id="fn:classes-vs-prototypes">
Classes vs. Prototypes - Some Philosophical and Historical Observations. Antero Taivalsaari. Journal of Object-Oriented Programming. 1996.
</li>
<li id="fn:apache-manual">
<a href="http://logging.apache.org/log4j/1.2/manual.html">Short introduction to log4j.</a> Ceki Gülcü, March 2002.
</li>
<li id="fn:categories-matter">
The conceptual grouping effect: Categories matter (and named categories matter more). Gary Lupyan. Cognition, Vol. 108, No. 2. August 2008.
</li>
<li id="fn:meyer">
Object Oriented Software Construction. Bertrand Meyer. August 1997.
</li>
<li id="fn:inheritance">
On the Notion of Inheritance. Antero Taivalsaari. ACM Computing Surveys, Vol. 28, pages 438 - 479. 1996.
</li>
<li id="fn:diamond-inheritance">
The programming language Jigsaw: Mixins, modularity and multiple inheritance. Bracha, G. Ph.D. thesis, Univ. of Utah, March 1992.
</li>
<li id="fn:name-collision">
Name Collision in Multiple Classification Hierarchies. Knudsen. European Conference on Object-Oriented Programming, Oslo, Norway. August 1988.
</li>
<li id="fn:linearization">
Proposal for a Monotonic Multiple Inheritance Linearization. Roland Ducournau, Michel Habib, Marianne Huchard, and Marie-Laure Mugnier. OOPSLA, page 164-175. ACM. 1994.
</li>
<li id="fn:scala-book">
Programming in Scala. Martin Odersky, Lex Spoon and Bill Venners. Artima Press, Mountain View, CA. 2 edition. January 2011.
</li>
<li id="fn:scala">
An Overview of the Scala Programming Language. Martin Odersky, and al.. IC/2004/64. EPFL Lausanne, Switzerland. 2004.
</li>
</ol>
</div> <!-- end of footnotes -->
</body>
</html>