Other Considerations


We have covered a lot of ground in this book and in this specific chapter, but it is practically impossible to cover everything about developing robust and secure applications in one book. However, the following sections provide a brief overview of additional items to consider when designing and developing solid applications. Note that I have covered most of these considerations at a conceptual level here.

Transaction Management

A transaction is series of operations that must be successful or the system should be placed back to its original state. The simplest example of this is perhaps two tables in the same database: one parent and one child. If we delete records from the parent table, we must also delete the children records. However, if the child record delete fails, we must roll back the transaction and restore the database to its original state. Although this is a single database example, the same concept applies across databases.

Ensuring transactional integrity is a vital part of any enterprise application. Typically, transaction management is handled in two ways: programmatically or declaratively. Whereas programmatic transaction management provides control to the developer in the code, declarative transaction management allows us to control the transaction demarcation points and isolation levels by manipulating XML (configuration) files. Also, whereas programmatic transaction management is static in nature (because it needs to be coded in), declarative transaction management is more dynamic in nature because it can be postponed to the time of deployment.

Declarative transaction management plays a large role in enterprise distributed computing these days because transaction management no longer applies only to single databases (local transaction) because organizations tend to store information across databases (global transaction).

Note

We already saw examples of programmatic transaction management using Hibernate in Chapter 5 and declarative transaction management using Spring earlier in this chapter. This book's code zip file contains demonstrations of both types of transaction management.

The programmatic transaction management code and configuration can be found under the timex/directory (the declarative transaction management code using Spring can be found under timex2/).


Declarative transaction management shifts the burden of transaction management to the container (an EJB container, for example) and enables the developer to focus on the business logic. Furthermore, it can unclutter code a bit because there is no transaction management code mixed in with the business logic. As we discussed earlier in this chapter, the Spring Framework provides support for declarative transaction management without requiring your applications to run in an EJB container; in other words, your application can run inside a servlet container such as Apache Tomcat. To understand how declarative transaction management works, let's look at some related concepts next.

Enterprise transactions typically conform to the ACID properties; that is, atomicity, consistency, isolation, and durability. ACID transactions ensure that a series of operations are either successful or are left in a pretransaction statein essence, an all-or-nothing proposition. Atomicity ensures that all operations in a transaction are successful or the system is restored to its original state. Consistency ensures that all transactions transition data from one state to the other consistently. Isolation means that transactions are isolated from other transactions until transactions are committed. Durability indicates that after all transactions have been successfully committed, the changes are permitted.

The following are some additional terms related to enterprise transaction management.

  • Demarcation This is a way of marking the boundaries for a given transaction. It also enables grouping of transactions, which can participate in a broader global transaction. In a distributed environment, you could contain transactions within transactions (known as nested transactions).

  • Transaction isolation level This is the level of separation of one transaction from others. In other words, it specifies how much work one transaction can see of another transaction. Although different technologies use different terms for isolation levels, some of the Spring Framework contains the following levels: ISOLATION_READ_COMMITTED, ISOLATION_READ_UNCOMMITTED, ISOLATION_REPEATABLE_READ, and ISOLATION_SERIALIZABLE. Note that ISOLATION_READ_UNCOMMITTED is the lowest isolation form, because dirty read/writes can occur, but it provides faster performance. ISOLATION_SERIALIZABLE, on the other hand, is the highest and safest form and accordingly impacts performance because of the extra safeguards.

  • Transaction propagation This implies whether a group of code should run within its own transaction or participate in an existing transaction, which might have already begun prior to reaching that code. For example, Spring supports the following transaction propagation types: PROPAGATION_MANDATORY, PROPAGATION_NESTED, PROPAGATION_NEVER, PROPAGATION_NOT_SUPPORTED, PROPAGATION_REQUIRED, PROPAGATION_REQUIRES_NEW, and PROPAGATION_SUPPORTS.

Again, declarative transaction has been supported by EJBs for some time now; however, the Spring Framework makes it possible to get this enterprise-level transaction management even in a servlet container and not force us to use an EJB container. So, if we wanted to unclutter the code in Time Expression, we could convert to using Spring's declarative transaction management support and remove all Hibernate programmatic transaction management code. For additional information on Spring's declarative transaction management code, refer to the springframework.org website.

Application Security

Application security is a huge topic in itself that can take several books to cover. However, let's review some application security concepts in the context of our sample application, which would include the following: authentication, authorization, and encryption (see Figure 10.6).

Figure 10.6. Application security concepts (authentication, authorization, encryption).


Authentication

This includes user-level authentication and application-level authentication. Authentication is a process of verifying user credentials to ensure that users are who they claim they are. In Time Expression, user-level authentication is a simple sign-in screen where the user provides credentials (for example, id and password). Application-level authentication is the credentials required for the application to connection to the database. In real-world projects, this can also include connections to an LDAP server and Java Message Service (JMS) server, for example.

Authorization

Authorization controls access to features based on the user's role (or type). For example, in Chapter 2 we defined various types of roles in our user stories, such as Employee, Manager, Executive, and Accounting. Each of these roles would have different types of access; for example, employees could not pay themselves.

Encryption

Encryption in the context of our sample application could occur in two places: the wire protocol and the configuration files. For the wire protocol, using HTTPS (port 443) is typically enough to protect the data being transferred over the wire, and even if the data was being hijacked over the wire, it would be encrypted. Encryption can also happen in configuration files. If you do not want the application-level passwords (for example, application-level database user id and password) stored in clear textyou could use an algorithm such as SHA or MD5 to store passwords as encrypted strings in your configuration files. By the way, this can be done using the Java Cryptography Extension (JCE). Visit the java.sun.com website for details.

Other

As I mentioned previously, security is a big topic and there are many types of books dedicated to this subject. However, I have provided a concise list on how to secure web applications in Appendix D, "Securing Web Applications."

Exception Handling

Exceptions come in two flavors: unchecked or checked. Unchecked exceptions (for example, java.lang. NullPointerException) do not need to be caught by the code, whereas checked exceptions (for example, java.io.IOException) do require the code to either catch the exception or throw it up the call chain using the throws statement. There are also errors (for example, OutOfMemoryError) that are generally difficult to recover from.

Deciding when to have your application's exception-handling code as one or the other requires some careful thought. I recently read the following line in Sun's Java Tutorial (at http://java.sun.com/docs/books/tutorial/):

"If a client can reasonably be expected to recover from an exception, make it a checked exception. If a client cannot do anything to recover from the exception, make it an unchecked exception."

Another reason to catch an exception and rethrow it, as either itself or repackaged as a new exception, is in case you want to do some central logging or send out alert notifications (for example, email or pager).

A Hypothetical Exception-Handling Scheme

Given the preceding considerations, we can see that the application exception-handling approach might vary from application to application. Figure 10.7 portrays how our sample application could use handling exceptions:

Figure 10.7. Sample exception handling for Time Expression.


  • com.visualpatterns.timex.modelAny exceptions that occur in the model package (for example, database errors) could be repackaged as class ModelException and rethrown as an unchecked exception. Similarly, the job package could contain a JobException class and the util package a UtilException class. If we wanted to, we could even define more specific exceptions such as IllegalTimesheetHoursException, but I typically use one exception class per package (just a personal preference).

  • com.visualpatterns.timex.controllerAny exception occurring in the controller package could be checked and a user-friendly error message displayed to the UI. For instance, this might include UI data validation parsing related exceptions (for example, caused by Integer.parseInt).

One last note about exceptions is that many projects tend to hide exceptions using the following type of code; this typically is not a recommended approach, but there might be times where this approach is valid if the exception truly can be ignored:

try { // some code that causes an exception ... } catch (Exception e) { e.printStackTrace(); }


Handling Exceptions Using the Spring Web MVC Framework

The Spring Web MVC Framework provides a convenient and practical exception-handling scheme. More specifically, Spring allows us to configure exception class names to views; this enables us to handle unexpected exceptions somewhat gracefully by displaying a formatted web page.

The following code excerpt from our springhibernate-servlet.xml file (under the springhibernate/ directory) demonstrates how the org.springframework.dao. DataIntegrityViolationException exception can be mapped to our view file, dberror.jsp (discussed earlier in this chapter).

<bean  >     <property name="exceptionMappings">         <props>             <prop key="org.springframework.dao. DataIntegrityViolationException">                 dberror


The following code excerpt from our dberror.jsp view file demonstrates how Spring passes the exception object via the request's session attribute named exception and we print its stacktrace:

<%   Exception ex = (Exception)request.getAttribute("exception");   if (ex != null)       ex.printStackTrace(new java.io. PrintWriter(out)); %>




Agile Java Development with Spring, Hibernate and Eclipse
Agile Java Development with Spring, Hibernate and Eclipse
ISBN: 0672328968
EAN: 2147483647
Year: 2006
Pages: 219

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net