What is the Solution Appliance Framework?
The Solution Appliance Framework, formerly known as the Java Object Oriented Library framework (“JOOL”), is a set of code libraries that provide the following basic features:
- Rich type support to properly describe core Java constructs, custom Java objects, as well a dynamic objects as might be stored in ad-hoc structures such as a Collection, Map, or a String.
- Complete and dynamic meta-data definitions allow any object or entity needed by the business to be defined once for all uses and applications.
- Multi-layer tooling permits developers to work with any layer of the framework. A developer may choose to use very high-level constructs to quickly perform a standard operation. When things get difficult, the developer can stay within the framework and integrate at lower levels of support where they have complete control over every aspect of the operation.
- Custom integrations allow organizations to use standard provided integration mechanisms for common data-stores, transports, and file formats, but also allows the simple creation of new integrations. The framework even permits entity specific integrations in which a specific business entity might have a completely custom integration with Oracle, as well a use-case specific integrations such as using a local MySQL database in some use cases and a high-power Oracle database in another.
Development with the Solution Appliance Framework begins with a developer defining entities. Most common Java frameworks define entities by having an architect or developer write a simple Java interface (known as a Plain Old Java Object, or POJO) with simple annotations that define a specific usage of the business object. For example, a developer working on a “Data Access Object” that defines how an entity is written to the database, will use annotations that describe how elements represented in Java should be represented in a database. In the standard model, every usage of an entity would require a different POJO. Want to create a “Data Transport Object” to describe how the entity works with a WebService or REST interface, that’s a new POJO with new annotations. Want to create a “Protobuf” version that can be transmitted efficiently over a publish/subscribe network, that’s a different definition.
Fortunately, that specific meta-data definition can go a step further. Where as other frameworks typically stop at the Java type definitions, specifying that a value is stored as a “String,” the Solution Appliance Framework has a more sophisticated type system that defines not only the Java type, but also the Java object that is used, what it represents, and how to convert between that representation and others. In our example of a simple String, perhaps it is actually a “URL-safe, base64 encoded String representing the big-endian raw bytes of IEEE 754 floating point value.” The Solution Appliance Framework would allow you to define that type without needing to create a custom Java type, something which Java developers very seldom do because it is too much work. Go into any system and count the number of String references.
When evaluating the power of an entity model, it’s interesting to see how many different ways that representation can be used. Where as most frameworks will require a different representation for every transport of an entity, separate frameworks for configuration, and no standard framework for the meta-data model itself, the Solution Appliance Framework’s entity model does it all! The single entity construct with its powerful, extensible, and highly visible meta-data model can be used to define an entity once for each business object, and can also be used to define configuration objects, protocol specific objects, and even the meta-data model itself.
For example, the Solution Appliance Framework has been used to represent the header objects used in video encoding (known as Atoms or Boxes). The single representation made it trivially easy to parse binary video encoding files, display them in a user-interface, and import/export them in JSON form.
Rich Type Support
Alluded to previously, the Solution Appliance Framework makes it easy to use standard Java constructs such as a String, but provide very specific information about how data is stored in that String, and how to covert between that String representation and other representations. String is used as an example, but it applies equally well to all types, especially those that have a tendency to be used for transport (byte streams, decimals, etc).
Cornerstone to the Solution Appliance Framework is a rich type library. Each type understands how it is materialized in Java, as well as how to convert itself to other types. New types can be easily defined by developers as part of the standard system model, or dynamically added to/modified as part of a transactional model that is specific to the individual execution of a code line (specific to a web call, for example). This allows for, if needed, use-case or customer specific representations of standard types.
This is relevant because many transports and datastore use high-level generic types to maximize reuse (string, bytes, decimal, boolean). However, the string used to store a value in one database might be different than that in another database (say the data warehouse database), and that is likely to be different than the String used in a web API call, and that again is different than the String used to represent the value in Java, and that is different than the String needed by a developer to debug a value.
Solution Appliance Framework allows the architect/developer to specify each of those Strings as different types with different validation and conversion rules, and then permits those types and conversions to be overridden for specific use-cases. For the specific use case example, imagine a single web API that can represent values as simple strings for most customers, or fuller definition strings for special super users. In one case a string might represent just a record id, but in the super-user case it might be a tenant id plus a record type id plus a record id.
Multi Layer Tooling
There is nothing worse than successfully using a framework for years to finally reach a point where the system requirements exceed the capabilities of the framework. While frameworks attempt to be rich, this richness typically results in complexity that reduces their facility. For example, the Hibernate framework that is used for reading/writing Java objects to a datastore, supports a simple model of reading and writing objects. One layer deeper, and the framework supports a complex in-memory caching model. In addition, the framework also supports a custom query framework to allow developers to almost write SQL.
The challenge comes from the statements that the developer writes the query language, and the query language is almost SQL. While this works fine for many simple cases, what happens then a developer needs to use a sophisticated feature of a high-end database to solve a specific problem? They might be able to use Hibernate 99% of the time, but in just a few cases they need control of the query. This becomes exceedingly difficult and often results in some code being done in-framework, and other code being done completely out-of-framework. The out-of-framework code is especially insidious as the developer typically cannot use any of the framework components to assist them in their job, they are completely outside of the framework!
The Solution Appliance Framework is written differently. It is written as a series of visible layers, and the developer can operate at any level appropriate. If they need the simple case, high level constructs provide simple fetch and save calls, the operations of which are defined in meta-data. If they need more sophistication, they can replace for just that one mechanism how the high level component works. Or, they can go down a few layers, have the framework generate a native SQL graph, re-use the entity meta-data to modify that graph, and then submit that graph to the rest of the framework for processing. The framework has been used to prove out the concept of “bolt-on-security” where a wrapper entity was able to generically take the queries associated with another entity, join on security concerns, and add new functionality to old code without any rework.
Entities typically are initially defined for a specific environment and usage. An entity might have meta-data definitions for an Oracle database and a JSON representation.
Eventually, requirements evolve or change. Perhaps the production environment involves a publish/subscribe data pipeline using Protobuf encoded data, and data is being migrated from Oracle to MySQL. With the Solution Appliance framework, these changes are simple. Simply add the protobuf meta-data and support to the entities, and add a MySQL definition. The high-level transport can then be swapped out with a custom transport that knows which database to write to and when (perhaps it is always dual writes, perhaps it is write new data to the new database only, etc), and which database to read from (read from new database, if it fails, read from old database and then insert into the new database).
Other frameworks would make it impossible to do this work. With the Solution Appliance Framework, it is a simple matter of swapping out the old definition with a new one. A senior engineering could likely complete this work in a matter of hours!
And things get even more exciting when considering non-standard transports. Perhaps a corporation has a mandate to support writing data to a S3 log on save. Defining the S3 meta-data representation and storage support could easily be done, and then it is simply a matter of adding support to all of the entities. If the support was trivial, meaning it doesn’t require any definition beyond that which already exists in the entities, it could easily be integrated with no work beyond modifying the existing database integration support.
The Solution Appliance Framework makes it easy to create a single definition of entities which are important to an organization. That single definition can be used by the framework, its integration with other frameworks and systems, and its interaction with the developer.
All models and tools are available to the developer. There are no hidden meta-data representations that cannot be reused, or cause unexpected results from the developer.
The framework is built around the model that most things are easy, and some things are really hard. The developer wants to spend their time on the hard problems, and they want to use every aspect of a framework they can to handle the mundane.
Finally, the framework supports change. The entities natively support tracking changes, and as the meta-data model is built upon the entity model, it means the meta-model also supports change. And changes to a model are not limited to just the elements of that model, but how that model interacts with other systems. A system build on Oracle today might be using multiple non-relational datastore in the future; a system using a JSON transport today might use a binary transport tomorrow.