Summary of Middleware Design Decisions

by Kevin Garwood

General Design Decisions

Decision Description
General Design-1 Support the feature set with a suite of interacting tools. They will include: a study submission tool, a study result retrieval tool, a data loader tool and an information governance tool.
General Design-2 Organise code using a common three tier architecture that has the following layers: a presentation layer for managing GUI code; a business concept layer for managing the way business concepts are expressed in the system; and a data storage layer for managing the task of reading data from or writing data to the database.
General Design-3 Ensure that the presentation layer only interacts with the data storage layer via the business concept layer. Never let presentation and data storage layer have direct communication with one another.
General Design-4 Wherever possible, limit the paths of execution that are likely to occur.
General Design-5 By default, give class variables and class methods the most restrictive visibility.
General Design-6 By default, give classes package-level access. Increase the visibility of a class only when there is a need to do so.
General Design-7 Encapsulate business concept and data storage layers of the architecture through service APIs. Do not allow clients to know which class is implementing the service interfaces.
General Design-8 Apply the steps of the coding philosophy:
  1. get it working
  2. get it working for the next developer
  3. get it working well

As well, favour coding to convention over coding to circumstance.

General Design-9 If a class is not abstract, it should be marked "final".

Business Concept Layer Decisions

Decision Description
Business Concept Layer-1 Provide a generic identifier field within each business class definition. The identifier allows Java objects to be mapped to primary key values in corresponding database records.
Business Concept Layer-2 Support a business class method getDisplayName(), which returns String that allows end-users to distinguish an object in a list.
Business Concept Layer-3 By default, the fields of business classes should be of type String.
Business Concept Layer-4 Business classes should have a method ArrayList getDifferences(), which describes the differences between two objects of the same class.

Data Storage Layer Decisions

Decision Description
Data Storage Layer-1 Classes that implement service APIs are responsible for: safe-copying parameter values; checking for empty or malicious values in parameters; checking for invalid users; and acquiring and relinquishing database connections from a pool of connections.
Data Storage Layer-2 A Manager class is responsible for: calling the checkErrors() method of parameter values that are business objects; constructing and executing SQL queries using parameter values; packaging results as business objects; recording SQL exceptions and returning human-readable exception messages; closing database resources associated with obtaining results.

Security Decisions

Decision Description
Security-1 The RIF Tool Suite should be installed within a secure corporate Intranet. The database server for the RIF should be isolated within that network, and its database access ports should be strictly limited.
Security-2 Design middleware methods for each tool as if it will be deployed as a web application. However, in the short term of RIF development, tools that do not require remote access should be developed as desktop applications that use Java-based RIF services. Tools that require remote access should be developed as web applications that communicate with the middleware via web services. The web server should be isolated from the rest of the corporate Intranet.
Security-3 Consider a service method which has a User object specified as a parameter. Immediately after the User object has been safe-copied, check whether the userID in the copy has been blacklisted. If executing the service method results in a security exception, blacklist the user.
Security-4 Business classes should have a method checkSecurityViolations(), which recursively check whether any String fields have any malicious code values. Field values should be compared against a variable collection of regular expression patterns that are commonly associated with code attacks.
Security-5 The class rifServices.util.FieldValidationUtility will be responsible for checking all String field values contain malicious code patterns.
Security-6 The class rifServices.util.FieldValidationUtility will obtain its list of malicious code patterns from an editable file MaliciousCodePatterns.txt. Projects may wish to modify this file so they can add additional patterns in response to new threats of code attacks.
Security-7 Support connection pooling on a per-user basis rather than having a pool of anonymous connections that can be shared by different users.
Security-8 Call a database procedure that helps create user-specific views and temporary views. This action makes it easier to control what users can access and what damage they could do if their identities were used as part of a malicious attack.
Security-9 For each user, maintain separate pools for read-only and write-enabled connections. If a middleware task does not require writing data, it should use a read-only connection.
Security-10 Execute queries using Java's PreparedStatement class and use bind variables to set query parameters.
Security-11 The RIF tool suite will manage user identities in the RIF database rather than delegate to services that might already be part of network administration services.
Security-12 The middleware will rely on the database's system roles to help limit the access users have to data.
Security-13 Error messages resulting from invalid login should not reveal information about whether a userID is valid.
Security-14 Whenever a java.sql.SQLException is thrown in the code, it will be caught and logged. A rifServices.system.RIFServiceException will be thrown, and its error messages will not expose sensitive information beyond what is necessary.

Concurrency Decisions

Decision Description
Concurrency-1 Identify scenarios for concurrent access that may occur in interactions between various pairings of tools in the tool suite. Systematically evaluate potential scenarios for concurrent writes and stale reads situations.
Concurrency-2 When the Data Loader Tool is loading data sets, the other tools should not be in use. When end user tools are being used, the Data Loader Tool should not be in use.
Concurrency-3 The Study Submission Tool should submit a new study as part of a single atomic database transaction. Once a study has been created it becomes immutable. However, it can be copied to make a new study. Until a study description has been completely created in the database, neither the Study Submission Tool nor the Study Viewer Tools should be able to access it.
Concurrency-4 The tool suite should allow only one instance of the Data Loader Tool and one instance of the IT Governance Tool to run at the same time.
Concurrency-5 In the Swing-based Data Loader Tool and Information Governance Tool, rely on guided data-entry features and modal dialogs in the GUI to help limit the likelihood of concurrency problems. For the web-based Study Submission and Study Result Viewer tools, assume they can may call any service method in any order.
Concurrency-6 Maintain test suites that will pass in a single-threaded environment. Then adapt copies of those test suites for a multi-threaded environment. Use the differences in pass results to identify potential concurrency problems.
Concurrency-7 Assume that various database vendors may not support concurrent access to records in exactly the same way. Further assume that none of the JDBC database connections are thread-safe, even though for some databases they definitely are. Assume that the middleware must take its own measures to mediate concurrent access for queries it applies to the database.
Concurrency-8 Assume that the front-end client applications will have multiple threads that may each be trying to alter parameter values the applications pass to the middleware service methods.
Concurrency-9 Perform a deep-copy of any mutable object that is passed to a service method by a client application. This action will prevent the client from altering parameter values while they are being processed by the middleware.
Concurrency-10 Where it is possible, favour using method variables over using class variables. Class variables can be accessed by multiple threads, but local variables in methods will be used by only a single calling thread.
Concurrency-11 Declare variables as close as possible to when they will be first used.
Concurrency-12 Support "safe construction" of business objects. In business classes, make constructors private and rely on static factory methods newInstance(...) and createCopy(...) to control the creation of new objects.
Concurrency-13 The business classes do not appear to be used in any scenario which would cause them to be the source of contention in a way that would affect the middleware.

Testability Decisions

Decision Description
Testability-1 Test coverage will be limited to public methods of classes and service interfaces that are defined within the business concept layer.
Testability-2 Test scenarios will be divided based on the following categories: common, uncommon, error, and malicious.

Validation Decisions

Decision Description
Validation-1 Assume the client applications will do no validation. Validation code will be distributed between the business concept and data storage layers of the architecture.
Validation-2 Limit validation support to execution paths that support service API methods. Specifically, focus validation efforts on validating values the client application passes to methods of service APIs.
Validation-3 By default, the fields in business classes should be of type String.
Validation-4 Identify and prioritise the validation checks that are applied to the parameter values of service methods. Order the validation checks so they
  • cause validation to fail as quickly as possible and
  • wherever possible, give highest priority to fail a security validation check over other types of checks
  • minimise the load placed on the database.

Maintenance Decisions

Decision Description
Maintenance-1 Maintain the text for all GUI components and text for error messages in a properties file.
Maintenance-2 Centralise code for creating and initialising Java Swing components in a single factory class.
Maintenance-3 Create classes that render user interface features that appear across multiple tools. Isolate these classes into a sub-project that shows no dependencies on classes that relate specifically to the RIF.
Maintenance-4 Contain rather than inherit from GUI classes.
Maintenance-5 Do not try to override the behaviour of equals() and getHashCode(). In the RIF code base, the effort needed to do this correctly outweighs the performance benefit we would gain from using Java's collection classes.
Maintenance-6 Instead of having one service API with many methods, develop a service API for each tool instead.
Maintenance-7 Develop a hierarchy of super classes which can reduce repetitive coding efforts and hold the bulk of implementation code.
Maintenance-8 Make service classes invoke delegation classes to support most of the implementation for a business task. Ensure that the service class and the manager classes have a clearly defined separation of concerns.
Maintenance-9 Create query formatter classes that standardise the way common types of SQL queries are constructed. Allow the query formatters to support changes of case and have them adopt a consistent way of indenting lines of SQL code to make them more readable.

Error Handling Decisions

Decision Description
Error Handling-1 Error handling will be designed to pass exceptions back to client applications via the service methods. The signatures of all methods for a service interface will allow them to throw an exception.
Error Handling-2 All service methods will be able to throw a checked exception rifServices.system.RIFServiceException. This checked exception will support two features:
  • an error code that provides a machine-readable cause for the error. The error codes will come from some enumerated type.
  • a collection of human-readable error messages that client applications can display or log for the benefit of end-users.
Error Handling-3 All checked exceptions should be caught and logged before being re-thrown using a RIFServiceException instead.