Changes between Version 24 and Version 25 of PRO_LIB_CORE_TUTORIAL


Ignore:
Timestamp:
07/02/09 20:29:04 (16 years ago)
Author:
gogov
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • TabularUnified PRO_LIB_CORE_TUTORIAL

    v24 v25  
    22[[TOC]] 
    33= Properties Library Tutorial = 
    4  
    5 == Properties Idea == 
    6 Properties give solution to the sequence of problems: 
    7  * Initialization order problems 
    8  * Dependency/updating 
    9  * Undo/Redo 
    10  * Save/Load 
    11  * Optimization (central point) 
    12  * Safety (detect errors) 
    13 == Properties Heirarchy == 
    14   * !ProObject - Object with properties. All objects needing property support should implement this interface. 
    15   * !ProBean - Each bean is associated one to one with a !ProObject. 
    16   * Prop<T> - Basic interface to access all properties. While the Property class is the base class for the implementation, once implemented, the clients interested in the value of the properties should use this interface to access it. 
    17    * Property - Basic class for all properties. 
    18   * !BeanData - !BeanData holds the information (properties, etc of a bean, and also a behavior for the make methods). 
    19   * !PropMetaInfo - Meta information for a property. Immutable. 
    20   * !PropretyStatus - A state of a trackable object. 
    21    * CREATED - initial state, you can only add/remove listeners 
    22    * META_INITIALIZED - get will throw !NotInitialized exception, other methods will work 
    23    * READY - get will return value 
    24    * DESTROYED - again get will throw.. 
    25   * !ProExp - Manages property expressions. 
    26   * Utils 
    27    * !ReflectionUtil - Misc helper static methods. 
    28    * !SwingUtil - Class which wraps a (legacy) !JavaBean for use in !ProBeans. 
    29    * Inspector - A GUI tool that allows browsing the application state while it still works. 
    30  *  
    31 [[Image(source:/trunk/sophie2-platform/modules/org.sophie2.core/doc/Properties.png)]] 
    32 [[BR]] 
    33 [[BR]] 
    34 [[BR]] 
    35 === List properties hierarchy === 
    36 [[Image(source:/trunk/sophie2-platform/modules/org.sophie2.core/doc/ProList.png)]] 
    37 [[BR]] 
    38 [[BR]] 
    39 [[BR]] 
    40 === Binding hierarchy === 
    41   * It is the existing bindings hierarchy but bindings are '''deprecated'''. 
    42 [[Image(source:/trunk/sophie2-platform/modules/org.sophie2.core/doc/Deprecated.png)]] 
    43 == Properties Kinds == 
    44  * Property 
    45   * !ObjectProperty - A property which holds a reference to a single object. 
    46    * !FinalProperty - One time write property. Once set, its value never changes. 
    47    * !AutoProperty - Smart property. A property which automatically monitors the information it depends on. In order to work, it should rely only on other properties and immutable values. 
    48    * !ResourceProperty - A property which holds a mutable resource. Useful for mutable non pro things like swing gui elements.   
    49    * !ValueProperty - A property that has a reference to an object and allows getting and setting it. 
    50     * !ParentProperty - Property which will hold a link to parent for parent-child relations. 
    51     * !UndoProperty - A property which holds the undo manager for given bean. If the bean does not have such property, the properties try to locate !UndoManager up (to parent).  
    52   * !ListProperty - Basic list property. Holds references to many objects. 
    53    * !ChildrenProperty - Property which manages list of children for a child/parent relation. 
    54  
    55 == Code Examples with different Properties Kinds == 
    56 === How to make === 
    57  * !FinalProperty 
    58 {{{ 
    59         public Prop<FrameView> frameView() { 
    60                 return getBean().makeFinalProp("frameView", FrameView.class); 
    61         } 
    62 }}} 
    63  
    64  * !AutoProperty 
    65 {{{ 
    66         public Prop<JScrollPane> scrollPane() { 
    67                 class scrollPane extends AutoProperty<JScrollPane> { 
    68                         @Override 
    69                         protected JScrollPane compute() { 
    70                                 JScrollPane res = new JScrollPane(list().get()); 
    71  
    72                                 res.setVerticalScrollBarPolicy( 
    73                                                 ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); 
    74  
    75                                 return res; 
     4The ProLib is a library written in Java which is intended to serve as somewhat an intermediate layer between client Sophie2 code and Java code. It has concepts and functionality which help solve a list of problems in an elegant (and hopefully efficient) manner. Its purpose is to ease the developer, not burden him, and in many cases leads to improved readability, more compact code which is also less error-prone if used correctly. Also, the problems which the ProLib solves are done (mostly) invisible to the developer so in the general case he shouldn't worry about how the ProLib works internally but just follow a set of rules and conventions for proper usage. 
     5 
     6The ProLib is now in a relatively stable state, though there are still new ideas to implement and integrate inside it as well as some performance optimizations. 
     7 
     8Basically, the structure looks like this: 
     9 
     10[[Image(source:branches/private/gogov/PRO_LIB_CORE_TUTORIAL_R1/sophie2-platform/modules/org.sophie2.core/src/test/resources/Layers.png)]] 
     11 
     12So, most Sophie2 client code is intended to use the ProLib in the cases when the ProLib solves problems and is helpful and use normal Java code in other cases. 
     13 
     14== ProLib basics == 
     15Here we'll provide a simple comparison between ProLib code and normal Java code as well as an example. 
     16 
     17== ProObject & Properties vs Java Object & Java fields == 
     18In Java, there are Objects and each Object has methods and fields. 
     19 
     20In the ProLib, there are ProObjects and each ProObject has normal Java methods and Properties instead of fields. The different concept here are that Properties are something like ''smart'' Java fields. 
     21 * You can create a ProObject by implementing the ProObject interface or by using the default implementation BaseProObject 
     22 * You can declare Properties inside the ProObject with Java methods which return a Prop<T> (later you'll get what is this), where T is a concrete class like Integer. The method executes some logic and returns the actual Property. 
     23  * There are different kinds of Properties, so inside these methods you can provide logic which returns the desired kind of Property. 
     24 
     25=== Example === 
     26Let's look at the following example: 
     27 
     28{{{ 
     29// Basic rectangle class which is ProObject. 
     30class Rectangle extends BaseProObject { 
     31        // Integer property for the width of the rectangle. Analogical to an Integer Java field. 
     32        RwProp<Integer> width() { 
     33                return getBean().makeValueProp("width", Integer.class); 
     34        } 
     35 
     36        // Integer property for the height of the rectangle. Analogical to an Integer Java field. 
     37        RwProp<Integer> height() { 
     38                return getBean().makeValueProp("height", Integer.class); 
     39        } 
     40 
     41        // Smart property which returns the area of the rectangle. 
     42        Prop<Integer> area() { 
     43                class area extends AutoProperty<Integer> { 
     44                        @Override 
     45                        protected Integer compute() { 
     46                                Integer res = width().get() * height().get(); 
     47                                return res; 
     48                        } 
     49                } 
     50 
     51                return getBean().makeProp(area.class); 
     52        } 
     53} 
     54 
     55// this is something like pseudo ProLib code which demonstrates basic ProLib usage 
     56public void demoCode() { 
     57    // create a new Rectangle 
     58    Rectangle rectangle = new Rectangle();               
     59 
     60    // set the width to 6 
     61    rectangle.width().set(6); 
     62 
     63    // set the height to 8 
     64    rectangle.height().set(8); 
     65 
     66    // it is true then that the area is equal to 6*8 = 48 
     67    assertEquals(48, (int)rectangle.area().get()); 
     68} 
     69}}} 
     70 
     71So, you can see the analogy with Java code, though the difference is with the area() Property. This is an AutoProperty: a property which is automatically computed. In the compute() method you specify the logic of the computation, and then this Property gets automatically computed. Even more, when the width and height change, this Property immediately gets recomputed and stay up-to-date which is very useful. 
     72 
     73Return statements might seem a bit awkward, though later in the tutorial you'll learn how to use and understand them. 
     74 
     75== Problems Solved == 
     76So, ProLib is intended to be used as somewhat intermediate layer between client code and normal Java code, thus some concepts are implemented in the ProLib and thus all client code which uses ProLib can benefit from these features. 
     77 
     78The ProLib gives solution to the following problems: 
     79 * '''Dependencies, initialization order and updating problems:''' [[BR]] 
     80 Let's say we've got lots of object which we're using in our application. These object depends on each other in a sense that: 
     81  * object A holds a reference to object B; 
     82  * object C must be initialized before object D because D needs data from object C to initialize itself; 
     83  * object E changes and object F depends on E, so F needs to get informed when E changes, in order to update itself. 
     84 The ProLib helps solve this problem by introducing somewhat a declarative way to state such dependencies and then handles initialization order and update notifications in an invisible and convenient manner for the client code developer. 
     85 
     86 * '''Undo/Redo''': [[BR]] 
     87  Serving as an intermediate layer helps the ProLib to keep histories of changes which occur to the ProObjects and properties involved in our application and thus the ProLib provides (at least soon will provide) a mechanism to automatically undo and redo these changes. 
     88 
     89 * '''Save/Load''': [[BR]] 
     90  The ProLib has the means for automatic persistence of objects which use it, as well as custom persistence options which let the developer choose how he want his object to be persisted which helps implementing saving and loading as well as transmission over a network by serializing, for instance, much simpler for the developer. 
     91 
     92 * '''Optimization''': [[BR]] 
     93  Being an intermediate layer allows the ProLib to serve as a central point for performance optimizations of the application and profiling and searching for bottlenecks. 
     94 
     95 * '''Safety''': [[BR]] 
     96  The ProLib helps (in the future in will help even more) to detect errors in the client code such as cyclic dependencies between objects (in the cases when such dependencies are unacceptable), missing logic, etc. 
     97 
     98It's fundamental to know that there are not many defensive mechanisms implemented in the ProLib against improper usage yet, so the developer can easily write stupid and not working ProLib code, though if he does it in the way ProLib is intended to be used, it will save him lots of time and headache. So, at least for now, a list of rules and recommendations on proper ProLib usage should be followed, which will be described later. 
     99 
     100== ProObjects and Properties == 
     101Now, we'll describe the ProLib fundamental classes and interfaces, what is their purpose and how are they intended to be used. 
     102 
     103=== ProObjects === 
     104[[Image(source:branches/private/gogov/PRO_LIB_CORE_TUTORIAL_R1/sophie2-platform/modules/org.sophie2.core/src/test/resources/ProObjects.png)]] 
     105 
     106 * '''ProObject''' is the base interface for all objects which want to use Properties. 
     107 * '''BaseProObject''' is the default implementation of ProObject. You should use it when possible to ease your life. 
     108 * Each ProObject is associated one-to-one with its own '''ProBean'''. A ProBean is basically the ''manager'' of the ProObject - it takes care for creating and remembering the Properties of the ProObject, initalizing them and other administrative work. 
     109 * Each '''ProObject''' can declare one or many Properties, like each Java object can declare one or many fields and methods. 
     110 
     111=== Properties === 
     112[[Image(source:branches/private/gogov/PRO_LIB_CORE_TUTORIAL_R1/sophie2-platform/modules/org.sophie2.core/src/test/resources/Property Hierarchy.png)]] 
     113 
     114==== Interfaces and classes ==== 
     115 Above the gray line are basic interfaces which Properties implement. Below the gray line are classes which implement these interfaces. 
     116 
     117==== Fundamental (GREEN) ==== 
     118 These are the fundamental interfaces and classes for all Properties. 
     119  * '''Prop<T>''':[[BR]] 
     120  This is the most basic interface which all Properties implement. 
     121   * Each Property holds an object, and with this interface you can use get() to get this object (which is actually the ''value'' of the Property). 
     122   * You can also get the owner of the Property (which is a ProObject) by using the owner() method. 
     123  * '''RwProp<T>''':[[BR]] 
     124  Extends the Prop<T> interface. 
     125   * The only thing this interface adds is the ability to set the value of the Properrty with the set() method. Thus Prop<T> provides read-only access and RwProp<T> provides read-write access to the value of the Property. 
     126  * '''ListProp<T>''':[[BR]] 
     127  While Prop<T>s hold reference to a single value, ListProp<T>s holds a reference to a ProList<T> which is the base interface for lists in the ProLib. 
     128   * You get the number of values this Property holds by the size() method; 
     129   * You can also get the value at a valid position in the ProList<T> by the get(int index) method. 
     130  * '''RwListProp<T>''':[[BR]] 
     131  This interface extends ListProp<T> and in analogy with RwProp<T>, provides read-write access to the ProList<T> which is the RwListProp<T> holds. 
     132   * You can add elements at the end of the underlying ProList<T>, remove a given element from it, or change a given element at a valid position by using the add(T element), set(int index, T element) and remove(int index) methods respectively. 
     133  * '''Property<T>''':[[BR]] 
     134  This is the base abstract implementation of the Prop<T> interface. 
     135   * It allows you to set an initial value to the Property by the init() method. [[BR]] 
     136   You should extend this class if you want to provide new Property kinds in the ProLib, like MapProperty for instance (good luck and God bless you if you do it (: ). 
     137  * '''ObjectProperty<T>''':[[BR]] 
     138  This class extends Property<T> and provides the base usable implementation of Prop<T> used for dealing with single object values. 
     139   * It implements the get() logic. 
     140   You should use this class when you need single Properties which you only need to initialize and get. 
     141  * '''ListProperty<T>''':[[BR]] 
     142  This is the base abstract implementation of the ListProp<T> interface. 
     143   * It provides basic get(), get(int index) and size() implementation. 
     144   You should extend this class if you want to provide new ListProperty kinds in the ProLib, like SkipListProperty (which internally uses skiplists) for instance (again, good luck and God bless (: ). 
     145    
     146==== Single Properties (BLUE) ==== 
     147 These are classes which extend ObjectProperty<T> and thus inherit its capabilities, though they implement specific behavior for specific purposes. 
     148  * '''ValueProperty<T>''':[[BR]] 
     149   This Property is the equvalent to a Java field of type T which allows getting and setting a value. The different thing is that any Property A which depends on a ValueProperty B gets notified when B changes and thus A can update accordingly. Sample usage was already shown in the rectangle example above: 
     150{{{ 
     151... 
     152    RwProp<Integer> width() { 
     153        return getBean().makeValueProp("width", Integer.class); 
     154    } 
     155... 
     156}}} 
     157    So, this is actually a Java method which returns a RwProp of Integer. The previously awkward return statement is now more clear: it instructs the ProBean of the ProObject to create a new ValueProperty with the name ''width'' which has a value of type ''Integer''. Other Properties are created in a similar fashion as is described later.[[BR]] 
     158    Thus, when you want to set or get the value of this Property you just use the set() and get() methods like in the demoCode() method above. 
     159  * '''FinalProperty<T>''':[[BR]] 
     160   This Property is somewhat analogical to the '''final''' fields in Java. You can set the value of a FinalProperty only once, though not it's not mandatory to do it in the constructor of the ProObject.[[BR]] 
     161   Such Properties are intended to be used in cases where some user action leads to set the value of a given Property exactly once. This is different than ''const'' AutoProperties as described below. 
     162  * '''AutoProperty<T>''':[[BR]] 
     163  This Property is one of the most commonly used and convenient Properties the ProLib offers.[[BR]] 
     164  Basically this is a Property which has a value which is computed directly from the values of some other Properties. In a way, the developer sets the logic of the computation of the AutoProperty's value in a declarative manner and the actual computation of the value is done automatically. Even more, the when some of the Properties on which the AutoProperty depends change their value, the AutoProperty automatically recomputes its value which is very convenient. This saves the developer the hassle of manually implementing some Observer like functionality in all objects a certain Java field X would logically depend and then manually notifying X when they've changed so X can then be manually forced to recompute. 
     165 
     166 So, like inside the Rectangle example, the area() AutoProperty is implemented like this: 
     167{{{ 
     168    Prop<Integer> area() { 
     169        class area extends AutoProperty<Integer> { 
     170            @Override 
     171            protected Integer compute() { 
     172                Integer res = width().get() * height().get(); 
     173                    return res; 
     174                } 
     175            } 
     176        } 
     177 
     178        return getBean().makeProp(area.class); 
     179    } 
     180}}} 
     181 In order to create an AutoProperty, by convention you declare a method structure like the structure of the area() method which declares a local class which extends the AutoProperty class. The type argument of the local class should be identical to the type argument of the Prop which the area() method returns - after all an AutoProperty is a Property which computes a given value following some logic and that value has a type which in our case is Integer.[[BR]] 
     182 So you override the compute() method to provide the AutoProperty's value computation logic inside. You can provide an arbitrary complex logic inside. In this example whenever the width() and height() Properties change their value, the AutoProperty is smart enough to call the compute() method again and update its value.[[BR]] 
     183 '''Something very important:''' compute() will be recomputed only in the cases when some of the '''Properties''' used inside it change their value!! If compute() depends on some normal Java field, there's no way for the ProLib to know when this field has changed its value and then notify the AutoProperty to change its value!! '''There's no magic here!!''' Expecting the ProLib to detect that means hooking to JVM's system events and maybe bytecode instrumentation which obviously we don't want to use (: 
     184   * Actually, AutoProperties have a '''doSet()''' method, which can be overriden to provide setting manually a value of a given AutoProperty. This can be used in ''very rare cases'' when you have an AutoProperty X which depends on other Properties but also there's an AutoProperty Y which depends on X. So let's say that we need Y to have a valid value but at this stage of execution of our program we don't have all the Properties which X depends on initialized. That's when we can manually set the value of X, so Y gets property computed, and later, when all the Properties X depends on initialize, then X gets recomputed and Y respectively.[[BR]] 
     185    This should be used very rarely, so if you think you need this, consult first with someone else (: 
     186   * There's a special case of AutoProperties which are '''const''' AutoProperties. Such AutoProperties depend on some other Properties, but their value should be computed only once. 
     187    For instance you can have this case: 
     188{{{ 
     189    public Prop<Integer> X() { ... } 
     190    public Prop<Char> Y() { ... } 
     191    public Prop<String> Z() { ... } 
     192 
     193    @Const 
     194    @Override 
     195    public Prop<JLabel> swingComponent() { 
     196        class swingComponent extends AutoProperty<JLabel> { 
     197            @Override 
     198            protected JLabel compute() { 
     199                assert getLastValue() == null; 
     200 
     201                JLabel res = new JLabel(); 
     202                res.setBackground(Color.green); 
     203                res.setText("text is " + X().get() + ", " + Y().get() + ", " + Z().get()); 
     204         
     205                return res; 
     206            } 
     207        } 
     208 
     209    return getBean().makeProp(swingComponent.class); 
     210} 
     211}}} 
     212    In this case the AutoProperty swingComponent() depends on X(), Y(), Z(), provide some relatively complex initializing logic in the compute() method and you want to make sure this component is created only once. Thus: 
     213    * You'll be happy if you don't want to worry about when X(), Y() and Z() get initialized and this way the ProLib can do it for you, 
     214    * You can capsulate the initialization logic in the compute() method so your ProObject constructor doesn't get bloated with it instead, 
     215    * By convention you insert ''assert getLastValue() == null;'' assertion which makes sure that the Property is still not initialized by the time the compute() method is called (which means that it's value is still null). 
     216    * Also by convention, you annotate such AutoProperties with '''@Const'''. 
     217 
     218 
     219  * '''ResourceProperty<T>''':[[BR]] 
     220   '''Important note:''' ResourceProperties just share partially their name with Resources. They are totally different concepts so don't mix them. 
     221   This Property is something like advanced AutoProperty. It wraps some nonProLib entity like a Swing Component, for instance, and manages creation, destruction and updating of this entity, so it's something like an AutoProperty-like bridge between nonProLib entities and the ProLib and makes life easier. You create a ResourceProperty<T> in a similar fashion to creating AutoProperties<T> though there are more methods to override: 
     222   * There's a '''create()''' method which is responsible for the initial creation of the managed entity. You should provide custom (maybe quite complex) creation logic here. 
     223   * There's a '''destroy()''' method which is responsible for the destruction of the managed entity. Currently it doesn't work very well, though it is intended to provide destruction logic like closing streams, freeing memory etc. 
     224   * There is a '''setup()''' method which is very similar to the '''compute()''' method of AutoProperties - each time something the ResourceProperty X depends on changes, X's setup() method gets invoked so X can update accordingly. 
     225 
     226   * Here's an example: 
     227{{{ 
     228    ... 
     229 
     230    @Override 
     231    public Prop<JButton> swingComponent() { 
     232        class swingComponent extends ResourceProperty<JButton> { 
     233            @Override 
     234            protected JButton create() { 
     235                JButton res = new JButton(); 
     236                res.addActionListener(new ActionListener() { 
     237                    @Override 
     238                    public void actionPerformed(final ActionEvent e) { 
     239                        userClick(); 
     240                    } 
     241                }); 
     242             
     243                return res; 
     244            } 
     245 
     246            @Override 
     247            protected void setup(JButton res) { 
     248                Icon icon = icon().get().toIcon(); 
     249                res.setIcon(icon); 
     250                Dimension sz = size().get().toDimension(); 
     251                res.setPreferredSize(sz); 
     252                res.setSize(sz); 
     253                res.setToolTipText(toolTip().get()); 
     254            } 
     255 
     256            @Override 
     257            protected void destroy(JButton res) { 
     258                // nothing 
     259            } 
     260 
     261        } 
     262 
     263        return getBean().makeProp(swingComponent.class); 
     264    } 
     265 
     266    ... 
     267}}} 
     268    * Further more, the setup() method can be "split" in pieces by the '''@Setup''' annotation. In the ResourceProperty descendant class you provide, swingComponent in our case, you can provide a multitude of methods which are annotated with @Setup and together they form the logic for updating the ResourceProperty. This is useful form performance reasons, because let's say you've got a very heavy setup() method which consists of logically independent parts P1 and P2, and P1 depends on some Property X while P2 doesn't depend on X so when X changes, P2 doesn't need to be executed again. Thus, providing two new setup methods which correspond to P1 and P2 leads to performance optimization (and capsulation of independent code in different methods) because the ProLib is smart enough to invoke only the needed setup methods. 
     269    For example the above setup() method can be split like this: 
     270{{{ 
     271... 
     272            @Setup 
     273            protected void setupIcon(JButton res) { 
     274                Icon icon = icon().get().toIcon(); 
     275                res.setIcon(icon); 
     276            } 
     277 
     278            @Setup 
     279            protected void setupSize(JButton res) { 
     280                Dimension sz = size().get().toDimension(); 
     281                res.setPreferredSize(sz); 
     282                res.setSize(sz); 
     283            } 
     284 
     285            @Setup 
     286            protected void setupToolTipText(JButton res) { 
     287                res.setToolTipText(toolTip().get()); 
     288            } 
     289... 
     290}}} 
     291 
     292==== Multi Properties (RED) ==== 
     293 The following Properties are all the current multi Properties, so they both implement RwProp<T> and extend ListProperty<T>. 
     294 '''Important remark''': Actually ListProperty<T> implements RwProp<ProList<T>>. ProList<T> is the base List interface intended to be used in the ProLib so what this means is that ListProperties actually hold one single value which is a List, and not multiple values. This List is actually a ProList and as the ListProperty is initialized a ProList instance is created and it doesn't change over time compared to the value instance of normal Properties which can change over time. From a client point of view you don't need to know internal specifics of Pros and ProLists, though if you want to use ListProperties effectively, you should read the Pros and ProLists section below. 
     295 * '''ValueListProperty<T>''' 
     296  This is the most basic ListProperty. It's analogical to ValueProperty in the sense you can set and get the values. 
     297  * This Property implements add, remove and set behavior by using the '''add(T element)''', '''remove(int index)''' and '''set(int index, T value)''' methods. 
     298  * It also has a '''getInitContents()''' method which you can override to specify a List<T> of initial content for the ListProperty when it's initialized. 
     299  Here's an example: 
     300{{{ 
     301... 
     302    public RwListProp<String> items() { 
     303        class Items extends ValueListProperty<String> { 
     304            @Override 
     305            protected List<String> getInitContents() { 
     306                return Arrays.asList("dog", "cat", null, "parrot"); 
     307            } 
     308        } 
     309         
     310        return getBean().makeListProp(Items.class); 
     311    } 
     312... 
     313}}} 
     314  
     315 * '''AutoListProperty<T>''' 
     316  This Property is analogical to AutoProperty, though it works with an underlying list of values. Basically, in a similar fashion to AutoProperty, you override one method where you specify the logic of computing the List of values and that List gets updated when any of the Properties it depends on change. 
     317  * You should override the '''constructList()''' method to return a ProList<T> and inside you specify the computing logic. Actually, there are a multitude of ProList<T> implementations which you can use and one of them is the ComposingProList<T> which is used in the example below. In the Pros and ProLists section below, you'll get the details. In the example below there is an AutoListProperty names() which depends on the Properties janitor(), president() and alcoholic() and basically returns a List of all these Properties' values. Whenever any of these changes, names() gets recomputed. 
     318  Here's the example: 
     319{{{ 
     320... 
     321    RwProp<String> janitor() { ... } 
     322    RwProp<String> president() { ... } 
     323    RwProp<String> alcoholic() { ... } 
     324 
     325    public ListProp<String> names() { 
     326        class names extends AutoListProperty<String> { 
     327            @Override 
     328            protected ProList<String> constructList() { 
     329                return new ComposingProList<String>() { 
     330                    @Override 
     331                    protected List<String> computeData() { 
     332                        return Arrays.asList(janitor().get(), president().get(), alcoholic().get()); 
     333                    } 
     334                }; 
     335            } 
     336        } 
     337                 
     338        return getBean().makeProp(names.class); 
     339    } 
     340... 
     341}}} 
     342 
     343== Pros and ProLists == 
     344'''Note''': For a more basic usage of the ProLib, you don't need to read this. If you do want to understand and use ListProperties effectively, then read (: 
     345 
     346[[Image(source:branches/private/gogov/PRO_LIB_CORE_TUTORIAL_R1/sophie2-platform/modules/org.sophie2.core/src/test/resources/Pros And ProLists.png)]] 
     347 
     348=== Interfaces(PURPLE) === 
     349So, these are the most fundamental interfaces in the ProLib. 
     350 * '''Pro''':[[BR]] 
     351  This is '''THE''' most fundamental interface in the ProLib though if you don't refactor the ProLib, you'll most probably never need to know it exists. [[BR]] 
     352  Basically a Pro is something which implements an Observer-like behavior so ProListeners can be attached and detached to/from it. So again, there's no magic in the ProLib, just some smart concepts, and actually detecting dependencies, automatically solving initialization order problems and getting automatic updates is implemented with the help of this Observer-like behavior laid down at the very foundations of the ProLib (: 
     353 
     354 * '''Prop<T>''':[[BR]] 
     355  Prop<T> was already mentioned, though here we'll add that Prop<T> actually extends Pro so it's also trackable for changes which means that all Properties can be tracked when they and respectively their value changes so that's how the magic happens. 
     356 
     357 * '''List<T>''':[[BR]] 
     358  This is simply the standard Java interface List<T> (: 
     359  
     360 * '''ProList<T>''':[[BR]] 
     361  ProList<T> extends Pro '''and''' List<T> so it's basically a List which can be tracked for changes. Now you should understand why ListProp<T> extends Prop<ProList<T>> (: 
     362 
     363=== Implementations(YELLOW) === 
     364 * '''BaseProList<T>''':[[BR]] 
     365  This is the abstract base implementation of the ProList<T> interface. From a client point of view you use it as a normal Java List<T>, though internally notifications for changes fly to interested parties and the ProLib is able to execute correctly. 
     366 
     367 All of the following extend BaseProList<T> to provide specific behaviour. 
     368 
     369 * '''EmptyProList<T>''':[[BR]] 
     370  This is just an empty ProList<T> and you cannot modify it in any way. Trying to do so will result in an UnsupprotedOperation Exception. This class is a useful shorthand for cases when you need and empty ProList, analogical to Collections.emptyList(), for instance. 
     371 
     372 * '''ValueProList<T>''':[[BR]] 
     373  This is the simplest modifiable ProList<T>. The major difference with BaseProList<T> is that ValueProList<T> allows read-write access to its values. 
     374 
     375 * '''ComposingProList<T>''':[[BR]] 
     376  This is the most powerful, yet one of the simpler ProList<T>. It is abstract, so you should provide your own descendant class and override a method if you want to use it. 
     377  * It has a '''computeData''' method, which similarly like the compute() method of the AutoProperty, defines the creation logic for its content. Now we can actually say the truth that AutoProperties, ComposingProList<T> and others actually monitor which ''Pro''s they depend on and update when any of them changes and notifies its listeners that it's changed. 
     378  * So if you take a look at the AutoListProperty example, you'll see that in the constructList() method of names() actually a new ComposingProList<T> is created and it's computeData() method is overridden to provide the custom creation logic. Very convenient. 
     379  '''Important remark''': When a Pro that a given ComposingProList<T> X depends on changes, the whole list gets constructed from scratch which is very inefficient, so this ProList should be used with caution, otherwise performance can be easily degraded. In lots of other cases another ProList<T> implementation should be used to improve performance. 
     380  
     381 * '''TrackingProList<T>''':[[BR]] 
     382  This is a ProList<T> which is something like an alias for another ProList<T>. 
     383  * It's got a '''computeSource()''' method which you should override when extending TrackingProList<T>. Inside this method you can specify a custom logic what ProList you should return. Analogical to the compute() method of AutoProperty, when the ProList X this TrackingProList Y depends on changes, then Y gets updated. 
     384   * One application of this is that you can simply return another ProList<T> inside this method which kindof makes the TrackingProList<T> an alias of the returned ProList<T>. 
     385    Here's an example from the FakeModuleRegistry: 
     386{{{ 
     387    public ListProp<SophieModule> activeModules() { 
     388        class activeModules extends AutoListProperty<SophieModule> { 
     389            @Override 
     390            protected ProList<SophieModule> constructList() { 
     391                return new TrackingProList<SophieModule>() { 
     392                    @Override 
     393                    protected ProList<SophieModule> computeSource() { 
     394                        return registeredModules().get(); 
     395                    } 
     396                }; 
     397            } 
     398        } 
     399 
     400        return getBean().makeProp(activeModules.class); 
     401    } 
     402}}} 
     403   * Another application is to provide more custom logic inside the computeSource() method, like this: 
     404{{{ 
     405    new TrackingProList<String>() { 
     406        @Override 
     407        protected ProList<String> computeSource() { 
     408            try { 
     409                ... some logic 
     410                return a ProList; 
     411            } catch (Exception e) { 
     412                return EmptyProList.get(String.class); 
     413            } 
     414        } 
     415    } 
     416}}} 
     417    Here, if the retrieval logic succeeds, some ProList is returned, though if it fails, an EmptyProList is returned which can be useful in certain cases. 
     418 
     419==== Filtering and transformations ==== 
     420 Actually, the ProLib borrows two declarative concepts from functional programming, namely map and filter. 
     421 
     422  * '''FilteringProList<T>''':[[BR]] 
     423   So I lied to you earlier - the ProList<T> interface has some more useful methods. One of them is '''ProList<T> filter(ProListFilter<T> filter)'''.[[BR]] 
     424   When this method is applied to any BaseProList<T>, it creates a '''FilteringProList<T>'''. This ProList<T> is basically a filtered view of another ProList<T>. The ProListFilter<T> is a visitor object which, given a T element, decides whether it should be filtered or not. You can create such filters by extending ProListFilter<T> and overriding its accepts() method to provide your custom logic. 
     425 
     426  * '''TransformingProList<S, T>''': (S for source, T for target) [[BR]] 
     427   Another useful method of the ProList<T> interface is '''<T> ProList<T> transform(ProListTransformer<S, T> transformer)''' (it's analogical to map in functional languages).[[BR]] 
     428   When this method is applied to any BaseProList<T>, it creates a '''TransformingProList<T>'''. This ProList<T> is basically a transformed view of another ProList<S>. The ProListTransformer<S, T> is a visitor object which, given a S element, decides how to transform it to a T object. You can create such transformers by extending ProListTransformer<S, T> and overriding its translate() method to provide your custom logic. 
     429 
     430 Now, here's an example which uses these ProLists as well as other of the ProLib stuff. It's from the EmbeddedBooksPalette. If you understand it, then you're cool (: 
     431 
     432{{{ 
     433    @Override 
     434    public ListProp<BookItem> items() { 
     435        class items extends AutoListProperty<BookItem> { 
     436            @Override 
     437            protected ProList<BookItem> constructList() { 
     438                return new TrackingProList<ResourceRef>() { 
     439                    @SuppressWarnings("synthetic-access") 
     440                    @Override 
     441                    protected ProList<ResourceRef> computeSource() { 
     442                        try { 
     443                            Book parentBook = ((OpenBooksPalette.BookItem) 
     444                                openBooksPalette().get().firstSelectedItem() 
     445                                .get()).book().get(); 
     446                            return parentBook.children().get(); 
     447                        } catch (NullPointerException e) { 
     448                           return EmptyProList.get(ResourceRef.class); 
    76449                        } 
     450                    } 
     451                }.filter(new ProListFilter<ResourceRef>() { 
     452                    @Override 
     453                    public boolean accepts(ResourceRef item) { 
     454                        return item.get(Resource.class) instanceof Book; 
     455                    } 
     456                }).transform(new ProListTransformer<ResourceRef, BookItem>() { 
     457                    @Override 
     458                    public BookItem translate(ResourceRef source) { 
     459                        BookItem res = new BookItem(); 
     460                        res.book().set(source.get(Book.class)); 
     461                        return res; 
     462                    } 
     463                }); 
     464            } 
     465        } 
     466         
     467        return getBean().makeProp(items.class); 
     468    } 
     469}}} 
     470 
     471== @Own & ParentProperties == 
     472So, you've noticed I missed describing the pink ParentProperty in the Properties section (: Good for you, it shows that you read carefully. 
     473 
     474[[Image(source:branches/private/gogov/PRO_LIB_CORE_TUTORIAL_R1/sophie2-platform/modules/org.sophie2.core/src/test/resources/Parent Property.png)]] 
     475 
     476 * '''ParentProperty''':[[BR]] 
     477  In many cases you've got an object which you want to have another object as a parent. So there are ProObjects and ParentProperty<T extends ProObject>. Note that T extends ProObject so each parent of a ProObject must be a ProObject. 
     478  * With the ProLib, parents are set automatically via the @Own annotation. 
     479{{{ 
     480class Person implements ProObject { 
     481... 
     482    @Override 
     483    public Prop<Meddle> parent() { 
     484        return getBean().makeParentProp(Meddle.class); 
     485    } 
     486... 
     487} 
     488 
     489class Meddle implements ProObject { 
     490... 
     491    @Own 
     492    Prop<Person> jesus() { ... } 
     493... 
     494} 
     495}}} 
     496   So jesus() is a Property which returns a Person object. But let's say that we want to "bind" this jesus Property only to one Meddle, so other Meddles couldn't get the same Person object, which jesus() holds, to be "bound" to them. So, each Person much declare a ParentProperty<Meddle> like in the example. In the Meddle object, the jesus() property is annotated with '''@Own'''. So the ProLib takes care for two things: 
     497   * Sets the parent() Property of the Person hold by the jesus() Property, to the concrete Meddle instance. 
     498   * And also makes sure that other Meddles cannot "own" the same jesus(). [[BR]] 
     499  These two things actually mean that that ''each Meddle has its oooown... peeeersonal... jeeesus'' (: 
     500 
     501== @Shared & ProUtil.clone() == 
     502There's a useful util class called '''ProUtil'''. It contains various methods which ease ProLib usage. 
     503 * The ProUtil.clone() method is responsible for cloning a ProObject into a new ProObject which is needed in certain cases. So, standard questions arise like whether to do deep copying or not. For instance: 
     504{{{ 
     505class Sheep implements ProObject { 
     506... 
     507    @Shared 
     508    Prop<BankAccount> account() { ... } 
     509... 
     510} 
     511}}} 
     512  When you clone this Sheep, the question what to do with all the Sheep's Properties arise. In the case of @Shared, when the Sheep dolly1 is cloned, the new Sheep dolly2's account() will hold the same BankAccount which dolly1 has.[[BR]] 
     513 In this context we should mention that the ProLib also makes sure that if account was @Own instead of @Shared, then dolly2 won't have the same BankAccount (: 
     514 
     515== @Immutable == 
     516This is an annotation which is used to mark a given class as immutable - once it's created, it doesn't change.[[BR]] 
     517In the next section you'll see why this is needed by the ProLib.[[BR]] 
     518'''Note''': The ProLib doesn't ''ensure'' that object annotated as @Immutable change because this is equal (again) to doing bytecode instrumentation. It is just a convention which has to be followed. 
     519 
     520== ProObjects, @Immutables and junk == 
     521In OOP there are two kinds of objects - mutable and immutable. In the ProLib mutable objects are intended to be only ProObjects and immutable objects should either be annotated with @Immutable or expand the list of ''known'' immutables in the ProLib which currently is limited to standard JDK immutables like Integer, Double etc. Why is this important: 
     522 
     523[[Image(source:branches/private/gogov/PRO_LIB_CORE_TUTORIAL_R1/sophie2-platform/modules/org.sophie2.core/src/test/resources/ProObjects And Immutables.png)]] 
     524 
     525This is an example how the dependency graph between ProObjects should look. 
     526 * It should contain cycles, otherwise we can never initialize this graph. 
     527 * An Immutable shouldn't depend on anything. 
     528 * ProObjects could depend on other ProObjects and Immutables. 
     529 * The leafs of this acyclic graph should be Immutables. 
     530 
     531  If a ProObject A depends by a Prop<X> P on some object X which doesn't depend on anything, then there are two cases: 
     532  * X is immutable. Then when someone changes P, it would be through P's interface so the ProLib can detect this change and A can get notified that X has changed. 
     533  * X is mutable and ProObject. X can change in two ways: 
     534   * A Property Q of X has changed. Then P would detect when X's Q changes and A would get notified about it. 
     535   * The same as the above but Q is a normal Java field. Well, nothing conventional can be done to detect when Q changes, so we're screwed, so '''don't use normal Java fields in ProObjects, unless you're sure what you're doing'''. 
     536  * X is mutable but is not a ProObject. In this case obviously nothing can be automatically done by the ProLib to detect when X changes. 
     537 
     538 This means that you should follow the rules above in order to produce non-flawed ProLib code. In general you can use ProObject, Immutables and the rest is junk (: 
     539 
     540== ProLists, findOne(), findAll(), ProUtil.getKey() and ListEntry == 
     541Let's have this case: 
     542{{{ 
     543... 
     544class Party implements ProObject { 
     545    public ListProp<Person> people() { ... } 
     546 
     547    public ListProp<Person> invitedPeople() { 
     548        class invitedPeople extends AutoListProperty<Person> { 
     549            @Override 
     550            protected ProList<Person> constructList() { 
     551                return new ComposingProList<Person>() { 
     552                    @Override 
     553                    protected ProList<Person> computeData() { 
     554                        ArrayList<Person> res = new ArrayList<Person>(); 
     555                        for (Person person : people().get()) { 
     556                            if (person.getName() == "Meddle") { 
     557                                res.add(person); 
     558                            } 
     559                        }; 
     560                    } 
    77561                } 
    78                 return getBean().makeReadProp(scrollPane.class); 
    79         } 
    80 }}} 
    81  
    82  
    83  * !ResourceProperty 
    84 {{{ 
    85         public Prop<JMenu> swingMenu() { 
    86                 class swingMenu extends ResourceProperty<JMenu> { 
    87  
    88                         @Override 
    89                         protected JMenu create() { 
    90                                 return new JMenu(); 
    91                         } 
    92  
    93                         @Override 
    94                         protected void destroy(JMenu resource) { 
    95                                 // TODO Auto-generated method stub 
    96                                  
    97                         } 
    98  
    99                         @Override 
    100                         protected void setup(JMenu res) { 
    101                                 List<MenuMember> data = items().get(); 
    102                                 assert data.size() == 0 || Collections.frequency(data, data.get(0)) == 1 : data; 
    103                                  
    104                                 res.removeAll(); 
    105                                 for(MenuMember m : data) { 
    106                                         res.add(m.swingMenu().get()); 
    107                                 } 
    108                         } 
     562            } 
     563        } 
     564 
     565        return getBean().makeProp(invitedPeople.class); 
     566    } 
     567... 
     568}}} 
     569 
     570So, in this example you want to get the List of all invited people to your party, invite only people whose name is "Meddle" and update this list when a potential candidate to come to the party is added. This is kinda slow though, because each time a new Person is added to People, I don't want to reconstruct the whole invitedPeople list. 
     571 
     572ProLists are smart though so they act not only as lists but as maps. In the ProLib there is the concept of ''keys'' when using ProList, depending on what kind of items are inside: 
     573 * Immutables -- the ''key'' of an Immutable is the Immutable itself, 
     574 * ListEntries -- there is a ListEntry class which is basically a pair of a key and a value. The ''key'' of a ListEntry is its key (: 
     575 * others -- ''key'' is always null. 
     576 
     577You can get the ''key'' of a given object by using the ProUitl.getKey() method. 
     578 
     579ProLists check if they're working with ListEntry descendants, so you can subclass ListEntry to improve the above example like this: 
     580 
     581{{{ 
     582... 
     583class Party implements ProObject { 
     584    static class PersonEntry extends ListEntry { 
     585        PersonEntry(String name, ... ) { ... } 
     586 
     587        Object getKey() { return name; } 
     588        Object getValue() { ... } 
     589    } 
     590 
     591    public ListProp<PersonEntry> people() { ... } 
     592 
     593    public ListProp<PersonEntry> invitedPeople() { 
     594        class invitedPeople extends AutoListProperty<PersonEntry> { 
     595            @Override 
     596            protected ProList<PersonEntry> constructList() { 
     597                return new ComposingProList<PersonEntry>() { 
     598                    @Override 
     599                    protected ProList<PersonEntry> computeData() { 
     600                        return people().findAll("Meddle"); 
     601                    } 
    109602                } 
    110                 return getBean().makeReadProp(swingMenu.class); 
    111         } 
    112 }}} 
    113  
    114  * !ParentProperty 
    115 {{{ 
    116         public RwProp<Page> parent() { 
    117                 return getBean().makeParentProp(Page.class, "frames"); 
    118         } 
    119 }}} 
    120  
    121  * !UndoProperty 
    122 {{{ 
    123         public UndoProperty undoManager() { 
    124                 return getBean().makeUndoProperty(); 
    125         } 
    126 }}} 
    127  
    128 ==== Methods To Use ==== 
    129 These are methods of the !ProBean class. 
    130  * Creates a read-write value prop by given property class. 
    131 {{{ 
    132         public <T> RwProp<T> makeRwProp(Class<? extends ObjectProperty<T>> cl) { 
    133                 return makeProp(cl); 
    134         } 
    135 }}} 
    136  
    137  * Creates a read-only prop by given property class. 
    138 {{{ 
    139         public <T> Prop<T> makeReadProp(Class<? extends Property<T>> cl) { 
    140                 // XXX access exposure 
    141                 return makeProp(cl); 
    142         } 
    143 }}} 
    144  
    145  * Makes (or returns if already made) a simple value property by the given information. 
    146 {{{ 
    147         public <T> RwProp<T> makeValueProp(String id, Class<T> valueClass) { 
    148                 return getData().makeValueProp(id, valueClass); 
    149         } 
    150 }}} 
    151  
    152 or  
    153  
    154 {{{ 
    155         public <T> RwProp<T> makeValueProp(String id, Class<T> valueClass, 
    156                         T initValue) { 
    157                 return getData().makeValueProp(id, valueClass, initValue); 
    158         } 
    159 }}} 
    160  
    161  * Creates a children property. 
    162 {{{ 
    163         public <T extends ProObject> ChildrenProperty<T> makeChildProp(String id, 
    164                         Class<T> childClass) { 
    165  
    166                 return getData().makeChildProp(id, childClass); 
    167         } 
    168 }}} 
    169  
    170  * Creates a parent property. 
    171 {{{ 
    172         public <T extends ProObject> ParentProperty<T> makeParentProp( 
    173                         Class<T> parentClass, String childPropId) { 
    174                 return getData().makeParentProp(parentClass, childPropId); 
    175         } 
    176 }}} 
    177  
    178  * Creates a list property. 
    179 {{{ 
    180         public <T> RwListProp<T> makeListProp(String id, Class<T> elementClass) { 
    181                 return getData().makeListProp(id, elementClass); 
    182         } 
    183 }}} 
    184  
    185 or 
    186  
    187 {{{ 
    188         public <T> RwListProp<T> makeListProp( 
    189                         Class<? extends ListProperty<T>> propClass) { 
    190                 return makeProp(propClass); 
    191         } 
    192 }}} 
    193  
    194  * Makes (or returns if already created) a final property (whose value may be written only once). 
    195 {{{ 
    196         public <T> Prop<T> makeFinalProp(String id, Class<T> valueClass) { 
    197                 return getData().makeFinalProp(id, valueClass); 
    198         } 
    199 }}} 
    200  
    201  * Creates (or returns if already have) an undo manager of this bean. 
    202 {{{ 
    203         public UndoProperty makeUndoProperty() { 
    204                 return getData().makeUndoProperty(); 
    205         } 
    206 }}} 
     603            } 
     604        } 
     605 
     606        return getBean().makeProp(invitedPeople.class); 
     607    } 
     608... 
     609}}} 
     610 
     611Here the '''E findAll(Object key)''' method of ProList<E> is used which basically returns all elements in the list which have the specified key. 
     612 
     613The difference here is that ProLib is smart enough to recompute invitedPeople() only when another PersonEntry with key "Meddle" is entered, such is removed or modified. Otherwise it doesn't make sense to recompute because the list hasn't changed if for instance you've added a PersonEntry with key "Christ". 
     614 
     615'''E findOne(Object key)''' is the same but it expects to find at most one element with the specified key and returns it. If there are more than one, an Exception is thrown. 
    207616 
    208617=== Bad Code Examples === 
    209  
    210618 * Resource Property is a better choice. 
    211  
    212619{{{ 
    213620        public Prop<JComponent> swingComponent() { 
     
    230637}}} 
    231638 
    232 == Demo == 
    233  * Tutorial unit test demonstrating the usage of !AutoProperty 
    234 [[Include(source:/trunk/sophie2-platform/modules/org.sophie2.core/src/test/java/org/sophie2/core/prolib/tutorial/AutoPropertyDemo.java)]] 
    235  
    236 == How to apply properties to Sophie 2.0 == 
    237  * To get rid of the fields, except for immutable classes, and public static final things. 
    238   * Note that final instance fields are not so safe, because they are initialized after the super constructors. 
    239  * To convert mutable classes to !ProObjects 
    240  * To gather more requirements to the properties library and apply them 
    241  * To keep the properties library with high quality, because everything else will depend on it. 
    242  * To be careful of cyclic dependencies (like a = b + 1, b = a + 1). No library can solve them. 
    243  
    244 = Comments = 
    245  * The tutorial should be updated with the new things about properties - @Own annotation, deprecation of ChildrenProperty, etc. --boyan@2009-01-12 
     639== Debugging ProLib == 
     640Some advice: 
     641 * Print. Debugging with a debugger is uglier that usual. 
     642 * Run the tests before commit. Don't break tests. 
     643 * Use the Inspector - this is a GUI tool that allows browsing the Properties in the application while it's running. 
     644 
     645== Good Practices  == 
     646 * Use ProObject and Immutables when using the ProLib. The rest is junk. Although if you know what you're doing, you can find useful stuff in the junk (: 
     647 * Convert mutable classes to ProObjects. 
     648 * Keep the ProLib and with high quality, because everything else will depend on it. 
     649 * Be careful not to create cyclic dependencies (like a = b + 1, b = a + 1). No library can solve them. 
     650 
     651== TODO == 
     652 * init final property with constant which isn't an argument of the constructor 
     653 * finalproperty.init(new stuff())