Trace:
Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision Next revision Both sides next revision | ||
jvx:reference [2020/06/10 12:14] cduncan [The Factory] |
jvx:reference [2020/06/15 09:57] cduncan [Where Are the Data Pages?] |
||
---|---|---|---|
Line 18: | Line 18: | ||
===== The Patterns ===== | ===== The Patterns ===== | ||
- | [[https://en.wikipedia.org/wiki/Factory_%28object-oriented_programming%29|The factory pattern]] is an important pattern in [[https://en.wikipedia.org/wiki/Object-oriented_programming|Object-oriented programming]] It empowers us to delegate the creation of objects to another object that is not known at design and/or compile time. That allows us to use objects which have not been created by us but merely “provided” to us by an unknown-to-us source. | + | [[https://en.wikipedia.org/wiki/Factory_%28object-oriented_programming%29|The factory pattern]] is an important pattern in [[https://en.wikipedia.org/wiki/Object-oriented_programming|object-oriented programming]] It empowers us to delegate the creation of objects to another object that is not known at design and/or compile time. That allows us to use objects which have not been created by us but merely “provided” to us by an unknown-to-us source. |
[[https://en.wikipedia.org/wiki/Bridge_pattern|The bridge pattern]], on the other hand, describes a technique which wraps implementations in another implementation and forwards all or most functionality to that wrapped implementation. This allows us to mix and match functionality without the need to have it in all implementations at once. | [[https://en.wikipedia.org/wiki/Bridge_pattern|The bridge pattern]], on the other hand, describes a technique which wraps implementations in another implementation and forwards all or most functionality to that wrapped implementation. This allows us to mix and match functionality without the need to have it in all implementations at once. | ||
Line 39: | Line 39: | ||
==== Extension ==== | ==== Extension ==== | ||
- | Next comes the extension layer. Components from the technology are extended to support needed features of [[https://sourceforge.net/projects/jvx/|JVx]]. This includes creating bindings for the databook, additional style options, and changing of behavior, if necessary. From time to time, this also includes creating components from scratch if the provided ones do not meet the needs or there simply are none with the required functionality. For the most part, we do our best that these layers can be used without [[https://sourceforge.net/projects/jvx/|JVx]], meaning that they represent a solitary extension to the technology. A very good example is our JavaFX implementation, which compiles into two separate jars, the first being the complete [[https://sourceforge.net/projects/jvxfx/|JVx/JavaFX]] stack, the second being stand-alone JavaFX extensions that can be used in any application and without [[https://sourceforge.net/projects/jvx/|JVx]]. | + | Next comes the extension layer. Components from the technology are extended to support needed features of [[https://sourceforge.net/projects/jvx/|JVx]]. This includes creating bindings for the databook, additional style options, and changing of behavior, if necessary. From time to time, this also includes creating components from scratch if the provided ones do not meet the needs, or there simply are none with the required functionality. For the most part, we do our best that these layers can be used without [[https://sourceforge.net/projects/jvx/|JVx]], meaning that they represent a solitary extension to the technology. A very good example is our JavaFX implementation, which compiles into two separate jars, the first being the complete [[https://sourceforge.net/projects/jvxfx/|JVx/JavaFX]] stack, the second being stand-alone JavaFX extensions that can be used in any application and without [[https://sourceforge.net/projects/jvx/|JVx]]. |
Theoretically, one can skip this layer and directly jump to the implementation layer, but, so far, it has proven necessary (for cleanliness of the code, object structure, and sanity reasons) to create a separate extension layer. | Theoretically, one can skip this layer and directly jump to the implementation layer, but, so far, it has proven necessary (for cleanliness of the code, object structure, and sanity reasons) to create a separate extension layer. | ||
Line 138: | Line 138: | ||
===== The Factory ===== | ===== The Factory ===== | ||
- | The heart piece of the UI layer is the factory that is creating the implemented classes. It’s a rather simple system, a singleton which is set to the Technology specific implementation and can be retrieved later: | + | The heart piece of the UI layer is the factory that is creating the implemented classes. It’s a rather simple system, a singleton which is set to the technology-specific implementation and can be retrieved later: |
<code java> | <code java> | ||
Line 166: | Line 166: | ||
It “just returns new objects” from the implementation layer. That’s about it when it comes to the factory, it is as simple as that. | It “just returns new objects” from the implementation layer. That’s about it when it comes to the factory, it is as simple as that. | ||
- | ===== Piecing it together ===== | + | ===== Piecing It Together ===== |
With all this in mind, we know now that [[https://sourceforge.net/projects/jvx/|JVx]] has swappable implementations underneath its UI layer for each technology it utilizes: | With all this in mind, we know now that [[https://sourceforge.net/projects/jvx/|JVx]] has swappable implementations underneath its UI layer for each technology it utilizes: | ||
Line 172: | Line 172: | ||
{{:jvx:reference:multi-layers.png?nolink|Multiple Extensions/Implementations/Technologies can be used}} | {{:jvx:reference:multi-layers.png?nolink|Multiple Extensions/Implementations/Technologies can be used}} | ||
- | Changing between them can be as easy as setting a different factory. I say “can”, because that is only true for Swing, JavaFX and similar technologies, Vaadin, obviously, requires some more setup work. I mean, theoretically one could embed a complete application server and launch it when the factory for Vaadin is created, allowing the application to be basically stand-alone and be started as easily as a Swing application. That is possible. | + | Changing between them can be as easy as setting a different factory. I say “can” because that is only true for Swing, JavaFX, and similar technologies. Vaadin, obviously, requires some more setup work. Theoretically, one could embed a complete application server and launch it when the factory for Vaadin is created, allowing the application to be basically stand alone and started as easily as a Swing application. That is possible. |
===== What else? ===== | ===== What else? ===== | ||
- | That is how [[https://sourceforge.net/projects/jvx/|JVx]] works in regards to the UI layer. It depends on “technology specific stacks” which can be swapped out and implemented for pretty much every GUI framework out there. We currently provide support for Swing, JavaFX and Vaadin, but we also had implementations for GWT and Qt. Additionally we do support a “headless” implementation which uses lightweight objects which can be serialized and send over the wire without much effort. | + | That is how [[https://sourceforge.net/projects/jvx/|JVx]] works in regards to the UI layer. It depends on “technology-specific stacks”, which can be swapped out and implemented for pretty much every GUI framework out there. We currently provide support for Swing, JavaFX, and Vaadin, but we also had implementations for GWT and Qt. Additionally, we support a “headless” implementation, which uses lightweight objects that can be serialized and send over the wire without much effort. |
- | ===== Adding a new Technology ===== | + | ===== Adding a New Technology ===== |
- | Adding support for a new Technology is as straightforward as one can imagine, simply creating the Extensions/Implementations layers and implementing the factory for that Technology. Giving a complete manual would be out for scope for this document, but the most simple approach to adding a new stack to [[https://sourceforge.net/projects/jvx/|JVx]] is to start with stubbing out the ''%%IFactory%%'' and implementing ''%%IWindow%%''. Once that one window shows up, it’s just implementing one interface after another in a quite straightforward manner. And in the end, your application can switch to yet another GUI framework without the need to change your code. | + | Adding support for a new technology is as straightforward as one can imagine: simply create the extensions/implementations layers and implement the factory for that technology. Giving a complete manual would be out for scope for this document, but the most simple approach to adding a new stack to [[https://sourceforge.net/projects/jvx/|JVx]] is to start with stubbing out the ''%%IFactory%%'' and implementing ''%%IWindow%%''. Once that one window shows up, it’s just implementing one interface after another in a quite straightforward manner. In the end, your application can switch to yet another GUI framework without the need to change your code. |
===== Conclusion ===== | ===== Conclusion ===== | ||
- | Even though the stack of [[https://sourceforge.net/projects/jvx/|JVx]] is more complicated compared with other GUI or application frameworks, this complexity is set off by the benefits it brings. One can change the used GUI Technology without much effort and, most important of all, without touching the application logic at all. | + | Even though the stack of [[https://sourceforge.net/projects/jvx/|JVx]] is more complicated compared with other GUI or application frameworks, this complexity is set off by the benefits it brings. One can change the used GUI technology without much effort and, most importantly, without touching the application logic at all. |
- | ====== Resource and UIResource ====== | + | ====== Resource and UI Resource ====== |
- | Let’s talk about Resources and UIResources, and why they sound similar but are not the same. | + | Let’s talk about resources and UI resources and why they sound similar yet are not the same. |
===== The Basics ===== | ===== The Basics ===== | ||
- | We’ve [[#encapsulated_by_a_wrapper_class|encapsulated by a wrapper class]]. An “UIResource” on the other hand is an encapsulated concrete implementation of one of the interfaces on the UI layer. | + | We’ve [[#encapsulated_by_a_wrapper_class|encapsulated by a wrapper class]]. A “UI resource”, on the other hand, is an encapsulated concrete implementation of one of the interfaces on the UI layer. |
- | Let’s do a short brush-up on how the [[https://sourceforge.net/projects/jvx/|JVx]] architecture looks like in regards to the GUI stack: | + | Let’s do a short overview of how the [[https://sourceforge.net/projects/jvx/|JVx]] architecture looks like in regards to the GUI stack: |
- | {{:jvx:reference:resource.png?nolink|The JVx layers revisited. UI-Wrapper and Implementation implement the interface, Extension and Technology do not.}} | + | {{:jvx:reference:resource.png?nolink|The JVx layers revisited. UI wrapper and implementation implement the interface, extension and technology do not.}} |
- | The UI Wrappers are the main UI classes which are used to create the GUI (f.e. ''%%UIButton%%''). These are wrapping the Implementations (f.e. ''%%SwingButton%%'') which themselves are wrapping the Extension/Technology (f.e. a ''%%JVxButton%%''/''%%JButton%%''). Only the UI and Implementation classes are implementing the interface are required for the component (f.e. ''%%IButton%%''). That also means that the Implementation is dependent on the Extension/Technology component, but the UI can use any object which implements the interface. | + | The UI wrappers are the main UI classes that are used to create the GUI (e.g., ''%%UIButton%%''). These are wrapping the implementations (e.g., ''%%SwingButton%%''), which themselves are wrapping the extension/technology (e.g., a ''%%JVxButton%%''/''%%JButton%%''). Only the UI and implementation classes implementing the interface are required for the component (e.g., ''%%IButton%%''). That also means that the implementation is dependent on the extension/technology component, but the UI can use any object which implements the interface. |
- | Now, with that knowledge we can start defining what is what: | + | Now, with that knowledge, we can start defining what is what: |
- | {{:jvx:reference:resource2.png?nolink|The UI-Wrapper is the uicomponent, the Implementation is the uiresource and the Extension and Technology are the resource.}} | + | {{:jvx:reference:resource2.png?nolink|The UI wrapper is the UI component, the implementation is the UI resource, and the extension and technology are the resource.}} |
- | The resource itself, accessed by calling ''%%<uiwrapper>.getResource()%%'', is the Extension/Technology component. The uiresource can be accessed by calling ''%%<uiwrapper>.getUIResource()%%''. The uicomponent can be accessed by calling ''%%<uiwrapper>.getUIComponent()%%'' and is usually the UI Wrapper class itself. If we use our previous Swing example, the resource would be a ''%%JVxButton%%''/''%%JButton%%'', the uiresource would be the ''%%SwingButton%%'' and the uicomponent would be the ''%%UIButton%%''. | + | The resource itself, accessed by calling ''%%<uiwrapper>.getResource()%%'', is the extension/technology component. The UI resource can be accessed by calling ''%%<uiwrapper>.getUIResource()%%''. The UI component can be accessed by calling ''%%<uiwrapper>.getUIComponent()%%'' and is usually the UI wrapper class itself. If we use our previous Swing example, the resource would be a ''%%JVxButton%%''/''%%JButton%%'', the UI resource would be the ''%%SwingButton%%'' and the UI component would be the ''%%UIButton%%''. |
- | As one can see, access to all objects which are comprising the GUI is at all times possible. We, of course, have the UI component, we can access the Implementation component and we can access the Extension/Technology component. Theoretically we could also swap them at runtime, but in [[https://sourceforge.net/projects/jvx/|JVx]] this is limited to the construction of the object to greatly reduce the error potential and complexity of the framework code. | + | As one can see, access to all objects which comprise GUI possible at all times. We, of course, have the UI component, we can access the implementation component, and we can access the extension/technology component. Theoretically, we could also swap them at runtime, but in [[https://sourceforge.net/projects/jvx/|JVx]], this is limited to the construction of the object to greatly reduce the potential for error and complexity of the framework code. |
- | ===== Creating custom components ===== | + | ===== Creating Custom Components ===== |
- | We will use an example from the [[#part_about_creating_custom_components|part about creating custom components]] which we will come to later. The ''%%BeepComponent%%'' is a simple ''%%UIComponent%%'' extension which contains a label and two buttons inside itself. | + | We will use an example from the [[#part_about_creating_custom_components|part about creating custom components]], which we will come to later. The ''%%BeepComponent%%'' is a simple ''%%UIComponent%%'' extension that contains a label and two buttons inside itself. |
<code java> | <code java> | ||
Line 234: | Line 234: | ||
} | } | ||
</code> | </code> | ||
- | We are setting a new UIResource (an ''%%UIPanel%%'') in the constructor (at line #5) which is to be used by the ''%%UIComponent%%''. In this case it is not an Implementation, but another UI component, but that doesn’t matter because the UIResource only must implement the expected interface. At line #15 we start using that custom UIResource. | + | We are setting a new UI resource (a ''%%UIPanel%%'') in the constructor (at line #5), which is to be used by the ''%%UI component%%''. In this case, it is not an implementation, but another UI component. However, that doesn’t matter because the UI resource must only implement the expected interface. At line #15 we start using that custom UI resource. |
- | Because UIComponent is an abstract component designed for exactly this usage, the example might not be the most exciting one, but it clearly illustrates the mechanic. | + | Because UI component is an abstract component designed for exactly this usage, the example might not be the most exciting one, but it clearly illustrates the mechanics. |
- | ===== Bolting on functionality ===== | + | ===== Bolting on Functionality ===== |
- | Also from from the [[#part_about_creating_custom_components|part about creating custom components]] we can reuse the ''%%PostfixedLabel%%'' as example: | + | Also, from the [[#part_about_creating_custom_components|part about creating custom components]], we can reuse the ''%%PostfixedLabel%%'' as example: |
<code java> | <code java> | ||
Line 251: | Line 251: | ||
}; | }; | ||
</code> | </code> | ||
- | Now ''%%testLabel%%'' will be using the ''%%PostfixedLabel%%'' internally, but with no indication to the user of the object that this is the case. This allows to extend the functionality of a component completely transparently, especially in combination with functions which do return an ''%%UIComponent%%'' and similar. | + | Now ''%%testLabel%%'' will be using the ''%%PostfixedLabel%%'' internally but with no indication to the user of the object that this is the case. This allows us to extend the functionality of a component completely transparently, especially in combination with functions that return a ''%%UI component%%'' and similar. |
- | ===== An important note about the component hierarchy ===== | + | ===== An Important Note About the Component Hierarchy ===== |
If we create a simple component extensions, like the ''%%BeepComponent%%'' above, it is important to note that there is one other layer of indirection in regards to the hierarchy on the technology layer. If we create a simple frame with the ''%%BeepComponent%%'' in it, one might expect the following hierarchy: | If we create a simple component extensions, like the ''%%BeepComponent%%'' above, it is important to note that there is one other layer of indirection in regards to the hierarchy on the technology layer. If we create a simple frame with the ''%%BeepComponent%%'' in it, one might expect the following hierarchy: | ||
Line 268: | Line 268: | ||
\-Button | \-Button | ||
</code> | </code> | ||
- | With the BeepComponent added and its sub-components as its children. However, the actual hierarchy looks like this: | + | with the BeepComponent added and its subcomponents as its children. However, the actual hierarchy looks like this: |
<code> | <code> | ||
Line 280: | Line 280: | ||
\-Button | \-Button | ||
</code> | </code> | ||
- | That is because such extended components are not “passed” to the Technology, they do only exist on the UI layer because they do not have a Technology component which could be used. That is done by adding the ''%%UIComponent%%'' to the UI parent, but for adding the actual Technology component the set UIResource is used. | + | That is because such extended components are not “passed” to the technology; they only exist on the UI layer because they do not have a technology component which could be used. That is done by adding the ''%%UI component%%'' to the UI parent, but for adding the actual technology component, the set UI resource is used. |
- | ===== The special case of containers ===== | + | ===== The Special Case of Containers ===== |
- | Another special case are containers. For example we could create a panel which does display an overlay in certain situations and we will need to use that throughout the whole application. | + | Another special case is containers. For example, we could create a panel that displays an overlay in certain situations, and we will need to use that throughout the whole application. |
{{:jvx:reference:uiresourcecontainer.png?nolink|UIResourceContainer Example}} | {{:jvx:reference:uiresourcecontainer.png?nolink|UIResourceContainer Example}} | ||
- | That means we do not want to build it every time anew, so one option would be to use a factory method to “wrap” the content, something like this: | + | That means we do not want to build it every time anew, so one option would be to use a factory method to “wrap” the content. Something like this: |
<code java> | <code java> | ||
Line 333: | Line 333: | ||
} | } | ||
</code> | </code> | ||
- | Which is easy enough, but let’s say we’d like to add logic to that wrapper, at that point it becomes more complicated. We can’t use the same technique as for custom component from above, because in that case the “overlaying panel” would simply not be displayed. However, there is a similar mechanism for containers, setting the UIResourceContainer. | + | This is easy enough, but let’s say we’d like to add logic to that wrapper. At that point, it becomes more complicated. We can’t use the same technique as the custom component from above because, in that case, the “overlaying panel” would simply not be displayed. However, there is a similar mechanism for containers: setting the UI resource container. |
- | The UIResourceContainer is another special mechanism which works similar to setting the UIResource, but it works exactly the other way round. While setting the UIResource does “hide” components from the Technology which are there in UI layer, setting the UIResourceContainer does hide components from the UI layer while there are added in the Technology. A little bit complicated, here is our example again using this technique: | + | The UI resource container is another special mechanism that works similar to setting the UI resource, but it works the other way round. While setting the UI resource “hides” components from the technology in UI layer, setting the UI resource container hides components from the UI layer, while they are added in the technology.. As it is a little complicated, here is our example using this technique again: |
<code java> | <code java> | ||
Line 363: | Line 363: | ||
} | } | ||
</code> | </code> | ||
- | What we’ve done is extend an UIPanel (line #1), setting it up and adding children and then we’ve declared one of its children as the UIResourceContainer (line #22). So all methods which are specific to IContainer (adding children, setting a layout, etc.) are now forwarding to the innerPanel and manipulating the contents of the OverlayedPanel directly is not directly available. | + | What we’ve done is extend a UI panel (line #1), setting it up and adding children, and then we’ve declared one of its children as the UI resource container (line #22). So all methods that are specific to UI container (adding children, setting a layout, etc.) are now forwarding to the inner panel and manipulating the contents of the overlaid panel directly. |
And here is how it is used: | And here is how it is used: | ||
Line 387: | Line 387: | ||
parentContainer.add(panel, UIBorderLayout.CENTER); | parentContainer.add(panel, UIBorderLayout.CENTER); | ||
</code> | </code> | ||
- | Notice that we can use it is any other panel (line #5) and simply add it to the parent (line #18). For a user of the API it is transparent as to whether there are more components or not, this is also visible in the created component hierarchy: | + | Notice that we can use it as any other panel (line #5) and simply add it to the parent (line #18). For a user of the API, it is transparent as to whether there are more components or not. This is also visible in the created component hierarchy: |
<code> | <code> | ||
Line 411: | Line 411: | ||
===== Conclusion ===== | ===== Conclusion ===== | ||
- | Because of the way the [[https://sourceforge.net/projects/jvx/|JVx]] framework is designed, it is easy to access all layers of the GUI framework and also facilitate the usage of these layers to create custom components and allow easy access to the wrapped components, no matter on what layer or of what kind they are. | + | Because of the way the [[https://sourceforge.net/projects/jvx/|JVx]] framework is designed, it is easy to access all layers of the GUI framework and facilitate the usage of these layers to create custom components and allow easy access to the wrapped components, no matter on what layer or of what kind they are. |
====== Launchers and Applications ====== | ====== Launchers and Applications ====== | ||
- | Let’s talk about Launchers, and how they are used to start [[https://sourceforge.net/projects/jvx/|JVx]] applications. | + | Let’s talk about launchers, and how they are used to start [[https://sourceforge.net/projects/jvx/|JVx]] applications. |
- | ===== Starting an application ===== | + | ===== Starting an Application ===== |
From a technical point of view, there are two prerequisites which must be fulfilled before a [[https://sourceforge.net/projects/jvx/|JVx]] application can run: | From a technical point of view, there are two prerequisites which must be fulfilled before a [[https://sourceforge.net/projects/jvx/|JVx]] application can run: | ||
- | * the JVM must have started. | + | * The JVM must have started. |
- | * the technology specific system must have started. | + | * The technology specific system must have started. |
- | Then, and only then, the [[https://sourceforge.net/projects/jvx/|JVx]] application can run. Depending on the implementation that is used, that can be as easily as instancing the factory (Swing, JavaFX), but can also mean that a servlet server has to start (Vaadin). Because we do not wish to encumber our applications with technology specific code, we have to entrust all this to an encapsulated entity, meaning the implementations of ''%%ILauncher%%'' and ''%%IApplication%%''. | + | Then, and only then, the [[https://sourceforge.net/projects/jvx/|JVx]] application can run. Depending on the implementation that is used, that can be as easy as instancing the factory (Swing, JavaFX), but it can also mean that a servlet server has to start (Vaadin). Because we do not wish to encumber our applications with technology-specific code, we have to entrust all this to an encapsulated entity, meaning the implementations of ''%%ILauncher%%'' and ''%%IApplication%%''. |
- | ===== Following the chain ===== | + | ===== Following the Chain ===== |
The steps for getting an application to start are as follows: | The steps for getting an application to start are as follows: | ||
- | * The first thing that must run is obviously the JVM, without it we won’t have much luck starting anything. | + | * The first thing that must run is, obviously, the JVM. Without it, we won’t have much luck starting anything! |
- | * The launcher must be created and it must start the Technology. | + | * The launcher must be created, and it must start the technology. |
- | * The launcher than creates the application which the user is seeing. | + | * The launcher then creates the application, which the user is seeing. |
{{:jvx:reference:launcher.png?nolink|First the JVM starts, then the ILauncher (the window) and finally the IApplication (the content).}} | {{:jvx:reference:launcher.png?nolink|First the JVM starts, then the ILauncher (the window) and finally the IApplication (the content).}} | ||
- | So we need two classes, the ''%%ILauncher%%'' implementation which knows how to start the Technology and the ''%%IApplication%%'' implementation. That we already knew, so let’s try to put this into code. For simplicity reasons (and because I don’t want to write a complete factory from scratch for this example) we will reuse the Swing implementation and write a new launcher and application for it. | + | So we need two classes, the ''%%ILauncher%%'' implementation that knows how to start the technology and the ''%%IApplication%%'' implementation. That we already knew, so let’s try to put this into code. For simplicity reasons (and because I don’t want to write a complete factory from scratch for this example), we will reuse the Swing implementation and write a new launcher and application for it. |
- | ===== Entry point ===== | + | ===== Entry Point ===== |
- | The ''%%Main%%'' class that we will use as example is very straightforward: | + | The ''%%main%%'' class that we will use as example is very straightforward: |
<code java> | <code java> | ||
Line 457: | Line 457: | ||
} | } | ||
</code> | </code> | ||
- | All we have to do there is start the launcher itself. As the comment suggests, there might be work required for a “real” application startup. For this example, it is all we need to do. Of course we could also directly embed this little function into the launcher implementation itself, to save us one class. | + | All we have to do there is start the launcher itself. As the comment suggests, there might be work required for a “real” application startup. For this example, however, it is all we need to do. Of course, we could also directly embed this little function into the launcher implementation itself to save us one class. |
- | ===== The launcher ===== | + | ===== The Launcher ===== |
- | The ''%%ILauncher%%'' implementation on the other hand contains quite some logic, but nothing not manageable: | + | The ''%%ILauncher%%'' implementation, on the other hand, contains quite a bit of logic but nothing unmanageable: |
<code java> | <code java> | ||
Line 540: | Line 540: | ||
} | } | ||
</code> | </code> | ||
- | In short, the launcher is kicking off the Swing thread by invoking the startup method on the main Swing thread. This startup method will instantiate the factory and then create the application. From there we only need to set it visible and then our application has started. | + | In short, the launcher is kicking off the Swing thread by invoking the startup method on the main Swing thread. This startup method will instantiate the factory and then create the application. From there, we only need to set it to visible and then our application has started. |
- | The launcher extends from ''%%SwingFrame%%'', that is required because there hasn’t been a factory created yet which could be used by UI components to create themselves. If we’d try to use an UI component before creating/setting a factory, we would obviously see the constructor of the component fail with a ''%%NullPointerException%%''. | + | The launcher extends from ''%%SwingFrame%%''. That is required because there hasn’t been a factory created yet that could be used by UI components to create themselves. If we’d try to use an UI component before creating/setting a factory, we would see the constructor of the component fail with a ''%%NullPointerException%%''. |
- | The method ''%%startup()%%'' is invoked on the main Swing thread, which also happens to be the main UI thread for [[https://sourceforge.net/projects/jvx/|JVx]] in this application. Once we are on the main UI thread we can create the application, add it and then set everything to visible. | + | The method ''%%startup()%%'' is invoked on the main Swing thread, which also happens to be the main UI thread for [[https://sourceforge.net/projects/jvx/|JVx]] in this application. Once we are on the main UI thread, we can create the application, add it, and then set everything to visible. |
- | ===== The application ===== | + | ===== The Application ===== |
- | The ''%%IApplication%%'' implementation is quite short, because we extend ''%%com.sibvisions.rad.application.Application%%'', an ''%%IApplication%%'' implementation created with UI components. | + | The ''%%IApplication%%'' implementation is quite short because we extend ''%%com.sibvisions.rad.application.Application%%'', an ''%%IApplication%%'' implementation created with UI components. |
<code java> | <code java> | ||
Line 572: | Line 572: | ||
} | } | ||
</code> | </code> | ||
- | Because the launcher has previously started the technology and created the factory we can from here on now use UI components, which means we are already independent of the underlying technology. So the ''%%IApplication%%'' implementation can already be used with different technologies and is completely independent. | + | Because the launcher has previously started the technology and created the factory, we can now use UI components, which means we are already independent of the underlying technology. So, the ''%%IApplication%%'' implementation can already be used with different technologies and is completely independent. |
- | ===== Notes on the launcher ===== | + | ===== Notes on the Launcher ===== |
- | As you might have noticed, in our example the launcher is a (window) frame, that makes sense for nearly every desktop GUI toolkit as they all depend upon a window as main method to display their applications. But the launcher could also be simpler, for example just a call to start the GUI thread. Or it could be something completely different, for example an incoming HTTP request. | + | As you might have noticed, in our example the launcher is a (window) frame. That makes sense for nearly every desktop GUI toolkit, as they all depend upon a window as the main method to display their applications. But the launcher could also be simpler: for example, just a call to start the GUI thread. Or it could be something completely different: for example, an incoming HTTP request. |
- | Also don’t forget that the launcher is providing additional functionality to the application, like saving file handles, reading and writing the configuration and similar platform and toolkit dependent operations, see the [[https://sourceforge.net/p/jvx/code/HEAD/tree/trunk/java/swing/src/com/sibvisions/rad/ui/swing/impl/SwingApplication.java|launcher for Swing for further details]]. | + | Also, don’t forget that the launcher is providing additional functionality to the application, like saving file handles, reading and writing the configuration, and similar platform and toolkit-dependent operations. See the [[https://sourceforge.net/p/jvx/code/HEAD/tree/trunk/java/swing/src/com/sibvisions/rad/ui/swing/impl/SwingApplication.java|launcher for Swing for further details]]. |
===== Conclusion ===== | ===== Conclusion ===== | ||
Line 584: | Line 584: | ||
This example demonstrates how a simple launcher is implemented and why it is necessary to have a launcher in the first place. Compared with the “[[#jvx|JVx]] are of course a lot more complex than these examples, that is because they implement all the required functionality and also take care of a lot of boiler plate operations. It is taking care of all technology specific code and allows to keep your application free from knowing about the platform it runs on. | This example demonstrates how a simple launcher is implemented and why it is necessary to have a launcher in the first place. Compared with the “[[#jvx|JVx]] are of course a lot more complex than these examples, that is because they implement all the required functionality and also take care of a lot of boiler plate operations. It is taking care of all technology specific code and allows to keep your application free from knowing about the platform it runs on. | ||
- | ====== DataBooks ====== | + | ====== Databooks ====== |
- | Let’s talk about DataBooks, which allow access to data without any effort. | + | Let’s talk about databooks, which allow access to data without any effort. |
===== What is it? ===== | ===== What is it? ===== | ||
- | DataBooks are an active model, which allow you to directly query and manipulate the data. Contrary to many other systems [[https://sourceforge.net/projects/jvx/|JVx]] does not map the data into objects, but instead allows you to directly access it in a table like fashion, exposing columns, rows and values. | + | Databooks are an active model that allow you to directly query and manipulate the data. Contrary to many other systems, [[https://sourceforge.net/projects/jvx/|JVx]] does not map the data into objects, but allows you to directly access it in a table-like fashion exposing columns, rows, and values. |
- | One could say that it is like a three dimensional array, with these dimensions: | + | One could say that it is like a three dimensional array with these dimensions: |
* DataPages | * DataPages | ||
Line 598: | Line 598: | ||
* Columns/Values | * Columns/Values | ||
- | With DataPages containing DataRows, which itself contain the values and everything is referencing the RowDefinition, which outlines how a row looks like. | + | with DataPages containing DataRows, which in turn contain the values and everything referencing the RowDefinition, which further outlines how a row looks like. |
{{:jvx:reference:databook.png?nolink|DataBook Architecture, the DataBook contains DataPages, which contain DataRows.}} | {{:jvx:reference:databook.png?nolink|DataBook Architecture, the DataBook contains DataPages, which contain DataRows.}} | ||
- | ===== RowDefinition ===== | + | ===== Row Definition ===== |
- | The RowDefinition defines what columns are available in the row and stores some additional information about them, like the names of the [[https://en.wikipedia.org/wiki/Unique_key|primary key]] columns. You can think of the RowDefinition as the headers of a table. | + | The row definition defines what columns are available in the row and stores some additional information about them, like the names of the [[https://en.wikipedia.org/wiki/Unique_key|primary key]] columns. You can think of the row definition as the headers of a table. |
- | Its creation and usage is rather simple, and if you’re working with RemoteDataBooks there is no need to create one at all, as it is automatically created when the DataBook is opened. A RowDefinition holds and manages ColumnDefinitions, which define the columns. | + | Its creation and usage is rather simple, and, if you’re working with RemoteDataBooks there is no need to create one at all, as it is automatically created when the databook is opened. A row definition holds and manages column definitions, which define the columns. |
<code java> | <code java> | ||
Line 616: | Line 616: | ||
dataBook.setRowDefinition(rowDefinition); | dataBook.setRowDefinition(rowDefinition); | ||
</code> | </code> | ||
- | ==== ColumnDefinition ==== | + | ==== Column Definition ==== |
- | The ColumnDefinition defines and provides all necessary information about the column, like its DataType, its size and if it is nullable or not. You can think of it as one column in a table. | + | The column definition defines and provides all necessary information about the column, like its datatype, its size, and whether it is nullable or not. You can think of it as one column in a table. |
<code java> | <code java> | ||
Line 624: | Line 624: | ||
columnDefinition.setNullable(false); | columnDefinition.setNullable(false); | ||
</code> | </code> | ||
- | ==== MetaData ==== | + | ==== Meta Data ==== |
- | Most of the ColumnDefinition is additional information about the column, like if it is nullable, the label of the column, default values, allowed values and similar information. | + | Most of the column definition is additional information about the column, like if it is nullable, the label of the column, default values, allowed values, and similar information. |
- | ==== DataType ==== | + | ==== Data Type ==== |
- | Of course we must define what type the value in the column has, this is done by setting a DataType on the ColumnDefinition. The DataType defines what kind of values the column holds, like if it is a String, or a Number or something else. We do provide the most often used DataTypes out of the box: | + | Of course, we must define what type the value in the column has. This is done by setting a data type on the column definition. The data type defines what kind of values the column holds, like if it is a string, a number, or something else. We provide the most often used data types out of the box: |
* BigDecimal | * BigDecimal | ||
Line 640: | Line 640: | ||
* Timestamp | * Timestamp | ||
- | It is possible to add new DataTypes by simply implementing ''%%IDataType%%''. | + | It is possible to add new data types by simply implementing ''%%IDataType%%''. |
- | ===== DataRow ===== | + | ===== Data Row ===== |
- | The DataRow repesents a single row of data, it holds/references its own RowDefinition and of course provides access to the values of the row. Accessing the DataRow can be done either by column index or column name, and the methods do either return or accept Objects. Let’s look at a simple usage example: | + | The data row represents a single row of data; it holds/references its own row definition and, of course, provides access to the values of the row. Accessing the data row can be done either by column index or column name, and the methods either return or accept objects. Let’s look at a simple usage example: |
<code java> | <code java> | ||
Line 653: | Line 653: | ||
dataRow.setValue("COLUMN_A", "New Value"); | dataRow.setValue("COLUMN_A", "New Value"); | ||
</code> | </code> | ||
- | ===== DataPage ===== | + | ===== Data Page ===== |
- | The DataPage is basically a list of DataRows, it also holds its own RowDefinition which is shared with all the contained DataRows. | + | The data page is basically a list of data rows. It also holds its own row definition, which is shared with all the contained data rows. |
- | The main usage of DataPages is to allow paging in a master/detail relationship. If the master selects a different row, the detail databook does select the related DataPage. | + | The main usage of data pages is to allow paging in a master/detail relationship. If the master selects a different row, the detail databook selects the related data page. |
- | ===== DataBook ===== | + | ===== Databook ===== |
- | The DataBook is the main model of [[https://sourceforge.net/projects/jvx/|JVx]], it provides direct access to its current DataPage and DataRow by extending from IDataRow and IDataPage. | + | The databook is the main model of [[https://sourceforge.net/projects/jvx/|JVx]], it provides direct access to its current data page and data row by extending from IDataRow and IDataPage. |
- | By default, the DataBook holds one DataPage and only has multiple DataPages if it is the detail in a master/detail relationship. | + | By default, the databook holds one data page and only has multiple data pages if it is the detail in a master/detail relationship. |
- | ===== Usage example ===== | + | ===== Usage Example ===== |
- | Here is a simple usage example of a ''%%MemDataBook%%'', an ''%%IDataBook%%'' implementation which does only operate in memory: | + | Here is a simple example of a ''%%MemDataBook%%'', an ''%%IDataBook%%'' implementation that only operates in memory: |
<code java> | <code java> | ||
Line 704: | Line 704: | ||
dataBook.delete(); | dataBook.delete(); | ||
</code> | </code> | ||
- | ==== Accessing the data with Strings ==== | + | ==== Accessing the Data With Strings ==== |
- | One of the major advantages of the DataBook concept is that there is no need to create new classes to represent each table, view or query result. One can always use the DataBook, directly and easily and model changes don’t necessitate changes on the client side. The downside to this approach is that we lose compile time checks because we access the data dynamically. However, This can be mitigated by using [[https://marketplace.eclipse.org/content/eplug-jvx|EPlug, an Eclipse plugin]] which provides compile time checks and many more features. | + | One of the major advantages of the databook concept is that there is no need to create new classes to represent each table, view, or query result. One can always use the databook directly and easily, and model changes don’t necessitate changes on the client side. The downside to this approach is that we lose compile time checks because we access the data dynamically. However, this can be mitigated by using [[https://marketplace.eclipse.org/content/eplug-jvx|EPlug, an Eclipse plugin]] which provides compile time checks and many more features. |
- | ==== No primitives, Objects only ==== | + | ==== No Primitives, Objects Only ==== |
- | We do not provide overloads to fetch primitives, that is because there are mainly three types of data inside a database: | + | We do not provide overloads to fetch primitives. This is because there are mainly three types of data inside a database: |
* Numbers | * Numbers | ||
Line 716: | Line 716: | ||
* Binary Data | * Binary Data | ||
- | Text and Binary Data are both objects (arrays of primitives are Objects after all) and Numbers are either primitives or Objects. Most of the time if we deal with numbers inside a database we want them to be of arbitrary precision, which means we must represent them as ''%%BigDecimal%%''. Supporting ''%%double%%'' or ''%%float%%'' in these cases would be dangerously, because one might write a ''%%float%%'' into the database [[https://en.wikipedia.org/wiki/Floating-point_arithmetic|which might or might not end up with the correct value]] in the database. To completely eliminate such problems, we do only support Objects, which means that one is “limited” to the usage of Number extensions like ''%%BigLong%%'' and ''%%BigDecimal%%'', which do not suffer from such problems. | + | Text and binary data are both objects (arrays of primitives are objects after all) and numbers are either primitives or objects. Most of the time, if we deal with numbers inside a database, we want them to be of arbitrary precision, which means we must represent them as ''%%BigDecimal%%''. Supporting ''%%double%%'' or ''%%float%%'' in these cases would be dangerous because one might write a ''%%float%%'' into the database [[https://en.wikipedia.org/wiki/Floating-point_arithmetic|, which might or might not end up with the correct value]] in the database. To completely eliminate such problems, we only support objects, which means that one is “limited” to the usage of number extensions like ''%%BigLong%%'' and ''%%BigDecimal%%'', which do not suffer from such problems. |
- | ==== Where are the DataPages? ==== | + | ==== Where Are the Data Pages? ==== |
- | What is not clear from this example is how and when DataPages are used. As a matter of fact, most of the time there is no need to think about DataPages because they are managed directly by the DataBook, and if used like this there is only one DataPage. Multiple DataPages will be used if there is a Master/Detail relationship defined in which case the DataBook does select the correct DataPage automatically. | + | What is not clear from this example is how and when data pages are used. As a matter of fact, most of the time there is no need to think about data pages because they are managed directly by the databook, and, if used like this, there is only one data page. Multiple data pages will be used if there is a master/detail relationship defined, in which case the databook selects the correct data page automatically. |
===== Master/Detail ===== | ===== Master/Detail ===== | ||
- | [[https://en.wikipedia.org/wiki/Master%E2%80%93detail_interface#Data_model|Master/detail]] is something that occurs in nearly every data model. It means simply that there is one master dataset which is referenced by one or multiple detail datasets. Or to express it in SQL: | + | [[https://en.wikipedia.org/wiki/Master%E2%80%93detail_interface#Data_model|Master/detail]] is something that occurs in nearly every data model. It simply means that there is one master data set that is referenced by one or multiple detail data sets. Or to express it in SQL: |
<code sql> | <code sql> | ||
Line 733: | Line 733: | ||
left join DETAIL d on m.ID=d.MASTER_ID; | left join DETAIL d on m.ID=d.MASTER_ID; | ||
</code> | </code> | ||
- | We can of course express a master/detail relationship when using DataBooks. For that we just create a ''%%ReferenceDefinition%%'' and assign it to the detail DataBook: | + | We can, of course, express a master/detail relationship when using data books. For that, we just create a ''%%ReferenceDefinition%%'' and assign it to the detail data book: |
<code java> | <code java> | ||
Line 751: | Line 751: | ||
detailDataBook.open(); | detailDataBook.open(); | ||
</code> | </code> | ||
- | Let’s assume the following data for illustration purposes: | + | Let’s assume the following data for illustrative purposes: |
<code> | <code> | ||
Line 767: | Line 767: | ||
8| 3 | 8| 3 | ||
</code> | </code> | ||
- | Now if we select the second row in the ''%%masterDataBook%%'', the ''%%detailDataBook%%'' will just contain the rows with the corresponding ''%%MASTER_ID%%'', so 3, 4 and 5. | + | Now, if we select the second row in the ''%%masterDataBook%%'', the ''%%detailDataBook%%'' will just contain the rows with the corresponding ''%%MASTER_ID%%'', so 3, 4, and 5. |
<code> | <code> | ||
Line 778: | Line 778: | ||
3 5| 2 | 3 5| 2 | ||
</code> | </code> | ||
- | The ''%%detailDataBook%%'' is automatically adjusted according to the selection in the ''%%masterDatabook%%''. Of course this can have an arbitrary depth, too. | + | The ''%%detailDataBook%%'' is automatically adjusted according to the selection in the ''%%masterDatabook%%''. Of course, this can have an arbitrary depth too. |
===== Conclusion ===== | ===== Conclusion ===== | ||
- | The DataBook is the backbone of [[https://sourceforge.net/projects/jvx/|JVx]], it provides a clean and easy way to access and manipulate data. At the same time, it is flexible and can be customized to specific needs with ease. | + | The data book is the backbone of [[https://sourceforge.net/projects/jvx/|JVx]]: it provides a clean and easy way to access and manipulate data. At the same time, it is flexible and can be customized to specific needs with ease. |
====== Application Basics ====== | ====== Application Basics ====== | ||
- | Let’s talk about the basics, how a [[https://sourceforge.net/projects/jvx/|JVx]] application starts, works and how the connection strings together the client and server side. | + | Let’s talk about the basics: how a [[https://sourceforge.net/projects/jvx/|JVx]] application starts, how it works, and how the connection strings together the client and server side. |
===== Multitier Architecture ===== | ===== Multitier Architecture ===== | ||
Line 796: | Line 796: | ||
The following method is a simplified way to launch a [[https://sourceforge.net/projects/jvx/|JVx]] application. Normally, you’d use the technology specific launcher to launch the application. These launchers do know exactly what is required to set it up and start the technology and the application. However, covering the launchers is out of scope for this post, so we will review them and their mechanics in a follow-up. | The following method is a simplified way to launch a [[https://sourceforge.net/projects/jvx/|JVx]] application. Normally, you’d use the technology specific launcher to launch the application. These launchers do know exactly what is required to set it up and start the technology and the application. However, covering the launchers is out of scope for this post, so we will review them and their mechanics in a follow-up. | ||
- | ===== The simplest JVx application: Just the GUI ===== | + | ===== The Simplest JVx Application: Just the GUI ===== |
- | But first, we will start without anything. The most simple application you can create with [[https://sourceforge.net/projects/jvx/|JVx]] is an application which does open a single window and only works with in memory data (if at all). This can be easily achieved by “just starting” the application. | + | But first, we will start without anything. The most simple application you can create with [[https://sourceforge.net/projects/jvx/|JVx]] is an application which opens a single window and only works with in-memory data (if at all). This can be easily achieved by “just starting” the application. |
[[https://blog.sibvisions.com/2016/12/07/jvx-reference-of-technologies-and-factories/|The JVx GUI is a simple layer on top of the Technology]] which implements the actual functionality. So if we want to have a GUI we’ll need to initialize the factory before doing anything else: | [[https://blog.sibvisions.com/2016/12/07/jvx-reference-of-technologies-and-factories/|The JVx GUI is a simple layer on top of the Technology]] which implements the actual functionality. So if we want to have a GUI we’ll need to initialize the factory before doing anything else: | ||
Line 805: | Line 805: | ||
UIFactoryManager.getFactoryInstance(SwingFactory.class); | UIFactoryManager.getFactoryInstance(SwingFactory.class); | ||
</code> | </code> | ||
- | With this little code we have initialized everything we need to create a simple Swing application. Now we can start to create and populate a window with something: | + | With this little code, we have initialized everything we need to create a simple Swing application. Now we can start to create and populate a window with something: |
<code java> | <code java> | ||
Line 817: | Line 817: | ||
frame.eventWindowClosed().addListener(() -> System.exit(0)); | frame.eventWindowClosed().addListener(() -> System.exit(0)); | ||
</code> | </code> | ||
- | We can start to create and manipulate the GUI, in this case we are building a simple window with a label inside. Last but not least, we make sure that the JVM will exit when the window is closed. | + | We can start to create and manipulate the GUI. In this case, we are building a simple window with a label inside. Lastly, we make sure that the JVM will exit when the window is closed. |
A very good example and showcase for that is the [[https://github.com/sibvisions/jvx.kitchensink|JVx Kitchensink]]. | A very good example and showcase for that is the [[https://github.com/sibvisions/jvx.kitchensink|JVx Kitchensink]]. | ||
- | That’s it. That is the most simple way to start a [[https://sourceforge.net/projects/jvx/|JVx]] application. We can use all controls and we can use ''%%MemDataBook%%''s without any problem or limitation. And best of all, we can simply switch to another Technology by using another factory. | + | That’s it! That is the most simple way to start a [[https://sourceforge.net/projects/jvx/|JVx]] application. We can use all controls, and we can use ''%%MemDataBook%%''s without any problem or limitation. Best of all, we can simply switch to another technology by using another factory. |
- | ===== Anatomy of a remote JVx application ===== | + | ===== Anatomy of a Remote JVx Application ===== |
- | Of course [[https://sourceforge.net/projects/jvx/|JVx]] wouldn’t be that useful if it would just provide static GUI components. Now, to explain what else is required for a remote [[https://sourceforge.net/projects/jvx/|JVx]] application I have to go far afield, so let’s head down the rabbit hole. | + | Of course, [[https://sourceforge.net/projects/jvx/|JVx]] wouldn’t be that useful if it would just provide static GUI components. Now, to explain what else is required for a remote [[https://sourceforge.net/projects/jvx/|JVx]] application, I have to go far afield, so let’s head down the rabbit hole. |
{{:jvx:reference:jvx-client-server.png?nolink| Layers}} | {{:jvx:reference:jvx-client-server.png?nolink| Layers}} | ||
- | What you are seeing here is a rough sketch of how the architecture of [[https://sourceforge.net/projects/jvx/|JVx]] looks like. Let’s walk through the image step by step. We will look at each successive layer and work our way from the database on the server to the databook on the client. | + | What you are seeing here is a rough sketch of how the architecture of [[https://sourceforge.net/projects/jvx/|JVx]] looks like. Let’s walk through the image step by step. We will look at each successive layer and work our way from the database on the server to the data book on the client. |
- | ==== DBAccess, accessing a database ==== | + | ==== DBAccess, Accessing a Database ==== |
Accessing a database is easy when using ''%%DBAccess%%''. All we must do is to set the [[https://en.wikipedia.org/wiki/Java_Database_Connectivity|JDBC]] URL of the server and connect to it: | Accessing a database is easy when using ''%%DBAccess%%''. All we must do is to set the [[https://en.wikipedia.org/wiki/Java_Database_Connectivity|JDBC]] URL of the server and connect to it: | ||
Line 842: | Line 842: | ||
dbAccess.open(); | dbAccess.open(); | ||
</code> | </code> | ||
- | As a note, the instance returned by ''%%getDBAccess(...)%%'' is the database specific ''%%DBAccess%%'' extension, which does know how to handle its database. | + | As a note, the instance returned by ''%%getDBAccess(...)%%'' is the database-specific ''%%DBAccess%%'' extension, which knows how to handle its database. |
- | We can of course use ''%%DBAccess%%'' to directly access the database: | + | We can, of course, use ''%%DBAccess%%'' to directly access the database: |
<code java> | <code java> | ||
Line 853: | Line 853: | ||
List<Bean> data = dbAccess.executeQuery("select * from SOME_TABLE"); | List<Bean> data = dbAccess.executeQuery("select * from SOME_TABLE"); | ||
</code> | </code> | ||
- | …or manipulate the database, or query information about the database or execute procedures or do anything else. | + | …or manipulate the database, query information about the database, execute procedures, or anything else! |
- | ==== DBStorage, preparing the database access for databooks ==== | + | ==== DBStorage, Preparing the Database Access for Databooks ==== |
- | The downside of using DBAccess is that everything must be database specific. To become database agnostic we must use ''%%DBStorage%%''. ''%%DBStorage%%'' does not care which database it is connected to and can operate on any of them: | + | The downside of using DBAccess is that everything must be database-specific. To become database-neutral, we must use ''%%DBStorage%%''. ''%%DBStorage%%'' does not care which database it is connected to and can operate on any of them: |
<code java> | <code java> | ||
Line 865: | Line 865: | ||
storage.open(); | storage.open(); | ||
</code> | </code> | ||
- | We can use this to insert, update, delete and fetch data. Additionally the ''%%DBStorage%%'' does retrieve and manage the metadata of the table we’ve set, which means that we can query all column names, what type they are, we can even access the indexes and the default values. Short, the ''%%DBStorage%%'' leaves little to be desired when it comes to operating on a database. | + | We can use this to insert, update, delete and fetch data. Additionally, the ''%%DBStorage%%'' does retrieve and manage the metadata of the table we’ve set, which means that we can query all column names, what type they are, we can even access the indexes and the default values. Short, the ''%%DBStorage%%'' leaves little to be desired when it comes to operating on a database. |
- | If we query data from the ''%%DBStorage%%'' we receive a List of rows. The rows are are either represented as ''%%Object%%'' array, ''%%IBean%%'' or a POJO and we can easily manipulate the data, like this: | + | If we query data from the ''%%DBStorage%%'', we receive a list of rows. The rows are either represented as ''%%Object%%'' array, ''%%IBean%%'', or a POJO, and we can easily manipulate the data, like this: |
<code java> | <code java> | ||
Line 876: | Line 876: | ||
} | } | ||
</code> | </code> | ||
- | As one can see, it looks quite familiar to the DataBook, which isn’t a coincidence. The ''%%DBStorage%%'' “powers” the DataBooks on the server side, a DataBook will get its data from and will send its modified data to the ''%%DBStorage%%''. | + | As one can see, it looks quite familiar to the DataBook, which isn’t a coincidence. The ''%%DBStorage%%'' “powers” the databooks on the server side, a databook will get its data from and will send its modified data to the ''%%DBStorage%%''. |
- | I’ve been using the ''%%DBStorage%%'' here as an example, but actually the Storage is not dependent on a database. ''%%IStorage%%'' can be implemented to provide any sort of data provider, like reading from an XML or JSON file, scraping data from a website, fetching data from a different process or reading it directly from a hardware sensor. | + | I’ve been using the ''%%DBStorage%%'' here as an example, but actually the storage is not dependent on a database. ''%%IStorage%%'' can be implemented to provide any sort of data provider, like reading from an XML or JSON file, scraping data from a website, fetching data from a different process, or reading it directly from a hardware sensor. |
==== Life Cycle Objects, the business objects with all the logic ==== | ==== Life Cycle Objects, the business objects with all the logic ==== |