Tutorial:Java EE Application Design for the Java Architect Exam
In this article, we will look at Java EE Application Design. We will describe the main advantages of an object-oriented approach to system design as well as the benefits of separations of concerns throughout the complete Java EE application stack. This is part of a larger series of articles to help you prepare for the java architect exam.
Many people have different definitions for what is an architecture. Sun defined architecture as the following:
Architecture is a set of structuring principles that enables a system to be comprised of a set of simpler systems each with its own local context that is independent of but not inconsistent with the context of the larger system as a whole.
One can create architecture to describe the structure of the system to be built as well as how that structure supports the business and service-level requirements. One can define the structure of a system with the mechanisms employed by the system to solve the common problems of the system. A mechanism is a capability that supports the business requirements in a consistent and uniform manner. An example of such a mechanism would be persistence that is used consistently throughout the system. In this way, anytime that the system uses persistence, it is done so in the same consistent manner. Persistence as an architectural mechanism provides a default method of addressing persistence that all designers can follow and implement consistently. This is the same for other architectural mechanisms such as distribution, communication, transaction management, and security. They are the infrastructure on which you build the system and therefore must be defined in your architecture.
When you create an architecture, you have create a software infrastructure that addresses the service-level requirements that have been identified for the system. For example, if the system has a service-level requirement around response times (i.e. no user response time will be greater than three seconds) then software infrastructure you create must ensure that the system can meet this requirement. It also implies that you have created an infrastructure that designers can use design and code without worrying about compromising a service-level requirement such as this. One of the key issues about architecture is:
Where is the boundary between the architecture and the design process?
There is no definitive answer to this for every system. It comes down to focus and control. Architecture defines what is being built, and design determines how you will build it. There is normally one or two individuals who focus on overall control of the architectural process, while design can be controlled by numerous individuals focused on the details of how to achieve the overall vision. The architect defines the architecture up to where the design team can use it to achieve the systemís overall goals. The level of detail that you need to provide when creating an architecture is dependent on the level of the experience of the designers who will use it. Itís an inverse relationship. The less experienced the designers, the more detail you will need to provide and vice versa.
Defining Architectural Design
When you create an architecture satisfying the business and service-level requirements for the system, you will need to work within the infrastructure, software and development resource limits that exist within the organization. For example, you might need to design a system that can scale to meet the demands of worldwide Internet consumers, while only having one computer to support your internal personnel. Creating architecture without funds to buy software products is one of the numerous challenges faced by architects when they are creating system architecture. There are many difficult choices and trade-offs that will be required in order to solve these types of problems when creating your architecture. As you make these tradeoffs, you need to document each decision in relation to the architecture of the system, so that developers understand why these decisions were made. Otherwise, you can end up being barraged by questions from developers about these trade-offs.
The documenting of these tradeoffs allows others working on the project or entering the project at a later time to understand why decisions were made and prevents you from justifying your decision over and over again. Most of the trade-offs you make when creating architecture focus on the service-level requirements or mechanisms. Most systems donít have the resources available to meet all of the service-level requirements that were originally envisioned by the system stakeholders. As the architect, you must find a way to balance the service-level requirements against the cost to achieve these requirements. If the costs of achieving 24x7 availability of the system are such that it will leave little to no funds to purchase other key resources such as the application servers, then you will need to discuss these tradeoffs with the stakeholders in order to determine what is prioritized and then adjust your software architecture to conform to the priorities outlined.
Goals of Architecture
When creating an architecture, there are a number of general principles that should guide architectural and implementation choices used to express the system. These principles are:
- Object orientation
- The primacy of business requirements
- The importance of empirical process
- The importance of testability
We will go into detail about these principles below.
The architecture and implementation that you and the designers create should always be as simple as possible. Complexity can be minimized up front to by supporting what is actually required in the foreseeable requirements. In this case, itís important to design a simple architecture allowing for architectural refactoring in order to scale up. Otherwise refactoring the architecture can become a complex task in order to meet additional requirements. The keys to enabling architectural refactoring within Java EE projects are:
Following OO design practice by programming to interfaces rather than classes. This is one of fundamental teachings of the classic Design Patterns.
To conceal the implementation technologies behind plain Java interfaces.
The architectural approach and frameworks can easily put in practice these principles.
Productivity is an very important consideration. The programming model for Java EE allows developers to quickly develop business logic using Plain Old Java Objects (POJOs) and annotations. This type of approach is highly productive as theyíre comparatively simple and dispense with a lot of unnecessary code.
As Java is a good OO language, object orientation is a given for Java EE applications? With Java EE, many of the common Java EE practices and patterns leverage object orientation in order to deliver very high code reuse and elegant design.
Primary of Requirements
All application architecture should be driven by business requirements, and not the target technology. Avoid situations where your Java EE 5 Developers assume phantom technical requirements, such as:
- Providing support for multiple databases in the one application
- The ability to port to another application server at zero cost
- The ability to port to another database easily
- Supporting multiple client types
Make sure they the actual requirements have been properly evaluated and communicated for each application. You want to avoid situations where Java EE 5 developers are expending effort because of the choice of technology rather than on client requirements.
One of the best things you can do is formalize the use of metrics in order to determine the efficiency and performance of your architecture. This approach is already formalized in iterative methodologies that use an executable architecture (RUP) or vertical slice or spike solution (XP). In both cases the object is to minimize risk by building an end-to-end executable as early as possible. For RUP, the goal is to address the most difficult architectural issues early in order to mitigate risks. For XP it is driven by key user stories. In either case, they must be relevant to actual requirements. Agile development process naturally tend towards the creation of a vertical slice so this becomes an integral activity. Once the vertical slice is built, it serves as the basis for metrics that serve to validate the architectural choices. The metrics on which you should focus are the following:
- Performance. Normally part of the non-functional requirements, this is often dealt with at the end of the development where it is more difficult to address.
- The ratio of benefits to cost for a particular requirement. The question is whether the development time and costs involved proportionate to the requirements implemented. Is the complexity of the result proportionate to the requirements?
- Maintainability. This deals with the extensibility of the vertical slice. It is difficult to add features to it? How quickly can a new developer grasp the applicationís architecture and implementation and become productive?
There are still too many projects that neglect to do this type of risk mitigation. Also there are still too many proposed Java EE architectures being driven by the specification or vendor rather than proven in production.
The test first development became popular more than 10 years ago as it was proven to produce impressive results. Writing effective unit tests for an application requires a high level architecture that is accommodative to testing. Testability is an essential characteristic of agile projects. Previously with J2EE architectures it was a challenge to test code, but now with Java EE 5 and itís POJO based business components, this approach to Java EE architecture is ideal for agile projects.
What Sort of Architecture to Use
Java EE 5 has excellent support for implementing distributed architectures. The POJO components of a distributed Java EE 5 application can be split across multiple JVMs running on one or more physical servers. Distributed Java EE applications are based on the use of EJBs with remote interfaces enabling the application server to conceal much of the complexity related to access and management of distributed components.
Although a distributed model can facilitate the realization of a robust, scalable application, there are other architectures that can achieve the same ends. An example would be to cluster applications that collocate all of their components in a single JVM.
The benefits of distributed architectures are the following:
- The ability to support numerous clients on different form factors that require a shared "middle tier" of business objects.
- The ability to deploy any application component on any physical server in order to achieve load balancing, scalability and generally to relieve possible bottlenecks.
- On the other hand, distributed architectures lead to many difficult issues, among these:
- Performance problems as remote invocations are many times slower than local invocations.
- Complexity distributed applications are difficult to develop, debug, deploy, and maintain.
- Constraints on practicing OO design. This is related This is an important point, which we'll discuss further shortly.
- Distributed applications pose many interesting challenges. It's best if possible to avoid the complexities of distributed applications by using simpler non-distributed architectures in your application.
Considerations of Java EE 5 Design
The Java EE platform is based on a distributed multitiered application model for enterprise applications. Application logic is encapsulated in components according to function and these components are installed on different machines depending on the relevant tier of a multitiered Java EE environment. The tiers of a multitiered Java EE applications are the following:
- Client-tier - for components run on the client machine.
- Web-tier - for components run on the Java EE server.
- Business-tier - for components run on the Java EE server.
- Enterprise information system (EIS)-tier - for software running on the EIS server.
A Java EE application consist generally of the three or four tiers. Most Java EE multitiered applications are considered to be three-tiered applications because they are distributed over three locations: client machines, the Java EE server machine, and the database or legacy machines at the back end. This is an extension of the standard two-tier client server model by adding a multithreaded application server between the client application and back-end storage.
All Java EE applications are comprised of components, which are self-contained functional software unit assembled into a Java EE application with its related classes and files and that communicates with other components. In the Java EE specification, Java EE components are defined as the following:
- Application clients and applets are client component
- Java Servlets, JavaServer Faces, and JavaServer Pages (JSP) technology web components that run on the server.
- Enterprise JavaBeans (EJB) components are business components that run on the server.
Since Java EE applications have a tendency to be large and complex, it's important to follow sound OO design practice, adopt consistent coding conventions, and leverage existing investment. In terms of code quality, at object-design and code level, the characteristics related to good code are the following:
- Is extensible without drastic modification. It's easy to add features without tearing it apart.
- Is easy to read and maintain.
- Is well documented.
- Is difficult to write bad code around it. (i.e. Objects exposing clean, easy-to-use interfaces promote good use)
- Is easy to test.
- Is easy to debug. Ensure that if a developer is trying to discover an error in imperfect code, that the stack trace doesnít disappear into some perfect but obscure code.
- Contains no code duplication.
- Gets reused.
Writing code that achieves these goals demands hard work. Java facilitates this through itís object oriented nature and other features.
Object Oriented Design Patterns
A well written Java EE application with an excellent overall design but poor implementation code will be an equally miserable failure. It is possible to design a Java EE application with elegant code that is still deemed a failure as a Java EE application. This is often because developers can become a bit too enamored with Java EE and not adhere to good coding practice.
Adherence to good OO principles always brings real benefits. This is despite there being some coding standards issues related to OO design that obscure the line between what is design and what is implementation. There are three key features of object oriented programming that a developer must always follow. These are:
- Encapsulation - this feature enforces modularity or the creation of self-contained modules that bind processing functions to the data. These user-defined data types are called "classes," and one instance of a class is an "object." For example, in a cargo management system, a class could be Cargo, and FedEx and UPS would be two instances of the Cargo class. Encapsulation ensures good code modularity that keeps logic separate and less prone to conflict with each other.
- Inheritance - this feature is used for classes to gain knowledge from existing classes. All classes are created in hierarchies, and inheritance allows the structure and methods in one class to be benefit classes lower down in the hierarchy. This means that less programming will be required when adding functions to complex systems. If a new behaviour is added at the bottom of a hierarchy, then only the processing and data associated with that behaviour needs to be added. All the other behaviour is inherited. Reuse of existing objects is considered one of major advantages of object oriented technology.
- Polymorphism - this feature allows for the object to take any shape. Object-oriented programming allows procedures about objects to be created whose exact type is not known until runtime. For example, in a drawing program, one can have a method for a shape object that is used for drawing the particular shape. Polymorphism allows for classes that inherit from this shape class to implement this method so that the particular shape, say a rectangle class can be properly drawn at runtime. Polymorphism also means you can add other new shapes and these can be easily integrated into the application.
Below is a table showing the the design patterns related to object oriented programming:
Separation of Concerns
The primary objective of an application is to encode the business logic that dictates its expected behavior. More simply, this is what a program does. For example, an online retail client must be able to let users browse, search, select, and purchase products. The functions that all relate to the fulfillment of business logic are part of what is considered the core concerns. The use of object-oriented principles help in modeling the business logic. This is usually done via separation of concerns, which is when a related set of functionality is compartmentalized in a module, with well-defined interfaces for how each component will interact with it. In the case of our online retail client, this might lead to separate modules for interacting with remote servers, rendering HTML, payment engines, fulfillment services, etc.
The core is usually with have rules unique to your application that can only be built by you and your team. The job of software engineers is to transform ideas into well designed and tested code. This can only be achieved this if the underlying system allows us to focus as much as possible on business logic and less on the inner workings of the underlying frameworks and systems that we are using. So if we look at the Java EE platform, we see that by dividing application logic into components, that are located on a particular tier of the Java EE platform, we can achieve efficiencies that would otherwise be difficult to replicate. Weíve already outlined the tiers and components that run on each tier. Below we provide more detail.
Components need to often exchange various types of data between themselves. In view of this, the Java EE platform requires support for the following data formats:
- HTML - this is the markup language that is used in browsers for rendering content in a human readable form. It is used to define hypertext documents accessible over the Internet that enables the embedding of images, sounds, video streams, form fields, references to other HTML documents, and basic text formatting. HTML documents have a globally unique location and can link to one another.
- Image files - the image file formats that are supported on the Java EE platform are: GIF (Graphics Interchange Format), a protocol for the online transmission and interchange of raster graphic data, and JPEG (Joint Photographic Experts Group), a standard for compressing gray-scale or color still images.
- JAR file - - this is a platform-independent file format that allows for many files to be aggregated into one file.
- Class file - this is the format of a compiled Java file defined in the Java Virtual Machine specification. Each class file contains one Java language type - either a class or an interface - and consists of a stream of 8-bit bytes.
- XML - this is a text-based markup language that allows you to define the markup required to identify the data and text in structured documents. The data is identified using tags. Although similar to HTML, XML differs in that the tags serve to describe the data, rather than the format for displaying it.
Java EE Clients
A Web Client consists of two parts:
- Dynamic web pages consisting of various types of markup language (HTML, XML, and so on) generated by web components running in the web tier.
- Web browser, which renders the pages received from the server.
A Web Client is also known as a thin client. Thin clients usually off-loaded business logic execution to enterprise beans running on the Java EE server that can leverage the security, speed, services, and reliability of Java EE server-side technologies.
A web page can include an embedded applet, which is a small client application written in the Java that executes in a Java virtual machine installed in the web browser. Generally the client systems requires a Java Plug-in and possibly a security policy file for the applet to successfully execute in the web browser.
- Application Clients
An application client runs on the client machine and has features that allow it to have a richer user interface than is provided using a markup language. This is done by using a graphical user interface (GUI) created using either Swing or the JavaFX API.
These types of clients access enterprise beans directly that running in the business tier. It is still possible for an application client to open an HTTP connection to establish communication with a servlet running in the web tier if needed. Non-Java application can interact with Java EE 5 servers as well (i.e. Flex). This enables the Java EE 5 platform to interoperate with legacy systems, clients, and non-Java languages. See the figure below of client tier elements:
Java EE web components consists of either servlets or pages created using JSP technology (JSP pages) and/or JavaServer Faces technology. The servlets are Java programming language classes that dynamically process requests and construct responses. JSP pages are text-based documents that are compiled into servlets and then executed. They facilitate a more intuitive approach to creating content. JavaServer Faces technology builds on servlets and JSP technology by providing a user interface component framework for building web applications. The figure below shows a web tier with JavaBeans component to manage the user input as well as interfacing with enterprise beans running in the business tier:
Business components consists of enterprise beans running on the business tier. They hold logic used to meet the requirements of the business domain such as banking, retail, or finance. When an enterprise bean receives data from a client, it processes the data and then returns a response back to the client. The processing of the data can involve sending it to an enterprise storage system, internal calculations or retrieving existing data from storage. The figure below outlines the actions of an enterprise bean:
The enterprise information system (EIS) tier handles all EIS software including enterprise infrastructure systems such as database systems, mainframes, enterprise resource planning (ERP) and other legacy information systems. Often Java EE application components will need to access to enterprise information systems for database connectivity.
Java EE Application Deployments
The standard practice for a Java EE application is for it to be packaged into one or more standard units ready for deployment to any Java EE platform-compliant system. Each unit will contain the following:
- One or more functional components such as enterprise bean, JSP page, servlet, applet, etc.
- An optional deployment descriptor that describes the application content and configuration settings
Once a Java EE package is produced, it is ready to be deployed. The deployment involves using a Java EE platform deployment tool to provide environment-specific information, such as a users who are permitted to access the application as well as the name of the local database. Once the application is deployed on the platform, it is ready to run.
Java EE application are deployed via an Enterprise Archive (EAR) file. This is a standard Java Archive (JAR) file with an .ear extension on the end. The use of EAR files and modules allows one to assemble a number of different Java EE applications using many of the same components. It is only a matter of assembling or packaging various Java EE modules into Java EE EAR files. There is no extra coding required.
The main contents of an EAR file are the Java EE modules and their deployment descriptors. A deployment descriptor is an XML document that provides the configuration used for an application, module or component during deployment. As the deployment descriptor information is declarative, it can be modified without need to update or recompile any source code. At runtime, the Java EE server will load and read the deployment descriptor and then configure the application, module, or component as specified.
A Java EE module consists of one or more Java EE components and one component deployment descriptor for that type. For example, an enterprise bean module deployment descriptor is used to declare transaction attributes and security authorizations for an enterprise bean. You can deploy a Java EE module as a stand-alone without a deployment descriptor. There are four types of Java EE modules. They are the following:
- EJB modules - these contain class files for enterprise beans and an EJB deployment descriptor. EJB modules are packaged as JAR files with a .jar extension.
- Web modules - these contain servlet class files, JSP files, supporting class files, GIF and HTML files, and a web application deployment descriptor. Web modules are packaged as JAR files with a .war (Web ARchive) extension.
- Application client modules - these contain class files and an application client deployment descriptor. Application client modules are packaged as JAR files with a .jar extension.
- Resource adapter modules - these contain all Java interfaces, classes, native libraries, and other documentation, along with the resource adapter deployment descriptor. They are part of the Java EE Connector Architecture for a particular EIS. Resource adapter modules are packaged as JAR files with an .rar (resource adapter archive) extension.
Java EE 5 APIs
Java EE provides a comprehensive set of APIs that are available for building components as well as integrating with a wide variety of resources. This varies from Enterprise Information Systems, to Directory Services as well as Mail Systems. The technologies and APIs that are available are listed in the table below:
Java EE Application Containers
Java EE provides a number of containers that serve as an interface between a component and the platform-specific functionality that supports the component. The container serves as the host to any web, enterprise bean, or application client component that is going to be executed. Any component that is assembled into a Java EE module is then deployed into its container.
The assembly process involves detailing container settings for each component in the Java EE application as well as for the Java EE application itself. The container settings are used to customize the underlying support provided by the Java EE server. This includes services such as security, transaction management, Java Naming and Directory Interface (JNDI) lookups, and remote connectivity. The most commonly used container services are:
- Java EE security model - this service allows you configure a web component or enterprise bean so that these system resources are only accessible to authorized users.
- Java EE transaction model - this service allows you to define relationships among the methods involved in a transaction so that all methods in one transaction are managed as a single unit.
- JNDI lookup services - this service provides a unified interface to multiple naming and directory services within an enterprise in order that application components can access these services.
- Java EE remote connectivity model - this service manages low-level communications between clients and enterprise beans. After an enterprise bean is created, a client invokes methods on it as if it were in the same virtual machine.
The Java EE architecture provides for configurable services. This means that application components in the same Java EE application can behave differently when they are deployed in different environments. For example, an enterprise bean deployed in a production environment can have security setting facilitating one level of database access, while the same enterprise bean deployed in another production environment could have completely different security settings for the database in that environment.
Finally, the container also manages non configurable services such as the lifecycles of enterprise bean and servlets, resource pooling of database and messaging systems connections, data persistence and access to the Java EE platform APIs.
Communication technologies provide mechanisms for communication between clients and servers and between collaborating objects hosted by different servers. The J2EE specification requires support for the following types of communication technologies:
Internet protocols define the standards by which the different pieces of the J2EE platform communicate with each other and with remote entities. The J2EE platform supports the following Internet protocols:
- TCP/IP - Transport Control Protocol over Internet Protocol. These two protocols provide for the reliable delivery of streams of data from one host to another. Internet Protocol (IP), the basic protocol of the Internet, enables the unreliable delivery of individual packets from one host to another. IP makes no guarantees as to whether the packet will be delivered, how long it will take, or if multiple packets will arrive in the order they were sent. The Transport Control Protocol (TCP) adds the notions of connection and reliability.
- HTTP 1.0 - Hypertext Transfer Protocol. The Internet protocol used to fetch hypertext objects from remote hosts. HTTP messages consist of requests from client to server and responses from server to client.
- SSL 3.0 - Secure Socket Layer. A security protocol that provides privacy over the Internet. The protocol allows client-server applications to communicate in a way that cannot be eavesdropped or tampered with. Servers are always authenticated and clients are optionally authenticated.
Remote Method Invocation Protocols
Remote Method Invocation (RMI) is a set of APIs that allow developers to build distributed applications in the Java programming language. RMI uses Java language interfaces to define remote objects and a combination of Java serialization technology and the Java Remote Method Protocol (JRMP) to turn local method invocations into remote method invocations. The J2EE platform supports the JRMP protocol, the transport mechanism for communication between objects in the Java language in different address spaces.
Object Management Group Protocols
Object Management Group (OMG) protocols allow objects hosted by the J2EE platform to access remote objects developed using the OMG's Common Object Request Broker Architecture (CORBA) technologies and vice versa. CORBA objects are defined using the Interface Definition Language (IDL). An application component provider defines the interface of a remote object in IDL and then uses an IDL compiler to generate client and server stubs that connect object implementations to an Object Request Broker (ORB), a library that enables CORBA objects to locate and communicate with one another. ORBs communicate with each other using the Internet Inter-ORB Protocol (IIOP). The OMG technologies required by the J2EE platform are Java IDL and RMI-IIOP.
Java IDL allows Java clients to invoke operations on CORBA objects that have been defined using IDL and implemented in any language with a CORBA mapping. Java IDL is part of the J2SE platform. It consists of a CORBA API and ORB. An application component provider uses the idlj IDL compiler to generate a Java client stub for a CORBA object defined in IDL. The Java client is linked with the stub and uses the CORBA API to access the CORBA object.
RMI-IIOP is an implementation of the RMI API over IIOP. RMI-IIOP allows application component providers to write remote interfaces in the Java programming language. The remote interface can be converted to IDL and implemented in any other language that is supported by an OMG mapping and an ORB for that language. Clients and servers can be written in any language using IDL derived from the RMI interfaces. When remote interfaces are defined as Java RMI interfaces, RMI over IIOP provides interoperability with CORBA objects implemented in any language.
Messaging technologies provide a way to asynchronously send and receive messages. The Java Message Service API provides an interface for handling asynchronous requests, reports, or events that are consumed by enterprise applications. JMS messages are used to coordinate these applications. The JavaMail API provides an interface for sending and receiving messages intended for users. Although either API can be used for asynchronous notification, JMS is preferred when speed and reliability are a primary requirement.
Java Message Service API
The Java Message Service (JMS) API allows J2EE applications to access enterprise messaging systems such as IBM MQ Series and TIBCO Rendezvous. JMS messages contain well-defined information that describe specific business actions. Through the exchange of these messages, applications track the progress of enterprise activities. The JMS API supports both point-to-point and publish-subscribe styles of messaging.
The JavaMail API provides a set of abstract classes and interfaces that comprise an electronic mail system. The abstract classes and interfaces support many different implementations of message stores, formats, and transports. Many simple applications will only need to interact with the messaging system through these base classes and interfaces.
In this article we have looked at Java EE Architectural Design. We have reviewed how the principle of separation of concerns has impacted on design across numerous aspects of the Java EE application architecture. We have also looked at the advantages of object orientation and outlined the key design patterns that an architect should be used in designing the architecture of a system.