The Reflect Framework
The ReflectFramework is a light weight Java Application Framework for creating business like applications that can read and manipulate information by using forms and tables.
With the ReflectFramework you only need to create DomainObjects. The ReflectFramework provides you the user interface, without writing any user interface code. This means that the ReflectFramework is ideal for rapid development and rapid prototyping (Domain Driven Design) or to teach or learn programming (e.g. Object Oriented Programming).
The ReflectFramework provides different user interface implementations that you can use for your DomainObjects. Please read the ReflectApplicationProjects section to learn what user interfaces are available and how to get started. If you want to know more about the details of the ReflectFramework, keep reading....
Reflect Core Values
The ReflectFramework is designed around the following core values:
Based on the Naked Objects Design Pattern
See the Wiki page on the Naked Objects Architectural pattern:- All business logic should be encapsulated onto the domain objects. This principle is not unique to naked objects: it is just a strong commitment to encapsulation.
- The user interface should be a direct representation of the DomainObjects, with all user actions consisting, explicitly, of creating or retrieving DomainObjects and/or invoking methods on those objects. This principle is also not unique to naked objects: it is just a specific interpretation of an object-oriented user interface (OOUI).
- The user interface should be created 100% automatically from the definition of the DomainObjects. Reflection is used instead of code generation. Hence the name of the ReflectFramework: The framework reflects the code of the ServiceObjects and DomainObjects to the user interface.
Written in Java
At the time of this writing, Java is still the most used programming language. Most developers are able to write (or read) Java code. There are many Java libraries available that can be used in your application.Provide a good structure for applications
- Enforce separation of concerns (see ReflectArchitecture).
- Facilitate domain driven design.
- DomainObject's, ServiceObject's and InfrastructureObject's should have no (or almost no) dependencies with the ReflectFramework so that it could easily be replaced with another dependency injection framework (such as Spring, Guice or Pico container, etc...) or visa versa. You would only need to change some annotations and link it to the other dependency injection framework
- The ReflectFramework must accept ServiceObjects, DomainObjects, InfrastructureObjects that are Plain Old Java Objects (POJO's).
- The ReflectFramework exists of a few basic interfaces like UserInterfaceController and Providers that can have multiple different implementations.
Have a modern graphical user interface
- Responsive Design: An optimized user experience on a variety of devices and screen sizes.
- Flat design: A minimalist graphical user interface (e.g. like Google's Material Design) that does not distract the user in executing his or her tasks
Write once and deploy as different type of applications
The ReflectFramework allows you to write your code once, and deploy it as different types of applications without much of a hassle. See the ReflectApplicationProjects for more information.
Simple to configure
The ReflectFramework has no configuration files (see “Code or configuration files” section in Martin Fowlers article for the arguments why).There are 3 things that need to be configured:
- Which implementations of the UserInterfaceController and Provider's are going to be used by the ReflectApplication.
- Which ServiceObject classes and InfrastructureObject classes are going to be used by the ReflectApplication.
- The ObjectBehavior of DomainObject's and ServiceObject 's (how the domain needs to handled by the ReflectApplication)
Furthermore the ReflectFramework prefers “Configure by Exception”. This means that the ReflectFramework uses reasonable defaults wherever possible. These default values can be overridden by the developer.
Lightweight
The ReflectFramework is aimed to have a small distribution size.
Open source and free
See the ReflectLicense.
Why the Reflect Framework was developed
Almost everyday new libraries, frameworks and tools are being released by the developer community, many of which reinvent the wheel.
This is called the "Yet Another Framework Syndrome" (YAFS), or in more general terms "Not Invented Here" (NIH). While innovation is something we should all welcome, YAFS can lead to confusion and frustration for users because there's a big risk of it introducing more noise than value.
So why did I develop a new framework while there are so many Java application frameworks out there?
Reason 1: Because its fun
Probably the best reason ever!Reason 2: Because I wanted to learn
The journey of developing yet another framework has thought me more than I could have learned implementing an existing framework. Specifically on how other frameworks solved issues that I run into.Reason 3: Because I could not find what I was looking for
There are already several frame works that are based on the Naked Objects pattern, e.g.:- Naked Objects (for .net)
- Apache Isis Wicket Viewer (for Java)
- And others
No mandatory persistence framework dependency
Most of the existing Naked Object Frameworks heavily depend on a persistence framework (at the time of this writing Apache Isis even wrote its own!). Editing and changing DomainObjects automatically triggers the persistence framework to store the DomainObject into a database. This is a handy feature, however DomainObjects do not necessarily need to be persisted after its been edited. The ReflectFramework chooses a different approach: DomainObjects can be passed to a method as a method parameter. This method parameter can be edited by a user before a method is executed (depending on how the method is annotated). The logic in the method than dictates how this (changed) DomainObject is processed. In some cases the method will use a InfrastructureObject that will store the DomainObject into a database (possibly using a persistence framework). But we do not always need to store the (changed) DomainObject in a database. Maybe your application does not need a database at all! Therefore the ReflectFramework should not have a mandatory dependency with a persistence framework.
Missing a good graphical user interface.
None of the existing Naked Object Frameworks (at the time of this writing) have a graphical user interface that meets modern design principles like:- Responsive Design: An optimized user experience on a variety of devices and screen sizes.
- Flat design: A minimalist graphical user interface that does not distract the user execute its tasks, e.g. like Google's Material Design
Missing a Naked Objects WORA framework
Java was first released in 1995 and was designed with the Write Once Run Anywhere (WORA) philosophy. A lot has changed since. So does WORA still apply for Java? The answer: Yes and No:- Yes: The Java Virtual Machine (JVM) can run on almost all devices: e.g. home appliances, personal computers, and even on devices out in space. It has been very successful on the server side.
- No: Java code can run on all platforms that support Java. Apple does not allow the Oracle JVM on its devices and Android devices use Googles JVM which is different. Furthermore: It is nearly impossible to write a GUI for a desktop, and deploy it as a web application or mobile application or vice-versa
At the time of this writing, none of the existing Naked Object Frameworks can be dispatched to different platforms (e.g. the command line, desktop, mobile devices and the web). The ReflectFramework lets you wrap your ServiceObjects, DomainObjects and InfrastructureObjects, in several native implementations of the ReflectFramework. For more information see: ReflectApplicationProjects
Reflect License
The ReflectFramework is an open source project under the GNU Lesser General Public License. The license can be found here.
Architecture of an Reflect Application
The ReflectFramework helps you to create a multi layer architecture for your application. A multi layer architecture has several design principles:
- Separation of concerns (separate responsibilities within the application into different layers).
- Low coupling between layers, high cohesion within them.
- Layers should be testable individual.
- Business logic layers contain no user interface and don't refer to user interface modules.
- No circular references between layers.
- Lower layers should not depend on upper layers.
- Layers should be shy about their internals.
- Layers may share infrastructural aspects (eg security)
- Inbound external interface modules (eg web service handlers) should not contain business logic.
These multi layer architecture design principles try to prevent spaghetti code, which is hard to extend, hard to trouble shoot, hard to test and hard to keep bug free.
There are many different opinions on the number of layers, the names of the layers and what each layer should do (see these examples). The definition of layers from Eric Evans Domain Driven Design approach is likely the most commonly used. The most important thing is that your multi layered architecture complies with the design principles above.
The ReflectArchitecture uses the following layer definition, which is pretty close to Eric Evans Domain Driven Design approach.:
- UserInterfaceLayer
- ServiceLayer (called "application layer" by Eric Evans)
- DomainLayer
- InfrastructureLayer
- ProviderLayer (extra layer for cross cutting concerns)
Red objects are provided by the ReflectFramework
Yellow objects need to be written or included by the developer.
Dependency Injection Container
The ReflectFramework is a dependency injection framework and consists of several dependency injection containers.
If you are new to Dependency Injection I recommend reading Martin Fowler's article in which he explains the basics dependency injection.
Each DependencyInjectionContainer is responsible for:
- Creating new instances of types that are registered to a DependencyInjectionContainer with the ReflectApplication .get...Class() or .get...Classes() methods
- Linking dependencies (references to other objects) to these new instances (using constructor injection)
- Caching these new instances, if we only need one instance (like a singleton)
The ReflectArchitecture consists of several layers. Each layer has its own DependencyInjectionContainer that manages the objects in that layer:
- UserInterfaceLayer: UserInterfaceController object is managed by a UserInterfaceContainer. The UserInterfaceContainer knows the ServiceContainer
- ServiceLayer: ServiceObject's are managed by a ServiceContainer. The ServiceContainer knows the DomainContainer
- DomainLayer: DomainObject's are managed by a DomainContainer. The DomainContainer knows the InfrastructureContainer
- InfrastructureLayer: InfrastructureObject's are managed by a InfrastructureContainer. The DomainContainer knows the ProviderContainer
- ProviderLayer: Provider object's are managed by a ProviderContainer.
Constructor Injection
The ReflectFramework favors constructor injection (see Martin Fowler's easy to read article for the arguments why).
All objects within an ReflectApplication can have references to (may know) other objects. These reference objects are injected into an object as constructor parameter during the creation of the object by the DependencyInjectionContainer of that specific layer. This constructor parameter can than be linked to a private final field, so that it can be used throughout the object.
In example:public class ProductService { private final ProductRepository productRepository; public ProductService(ProductRepository productRepository) { this.productRepository = productRepository; } public List<Product> findProduct(ProductSearchCritiria searchCritiria) { return productRepository.findProduct(searchCritiria); } // other action methods... }
It is good practice to link the constructor parameter (reference object) to a private final field, so that it is encapsulated and immutable.
If your object needs a lot of references to other objects (too many constructor parameters), your object has most likely to many responsibilities, which could be solved by splitting up this object.
Note that you can only inject reference object types (use constructor parameters types) that are known to the that specific layer:- The ReflectApplication class can be injected in all layers
- You can only inject objects of the same layer or lower layers (see ReflectArchitecture). The ReflectFramework tries to prevent that objects in the lower layer know (have references to) objects in the higher layers because this is against several design principles of an layered architecture
- You can only inject objects that are registered to the ReflectApplication by overriding the get...Classes() or get...Class() methods.
The Reflect Application
ReflectApplication is used as initialization parameter for the ReflectFramework.
A ReflectApplication has several purposes:
- It provides the name, icon and description of the application (see ObjectBehavior)
- It provides the location of the distribution package (jar, war)
- It provides the UserInterfaceController type, needed for the application with the ReflectApplication.getUserInterfaceControllerClass() method. Each application type (e.g. for the command line, desktop, mobile devices or the web) requires different implementations of the UserInterfaceController
- It provides a list of ServiceObject types with the ReflectApplication.getServiceClasses() method. ServiceObjects basically provide the actionable/menu items
- It provides a list of DomainObject types that need to be created using dependency injection, with the ReflectApplication.getDomainClasses() method.
- It provides a list of InfrastructureObject types with the ReflectApplication.getInfrastructureClasses() method. InfrastructureObjects basically communicate to the outside world (i.e. data base access objects, email clients, soap clients, etc)
- It provides the Provider types with the ReflectApplication.get...ProviderClass() methods. Provider Objects help with cross cutting concerns. Each application type (e.g. for the command line, desktop, mobile devices or the web) requires different implementations of the providers
Each application type (e.g. for the command line, desktop, mobile devices or the web) has its own implementation of ReflectApplication to help initializing the framework. See the type hierarchy of ReflectApplication to learn which classes can be used and read their java doc to learn how to use them.
If you create a new application you will be extending one of these classes. You will only need to implement some of the methods mentioned above (at least the ReflectApplication.getServiceClasses() method).
An example of a desktop application:public class WebShopForJavaFX extends ReflectApplicationForJavaFX { private List<Class<?>> serviceClasses; private List<Class<?>> infrastructureClasses; public class WebShopForJavaFX() { serviceClasses=Arrays.asList(ShoppingCartService.class, ProductService.class); infrastructureClasses=Arrays.asList(ProductRepository.class, EmailClient.class, PaymentClient.class); } @Override public List<Class<?>> getServiceClasses() { return serviceClasses; } @Override public List<Class<?>> getInfrastructureClasses() { return infrastructureClasses; } }
For more (detailed) examples see the ReflectApplicationProjects section.
Starting a new Reflect Project
How you create a new ReflectApplication depends on the type of application type that you want to create.
First decide on the type of application you want to create. Then look up the corresponding paragraph in the ReflectApplicationProjects section. There you will learn how to create a java project that contains an application class that extends the ReflectApplication class. This class will initialize and start the ReflectFramework. This class also contains methods that you need to implement to provide the ServiceObject classes and InfrastructureLayer classes that are required in the application.
The Domain Layer
The DomainLayer is the heart of any ReflectApplication. The DomainLayer represents:
- The concepts of the business
- The business rules
- The state that reflects the business situation
- Business layer
- Business logic layer
- Domain model layer
The domain layer is basically where all the domain objects are. The DomainContainer is an DependencyInjectionContainer that can be used to create and hold DomainObject's that need dependency injection.
Note that the DomainLayer is a middle layer (see ReflectArchitecture):- The DomainObjects have NO references to objects in the upper UserInterfaceLayer nor ServiceLayer
- The DomainObjects may have references to the objects in the lower InfrastructureLayer or ProviderLayer, but not visa versa!
Domain Objects
DomainObjects represent entities; the nouns of the domain. If your application domain is a sales application it’s likely that your domain model contains DomainObjects such as: customers, products and orders.
DomainObjects are created by a developer or are reused from an existing application that needs to be re-written. They can be created from scratch or generated from a schema (in example from a database schema, XML schema or web service)
Naming
DomainObjects names are nouns, such as customer, product and order. They basically describe the things that are important in your application. DomainObjects names are part of the Ubiquitous Language: in terms understood by both users and developers.
Presentation
An UserInterfaceController can display domain objects in 3 ways:
- Domain object as form:
- Domain object as a field in a form:
- Domain object as a row in a table:
Construction
The principle of “naked objects” is that any 'Plain Old Java Object' (POJO) can function as a domain object. In other words: a domain class does not have to inherit from any special class, nor implement any particular interface, nor have any specific attributes.
DomainObjects can be created by different objects e.g.:- By a ServiceObjectActionMethod such as customerService.createNewCustomer()
- By a DomainObjectActionMethod such as shoppingCart.lineItemCreate(LineItem lineItem)
- By a DomainContainer such as domainContainer.getObject(Customer.class)
- By a InfrastructureObject method such as orderRepository.allOpenOrders() or shoppingCartFactory.createForCustomer(Customer customer).
There are 2 ways to create new DomainObjects:
- Creating a new DomainObject with the new keyword:
In example: Order order=new Order() - Creating a domain object using Dependency Injection:
Sometimes you want a new DomainObject to have references to other objects (being other DomainObjects, InfrastructureObjects or ProviderObjects). In example: A Customer object needs a references to a ShoppingCartFactory object. The Customer object can therefore be created by the DomainContainer with Customer customer= domainContainer.getObject(Customer.class). The ShopingCart object will automatically be injected as a constructor parameter of the Customer class. In order to create DomainObjects using dependency injection you need to: - Add the reference object as a parameter in the constructor and link it to a private field, so that it can be used throughout the class.
- Make sure that the referenced object type is known by the ReflectFramework: Its class must be returned by the ReflectApplication.getDomainClasses() method.
- The object that creates the DomainObject needs to have a reference to the DomainContainer as a constructor parameter, so that that the DomainContainer.get(Class) method can be called to get or create the DomainObject with the required dependencies injected by the ReflectFramework
Domain object members
Domain objects contain:
- Getter and setter methods (and possible fields): that define properties
- DomainObjectActionMethods: that define user actions
- Methods: that define ObjectBehavior
- Annotations: that define ObjectBehavior
Properties
DomainObjects have state. This means the domain objects contain information that may change over time. This information is represented by properties.
Here is an example of a domain class customer that has the following properties:- givenName
- familyName
- fullName
- bonusMember
public class Customer { private String givenName; private String familyName; private boolean bonusMember; public String getGivenName() { return givenName; } public void setGivenName(String givenName) { this.givenName = givenName; } public String getFamilyName() { return familyName; } public void setFamilyName(String familyName) { this.familyName = familyName; } public String getFullName() { return new TitleBuilder().append(givenName).append(familyName).toString(); } public boolean isBonusMember() { return bonusMember; } public void setBonusMember(boolean bonusMember) { this.bonusMember = bonusMember; } }
Properties are a special type of class members and are an intermediate between getter and setter methods and a field. The following 3 sections will explain this in more detail.
Getter methods
- A property always has a getter method, so that other objects can read its value
- The getter method name starts with get, followed by the property name in CamelCase when the property type is NOT a boolean (See the getGivenName() method in the example above)
- The getter method name starts with is, followed by the property name in CamelCase when the property type IS a boolean (See the isBonusMember() method in the example above)
- The getter methods are always public (accessible by other objects)
Setter methods
- A property might have a setter method, so that other objects can change its value. The property is read-only when it does not have a setter method
- The setter method name starts with set, followed by the property name in CamelCase (See the setFamilyName() method in the example above)
- The setter methods are always public (accessible by other objects)
- The setter methods are commonly placed after the corresponding getter method
Fields
- Properties can use fields to hold information in the domain object. These fields need to be private (not accessible by other objects) to ensure encapsulation (See private fields givenName, familyName and male in the example above)
- A property does not need to have a field. The value can be a computation of fields of other properties (such as the fullName property in the example above), or maybe even a value from an InfrastructureObject or a Provider.
- Fields are commonly defined at the beginning of the class
Property types
The ReflectFramework supports several data types. See PropertyFieldProvider for more information.Property behavior
You can specify certain things about both the behavior and presentation of properties by adding specific attributes or methods. See section ObjectBehavior.Action Methods
Domain objects can contain action methods (see DomainObjectActionMethod section)
The Service Layer
The ServiceLayer (sometimes also called application layer) gives the user access to the DomainObjects so that the user can work on them.
The ServiceContainer is an DependencyInjectionContainer that represents the ServiceLayer and holds and manages ServiceObjects.
Note that the ServiceLayer is a middle layer (see ReflectArchitecture):
- The ServiceObjects have NO references to objects in the UserInterfaceLayer
- The ServiceObjects may have references to the objects in the lower DomainLayer, InfrastructureLayer and ProviderLayer, but not visa versa!
Service Objects
The word 'service' implies:
- There is a client that needs to be served. For the ReflectFramework this is the user, trough the UserInterfaceController
- There are activities\ operations. For the ReflectFramework these are defined as ActionMethod's
- An activity\ operation is done with other things. For the ReflectFramework these operations are done with or on DomainObject s trough ActionMethod parameters and return values
- The operation relates to a domain concept that is not a natural part of a DomainObject (Entities or Value Objects).
- The interface is defined in terms of other elements of the domain model.
- The operation is state-less
Service objects operations relates to a domain concept that is not a natural part of a DomainObject
ServiceObjects contain ServiceObjectActionMethods. The UserInterfaceController displays these methods as menu items and invokes these methods once a user clicks on the menu item. Most ServiceObjectActionMethods create or retrieve DomainObjects where the user does not have an existing DomainObject to navigate from.
Service objects define an interface in terms of the domain model
ServiceObjects basically provides the user access to DomainObjects, so that the user can work on them (via the UserInterfaceController).
Service objects are state-less
Quoting Eric Evans: “ServiceObjects should be state-less. State-less here means that any client can use any instance of the ServiceObjects without regard to the instance’s individual history. The execution of the service will use information that is accessible globally, and may even change that global information (have side-effects). But it does not hold state of its own that affects its behavior, as most domain objects do."
ServiceObjects do not have state and therefore should not have properties (no getter and setter methods). My personal opinion is that a ServiceObject with state is a code-smell, which you can solve by moving the ServiceObjectActionMethods that share state (fields) to new or existing DomainObjects.
Service Objects should be flat
Object Orientated Programming favors to put business logic and the validation logic into the DomainObjects (and sometimes InfrastructureObjects) as much as possible. ServiceObjectActionMethods should therefore not contain business logic or validation logic, but delegate the work to collaborations of DomainObjects and InfrastructureObjects, in order to prevent the Anemic Domain Model - anti-pattern.
A web shop example
- The UserInterfaceController class calls the ServiceObjectActionMethod findProduct(searchCriteria) method on ServiceObject: ProductService
- This method will call the findProduct method on the InfrastructureObject : ProductRepository
- This method will return a list of DomainObjects that meet the search criteria
- The UserInterfaceController displays the found list of DomainObjects as a table in a new tab.
Construction
The principle of “naked objects” is that any 'Plain Old Java Object' (POJO) can function as a ServiceObject. In other words: a service class does not have to inherit from any special class, nor implement any particular interface, nor have any specific attributes.
ServiceObjects are instantiated by the ReflectFramework, and therefore need to be registered to the ReflectApplication.getServiceClasses() method.
In example:public class WebShop extends ReflectApplicationFor... { @Override public List> getServiceClasses() { List > serviceClasses = new ArrayList<>(); serviceClasses.add(ProductService.class); serviceClasses.add(ShoppingCartService.class); serviceClasses.add(OrderService.class); return serviceClasses; } // etc... }
ServiceObjects can have references to other objects. These objects are injected into the ServiceObject (see the ConstructionInjection section)
Naming
ServiceObjects are normally named after the DomainObjects that they service and have the suffix 'Service' (e.g. CustomerService, OrderService, etc).
Service object members
Service objects contain:
- ServiceObjectActionMethods: that define user actions
- Methods: that define ObjectBehavior
- Annotations: that define ObjectBehavior
Action Methods
ServiceObjects are all about ActionMethods that represent the main menu items (see section ServiceObjectActionMethod)
The Infrastructure Layer
The InfrastructureLayer contains InfrastructureObject's that provide generic technical capabilities to support the higher layers.
The InfrastructureLayer is also know as:
- Data access layer
- Persistence layer
- Logging Layer
- Networking Layer
- And other services which are required to support the ServiceLayer or DomainLayer
The InfrastructureContainer is an DependencyInjectionContainer that represents the InfrastructureLayer and holds and manages InfrastructureObjects.
- The InfrastructureObjects have NO references to objects in the upper UserInterfaceLayer, ServiceLayer nor DomainLayer
- The InfrastructureObjects may have references to the objects in the lower ProviderLayer, but not visa versa!
Infrastructure Objects
InfrastructureObjects provide generic technical capabilities to support the higher layers. InfrastructureObjects communicate with other systems such as external hardware (like disks), databases, web-services, etc...
Function and naming of InfrastructureObjects
The name of an InfrastructureObjects depends on what it does. It is common practice to use the following naming:
- Communicating with a database:
class names end with 'Repository', e.g.: CustomerRepository, OrderRepository, etc... - Communicating with a web-service:
class names end with 'Client', e.g.: EmailClient, GoogleMapsClient, SOAPClient, etc.. - Creating objects with a factory class:
class names end with 'Factory', e.g.: ReportFactory, etc.. - Logging:
class names end with 'Logger'
Infrastructure Object Presentation
The methods of infrastructure object are unknown to the UserInterfaceController and are not displayed on the UserTestObject Interface. *
Construction
The principle of “naked objects” is that any 'Plain Old Java Object' (POJO) can function as a InfrastructureObject. In other words: a InfrastructureObject class does not have to inherit from any special class, nor implement any particular interface, nor have any specific attributes.
You can:
- write new InfrastructureObjects.
- reuse InfrastructureObjects from existing projects
- use or extend one of the InfrastructureObjects of one of the ReflectInfrastructureProjects. Open the type hierarchy of the InfrastructureObject, to see all these convenience classes
- or use or extend InfrastructureObjects from other (open source) projects
The Provider Layer
The ProviderLayer contains Provider objects that provide generic ReflectFramework capabilities (cross cutting concerns) to support the higher layers (see ReflectArchitecture)
The ProviderContainer is an DependencyInjectionContainer that represents the ProviderLayer and holds and manages Provider Objects.
Note that this layer is the bottom layer (see ReflectArchitecture ), which means that objects in the upper layers may have references to ProviderObjects, but not visa versa!
Providers
Providers are like ServiceObjects, but they provide access to objects that provide information for the ReflectFramework, such as:
- Authorization (see AuthorizationProvider)
- Validation (see ValidationProvider)
- Multiple languages (see LanguageProvider)
- Notifications (see NotificationProvider)
- URL information (see UrlProvider)
- Object meta information (see ReflectionProvider)
- Version information (see VersionProvider)
Providers may be used by any class within an application.
Providers have a default implementation and each ReflectApplication can use different implementations of these Providers where needed. For more information see the ReflectApplication.get...Service()} methods
You can easily change or add to the ReflectFramework functionality by implementing or overriding the existing Providers.
Reflect Service Object Construction
Provider's are instantiated by the ProviderContainer (see DependencyInjectionContainer) Providers can have references to other Providers. These objects are injected into the Providers (see the ConstructionInjection section.
Provider Presentation
The methods of Providers are not displayed by the UserInterfaceController.
Authorization Provider
Authorization, means the ability to control what an individual user can see and do within an application, based upon their identity and the role(s) assigned to them.
The AuthorizationProvider facilitates this with methods:Types of AuthorizationProvider
There can be different types of AuthorizationProvider implementations, depending on the authorization mechanism you prefer. In example: you could write an implementation that uses:- hard coded authorization
- file based authorization
- database authorization
- web container authorization (e.g. Apache Tomcat Realm)
- LDAP
- Active directory
- or other
public class AuthorizationProviderTestObject implements AuthorizationProvider { private final List<UserTestObject> users; private UserTestObject currentUser; public AuthorizationProviderTestObject() { users = new ArrayList<>(); users.add(new UserTestObject("carla", "pasword1", "salesmanager")); users.add(new UserTestObject("john", "pasword2", "customer")); } public void login(String userName, String password) throws InvalidNameOrPasswordException { for (UserTestObject user : users) { if (user.isValid(userName, password)) { currentUser = user; return; } } throw new InvalidNameOrPasswordException(); } @Override public String getCurrentUserName() { return currentUser == null ? "" : currentUser.getName(); } @Override public boolean userInRole(String role) { return currentUser == null ? false : currentUser.inRole(role); } }
Registering an AuthorizationProvider
The AuthorizationProvider is registered to the framework with the ReflectApplication.getAuthorizationProviderClass() method. By default it returns the DefaultAuthorizationProvider, which always returns true on the userInRole(String) method. You can register another AuthorizationProvider implementation by overriding the ReflectApplication.getAuthorizationProviderClass() method.
Using an AuthorizationProvider
The AuthorizationProvider is used by the @Hidden and @Disabled annotations (see ObjectBehavior). If you want to use the AuthorizationProvider in your code you need to inject it into your object (see ConstructionInjection)
Validation Provider
The UserInterfaceController sometimes let’s the user edit an ActionMethod parameter (e.g. a primitive type or a DomainObject), depending on how the ActionMethod is annotated, see ExecutionMode. The UserInterfaceController then validates the edited ActionMethod parameter using the ValidationProvider before the ActionMethod is invoked. The ValidationProvider will use ValidationAnnotations and ValidationMethods.
Validation annotations
A DomainObjectProperty can be validated by putting validation annotations before the getter method of a property. The ReflectFramework uses the JSR303 compliant Apache BVal library for validation. Please read the Apache BVal documentation on how to annotate the getter methods of the properties.
Validation methods
DomainObjects and DomainObjectPropertys can also be validated with ValidationMethods located in the DomainObject so that you can do more complicated validation using code.
ValidationMethods conventions:
- Syntax: public ValidationViolations <DomainObjectPropertyName><constraint name>Validation.
E.g. for a DomainObjectProperty startDate: public ValidationViolations startDateAfterTodayValidation()
E.g. for business rule custommerUnique: public ValidationViolations customerUniqueValidation() - Method may not have a method parameter
- Method must return a ValidationViolation
- Method must be public
- Method may not be static
- May not change the state of the DomainObject
ValidationProvider implementation
There are many validation libraries and frameworks available. The ReflectFramework complies with the JSR303 by using the Apache Bean Validator (BVal) library, combined with ValidationMethods. You are free to implement or extend your own implementation and register it to your ReflectApplication by overriding the ReflectApplication.getValidationProviderClass() method
Language Provider
The LanguageProvider provides support multiple languages.
English by default
The ReflectFramework supports the English language by default because it uses the Class names, DomainObjectProperty names and ActionMethod names that are used in the code as part of the Ubiquitous Language (in terms understood by both users and software developers). For more information see TranslatedDisplayName.
DisplayName Annotation
In some cases the default English text is incorrect because the Class name, DomainObjectProperty name or ActionMethod name is incorrectly translated to the default English text by the ReflectFramework. In this case you can correct this using a DisplayName annotation.
How texts are translated to other languages
The UserInterfaceController will call the LanguageProvider to try and get the appropriate text from the LanguagePropertyFiles (depending on the selected language). If it can’t find this value it will display the default values (in English)
Language property files
Texts for other languages are stored in property files. The name of these files need to be: <application configuration folder>/language_<language_code>.properties
- <application configuration folder> These files need to be located at the configuration folder of the application. These files are often stored in the src/main/resources folder. See UrlProvider for more information
- <Language_code> two letter language code (see java Locale)
The language property files comply to the Java .properties standard and thus contain key value pairs.
- The key is an unique reference to a text. The ReflectFramework therefore uses the canonical name of the class of class member. Keys have the following format: <packageName>.<classname> or <packageName>.<classname>.<propertyName> or <packageName>.<classname>.<actionMethodName>, followed by .displayname or.description (see examples below)
- The value is the translated text. Special characters are supported with Unicode (\u
e.g. \u20AC=€). There are several free tools available to edit .properties file with good Unicode support.
Examples of key value lines in property files:
- com.acme.order.ShoppingCart.displayname=Winkel wagen
- com.acme.product.ProductService.displayname=Producten
Creating and updating LanguagePropertyFiles
See the ReflectUtilMavenPlugin:UpdateLanguageFiles goal, to learn how you can create and update LanguagePropertyFiles
Using translations in your application
There are multiple ways to use translatable texts in your application:
A TranslatableString will provide the translated text using the LanguageProvider and then replace the place holders (e.g. %s) with the parameter values (if any). TranslatableStrings can best be created as a static Field, so that the ReflectUtilMavenPligin can automatically find all TranslatableStrings in an application and and update LanguagePropertyFiles.
A TranslatableException will show the translated error message using the LanguageProvider and then replace the place holders (e.g. %s) with the parameter values (if any). TranslatableExceptions need to define a TranslatableString. TranslatableStrings are best created as a static Field, so that the ReflectUtilMavenPlugin can automatically find all TranslatableStrings in an application and and update LanguagePropertyFiles.
- By inject the LanguageProvider into the object that needs it and use it in your code (see ConstructionInjection)
Notification Provider
- TODO What it does
- TODO How you can use it (or explain who uses it)
- TODO Code example
- TODO How to register a custom ... provider
Reflection Provider
The ReflectionProvider provides information on objects ( ApplicationClassInfoTest, ServiceClassInfo, DomainClassInfo), properties ( PropertyInfo) of ActionMethod ( ActionMethodInfo) using reflection. The UserInterfaceController uses this information to know how the user interface should look like and behave. You can use the ReflectionProvider in your code when you need meta information (See ConstructionInjection) TODO Code example
Version Provider
The VersionProvider provides the following information on all objects used in an ReflectApplication:
- The class name
- The package name (jar,war,etc...)
- The version of the jar file (from the meta info file)
- The authors of the jar file (from the meta info file)
URL Provider
The UrlProvider is a Provider that ensures you can use ReflectUrl's. It knows ReflectUrlStreamHandlers that can convert a ReflectUrl to a normal URL. The following paragraphs show examples of ReflectUrlStreamHandlers
ApplicationUrlStreamHandler
A ApplicationUrlStreamHandler handles a ApplicationUrl.
A ApplicationUrl is a ReflectUrl that helps to create a reference to the application folder e.g. to get a resource file.
The format of a ApplicationUrl is: reflect-application://<relative path to resource>
E.g.: reflect-application://images/sales.png (for a reference to the sales.png file in the application sub folder images)
ClassResourceUrlStreamHandler
A ClassResourceUrlStreamHandler handles a ClassResourceUrl.
A ClassResourceUrl is a ReflectUrl that helps to create a reference to a class resource (See Class.getResource(String))
The format of a ClassResourceUrl is: reflect-class-resource://<class path>/<resource name>
E.g.: reflect-class-resource://com.acme.SalesApp/sales.png; (for a sales.png file in the com.acme package, next to the SalesApp class)
FontIconUrlStreamHandler
The FontIconUrlStreamHandler resolves FontIconUrls.
A FontIconUrl is a ReflectUrl that helps to create a reference to a FontIcon.
The format of a FontIconUrl is: reflect-font-icon://<font name>/<font fontIconUrl>#<uni code>
E.g.: reflect-font-icon://FontAwesome/META-INF/resources/webjars/font-awesome/4.5.0/ fonts/fontawesome-webfont.ttf#F0C9 for a menu/navigation icon
FontIconUrl's can be used in your code with e.g. FontAwesomeUrl.NAVIGATION
ServiceMethodUrlStreamHandler
A ServiceMethodUrlStreamHandler handles a ServiceMethodUrl.
A ClassResourceUrl is a ReflectUrl that helps to create a reference to a class resource (See Class.getResource(String))
The format of a ClassResourceUrl is: reflect-class-resource://<class path>/<resource name>
E.g.: reflect-class-resource://com.acme.SalesApp/sales.png; (for a sales.png file in the com.acme package, next to the SalesApp class)
String Converter Provider
The StringConverterProvider is a Provider that provides a StringConverter for a given TypeInfo and a given (optional) Format pattern.
A StringConverter converts between a string and a given type. The type of objects and formats of strings are defined by the subclasses of the StringConverter.
StringConverters are often used in PropertyFields or a Table cells.
You can append or override custom StringConverters by overriding the ReflectApplication.getStringConverterProviderClass() method.
The StringConverterProvider provides the following StringConverters per default:
Java Numbers:
- ByteStringConverter
- ShortStringConverter
- DoubleStringConverter
- FloatStringConverter
- IntegerStringConverter
- LongStringConverter
- BigDecimalStringConverter
- BigIntegerString
- CalendarStringConverter
- DateStringConverter
- LocalDateTimeStringConverter
- LocalDateStringConverter
- LocalTimeStringConverter
- StringStringConverter
- BooleanStringConverter
- CharacterStringConverter
- UriStringConverter
- UrlStringConverter
- FileStringConverter
- PathStringConverter
Property Field Provider
The PropertyFieldProvider is a Provider that creates PropertyFields using PropertyFieldFactorys. These are configured in the ReflectApplication:
- PropertyFieldProvider with the GraphicalUserInterfaceApplication.getPropertyFieldProviderClass() method
- PropertyFieldFactorys with the GraphicalUserInterfaceApplication.getPropertyFieldFactoryClasses() method
The ReflectFramework supports the following PropertyFields:
You can add custom fields by implementing PropertyField and PropertyFieldFactory and overriding the GraphicalUserInterfaceApplication.getPropertyFieldFactoryClasses(). Look at the existing implementations for inspiration.
Property Action Method Execution Provider
Property Action Method Pre-Handler Provider
Property Action Method Result Handler Provider
Processes the ActionMethod return value (e.g. displays the results) when the ActionMethod is invoked
The UserInterface Layer
The UserInterfaceLayer is also know as presentation layer (although I think that 'presentation layer' is a poor name, because it is responsible for so much more). The UserInterfaceLayer contains the UserInterfaceController.
The UserInterfaceContainer is an DependencyInjectionContainer that represents the UserInterfaceLayer and holds and manages the UserInterfaceController.
Note that this layer is the top layer, which means it may know all the objects in the lower layers but not visa versa! See ReflectArchitecture
The ReflectFramework has multiple user interface implementations. See the ReflectApplicationProjects section to learn what types of user interfaces are available, or download all the sources of the ReflectFramework projects and see the class hierarchy of the UserInterfaceController class to find all the different user interface implementations.
User Interface Controller
The UserInterfaceController is responsible for showing information to the user (or other systems) and processing the information from the user using the objects in the lower layers (see ReflectArchitecture).
The UserInterfaceController provides a basic interface for handling communication with other systems (e.g. a SOAP or RESTFULL interface) or with a person or other system via a command line interface.
Graphical User Interface Controller
The GraphicalUserInterfaceController extends the UserInterfaceController and adds functionality needed for a Graphical User Interface. The GraphicalUserInterfaceController creates and manipulates a MainWindow for a person to interact with.
Reflect GUI Components
A ReflectFramework GraphicalUserInterfaceApplication is made of several ReflectGuiComponents. A ReflectGuiComponent is a graphical user interface component. These classes normally extend some Component class of the graphical user interface framework (e.g. for Android, JavaFx or Vaadin).
Main Window
The MainWindow contains all the ReflectGuiComponents needed for a ReflectApplication:
Application Bar
TODO PICTURE ApplicationBar
An ApplicationBar is a ReflectGuiComponent. It is located at the top over the whole width of the MainWindow. It provides content and actions related to the current screen. It’s used for branding, screen titles, navigation, and actions.
Principles
- Persistent: Top app bars appear at the top of each screen in an app, and can disappear upon scroll when the ReflectDisplayHeight.SMALL.
- Guiding: Top app bars provide a reliable way to guide users through an app.
- Consistent: Top app bars have a consistent position and content to increase familiarity.
Anatomy
The recommended placement of elements in a top app bar for left-to-right languages is:
- Place navigation on the far left
- Place any titles to the right of navigation
- Place contextual actions to the right of navigation
- Place an overflow menu (if used) to the far right
Main Menu
The MainMenu is displayed on a panel on the left hand side of the user interface. Sometimes this panel is hidden but it can always be made visible again using the menu icon on the ApplicationBar. The MainMenu provides the user access to the DomainObjects so that the user can work on them. The MainMenu contains all ActionMethods of ServiceObjects that either have no method parameter or have an ParameterFactory.
ActionMethods of ServiceObjects that take a DomainObject as a parameter and have no ParameterFactory are displayed in FormTabMenus and propertyMenus.
Each ServiceObject is always displayed as a sub menuTabs
A Tab is a ReflectGuiComponent on which some kind of information is displayed. This is often a FormTab or a TableTab that show the results or parameter of a ActionMethod. A graphical user interface of a ReflectApplication can have multiple tabs at the same time (see tabbed document interface (TDI)). Only one Tab wil be displayed at a time. Each Tab will have a TabHeader that is displayed in the TabHeaderBar. You can select another Tab by clicking on one of the other TabHeaders or the TabSelectionButton
A GraphicalUserInterfaceApplication can contain multiple types of tabs.
Table Tab
A TableTab is a ReflectGuiComponent. It shows the user a table or grid of values which could be DomainObject. These values (an array, list, set or queue) is the result of a ActionMethod. TableTabs are normally used to select e DomainObject, so that it can be viewed or manipulated with a FormTab
Table Tab Menu
TODO PICTURE TableTabMenu
A TableTabMenu is displayed as a context menu when a user clicks on one of the rows of the grid or table. It contains all the ActionMethods of the DomainObject and all ActionMethod s of ServiceObjects that take the DomainObject as a parameter. Each ServiceObject is displayed as a sub menu.
Form Tab
Customized tabs
The TableTab and FormTab are normally used to select a DomainObject and view or manipulate it. You can create your own Tab and configure it to be used in your ReflectApplication if you need a different representation of the DomainObjects. Typical examples are:
- A Blog where a list of Comments (DomainObjects) are displayed in a alternative manner (See this blog example)
- A map that represents information from a MapInformation (DomainObject (See this this map example)
Graphical Design Rules
Big software companies like Google, Micro$oft, Apple and Facebook spend a lot of research and effort in maximizing usability and the user experience for their graphical user interface designs. These companies all have a set rules that say something about usability, graphical design and typography. All these companies use a flat design style.
ReflectFramework applications also uses a set of set of graphical user interface design rules in order to make them consistent across all ReflectApplicationProjects.
Google's Material Design
Google's Material Design is beautiful, simple, well accepted, and well defined. ReflectFramework applications follow the Google's Material Design as much as possible. For more information see https://material.io/design/
Responsive Design
ReflectFramework applications have a responsive design: a graphical user interface that optimizes its layout and its components, for a variety of devices and screen sizes, in order to maximize usability and user experience.
The size of the ReflectApplication can be anywhere between a small smart phone until a desktop monitor.
Different display widths
The layout and components vary depending on the ReflectDisplayWidth:- ReflectDisplayWidth.SMALL:
- The application title in the ApplicationBar is only visible when the MainMenu is displayed (overlapping the tab headers because there is no space to show both of them at the same time).
- The ActionMethods of the active Tab are displayed as OverflowMenu after clicking the Overflow icon on the ApplicationBar (because there is no space to show the ActionMethods in the ApplicationBar).
- The MainMenu is displayed as a navigation drawer (overlapping the content area (tab panels) because there is no space to show both of them at the same time).
- Tables only have one column that show the DomainObject TitleModel because there is no space to show more columns
- FormTabs show all PropertyPanel's underneath each other
- ReflectDisplayWidth.MEDIUM:
- The application title in the ApplicationBar is only visible when the MainMenu is displayed (overlapping the tab headers because there is no space to show both of them at the same time).
- The ActionMethods of the active Tab are displayed as OverflowMenu after clicking the OverflowMenu icon on the ApplicationBar (because there is no space to show the ActionMethods in the ApplicationBar).
- The MainMenu is displayed as a navigation drawer (overlapping the content area (tab panels) because there is no space to show both of them at the same time).
- Tables only can have a few columns, depending on the available width
- FormTabs could have more PropertyPanel's next to each other, depending on the available width.
- ReflectDisplayWidth.LARGE:
- The application title is visible in the ApplicationBar when the MainMenu is displayed.
- The ActionMethods of the active Tab are displayed on the ApplicationBar or in a OverflowMenu after clicking the OverflowMenu icon on the ApplicationBar (if there is no space to show all the ActionMethods in the ApplicationBar).
- The MainMenu is displayed on the left when it is not hidden (shifting the content area (tab panels) to the right so that both are visible)
- Tables only can have multiple columns, depending on the available width
- FormTabs could have more PropertyPanel's next to each other, depending on the available width
Different display heights
The layout and components vary depending on the ReflectDisplayHeight:- ReflectDisplayHeight.SMALL:
- The ApplicationBar can scroll out of sight to make more space for the Tabs
- ReflectDisplayHeight.MEDIUM:
- The ApplicationBar is always visible on top
- ReflectDisplayHeight.LARGE:
- The ApplicationBar is always visible on top and may have more height
- The ActionMethods of the active Tab can either be displayed on the higher ApplicationBar or on a ToolBar on the top of the Tab
Colors
The ColorProvider is a Provider that provides the with the GraphicalUserInterfaceApplication.getColorProvider() method. GraphicalUserInterfaceApplications can use 3 main colors:
- PrimaryBackgroundColor: A color that is prominent visible, e.g.: the background color of the application tool bar
- AccentBackGroundColor: A color that is used for things that need attention (i.e. important buttons or controls that have focus)
- ContentBackgroundColor: A color used for the background of the content. This color should preferably either be very light (e.g. White) or very dark (e.g.Black)
Google's Material Design recommends to use colors from color palettes that they recommend. See Google's Material Design Palettes for more information.
Each color can be derived into a ReflectColorSet.
A ReflectColorSet is a group of background and foreground colors, based on a given background color and a predefined set of rules.
You can override the default colors by extending the GraphicalUserInterfaceController and overriding the GraphicalUserInterfaceController.getColorProvider() method. You then must return this GraphicalUserInterfaceController by overriding the ReflectApplication.getUserInterfaceControllerClass()
Action Methods
An ActionMethod is a method in a DomainObject or ServiceObject that is displayed by the UserInterfaceController as a menu item. An ActionMethod is invoked by the UserInterfaceController when the user clicks on the menu item.
There are several menu's where these ActionMethods are displayed:
Action Methods for Domain Objects
DomainObjects may have ActionMethods that to do something with or for the given DomainObject. In example: an ShoppingCart object may have an ActionMethod such as checkout().
ActionMethods of DomainObjects are displayed as menu items in the FormTabMenu.
Action Methods for Domain Object Properties
DomainObjects may have ActionMethods that do something with the value of a DomainObjectProperty, e.g. modify it or display it. These DomainObjectPropertyActionMethod's are displayed in a PropertyPanelMenu
The name of the ActionMethod for a DomainObjectProperty always begins with the DomainObjectPropertyname, followed by the ActionMethodname.
Example: A WebShop object may have an property products that has a DomainObjectPropertyActionMethods such as:
- productsAdd(Product product)
- productsRemove(Product product)
- productsFind(String query)
Action Methods for Service Objects
ServiceObjects exist because they always have one ore more ActionMethods. ActionMethods of serviceObjects can appear as menu items in the MainMenu, FormTabMenu, or PropertyPanelMenu
In Example: a CustomerService object may have an ActionMethod such as findCustomer(CustomerSearchArgument searchArgument) that is displayed in the MainMenu.
Action Methods Convention
Any method in a DomainObject or ServiceObject can be an Action method, provided that it complies with the following convention:
- The method has no parameter or a single DomainObject parameter
- Its return type (if any) are types recognized by the ReflectFramework (see below)
- The method is not a getter method or a setter method (see DomainObjectProperty)
- The method is not a BehavioralMethod
- The method is public (not private)
- The method is NOT static
Action method names
The name of an ActionMethod should describe the action in a Ubiquitous Language (in terms understood by both users and developers). Keep in mind that the goal of a user is almost never to create, update or delete objects. Method names like: createPerson(Person person), updatePerson(Person person) and removePerson(Person person) should therefore be avoided where possible. Method names like addNewBorn(BirthCirtificate birthCirtificate), addMarriage(Marriage marriage), deceased(DeathCertificate deathCertificate) would be better method names.
Action method parameter
An action method either has no parameter or a single DomainObject as a parameter. If not, the ReflectFramework will not recognize a method as an ActionMethod.
Action method return value
The UserInterfaceController renders the output of a method, depending on the type of the action method return value:
- No return value (void method): The UserInterfaceController will display a short message when the method has been executed
- A primitive data type: The UserInterfaceController will display a message dialog that displays the return value after the method is been executed
- A DomainObject: The UserInterfaceController displays the DomainObject in a new FormTab.
- A collection of DomainObjects: The UserInterfaceController displays the DomainObjects in a new GridTab.
- A URI: The UserInterfaceController displays the contents of the URI on a new Tab.
- A DownloadStream: The UserInterfaceController will open a "Save as" dialog" so that the file can be down loaded.
Action Method behavior
You can specify certain things about both the behavior and presentation of ActionMethods with help of BehavioralAnnotations or BehavioralMethods, in example:
- Display name
- icon
- visibility
- enabled state
- ExecutionMode
- ReadOnlyActionMethod
Object behavior
The ReflectApplication, ServiceObjects and DomainObjects can have behavior that defines how the objects act or how they are displayed. Behavior can be defined with:
Behavioral Annotations
BehavioralAnnotations are recognized by the ReflectFramework and define how DomainObjects, DomainObjectPropertys or ActionMethods behave (how they act and how they are displayed).
BehavioralAnnotations are normally located before the declaration of the member:- BehavioralAnnotations for a class: are located before the class key word
- BehavioralAnnotations for a DomainObjectProperty: are located before the getter method of a DomainObjectProperty
- BehavioralAnnotations for an ActionMethod: are located before the ActionMethod
Behavioral Methods
BehavioralMethods are recognized by the ReflectFramework and dynamically define how DomainObjects, DomainObjectPropertys or ActionMethods behave (how they act and how they displayed). The ReflectFramework will call these BehavioralMethods when the user interface is updated to get the current behavioral values depending on the state of the object (property values)
Behavioral Method Convention
- Syntax: <memberName><behaviourName>
<memberName>= can be a ClassName, a DomainObjectProperty Name or a ActionMethodName
<behaviourName>= A behavior like FontIcon, Hidden, Disabled, Validation, etc - BehavioralMethods do NOT have any parameters
- BehavioralMethods ALWAYS return a value (see BehavioralMethod.returnType() of the different implementations
- BehavioralMethods are public
- BehavioralMethods are not static
- BehavioralMethods are normally located after the declaration of the member:
- BehavioralMethods for classes: are located after the constructors
- BehavioralMethods for DomainObjectProperty: are located after the getter and setter methods of the properties
- BehavioralMethods for ActionMethod: are located after the ActionMethod
Display Name
The ClassNames, DomainObjectProperty names and ActionMethodNames are part of the ubiquitous language (in terms both understand by users and developers). The ReflectFramework therefore displays the same names as used in the program code.
DisplayName Default
Class names, DomainObjectProperty names and ActionMethod names in the codebase use names such as OrderService, orderLines, addOrderLine (using no spaces, camelCase and no special characters). If the user is a an human, more user friendly names are needed such as “Orders” “Order lines” and “Add order line”. This format is called the DisplayName. The ReflectFramework will automatically convert the names used in the code to a human readable format (DisplayName) when needed.
The ReflectFramework supports DisplayNames for multiple languages. The LanguageProvider is used to get the default displayNames from a language specific property files. For more information see LanguageProvider.
DisplayName Annotation
The ReflectFramework will automatically convert the names used in the program code to a human readable English format by default. In some cases the default DisplayName does not suffice, in example when:
- A different use of capital case is needed
- Special characters are needed that can not be used in the code
- The plural form of the default displayName of a ServiceObject is incorrect
In these cases you can use a DisplayName annotation. The DisplayName annotation is placed:
- before the class keyword
- before the getter method of a DomainObjectProperty
- or before a ActionMethod
Description
A DomainObject, {link DomainObjectProperty} or ActionMethod can have a text to explain the class member in more detail. This TranslatedDescription is often displayed in a graphical user interface as tooltip or can be used by most accessibility tools (e.g. for blind people) when the user hovers over the DomainObjectProperty or ActionMethod (menu item) or icon
Description Default
By default the description is the same as the default DisplayName, therefore it is recommended to override the default value where needed. You can override the default value by by adding the description in the language property files (see LanguageProvider) or by adding a Description annotation.
Description Annotation
You can override the default description value for the English language, by putting the Description annotation before the getter method of a DomainObjectProperty or before an ActionMethod
TODO EXAMPLENote that the Description annotation is intended for the English language only. Use the Description default if you want to use multiple languages
Title
DomainObjects that have identity (entities) need to have a dynamic title that help users to distinguish objects of the same type (e.g. Type customer versus “John Doe”). This title should exist of all the properties that identify the object. The title is therefore dynamic: it changes when the value of these properties change.
In example: The title of a customer could be a customer number, followed by the given name, followed by the family name. If the customer changes it’s name, than so does the title (but not its identity)
Title Default
The ReflectFramework provides a default title based on the properties that are normally displayed in tables. This is a best guess. It is therefore recommended to always implement the toString method.
Title (toString) method
You can define the title by overriding the the toString() method of your DomainObject
(TODO example with Customer toString and TitleBuilder)
Title builder
Often a DomainObject can be identified by a single property. The toString() method can than simply return this property value to return the title.
In other cases a DomainObject is identified by multiple property values. In this case it is recommended to override the toString() method and using the TitleBuilder to create an identification string.
The TitleBuilder can be compared with a StringBuilder, but has some additional functionality such as:
- The “append” methods will append a separator and a given value. You can use the default separator (a comma and a space) or use an “append” method where you pass the separator as a first parameter followed by the value.
- The “contact” methods will append a given value without a separator
- Both “append” and “contact” methods will ignore null values or reference objects that have not overridden the toString method
- Both “append” and “contact” methods have methods where you can specify format values (e.g. date, time and numbers)
- Enumeration values will be translated to a readable format
FontIcon
ServiceObjects ,DomainObjects and ActionMethods can have FontIcons that are displayed in graphical user interfaces. These icons help the user to quickly identify what they are looking at.
Fonticons have become very popular in graphical user interface design. ApplicationIcon fonts are just fonts. However, instead of containing letters or numbers, they contain symbols and glyphs that can be used in a graphical user interface. Advantages of font icons over raster format files:
- Browsers are usually faster in rendering fonts than loading image files.
- Fonts Icons are vector graphics, so they scale well at any size.
- As font icons are text characters, all icons can be styled in the same way (size, color, shadow, etc)
There are many free font icons that you can use in your application (e.g. download or include with a build tool like Maven). Examples of free ApplicationIcon fonts are:
There are free online tools to create your own icon font, e.g by: importing from icons from their (free) database, other (free) icon fonts or XML-based vector image format (SVG) from other (free) web sites. Example of web site that help you build your icon font are:
Note that the icon is also linked to the Description of that class so that it can be displayed as a tooltip or can be used by most accessibility tools (e.g. for blind people) when the user hovers over the icon.FontIcon Default
The default is no FontIcon
FontIcon Annotation
You can define the FontIcon by placing an FontIcon annotation before the class key word of the ServiceObject or the DomainObject or before the ActionMethod.
Syntax: FontIcon(String fontIconUrl)
Parameter fontIconUrl: See FontIconUrl
FontIcon Method
Instead of the FontIcon annotation you can also define the icon with a FontIconMethod. This allows you to change the icon dynamically during runtime, based on the object state (e.g. when the DomainObject Person is a male or female).
Syntax: public string <className or ActionMethodName>FontIcon()
The return value must be an FontIconUrl. TODO EXAMPLE customer male or female iconApplicationIcon
With a ApplicationIcon the graphical user interface of a ReflectApplication can easily be identified by the user. This icon is a file that contains an image. The type, size and depends on the type(platforms) of your application. In example:
- Icon requirements for JavaFX (desktop) applications
- Icon requirements for Android (mobile) applications
- Icon requirements for Web applications
ApplicationIcon Default
The default is no ApplicationIcon
ApplicationIcon Annotation
You can define the ApplicationIcon by placing an FontIcon annotation before the “class” of the ReflectApplication.
Syntax: ApplicationIcon(String iconURL)
Parameter iconURI: a URL to a image file. Best practice is to put the icon file in the package of the ReflectApplication class and refer to it using a ClassResourceUrl. TODO: example.
ApplicationIcon Method
Instead of the FontIcon annotation you can also define the icon with a ApplicationIconMethod. This allows you to change the icon dynamically during runtime, based on state (e.g. when the DomainObject Person is a male or female).
Syntax: public string <ApplicationClassName>ApplicationIcon()
The return value must be an a URL to the ApplicationIcon file, e.g. a ClassResourceUrl. TODO EXAMPLE of a changing application iconHidden
DomainObjectProperty or ActionMethod is visible on the user interface by default,but in some cases you may want to hide them, e.g.:
A- Because not all information needs to be displayed in the user interface (e.g. a database id key or version number for optimistic locking)
- Because you want to limit the number of visible properties in a table (e.g. to limit the number of columns in a table to prevent the table to become cluttered with to much information)
- Depending on the state of a DomainObject you do not want to display Irrelevant information
- Depending on the state of a domain object you do not want a user to activate an action method (e.g. hide an ActionMethod “submit” once the domainObject already is submitted)
- Because a user is not authorized to see a property value
- Because a user is not authorized to activate an ActionMethod
Hidden Annotation
You can hide a DomainObjectProperty by putting the Hidden annotation before the getter method or you can hide an ActionMethod by putting the Hidden annotation before the ActionMethod.
Syntax: @Hidden(propertyHiddenFor, exceptForRoles)
Parameters:
- propertyHiddenFor(): optional and for properties only: to indicate if the property should be hidden in FormTabs, TableTabs or both (hidden for both is default).
- exceptForRoleNames() : optional comma separated string of user roles that are allowed to see the DomainObjectProperty or ActionMethod
Hidden Method
You can hide a DomainObjectProperty or DomainObjectActionMethod depending on the DomainObject state (the value of its properties), with an ...Hidden method. If you have a Hidden annotation and a ...Hidden method, both need to be true in order to hide the DomainObjectProperty or ActionMethod.
Note that you can not change the visibility with a ...Hidden method for DomainObjectProperty in a TableTab!
Syntax: public boolean <property name or actionMethodName>Hidden;()
ReturnValue: a boolean that is true if the DomainObjectProperty or ActionMethod needs to be hidden
Disabled
A DomainObjectProperty or ActionMethod is enabled on the user interface by default, but in some cases you may want to disable them. If something is disabled they are grayed out on the user interface. Disabled properties can not be edited (read only) and disabled ActionMethods can not be invoked.
You may want to disable items when:
- Not all properties need to be editable on the user interface but the code might need a setter method to set the DomainObjectPropertyvalue when the DomainObject is created from the database
- Depending on the state of a DomainObject you do not want the user to edit certain DomainObjectProperty
- Depending on the state of a DomainObject you do not want a user to invoke an ActionMethod (e.g. prevent invoking ActionMethod “submit” once the DomainObject already is submitted)
- Because a user is not authorized to edit a DomainObjectProperty Value
Important note: If an user is not authorized to change a DomainObjectProperty or call an ActionMethod it is best to hide the method or property instead of disabling it. In general you do not want to confuse users (clutter the user interface) with options that they are not allowed to use anyway. Disabled ActionMethods have a bad impact on usability.
Disabled Annotation
You can disable a DomainObjectProperty by putting the Disabled annotation before the getter method or you can disable an ActionMethod by putting the Disabled annotation before the ActionMethod.
Syntax: @Disabled(exceptForRoles)
Parameter: exceptForRoleNames(): optional comma separated string of user roles that are allowed to edit the DomainObjectProperty or invoke a ActionMethod
TODO EXAMPLEDisabled Method
You can disable a DomainObjectProperty or DomainObjectActionMethod depending on the DomainObject state (the value of its properties).
If you have a Disabled annotation and a disabled method, only one needs to be true in order to disable the DomainObjectProperty or ActionMethod.
Syntax: public boolean <property name or actionMethodName>Disabled()
ReturnValue: a boolean that is true if the DomainObjectProperty or ActionMethod needs to be disabled
Disabled Annotation and Disabled Method
If the code has both a "disabled annotation" and a "disabled method", the ReflectFramework work will disable the item when on of them is true (if the user is not authorized by the definition of the Disabled annotation OR if the disabled method returns true).
Order
The order in which the class members (DomainObjectProperty and ActionMethod) are displayed is defined with the Order annotation. Note that the order of class members can not be changed during runtime.
The Order annotation can be added before the getter method of a DomainObjectProperty or before an ActionMethod. Both DomainObjectProperty and ActionMethods are ordered separately but use the same annotation.
Syntax: @Order(double sequenceNumber)
The sequenceNumber of the Order annotation determines the position of the class member. The class member with the lowest sequenceNumber will be shown first, a higher sequenceNumber later. Class members that are not annotated will be shown last.
It is recommended to use an interval (of let's say 10) between the sequenceNumbers so that you do not have to renumber all the existing Order annotations every time you add a new class member in between. Otherwise you can always fall back on using decimals (e.g. 1.5 or 10.25).Format
Some property types such as Date, time, Number can be formatted with help of the Format annotation. Note that the format can NOT be changed during runtime.
The Format annotation can be added before the getter method of a DomainObjectProperty.Syntax: @Format(string pattern)
Please see the JavaDoc of the SimpleDateFormat and DecimalFormat formatters to learn more about the patterns that can be used. See the FormatFactory to learn how the formating works for the different DomainObjectProperty types.
TODO exampleText Field Mode
DomainObjects are rendered by the user interface layer as fields when a DomainObject is displayed in a FormTab. The FormTab will determine in what type of field these DomainObjectPropertys are displayed (textbox, combobox, etc). When the DomainObjectProperty is a Text (String, number, etc) , you can select an alternative field type using the TextFieldMode annotation. The TextFieldMode annotation needs to be put before the getter method of a DomainObjectProperty. Note that the format can not be changed during runtime.
Syntax: @TextFieldMode(FieldModeType mode)
Examples of alternative FieldModeTypes:
- TextFieldModeType.SINGLE_LINE: renders a text field to edit a string with a single line
- TextFieldModeType.PASSWORD: renders a field to edit a password (obscuring the input so that other users can not read the secret password)
- TextFieldModeType.MILTI_LINE: renders a field to edit a string, with multiple lines
Date Time Field Mode
DomainObjects are rendered by the user interface layer as fields when a DomainObject is displayed in a FormTab. The FormTab will determine in what type of field these DomainObjectPropertys are displayed (textbox, combobox, etc). When the DomainObjectProperty represents a date or time (Date, Calendar, LocalDate, LocalTime) , you can specify a specific field type using the DateTimeFieldMode annotation. The DateTimeFieldMode annotation needs to be put before the getter method of a DomainObjectProperty.
Note that the DateTimeFieldMode can not be changed during runtime.
Note that the DateTimeFieldMode can also be specified with the Format annotation.
Syntax: @DateTimeFieldMode(DateTimeFieldModeType mode)
Examples of alternative DateTimeFieldModeTypes:
- DateTimeFieldModeType.DATE: renders a date only field
- DateTimeFieldModeType.TIME: renders a time only field
- DateTimeFieldModeType.DATE_TIME: renders a date and time field
Execution Mode
ActionMethods can be annotated, so that the UserInterfaceController knows how the ActionMethod needs to be invoked after the user has clicked on the corresponding menu item. Note that the ExecutionMode can not be changed during runtime.
Syntax: @ExecutionMode(ExecutionModeType mode)
- ExecutionModeType.EXECUTE_METHOD_DIRECTLY : executes the method directly without user intervention
- ExecutionModeType.EXECUTE_METHOD_AFTER_CONFORMATION: the UserInterfaceController opens a confirmation dialog. The method is executed after the user activates the confirmation button. The method is NOT executed when the user cancels the confirmation dialog.
- ExecutionModeType.EDIT_PARAMETER_THEN_EXECUTE_METHOD_OR_CANCEL: the UserInterfaceController opens a form on a new tab, so that the user can modify (edit) the DomainObject. The method is executed with the edited DomainObject as the method parameter, when the user clicks the confirmation button on the button bar. The method is NOT executed when the user clicks on cancel in the bottom bar.
Read Only Action Method
Most ActionMethods can modify values in a DomainObject, e.g. change a DomainObjectProperty value. In this case the DomainObjectActionMethod or DomainObjectPropertyActionMethod is only visible in the PropertyPanelMenu when the DomainObject is edited in a FormTab (FormMode.EDIT).
You can annotate an ActionMethod with the @ReadOnlyActionMethod annotation if the ActionMethod does not not modify the DomainObject. In this case the DomainObjectActionMethod or DomainObjectPropertyActionMethod is also visible when the DomainObject is viewed in a FormTab (FormMode.READ_ONLY)
Execution Mode
ActionMethods can be annotated, so that the UserInterfaceController knows how the ActionMethod needs to be invoked after the user has clicked on the corresponding menu item. Note that the ExecutionMode can not be changed during runtime.
Syntax: @ExecutionMode(ExecutionModeType mode)
- ExecutionModeType.EXECUTE_METHOD_DIRECTLY : executes the method directly without user intervention
- ExecutionModeType.EXECUTE_METHOD_AFTER_CONFORMATION: the UserInterfaceController opens a confirmation dialog. The method is executed after the user activates the confirmation button. The method is NOT executed when the user cancels the confirmation dialog.
- ExecutionModeType.EDIT_PARAMETER_THEN_EXECUTE_METHOD_OR_CANCEL: the UserInterfaceController opens a form on a new tab, so that the user can modify (edit) the DomainObject. The method is executed with the edited DomainObject as the method parameter, when the user clicks the confirmation button on the button bar. The method is NOT executed when the user clicks on cancel in the bottom bar.
Parameter Factory
The parameter factory allows you to create an object for an ActionMethod. This object can then be edited by the user (depending how the ActionMethod is annotated, see ExecutionMode annotation) after which it is passed as method parameter when the ActionMethod is invoked.
The MainMenu will display all ActionMethods of all registered ServiceObjects that can directly be executed (without the need of an opened DomainObject). This means that only ActionMethods that either have no method parameter or have an ParameterFactory are displayed as menu items in the MainMenu.
ParameterFactory Annotation
When adding the ParameterFactory Annotation before an ActionMethod, the UserInterfaceController know's it is allowed to try to instantiate a new DomainObject. This DomainObject can then be edited by the user (depending how the ActionMethod is annotated, see ExecutionMode) after which it is passed as method parameter when the ActionMethod is invoked.
Note that the method parameter (a DomainObject) can only be instantiated by an ParameterFactory annotation if it has a public constructor without parameters. If not use the ...ParameterFactory method.
Syntax:
ParameterFactory Method
When adding the ParameterFactory method (normally located after an ActionMethod), the UserInterfaceController will first get a new DomainObject from the ParameterFactoryMethod. This object can then be edited by the user (depending how the ActionMethod is annotated, see ExecutionMode) after which it is passed as method parameter when the ActionMethod is invoked.
Syntax: public<domainObject type> prameterFactory<actionMethodName>()
TODO EXAMPLE OF ordersWithinPeriod METHOD
Validation
The UserInterfaceController sometimes let’s the user edit an ActionMethod parameter (e.g. a primitive type or a DomainObject), depending on how the ActionMethod is annotated, see ExecutionMode. The UserInterfaceController then validates the edited ActionMethod parameter using the ValidationProvider before the ActionMethod is invoked. The ValidationProvider will use ValidationAnnotations and ValidationMethods.
Validation annotations
A DomainObjectProperty can be validated by putting validation annotations before the getter method of a property. The ReflectFramework uses the JSR303 compliant Apache BVal library for validation. Please read the Apache BVal documentation on how to annotate the getter methods of the properties.
Validation methods
DomainObjects and DomainObjectPropertys can also be validated with ValidationMethods located in the DomainObject so that you can do more complicated validation using code.
ValidationMethods conventions:
- Syntax: public ValidationViolations <DomainObjectPropertyName><constraint name>Validation.
E.g. for a DomainObjectProperty startDate: public ValidationViolations startDateAfterTodayValidation()
E.g. for business rule custommerUnique: public ValidationViolations customerUniqueValidation() - Method may not have a method parameter
- Method must return a ValidationViolation
- Method must be public
- Method may not be static
- May not change the state of the DomainObject
Options
A DomainObjectProperty can sometimes only have a limited amount of valid values. Such an DomainObjectProperty can be displayed as a Combo Box to select one of these values when its been edited.
Option Method
The Options method returns a java.util.List with values that can be selected for a DomainObjectProperty e.g. with a Combo Box
Syntax: public List<DomainObjectPropertyType > <DomainObjectProperty name>Options();
Return Value: A List with values of the DomainObjectProperty Type. This java.util.List should not be empty because than a user can not select a value. The java.util.List may contain a null value when the DomainObjectProperty may be null. It is best to use an ordered java.util.List (e.g. an ArrayList) so that the items stay in the same sequence for the user to choose from.
Reflect Application Projects (Getting started)
There are different implementations of the ReflectApplication class, to support different type of applications (e.g. for the command line, web applications, etc...). This chapter will explain the different ReflectApplication, and how to get started with them. If needed you can also write your own implementation of the ReflectApplication class.
Setting up your development computer
First step is installing the following software on your development computer (if you did not do so already):
- Operating system: The ReflectFramework was created and tested on Microsoft Windows. It is therefore recommended to use Microsoft Windows for your development computer. You might also be able to use another operating system, because both Java and Integrated Development Environments will work on multiple operating systems. This however never was tested.
- Java Development Kit: You need to install a Java Development Kit on your development computer in order to compile and run Java code. There are multiple Vendors that supply OpenJdk versions. The ReflectFramework was created and tested with AdoptOpenJDK version 11 and is therefore recommended for your development computer. You can install and use it for free by downloading the correct version for your operating system from adoptopenjdk.net.
- Integrated Development Environment: You need to install a Integrated Development Environment on your development computer. The ReflectFramework was created with Eclipse and this is therefore recommended for your development computer. You can install and use Eclipse for free by downloading the installer from https://www.eclipse.org/downloads/. You might also be ale to use another Integrated Development Environment. This however never was tested.
- NodeJs: NodeJs is a javascript framework that you will need to install when using the ReflectApplicationForVaadin14. It can be downloaded from: https://nodejs.org/en/. It automatically comes with NPM: a Node Package Manager for downloading java script libraries.
Reflect for the Web
ReflectApplicationForVaadin14 is an implementation of the ReflectFramework that provides a graphical user interface for web applications, using the Vaadin Framework. ReflectApplicationForVaadin14 tries to comply with the Google Material Design as much as possible. The application can be used on a desktop, lap-top, tablet or mobile device. It has an responsive web design: it optimizes the user interface depending on the size of the MainWindow.
This class will be created and used by the Vaadin framework when a new VaadinSession for this application is created (after receiving a new HttpServletRequest from a user that does not have a active VaadinSession). It will:
- initialize the ReflectFramework with implemented methods from this class
- create the MainWindow
How to download a ReflectForJavaFX demo project
TODO
How to create a new ReflectForJavaFX project
TODO
How to start the application in the IDE
You start the application with Mvn jetty:run
E.g. in the Eclipse IDE create a debug configuration:
- Ensure that you got a Java JDK installed and Eclipse knows where to find it
- Ensure you have downloaded and installed a Java JDK on your computer (for windows see: c:\program files\java)
- On the Eclipse main menu click Window, Preferences, Java, Installed JRE's
- Add the JDK to the list if it is missing: Add, Standard VM, and select the folder where the JDK is installed
- Ensure the JDK is now in the list and selected as default
- Select Debug as
- Select Maven Build...
- Give the debug configuration a logical name: e.g.
-run-jetty - On Source tab:
- Click add button
- Select Java Project and click OK button
- Select Your and click OK button
- On Main tab:
- Base Directory: Click on Workspace button, select your project and click OK button
- Enter Goal: jetty:run
- Click on debug button
- Check if there are no build errors in the console window: almost at the end it should read: [INFO] Started Jetty Server
- Open the application in a browser, and open address: localhost:8080
Reflect for JavaFx
ReflectApplicationForJavaFX is an implementation of the ReflectFramework that provides a graphical user interface for a computer with an desktop environment. It might also be used for mobile devices in the future as well, but porting JavaFX for Android is still somewhat of a problem at the time of this writing. ReflectApplicationForJavaFX tries to comply with the Google Material Design as much as possible. The application can be used on a desktop, lap-top, tablet or mobile device. It has an responsive web design: It optimizes the user interface depending on the size of the MainWindow.
How to download a ReflectForJavaFX demo project
TODO
How to create a new ReflectForJavaFX project
TODO
Reflect for CommandLine
The ReflectApplication is an implementation of the ReflectFramework for command line interfaces.
If you execute the application with parameters it will:
- parse the given command line
- call one of the ServiceObjectActionMethod's with an optional parameter
- Return the result of the method or return a message if a method was successfully executed or not
- The ReflectApplicationForCommandLine is than terminated (state is lost unless the application stores state somehow)
- Return a list of possible commands and arguments
- The ReflectApplicationForCommandLine is than terminated
How to download a ReflectForCommandLine demo project
TODO
How to create a new ReflectCommandLine project
TODO
Reflect for JUnit
The ReflectApplicationForJUnit is created to be used for JUnit tests. Its big advantage over using one of the other ReflectApplication implementations in a JUnit test is that the ReflectApplicationForJUnit:
- Does not have a UserInterfaceLayer, because it is not needed for testing. None of the ServiceObjects, DomainObject's InfrastructureObject, Provider Objects that you create or maintain do know the UserTestObject Interface (see ReflectArchitecture). We do not need to test the ReflectFramework UserInterfaceLayer if we assume it works as it should.
- You only need to register the classes that need testing. You register classes by overriding the get...Class or get...Classes methods in the ReflectApplicationForJUnit class
If you are new to JUnit test I recommend to watch one of the many instruction video's on the Internet. Your IDE most likely supports you with implementing and running JUnit tests (and if not you can probably download a plug-in for it)
How to download a ReflectForJUnit demo project
TODO
How to create a new ReflectForJUnit project
TODO
Example of a testing a ServiceObject and InfrastructureMockUpObject in a JUnit test case
public class ProductServiceTest { private ProductService productService; @Before public void setUp() throws Exception { DependencyInjectionContainer container = new ReflectApplicationForJUnit() .addServiceClass(ProductService.class) .addInfrastructureClass(ProductRepositoryMockup.class) .createContainer(); productService = container.get(ProductService.class); } @Test public void bestSellingProductsTest() { List<Product> products = productService.bestSellingProducts(); // assert method calls ... } // other test methods ... }
Possible future projects
This is a list of possible future projects (still to be developed)
Reflect for Android
An application with a graphical user interface for mobile devices such as smart phones and tablets.
Reflect for SOAP
A web service that allows other computer applications to interact via the Simple Object Access Protocol (SOAP)
Reflect for RESTfull XML
A web service that allows other computer applications to interact using Representational State Transfer (RESTfull) with XML
Reflect for RESTfull JSON
A web service that allows other computer applications to interact using Representational State Transfer (RESTfull) with JSON
Reflect Provider Projects
Provider objects can have different implementations. Depending on the type of application you can write your own implementation of a provider or use or extend one of the ReflectProviderProjects that come with the framework. In example, depending on your application you might need a different AuthorizationProvider such as:
- hard coded authorization
- file based authorization
- database authorization
- web container authorization (e.g. Apache Tomcat Realm)
- LDAP
- Active directory
- or other
If you wish to use a non default Provider, you need to register a Provider by overwriting the matching ReflectApplication.get...ProviderClass() method.
The following sections will describe the optional ReflectProviderProjects that come with the ReflectFramework.
ReflectProviderTomcatAuthorization
TODO
Reflect Infrastructure Projects
Depending on your application you are creating, you might need different InfrasturcoreObjects to communicate with databases (repositories), mail servers (email clients), web servers (e.g. SOAP or restful clients), etc. The ReflectFramework comes with several ReflectInfrastructureProjects that you can optionally use and/or extend.
Before you can use an InfrastructureObject, you need to register an InfrastructureObject by overwriting the ReflectApplication.getInfrastructureClasses() method.
You can use an InfrastructureObject in a DomainObject or ServiceObject by adding the InfrastructureObject as a parameter of the constructor and linking it to a private final field.
The following sections will describe the optional ReflectInfrastructureProjects that come with the ReflectFramework.
TODO
Reflect Util Projects
ReflectUtilProjects are reusable Java components that are or can be used in ReflectApplications. Most ReflectUtilProjects do not require (have no dependencies with) the ReflectFramework.
reflect-util-maven-plugin
ReflectUtilMavenPlugin can be used to execute goals for a ReflectApplication.
Adding a ReflectUtilMavenPlugin to a ReflectApplication
Add the following XML tags to the pom.xml file:<build> <plugins> <plugin> <groupId>com.github.reflect-framework</groupId> <artifactId>reflect-util-maven-plugin</artifactId> <!-- Replace version with the latest available version, see https://mvnrepository.com/artifact/com.github.reflect-framework --> <version>0.1</version> </plugin> </plugins> </build>
Executing a ReflectUtilMavenPlugin goal
- In Eclipse you can execute goals by right clicking the project, selecting Debug as, Maven build... and entering the goal.
e.g.: com.github.reflect-framework:reflect-util-maven-plugin:updateLanguageFiles - You can also open a command console, go to the project folder and enter mvn followed by the goal.
e.g.:mvn com.github.reflect-framework:reflect-util-maven-plugin:updateLanguageFiles
Git Hub Documentation goals
GitHubDocumentationGoals read JavaDoc of given class or interface source files and convert these to: Only the class or interface description (the JavaDoc before the class or interface keyword) is used. JavaDoc of fields and methods or other members are not included.The advantages
- All your project documentation will be consistent (JavaDoc, manual, web site and Wiki)
- All your project documentation is directly available to the developer in the form of JavaDoc
- Basic formating can be used with HTML in JavaDoc
- GitHub Html page and or Wiki pages can automatically be committed (uploaded)
- All your project documentation is spelling checked and grammar checked when during editing (basic functionality of most EDI's)
Creating GitHub Repositories
Getting started from scratch:
- Create a GitHub account via https://github.com/join
- Create a GitHub project via https://github.com/new
- Clone the GitHub project repository ( https://github.com/{GIT_HUB_USER_NAME}/{REPOSITORY_NAME}.git) with your IDE to your local hard disk
Making documentation
- Add documentation in the JavaDoc of your classes.
- Create a class or interface that ties all the documentation together. This Class or Interface file must contain JavaDoc with {@insert} tags to refer to other Classes or Interfaces with JavaDoc that needs to be included into the documentation. See the JavaDoc of the ReflectUtilMavenPlugin class as an example
- Updating the documentation to the GitHub server when the JavaDoc has been updated (see next chapters).
Conventions
- You can use images with the HTM tag <img href="pictureName.png">. This image must be located in the same package.
- You can include a main picture, which will be added at the beginning of the documentation. This image must have the same name as the class name, have the png extension and be located in the same package.
- You can insert other class or interface files using the Javadoc in-line tag @insert
- You can include Chapters by adding a MaterialAppBarTitle between <H1> </H1> tags
- You can include SubChapters by adding a MaterialAppBarTitle between <H2> </H2> tags
- You can include SubSubChapters by adding a MaterialAppBarTitle between <H3> </H3> tags. Sub SubSubChapters are normally not rendered in the table of contents
- It is good practice to create a documentation class that ties all the java files together in one document.
Updating documentation on GitHub Wiki
You first you need to clone your Github Wiki repository (e.g. https://github.com/{GIT_HUB_USER_NAME}/{REPOSITORY_NAME}.wiki.git) with your IDE to your local hard disk. This you only need to do once.
You can than update the documentation to the GitHub Wiki by running the UpdateGitHubWikiPageGoal with the following Maven command:
mvn com.github.reflect-framework:reflect-util-maven-plugin:updateGitWikiPages -DdocumentationRootClassName={CLASS_NAME_OF_DOCUMENTATION_ROOT} -DlocalGitHubWikiRepository={FILE_LOCATION_LOCAL_GIT_HUB_WIKI_REPOSITORY} -DgitHubUserName={GIT_HUB_USER_NAME} -DgitHubPassword={GIT_HUB_PASSWORD}Where:
- {CLASS_NAME_OF_DOCUMENTATION_ROOT}: The name of the class or interface that is the root of your documentation that ties in all this other documentation classes or interfaces with help of the in line insert tag. E.G."ReflectDocumentation"
- {FILE_LOCATION_LOCAL_GIT_HUB_WIKI_REPOSITORY}: Local file location of the GitHub repository for the Wiki pages. E.g.:"C:/Users/nilsth/.git/reflect-framework.wiki"
- {GIT_HUB_USER_NAME}: UserTestObject name of GitHub account. E.g.:"superman"
- {GIT_HUB_PASSWORD}: Password of GitHub account. E.g.:"superSecret"
The UpdateGitHubWikiPageGoal will then parse the JavaDoc of the {CLASS_NAME_OF_DOCUMENTATION_ROOT} and generate Wiki pages into the local GitHub {FILE_LOCATION_LOCAL_GIT_HUB_WIKI_REPOSITORY}. This GitHub repository will then be committed and pushed onto the GitHub server (effectively publishing the Wiki documentation).
The updated GitHub Wiki documentation can then be found at https://github.com/{GIT_HUB_USER_NAME}/{REPOSITORY_NAME}/wiki
Updating documentation on GitHub Wiki
You first you need to clone your Github Wiki repository (e.g. https://github.com/{GIT_HUB_USER_NAME}/{REPOSITORY_NAME}.wiki.git) with your IDE to your local hard disk. This you only need to do once.
You can than update the documentation to the GitHub Wiki by running the UpdateGitHubWikiPageGoal with the following Maven command:
mvn com.github.reflect-framework:reflect-util-maven-plugin:updateGitWikiPages -DdocumentationRootClassName={CLASS_NAME_OF_DOCUMENTATION_ROOT} -DlocalGitHubWikiRepository={FILE_LOCATION_LOCAL_GIT_HUB_WIKI_REPOSITORY} -DgitHubUserName={GIT_HUB_USER_NAME} -DgitHubPassword={GIT_HUB_PASSWORD}Where:
- {CLASS_NAME_OF_DOCUMENTATION_ROOT}: The name of the class or interface that is the root of your documentation that ties in all this other documentation classes or interfaces with help of the in line insert tag. E.G."ReflectDocumentation"
- {FILE_LOCATION_LOCAL_GIT_HUB_WIKI_REPOSITORY}: Local file location of the GitHub repository for the Wiki pages. E.g.:"C:/Users/nilsth/.git/reflect-framework.wiki"
- {GIT_HUB_USER_NAME}: UserTestObject name of GitHub account. E.g.:"superman"
- {GIT_HUB_PASSWORD}: Password of GitHub account. E.g.:"superSecret"
The UpdateGitHubWikiPageGoal will then parse the JavaDoc of the {CLASS_NAME_OF_DOCUMENTATION_ROOT} and generate Wiki pages into the local GitHub {FILE_LOCATION_LOCAL_GIT_HUB_WIKI_REPOSITORY}. This GitHub repository will then be committed and pushed onto the GitHub server (effectively publishing the Wiki documentation).
The updated GitHub Wiki documentation can then be found at https://github.com/{GIT_HUB_USER_NAME}/{REPOSITORY_NAME}/wiki
Updating documentation on GitHub Wiki and GitHub Web
The UpdateGitHubWikiAndWebPagesGoal executes both UpdateGitHubWikiPageGoal and UpdateGitHubWebPageGoal.
updateLanguageFiles goal
The ReflectUtilMavenPlugin: UpdateLanguageFiles goal will:- Find all texts within a ReflectApplication that will need to be translated
- Adds key and text values for text that where not already translated to the LanguagePropertyFile. New text values will start with the @(at) symbol to indicate that the English default text (derived from the program code) needs to be translated to another language.
- Adds the "deprecated." prefix to the key's for deprecated texts that where already translated but are no longer in use in the code.
A new LanguagePropertyFile is created by creating a new empty text file (e.g. src/test/resources/language_de.properties for the German language). New or empty LanguagePropertyFile or existing LanguagePropertyFile can be updated by executing the UpdateLanguageFiles goal when when changes to the ServiceObjects and DomainObjects have been completed. The files can then be translated.
You can execute the UpdateLanguageFiles goal after installing the ReflectUtilMavenPlugin. The Maven goal can than be executed: com.github.reflect-framework:reflect-util-maven-plugin:updateLanguageFiles
reflect-util-random-generator
A Factory for creating RandomGenerators to generate many types of random objects using a fluent interface
reflect-util-regex
A Fluent interface to create regular expressions (see Pattern)
reflect-util-java-archive-scanner
The JavaArchiveScanner is a library for scanning Java archives (jar,war,ear files or folders with classes) for classes or class members (fields, methods or properties) using a filter and a Collector
reflect-util-english-plural
EnglishPlural converts a English singular noun to a plural form by a set of rules. Note this is on best effort. Not all forms are covered!
Based on https://www.grammarly.com/blog/plural-nouns/
Downloads
Documentation
The documentation of the ReflectFramework is generated from its JavaDoc (starting with the ReflectDocumentation file) and is published in different formats and at different locations with help of the ReflectUtilMavenPlugin:
- Documentation as Git Hub Wiki
- Documentation as Web Page
- Documentation as a printable Web Page (single page)