Tuesday, October 27, 2009

Alternatives to Spring




















Alternatives to Spring



Going back to our previous comments on the number of open source projects, you should not be surprised to learn that Spring is not the only framework offering Dependency Injection features or full end-to-end solutions for building applications. In fact, there are almost too many projects to mention. In the spirit of being open, we include a brief discussion of several of these frameworks here, but it is our belief that none of these platforms offers quite as comprehensive a solution as that available in Spring.




PicoContainer


PicoContainer (www.picocontainer.org) is an exceptionally small (50k) DI container that allows you to use DI for your application without introducing any other dependencies other than PicoContainer itself. Because PicoContainer is nothing more than a DI container, you may find that as your application grows, you need to introduce another framework, such as Spring, in which case you would have been better off using Spring from the start. However, if all you need is a tiny DI container, then PicoContainer is a good choice, but since Spring packages the DI container separate from the rest of the framework, you can just as easily use that and keep the flexibility for the future.





NanoContainer


NanoContainer (www.nanocontainer.org) is an extension to PicoContainer for managing trees of individual PicoContainers. Because Spring provides all the same functionality in the standard DI container, NanoContainer is not really a major improvement over Spring. Where NanoContainer becomes interesting is in its support for scripting languages that interact with the container. However, expect to see this functionality in Spring in the near future.





Keel Framework


The Keel Framework (www.keelframework.org) is more of a meta-framework in that most of its capabilities come from other frameworks that are all brought together under a single roof. For instance, DI functionality comes from the Apache Avalon container and web functionality comes from Struts or a similar framework. Keel has many implementations of the same components and links them all together into a cohesive structure, allowing you to swap out implementations with minimal impact on your application. Despite its wide feature set, Keel does not seem to have enjoyed the same level of acceptance as Spring. Although we have investigated Keel only briefly, we feel that this is partially to do with the level of accessibility. Spring is immediately accessible to developers of all levels, whereas Keel seems to be more complex. Having said that, the feature set is impressive, and this is certainly a direct competitor to Spring.




















25.4 Storing Grades in a STL Map




I l@ve RuBoard










25.4 Storing Grades in a STL Map



Let's change our class roster so that
we





record not only the name of each student, but also the
student's grade as well. We do this using something
called a map. To define our class map, we use the
following declaration:



#include <map>

// Map key=name(string), value = grade(char)
template map<string, char> student_roster;


Inserting an item into a map is a little trickier
that inserting one into a set because we are
inserting a pair of items. The STL handles this nicely by providing a
pair class that takes two elements and turns them
into an item that a map can handle. For example, if John Smith is in
the class and got an A, we would write:



    student_roster(pair(string("John Smith"), 'A'));


Suppose we want to find out what Mr. Smith's grade
is. We can search for his record using the find
function call. It takes three parameters: a place to start the
search, a place to end the search, and something to look for. It
returns an iterator pointing to the item found or, if nothing is
found, the value returned by the end function. To
look for Mr. Smith's grade, we use the code:



    map<string, char>::const_iterator record_loc;

record_loc = find(student_roster.begin(), student_roster.end( );
string("John Smith"));


Now let's check to see if we found the student:



    if (record_loc == student_roster.end(  ))
std::cerr << "John Smith not found in the class\n";


The iterator points to a pair consisting of the
student's name and grade. The fields of a
pair are named first and
second. To print John's record,
we use the statement:



    std::cout << "Student: " << record_loc->first << " Grade:" << 
record_loc->second << '\n';








    I l@ve RuBoard



    Item 57: Security is a process, not a product











     < Day Day Up > 





    Item 57: Security is a process, not a product



    "If you think technology can solve your security problems, then you don't understand the problems and you don't understand the technology" [Schneier01, xii].



    To the casual eye cruising the Internet, the various trade press publications, or the various security vendor Web sites, security would seem a kind of postdevelopment add-in that we can sprinkle all over an application to render it suddenly "secure," immune to attack and safe from harm. Just buy a product, make a few API calls, and voilà! Instant secure application, and it took only a few minutes to put it in. What could be better?



    Developers look at cryptography in much the same way. All we have to do to make the application secure is encrypt the data somehow, relying on the mathematics of the cryptographic algorithm to prevent the data from being viewed by unfriendly eyes. Bruce Schneier himself even subscribed to this view when he wrote, "It is insufficient to protect ourselves with laws; we need to protect ourselves with mathematics" [Schneier95, xx].



    Unfortunately, this attitude is exactly the wrong way to think about security. The various vendor products across the Internet cannot make your application secure. No one security technology will protect your application from all harm, not even Transport Layer Security (TLS), also known as the Secure Sockets Layer (SSL).



    The problem is simple: developers wrap themselves in the belief that "cryptography equals security" and that if the crypto key is strong enough, the system will be secure. Unfortunately, it's a horrible fallacy and one that Schneier himself admits to in the Preface to Secrets and Lies:





    The error of Applied Cryptography is that I didn't talk at all about the context. I talked about cryptography as if it were The Answer. I was pretty naïve.



    The result wasn't pretty. Readers believed that cryptography was a kind of magic security dust that they could sprinkle over their software and make it secure. That they could invoke magic spells like "128-bit key" and "public-key infrastructure." A colleague once told me that the world was full of bad security systems designed by people who read Applied Cryptography [Schneier01, xii].



    This is not a confidence-inspiring editorial. If the one man who arguably knows most about cryptography in the Internet era suddenly feels that cryptography isn't the solution, then how, exactly, are enterprise developers who haven't the time to learn cryptography to the depths that Schneier knows it supposed to make our systems secure?



    The problem isn't in the use of cryptography itself; the problem is in the belief that most developers have that cryptography holds the solution to all of our security needs. Consider the canonical e-commerce Internet application: a new company, seeking to peddle its wares across the Internet, creates the onlisne shopping site e-socks.com, the World's Premier Internet Retailer of Soft Fluffy Footwear. As developers, we build the site to provide all the classic e-commerce functions: shopping cart, customer checkout, and so on. And, in typical fashion, to allay customers who fear sending their credit card numbers over the Internet,[1] we take their credit card information over an HTTPS connection. So we're secure, right?

    [1] Ironically, these same customers have no qualms about giving their numbers over the phone to unknown customer service representatives or handing their credit cards, on which the numbers are prominently displayed to any who look, to servers at restaurants to pay for dinner.



    Unfortunately, no. While the system may be sending the credit card number in secure format to render it inaccessible to prying eyes, the wily hacker is far from stymied. Any number of ways into the system are possible, some of which are highlighted here.





    • Social engineering attack:

      "Social engineering" is the euphemistic name we give to that form of attack traditionally practiced by those whom we used to call "con men"�in short, a charming, swift-talking, charismatic individual convinces someone within the system to surrender information. Kevin Mitnick, in The Art of Deception [Mitnick, 45�46], describes a story in which a son was able to win a $50 bet with his father�the challenge was to obtain Dad's credit card number from a video store. It took three phone calls and about ten minutes to do so. How hard would it be to convince a customer service rep to hand out a particular consumer's credit card number? Ask Mitnick�he made a living off the idea (and continues to do so today, although from the other direction).



    • Database attacks:

      Many systems store consumer information as part of the users' profile on the company site, as a feature to prevent users from having to enter their credit card numbers on every purchase. Most companies don't bother to encrypt these numbers, and in fact many companies aren't quite as tight on security procedures on the database as they are elsewhere. (Most companies don't assume insecurity, as explained in Item 60, for example.)



    • Man-in-the-middle attacks within the corporate firewall:

      As long as any part of the company firewall can be compromised, the attacker now has free reign anywhere within it. SSL typically runs only to the proxy server or firewall of the corporate network, since load-balancers and routers need access to the underlying data if they're to do their jobs. So the hacker gets into the demilitarized zone (DMZ), sets up a network sniffer, and watches the packets after they've been decrypted by the proxy.



    Other attacks are certainly possible, and I'm sure we've not even scratched the surface of possible attack vectors. Note that none of them involved trying to go directly against the SSL layer itself; instead, they attack other parts of the overall security of the system. Why bother going against SSL and its key exchange protocol when it's far easier for the attacker to engage in one of the dozens of other forms of attack, all of which end with the same result (i.e., your credit card number in his highly immoral fist)?



    Security is not something that we can simply "turn on" as a feature at some point in the system's implementation lifecycle. Unfortunately, this is exactly the attitude that most development teams and managers take: "Well, sure, the system needs to be secure, but we'll get to that after we get it up and running." While this particular approach and attitude might work for optimizing a system (even then, it's debatable), this will never work when discussing the security of a system as a whole. Concerns about security have to be factored into the analysis, design, implementation, and test phases of every iteration of the system's development, or gaping security holes will result.



    For example, consider the e-socks.com e-commerce application again. Assuming this is a classic Model-View-Controller application, where do we need to worry about security? What are the security concerns? A partial list includes the following issues.



    • Assuming the site makes use of some kind of per-user session state (e.g., HttpSession), we need to ensure somehow that an attacker cannot "guess" a valid in-use JSESSIONID value and thus gain access to another user's session state. For e-socks.com, the concern would be that an attacker could use my credit card to ship silk stockings to his shipping address. For a site dealing with financial or medical data, the implications could be far, far worse. Never use a servlet container that doesn't generate some kind of secure random value for the JSESSIONID query parameter.

    • Each servlet processing input on the page must make sure the input falls within valid ranges. For example, when verifying login credentials for the user against the database (SELECT * FROM user WHERE...), make sure the username and password aren't hiding a SQL injection attack.

    • Each servlet and JSP page must be carefully examined to make sure that out-of-order page requests don't bypass critical data-entry information. For example, it shouldn't be possible to bypass the "select method of payment" page to go directly to the "confirm this order!" page. Ideally, of course, the rest of the back-end processing would verify that the order had, in fact, been paid for before sending it out, but how often do you as a programmer double-check something that "I know has already been processed" further up the chain?

    • How do the pages calculate the current running price total of the user's shopping cart? If the value is cached in a hidden field, an attacker can always bypass the browser entirely and hand-submit (via Telnet) an HTTP request that contains thousands of items in the shopping cart and that hidden field containing a value of $0.01. Even if the value is calculated on each request, where does the shopping cart get the prices of the items put into the cart? Again, if it's from an HTML form field, this data can be mocked up pretty easily.



    Subsequent items in this chapter cover many of these concerns in further detail, but all of these issues are meant to serve as background material to support the main title of this item, a phrase Schneier uses over and over again: "Security is a process, not a product." You have to consciously think about this at every stage of the system's development if you're to have any hope of building a system that's remotely attacker-resistant. This requires a shift in your mental model: it requires you to briefly put on the attacker's black hat and think about how you might attack the system and then, putting the white hat back on, what you might do to prevent that attack. And not only the architect or technical lead needs to think about this�everybody, at all levels of the system's implementation, needs to have security in mind. "Write secure code" should be a driving principle of every programmer, just as "write good code" and "write elegant code" are.













       < Day Day Up > 



      A Pride of Linuxes













      A Pride of Linuxes

      Complete Linux systems are packaged into distributions, which describe not how Linux is distributed but rather how the operating system and the GNU programs are bundled. A few distributions are in common use: Slackware, Red Hat, Mandrake, and Debian. All are available for free via the Internet or for a small charge on CD-ROM. As a user, which distribution you use doesn’t matter because they all behave in much the same way. As a system administrator, though, you should consider the important differences the distributions have among them.



      Slackware, the oldest of the three, has been around since the beginning of Linux. It is the most traditional distribution (traditional in the UNIX sense, as in not particularly user-friendly) and has relatively little in the way of utilities to facilitate the management of a Linux system. For this reason, those who have been around UNIX systems for a while tend to favor it.















      Red Hat Linux is the most popular distribution. It features plenty of tools to make the life of a system administrator easier, most notably the Red Hat Package Manager (RPM), which eases the installation, upgrade, and deletion of software packages, and even the operating system itself. For about $40, you can get a CD set with the Mozilla Web browser, OpenOffice office suite, KDE, GNOME, and about a hundred other packages. The $40 is for the CDs, not the software on them (which is free), and one month of Web-based software support. (More support — Red Hat’s main business — is available for more money.)


      The Debian and Mandrake distributions, like Red Hat, also provide interfaces that ease the task of a system administrator. Although these distributions are not as popular as Red Hat, they both have plenty of followers.


      If you enjoy editing lots of configuration files and moving them around by hand, the old-fashioned way (believe it or not, some people like to do it that way), you should go with Slackware. Everyone else will find life easier with Red Hat, Debian, or Caldera.


      Many other Linux distributions are out there, of course, so you may want to do a little more investigating before deciding on a package:





      • Knoppix: For PC users without much free space, this version of Linux can run (kind of slowly) directly from its CD-ROM without needing to be installed on a regular disk. (See www.knoppix.org.)





      • Lindows: A combination of Linux and proprietary add-ons intended to be easy to set up and easy for Windows users to use. Costs about $50 at www.lindows.com.





      • SuSe Linux: Comes with all kinds of preconfigured software packages, X servers, and graphical utilities for novice users.





      • Turbolinux: Primarily intended for larger businesses and servers; developed in Japan and popular in Asia.













      6.5 Generalization and Specialization




      I l@ve RuBoard









      6.5 Generalization and Specialization


      All of the instances of a class must share common characteristics and common behavior. But we often face things that are somewhat common yet somewhat different.


      6.5.1 The Concept of Generalization and Specialization


      In Section 5.5: Checking Classes and Attributes, we presented a Product as an example of a uniformity problem. The online store sells more than just books; it also sells videotapes, CDs, DVDs, and computer software. All these products have a sale price and are identified by a universal product code (UPC). Books have an ISBN number; CDs, videotapes, and DVDs have a running time; computer software titles have version numbers. We noted a uniformity problem that made a single Product class undesirable and promised to show how to correct the problem.


      An alternative to the single Product class is to have separate classes for each type of product, as shown in Figure 6.11. But while this is a more precise attribution, it isn't quite satisfying either. Attributes (and behaviors) that ought to be common are spread across many classes.


      Figure 6.11. Separate Product Classes



      The concept of generalization allows us to have the best of both worlds when confronted by this type of problem. We can have both a single Product class and individual classes for BookProduct, RecordingProduct, and SoftwareProduct. Figure 6.12 shows how these products may be partitioned into subsets, one for each kind of product.


      Figure 6.12. Partitioning of Products into Subsets



      Figure 6.13 models the Product class as a generalization of BookProduct, RecordingProduct, and SoftwareProduct. This means that the superclass Product contains attributes and associations applicable to all of the subclasses BookProduct, RecordingProduct, and SoftwareProduct. Likewise, BookProduct is a specialization of the Product class. It contains additional attributes and associations that are relevant only to books.


      Figure 6.13. Product Generalization and Specialization



      Definition:
      A superclass is a class that generalizes classes in a generalization-specialization hierarchy.


      Definition:
      A subclass is a class that specializes classes in a generalization-specialization hierarchy.


      Definition:
      A leaf subclass is a subclass that is not the superclass of any other class.


      Each superclass and each subclass is a class like any other. It may have attributes and participate in associations. It must have a class description and descriptions for each attribute and association in which it participates.




      Inheritance is a related, but different, concept. The UML Reference Manual [2] (p. 287) states: "Generalization is a taxonomic relationship among elements. It describes what an element is. Inheritance is a mechanism for combining shared incremental descriptions to form a full description of an element. They are not the same thing, although they are closely related." (See also the formal definition of UML in [3].)


      The reference manual clearly distinguishes between the two concepts. Executable UML uses generalization and specialization, also called subclassing.


      Of course, generalization and specialization can be implemented using inheritance, and inheritance can be used as an implementation mechanism in other contexts.



      With the preceding in mind, we may now (finally!) define an object.


      Definition:
      An object is an instance of a class, or an instance of several classes in a generalization-specialization hierarchy.



      6.5.2 Mutual Exclusion and its Implications


      Executable UML prescribes a strict mutual exclusion principle in defining generalizations: Each instance of a superclass must be one and only one of its superclasses, and each instance of a subclass must be an instance of the superclass.


      Definition:
      An abstract class is a class whose instances can be created only in conjunction with an instance of one of its descendant subclasses.


      In UML terms, all Executable UML superclasses are tagged {abstract} and all generalizations are tagged {disjoint, complete}. This means:



      • Each Product must be one of the subclasses: a BookProduct, SoftwareProduct, or RecordingProduct. This makes the Product class abstract, because you can't make an instance of Product that is not an instance of one of its subclasses.


      • Each Product must be one or the other of the subclasses. It is not possible to create an instance of a Product that is both a BookProduct and a SoftwareProduct ("disjoint").





      We are careful to use "instance" to mean an instance of a class and to use "object" in the object-oriented way to mean an instance of a class potentially combined with instances of other classes in a generalization hierarchy to make a single object.


      Hence, the instance of the class BookProduct for a book on Executable UML and an instance of the class Product for the same Executable UML book constitute a single object.





      Superclasses in Executable UML are all abstract�you cannot create an object that is only an instance of the superclass without its also being an instance of exactly one of the subclasses.




      • The stated subclasses are the only subclasses of Product; there are no other hidden or unknown subclasses ("complete"). Since an Executable UML model is a precise specification, all subclassings are complete.



      This approach supports the semantic modeling properties of Executable UML, and abstraction from things in the domain: the several products. Consequently, each product is a member of the superset and exactly one subset. The set partitioning is disjoint and complete as shown by the tag {disjoint, complete}.



      6.5.3 Repeated Specialization


      A class can be specialized repeatedly, as shown in Figure 6.14. Bank accounts can be subclassed into checking and savings accounts. A checking account can be further subclassed into regular and interest-bearing accounts.


      Figure 6.14. Repeated Specialization



      In cases of repeated specialization, all the non-leaf classes are abstract; hence the class CheckingAccount is abstract even as it is also a subclass.



      6.5.4 Multiple Generalization


      Consider now the hierarchy of Figure 6.15, in which a single subclass is the subclass of multiple superclasses. In this model, the class InterestCheckingAccount is a subclass of InterestBearingAccount and CheckingAccount. This is perfectly legal. Figure 6.16 illustrates how the accounts are organized into {disjoint, complete} subsets.


      Figure 6.15. Multiple Generalization



      Figure 6.16. Illustration of Multiple Generalization



      However, when building these kinds of structures, watch out for "diamond generalization," as illustrated in Figure 6.17, wherein the same instance purports to be a subclass of two superclasses that have the same parent.


      Figure 6.17. Improper Multiple Generalization



      Here we have made the InterestBearingAccount a subclass of an Account. (After all, the InterestBearingAccount is surely some kind of account.) The result of this innocuous change is that an InterestCheckingAccount has a parent CheckingAccount that is a subclass of Account, and a parent InterestBearingAccount that is a different subclass of Account. The mutual exclusion rule forbids this. This situation is quite rare, but it is subtle and can cause a great deal of confusion.



      6.5.5 Compound Generalization


      In Figure 6.13 we subclassed Product into Book, Recording, and Software. In addition, some of each kind of Product are not actually kept in stock, but are special-ordered from the Publisher whenever ordered by a Customer. This subclassing is separate and distinct from whether the Product is a Book, Recording, or Software product. Figure 6.18 shows how we can represent this with a distinct generalization-specialization relationship.


      Figure 6.18. Compound Generalization




      UML allows Figure 6.18 to be an easier-to-draw version of a single hierarchy, if the association name is the same. That is, if both hierarchies were labeled R13, a Product would be just one of the five subclasses (Book Product, Recording Product, Software Product, In-Stock Product, and Special Order Product) as well as the superclass.


      Formally, the relationship number here is called a discriminator.



      We call this a compound generalization since the superclass is a disjoint, complete generalization in more than one hierarchy. Each generalization is shown as a separate relationship with its own triangle and collection of subclasses









        I l@ve RuBoard



        Chapter 5.&nbsp; Iterative Processing with Loops









        Chapter 5. Iterative Processing with Loops


        This chapter explores the iterative control structures of PL/SQL, otherwise known as loops
        , which let you execute the same code repeatedly. PL/SQL provides three different kinds of loop constructs:


        • The simple or infinite loop

        • The FOR loop (numeric and cursor)

        • The WHILE loop


        Each type of loop is designed for a specific purpose with its own nuances, rules for use, and guidelines for high-quality construction. As we explain each loop, we'll provide a table describing the following properties of the loop:


        Property

        Description

        How the loop is terminated

        A loop executes code repetitively. How do you make the loop stop executing its body?

        When the test for termination takes place

        Does the test for termination take place at the beginning or end of the loop? What are the consequences?

        Reason to use this loop

        What are the special factors you should consider to determine if this loop is right for your situation?










          Section 3.17.&nbsp; Summary










          3.17. Summary


          This chapter has described the basic I/O functions provided by the UNIX System. These are often called the unbuffered I/O functions because each read or write invokes a system call into the kernel. Using only read and write, we looked at the effect of various I/O sizes on the amount of time required to read a file. We also looked at several ways to flush written data to disk and their effect on application performance.


          Atomic operations were introduced when multiple processes append to the same file and when multiple processes create the same file. We also looked at the data structures used by the kernel to share information about open files. We'll return to these data structures later in the text.


          We also described the ioctl and fcntl functions. We return to both of these functions in Chapter 14, where we'll use ioctl with the STREAMS I/O system, and fcntl for record locking.










            Project 6. CSS-Driven Drop-Down Menus











             < Day Day Up > 







            Project 6. CSS-Driven Drop-Down Menus





            Parents who want a fresh point of view on their furniture are advised to drop down on all fours and accompany the nine or ten month old on his rounds.

            SELMA H. FRAIBERG



            As we saw in the preceding project, it's possible to take a simple, unordered list of links and make it look good. The missing component there was the capability to have submenus and even sub-submenus. Is there a way to use CSS and simple HTML to create drop-down menus, and menus within menus?



            As you might have expected, the answer is "yes." It does require using a bit of proprietary technology to get one browser on board, but since that browser is Internet Explorer for Windows, the nonstandard bit is very likely more than worth it. As we'll see in this project, we can take simple nested lists of links and turn them into multilevel menu systems.















               < Day Day Up > 



              Database I&amp;A




















              Database I&A


              The database’s primary I&A mechanism is username and password. The authentication is critical because usernames can be predicted and in some cases are well known. For users identified in the database you have the following authentication choices:





              • Passwords Passwords can be either authenticated by the database or by the Oracle LDAP directory as shown in Chapter 5.





              • External/Strong Oracle supports operating system authentication and strong authentication that includes PKI certificates, Kerberos, DCE, and RADIUS. The RADIUS standard extends the authentication capabilities to include token cards, biometrics, and smart cards. Details on how to setup and configure Oracle for strong authentication are given in the Oracle Database Advanced Security Administrator’s Guide 10g.





              • Proxy This is covered in detail in Chapter 4.




              Oracle supports single sign-on both directly to the database and for Web applications deployed to the Oracle Application Server. The database’s support for strong authentication also includes support for single sign-on technologies such as Kerberos, DCE, and PKI certificates.


              The Oracle Application Server single sign-on capability is deployed on an Oracle database, which provides the scalability, security, and high-availability requirements needed for an effective implementation. The server supports passwords, PKI certificates, Microsoft Windows (Kerberos on Windows 2000) authentication, and an extensible framework for plugging in third-party authentication such as token cards and biometrics. Refer to the Oracle Application Server 10g Security Guide for further details.




              Associating Users with Database Schemas


              Now that you have a good understanding of the various I&A techniques, you have to decide how to represent your end users (applications users) to the database. The overall security of your application and the data it touches is largely affected by how this process is done.


              When it comes to building applications, there are typically three models that can be used for mapping actual end users to database accounts. There are different benefits and risks within each model, so it’s important to understand each. This understanding is crucial, because the model often restricts what you do and how you do it.





              • 1:1 This one-to-one mapping occurs primarily in client-server programs. This means that every end user has a distinct database account, or schema.





              • N:M This all-to-several mapping occasionally happens in Web applications. It means that all the end users are mapped to several different schemas. Each account is created based on the shared end-user privileges. All users with the same privileges are connected to the same schema.





              • N:1 This all-to-one mapping is a typical Web application. The application connects all end users to the same database schema. The schema has the union of all privileges for all users connected to it.




              The mappings are listed in order of easiest to hardest to build database security. There are many factors influencing the model choice. Scalability, performance, and administration ease-of-use often get most of the attention. Security, however, must also be part of the consideration. In some cases, the security requirements may supersede other requirements, such as the administration.




              User Privileges for Unique Database Accounts


              Depending on how your database will be accessed and the role of your application(s), you may or may not have a lot of actual end-user accounts, that is, the 1:1 mapping model. For example, it’s typical for client-server programs to run in this manner and less common for Web applications to do so.


              The 1:1 mapping can occur several ways, but the bottom line is that there is a direct mapping of each user to an identity in the database (that is, the database account). In its simplest mode, the user supplies a username and password that are the actual database user account names and account passwords. Alternatively, the application could provide its own mapping. The point is not necessarily how it’s done, but that it’s done.


              When creating the 1:1 database accounts, it’s important to apply the same least-privilege lessons and process used in managing accounts on operating systems. That is, you should create users with no privileges and then selectively grant them the privileges they need to get their job done.


              This mapping is especially critical for database administrators and other privileged users. Sharing a privileged account among a group of users is a bad practice. In many organizations, sharing user accounts is prohibited by policy, but is nonetheless still often practiced. If something goes wrong in that case, you’ll not be able to tell which user was connected as the database user when that something happened. Therefore, there is no user accountability.


              The 1:1 mapping makes the database security easy because the user’s identity is always available to the database; therefore, the user is accountable. In addition, many of the database security capabilities operate at the individual schema level. If every user has a unique schema, then the database can easily apply appropriate security to the appropriate users based on the schemas. The database can, with high assurance, distinguish between each end user, and in doing so it can employ all of its security capabilities.





              Shared Database Accounts



              Least privileges are important even if the users are not connecting directly to the database. It’s most common for users to have a unique application account and share a database schema. There are two mappings for this.


              The first mapping, N:M, partitions users into various schemas. This is generally done by organizing the users by role—all users with the same role connect to the same schema. The important part to this is ensuring that the least-privilege principle is still upheld. You can effectively do this if all users that attach to the shared database schema are supposed to have the exact same database privileges. That is, the users are homogeneous from a privilege perspective. Conveying the user’s identity is important in this design, too, since the database may be unable to distinguish between users connected to the same schema. Chapter 6 explores how to do this using Client Identifiers.


              The last mapping model, N:1, connects all end users to the same database schema. This mapping is always the most questionable with regard to security. The problem with the design is that it’s difficult for the database to separate the security privileges for the different users since they are all connected to the same schema. Ensuring that only the right privileges are available to the user is left mostly to the application. From an auditing perspective, unless you are using Oracle Enterprise Users (discussed in Chapter 5), the user’s identity is not natively supported with this design, so their individual actions may be untraceable as well as unregulated.


              Consider the scenario of users requiring different privileges sharing the same database schema. Figure 3-1 represents the N:1 mapping. Suppose you have three user groups—one with read-only access, another with read and write access, and an administrator group that can create and drop objects as well as read and write. If all three user groups are mapped to the same database schema, then the application must regulate what privileges to enable and disable based on what it knows about the user.






              Figure 3-1: End users with different privilege sets shouldn’t be mapped to a single schema that has all the privileges of all the users.

              From the database’s perspective, all users have the same privileges. This violates least privilege and defense in depth. If the application security fails, or the user circumvents the application, then the security can be compromised.


              When you are designing and building an application, you should ensure that the least-privilege principle is upheld. Isolating schemas to shared users with the same privileges is one way to do this. Alternatively, using other features of the database such as Enterprise Users, Secure Application Roles, and identity preservations techniques (all covered in later chapters) will allow you to securely share database schemas among the end users.






              Separate Users and Data


              A critical part to ensuring a successful application is to ensure you have a separation of user database accounts and data/application database accounts. The data owner has all privileges on the data. If the users connect to this schema, even if by way of your application, you run a significant risk of a security incident. That is, if a user can break the application, or the application breaks itself, the user will have complete control on every part of the data. This includes not only access but also destructive capabilities such as truncating tables and dropping objects.


              For this reason, a security best practice is to ensure the application users don’t connect directly to the data account. You may also consider disabling all user log on to the data schema using one of the techniques discussed in Chapter 2, such as locking the account, revoking privileges to connect, or creating an impossible password.


              In the safest design, you have one schema that holds the data, one schema that holds any PL/SQL programs that work on the data, and at least one other schema to which the users attach.






              Tip 


              Never allow your end users to connect to the data schemas.






              Identity Preservation


              An important aspect of the identification process is identity preservation and propagation. You must ensure that user identities are available everywhere security requires them. The minute the identity stops, security stops. From a secure database perspective, this is a particularly acute problem. It often occurs that the user authenticates to an application, and the application connects to the database not as the actual user but anonymously or pseudo-anonymously. When designing database applications, the more information you can provide about the user’s identity, the finer levels of security you can apply. Or as some like to say, “The more the identity, the better the security.”


              Although many applications (or databases) are designed around user-level access control and auditing, not all require it. This doesn’t imply the application or its data is not secure. Almost all applications are based on the users identifying themselves as themselves or as a member of a role or group.





              Determining the Appropriate Level of I&A


              After all the possible ways of doing I&A, you may be left feeling a little overwhelmed. You shouldn’t. There is a practical and sensible approach to determining what tactics and techniques you should be using. Your I&A should be determined by considering the sensitivity of the data and the privileges and access rights of the user as well as by balancing other competing factors.


              Your first guiding directive is based on what you are protecting. Stronger I&A is usually required as the sensitivity of the data increases. If an application allows users access to their favorite stock list, then simple passwords with no password restrictions may suffice. If the access granted to the person allows them to obtain the nuclear launch codes, then obviously strong authentication, probably multifactor authentication, is a good choice.


              The second factor for determining appropriate I&A is based on what it is the user can see and do. Remember that the greater the privileges and the greater the access, the stronger the authentication. For general users whose access is controlled, strong passwords are generally a good practice. For users with more privileges, such as DBAs, stronger authentication is desirable.


              You’re probably wondering, “Why not just use strong authentication all the time?” Before you invest in this approach, you have to consider that there are other tradeoffs. Practical security has to be balanced with usability, Chapter 2 which highlights how a password policy that is too strong can be self-defeating. Therefore, the correct authentication method must consider all aspects, not only the security. Note that this doesn’t imply that strong I&A is bad; you have to do the cost-benefit comparison that compares the cost of implementation to the cost of a security breech.




















              14.2 Menu Bar Selection Models




              I l@ve RuBoard










              14.2 Menu Bar Selection Models



              In all GUI environments, menu components
              allow only one selection to be made at a time. Swing is no exception.
              Swing provides a data model that menu bars and menus can use to
              emulate this behavior: the SingleSelectionModel.




              14.2.1 The SingleSelectionModel Interface



              Objects implementing the SingleSelectionModel
              interface do exactly what its name suggests: they maintain an array
              of possible selections and allow one element in the array to be
              chosen at a time. The model holds the index of the selected element.
              If a new element is chosen, the model resets the index representing
              the chosen element and fires a ChangeEvent to each
              of the registered listeners.




              14.2.1.1 Properties


              Objects implementing the SingleSelectionModel
              interface contain the properties shown in Table 14-1. The selected property is a
              boolean that tells if there is a selection. The
              selectedIndex property is an integer index that
              represents the currently selected item.






























              Table 14-1. SingleSelectionModel properties

              Property



              Data type



              get



              is



              set



              Default value



              selected



              boolean


               

              ·


                

              selectedIndex



              int



              ·


               

              ·


               






              14.2.1.2 Events




              Objects implementing the
              SingleSelectionModel interface must fire a
              ChangeEvent (not a
              PropertyChangeEvent) when the object modifies its
              selectedIndex property, i.e., when the selection
              has changed. The interface contains the standard
              addChangeListener( ) and
              removeChangeListener( ) methods for maintaining a
              list of ChangeEvent listeners.



              void
              addChangeListener(ChangeListener listener)

              void removeChangeListener(ChangeListener listener)


              Add or remove the specified ChangeListener from
              the list of listeners receiving this model's change
              events.









              14.2.1.3 Method


              The SingleSelectionModel interface contains one
              other method:



              public void clearSelection( )


              Clear the selection value, forcing the selected
              property to return false.








              14.2.2 The DefaultSingleSelectionModel Class



              Swing provides a simple default implementation of the
              SingleSelectionModel interface in the
              DefaultSingleSelectionModel
              class.




              14.2.2.1 Properties


              DefaultSingleSelectionModel contains just the
              properties required by the SingleSelectionModel
              interface, as shown in Table 14-2. The
              selectedIndex property is an integer index that
              represents the currently selected item. The default value of
              -1 indicates that there is no selection. The
              selected property is a boolean
              that returns true if the
              selectedIndex is anything other than
              -1, and false otherwise.






























              Table 14-2. DefaultSingleSelectionModel properties

              Property



              Data type



              get



              is



              set



              Default value



              selected



              boolean


               

              ·


               

              false



              selectedIndex



              int



              ·


               

              ·



              -1







              14.2.2.2 Events and methods


              The


              DefaultSingleSelectionModel
              object provides all the events and methods specified by the
              SingleSelectionModel interface discussed earlier.











                I l@ve RuBoard



                Section 3.1. Activity Diagram Essentials










                3.1. Activity Diagram Essentials




















                Let's look at the basic elements of activity diagrams by modeling a process encountered earlier in the bookthe steps in the blog account creation use case. Table 3-1 contains the Create a new Blog Account use case description (originally Table 2-1). The Main Flow and Extension sections describe steps in the blog account creation process.


                Table 3-1. Create a new Blog Account use case description

                Use case name

                Create a new Blog Account

                Related Requirements

                Requirement A.1.

                Goal In Context

                A new or existing author requests a new blog account from the Administrator.

                Preconditions

                The system is limited to recognized authors, and so the author needs to have appropriate proof of identity.

                Successful End Condition

                A new blog account is created for the author.

                Failed End Condition

                The application for a new blog account is rejected.

                Primary Actors

                Administrator.

                Secondary Actors

                Author Credentials Database.

                Trigger

                The Administrator asks the Content Management System to create a new blog account.

                Main Flow

                Step

                Action

                 

                1

                The Administrator asks the system to create a new blog account.

                 

                2

                The Administrator selects an account type.

                 

                3

                The Administrator enters the author's details.

                 

                4

                The author's details are verified using the Author Credentials Database.

                 

                5

                The new blog account is created.

                 

                6

                A summary of the new blog account's details are emailed to the author.

                Extensions

                Step

                Branching Action

                 

                4.1

                The Author Credentials Database does not verify the author's details.

                 

                4.2

                The author's new blog account application is rejected.



                Figure 3-2 shows this blog account creation process in activity diagram notation. An activity diagram is useful here because it helps you to better visualize a use case's steps (compared to the table notation in the use case description), especially the branching steps that depend on whether the author is verified.


                In Figure 3-2, the activity is launched by the initial node
                , which is drawn as a filled circle. The initial node simply marks the start of the activity. At the other end of the diagram, the activity final node, drawn as two concentric circles with a filled inner circle, marks the end of the activity.



                Figure 3-2. Activity diagrams model dynamic behavior with a focus on processes; the basic elements of activity diagrams are shown in this blog account creation process



                In between the initial node and the activity final node
                are actions
                , which are drawn as rounded rectangles. Actions are the important steps that take place in the overall activity, e.g., Select Account Type, Enter Author's Details, and so on. An action could be a behavior performed, a computation, or any key step in the process.


                The flow of
                the activity is shown using arrowed lines called edges or paths. The arrowhead on an activity edge shows the direction of flow from one action to the next. A line going into a node is called an incoming edge, and a line exiting a node is called an outgoing edge. Edges string the actions
                together to determine the overall activity flow: first the initial node becomes active, then Ask System to create new Blog Account, and so on.


                The first diamond-shaped node is called a decision, analogous to an if-else statement in code. Notice that there are two outgoing edges from the decision in Figure 3-2, each labeled with Boolean conditions. Only one edge is followed out of the decision node depending on whether the author is authorized. The second diamond-shaped node is called a merge. A merge node combines the edges starting from a decision node, marking the end of the conditional behavior.


                The word "flow" was mentioned several times previously and you may askwhat's flowing? The answer depends on the context. Typically, it's the flow of control from one action to the next: one action executes to completion, then gives up its control to the next action. In later sections you'll see that, along with control, objects can flow through an activity.












                Interface and Abstract Class




















                Chapter 4 -
                Fundamental Design Patterns
                Patterns in Java, Volume 1: A Catalog of Reusable Design Patterns Illustrated with UML, Second Edition
                by Mark Grand
                John Wiley & Sons � 2002



























                Interface and Abstract Class





                Synopsis


                You need to keep client classes independent of classes that implement a behavior and ensure consistency of behavior between the behavior-implementing classes. Don’t choose between using an interface and an abstract class; have the classes implement an interface and extend an abstract class.






                Context


                You are designing a framework. You want to hide the class or classes that implement some behavior by making the classes private to their package and having them implement a public interface. For the sake of consistency and convenience of implementation, you want the classes to extend a common abstract class. You are not sure how to decide between basing the classes on an interface and an abstract class.






                Forces

















                J



                Using the Interface pattern, Java interfaces can be used to hide the specific class that implements a behavior from the clients of the class.




                J



                Organizing classes that provide related behaviors with a common superclass helps to ensure consistency of implementation. Through reuse, it may also reduce the effort required for implementation.




                L



                When people are presented with two different ways to improve the organization of classes, there is a common tendency to choose either one or the other.








                Solution


                If you are presented with the need to hide from its clients the class of an object that provides a service, then use the Interface pattern. Have the client objects access the service-providing object indirectly through an interface. The indirection allows the clients to access the service-providing object without having to know what kind of objects they are.


                If you need to design a set of related classes that provide similar functionality, then organize the common portions of their implementation into an abstract superclass.


                If you are presented with both of these needs in the same object design, then use both an interface and an abstract class as shown in Figure 4.11.






                Figure 4.11: Interface and abstract class.

                When using the combination of an interface and abstract class in this way, the interface is public; the abstract class is package private, if possible.






                Consequences











                J



                Using the Interface and Abstract Class pattern allows an object design to benefit from both an interface and an abstract class.








                Java API Usage



                The package javax.swing.table contains interfaces and classes to support tables in a user interface. For every table that appears in a user interface, a corresponding data model object contains the data values displayed in the table. To be used as the data model for a table, an object must be an instance of a class that implements the javax.swing.table.TableModel interface. The package also includes a class named AbstractTableModel. AbstractTableModel is an abstract class that contains some default logic useful in implementing the methods declared by the TableModel interface. Finally, there is a concrete class named DefaultTableModel that is the default class used to instantiate a data model for a table. These relationships are shown in Figure 4.12.






                Figure 4.12: javax.swing.table relationships.





                Code Example


                The code example for the Interface and Abstract Class pattern consists of an interface and classes for managing a data structure called a doubly linked list. There is a class called DoubleLinkedListMgr that performs various insert and delete operations on the elements of a doubly linked list. The DoubleLinkedListMgr class does not require that the objects in the doubly linked list be instances of any particular class. It does require that all of the elements implement an interface called DoubleLinkIF. There is an abstract class called AbstractDoubleLink that implements the DoubleLinkIF interface. Extending the AbstractDoubleLink class is a convenient way to write concrete classes that can be manipulated in a doubly linked list.


                These classes and the interface are part of org.clickblocks.dataStructure package of the ClickBlocks software on the Web site for this book.








                The following is a listing of the DoubleLinkIF interface:




                public interface DoubleLinkIF {
                /**
                * Return the node that follows this one in the linked
                * list or null if this is the last node.
                */
                    public DoubleLinkIF getNext() ;
                /**
                * Set the node that is to follow this one in the linked
                * list.
                *
                * @param node
                * The node that is to follow this one in the
                * linked list or null if this node is to be the
                * last one in the list.
                */
                    public void setNext(DoubleLinkIF newValue) ;
                /**
                * Return the node that precedes this one in the linked
                * list or null if this is the first node.
                */
                    public DoubleLinkIF getPrev() ;
                /**
                * Set the node that is to precede this one in the linked
                * list.
                *
                * @param node
                * The node that is to precede this one in the
                * linked list or null if this node is to be the
                * first one in the list.
                */
                    public void setPrev(DoubleLinkIF newValue) ;
                }  // interface DoubleLinkIF


                The following is a listing of the abstract class AbstractDoubleLink that implements the DoubleLinkIF interface:




                public abstract class AbstractDoubleLink
                                implements DoubleLinkIF {
                    private DoubleLinkIF previous;
                    private DoubleLinkIF next;
                /**
                * Return the node that follows this one in the linked
                * list or null if this is the last node.
                */
                    public DoubleLinkIF getNext() { return next; }
                /**
                * Set the node to follow this one in the linked list.
                *
                * @param node
                * The node to follow this one or null if this node
                * is to be the last one in the list.
                */
                    public void setNext(DoubleLinkIF newValue) {
                        next = newValue;
                } // setNext(DoubleLinkIF)
                /**
                * Return the node that precedes this one or null
                * if this is the first node.
                */
                public DoubleLinkIF getPrev() { return previous; }
                /**
                * Set the node that is to precede this one.
                *
                * @param node
                * The node that is to precede this one or
                * null if this node is to be the first.
                */
                    public void setPrev(DoubleLinkIF newValue) {
                        previous = newValue;
                } // setPrev(DoubleLinkIF)
                ...
                }  // class AbstractDoubleLink


                Classes that extend the AbstractDoubleLink class generally add additional information of their own.






                Related Patterns



                Interface.  The Interface and Abstract Class pattern uses the Interface pattern.



                Abstract Class.  The Interface and Abstract Class pattern uses the Abstract Superclass pattern.


















                Styling for Print











                 < Day Day Up > 





                Styling for Print



                Now that we've created a style sheet for the screen, it's time to turn our attention to the print styles defined in the project goals. The goals specifically related to print are as follows:



                • In print, every other row should have a light gray background, and light gray vertical lines should separate columns.

                • Any negative number should be italicized in print.



                These are in addition to the other project goals, but those have already been satisfied by the style sheet we've written. All we really need to do is override and adjust styles to optimize them for print.



                Starting Out



                The first thing to do is set up a second style sheet. Although it's eventually intended for print styling, this is what we'll add after the previous style sheet:





                </style>

                <style type="text/css" media="screen">



                </style>

                </head>



                The attribute media="screen" is there because we'll be using a Web browser to preview our changes. When we're all done, screen will be changed to print and�hey presto!�a print style sheet.



                A Better Way

                CSS3 does define an easy way to select alternate rows (or really any pattern in a series of elements) using the pseudo-class :nth-child(). As of this writing, it was almost completely unsupported, so classes are the best way to accomplish effects such as these.




                The other thing we need to do is modify the markup a little bit more so that we can accomplish the alternate-row highlighting called for in the project goals. As of this writing, browsers didn't make it possible to accomplish such things with CSS alone, so we'll need to add some classes to our markup. To be as flexible as possible, we'll use the classes even and odd. Thus, the table will generally have the basic structure shown in Listing 3.3. (The cells were removed from the rows for the sake of brevity.)



                Listing 3.3. Basic Table Structure






                <table cellspacing="0">

                <thead>

                <tr>...</tr>

                </thead>

                <tbody>

                <tr class="odd">...</tr>

                <tr class="even">...</tr>

                <tr class="odd">...</tr>

                <tr class="even">...</tr>

                <tr class="odd">...</tr>

                <tr class="even">...</tr>

                <tr class="odd">...</tr>

                <tr class="even">...</tr>

                <tr class="odd">...</tr>

                <tr class="even">...</tr>

                <tr class="totals">...</tr>

                </tbody>

                </table>



                Row Highlighting



                Now that we've appropriately classed all the rows (remember that the first row is row 1, and 1 is an odd number), we can go ahead and highlight every other row. We'll choose to highlight the odd rows, as shown in Figure 3.10.





                <style type="text/css" media="screen">

                tr.odd {background: #EEE;}

                </style>



                Figure 3.10. Alternate-row highlighting via even and odd classes.




                Pretty nifty, but there's a problem. The profit figures aren't taking on the highlighting style, and we want them to do so. We could change the selector from tr.odd to tr.odd td, and that would get the profit cells to take on the highlight in odd rows. Since the city names are actually in th elements, though, they would lose the highlight effect. So we'll use a universal selector to select both.



                Being More Specific

                We used the construction table tr.odd * because, by adding the table, we've ensured that this selector has more specificity than the selectors td.profit and td.neg, which appear in the all-media style sheet we wrote earlier in the project and which apply in print as well as onscreen. If we'd left off table, the selectors in the all-media style sheet would have the same specificity as the one we're writing now for print. When selectors have equal specificity, meaning that the last one declared wins, if the style sheet were ever reversed, the presentation would change. By making sure the print declaration is more specific, we make it sure it will always win and is therefore more robust.






                table tr.odd * {background: #EEE;}



                These simple little changes mean that all elements descended from a tr with a class containing the word odd that's descended from a table element will be selected and thus given a background color of #EEE. Both the th and td elements are descended from the odd rows, so both will be directly selected.



                This means, however, that the profit cells in the even rows are still being given a green background (from the rule in our first style sheet). We need to override that, with the result shown in Figure 3.11.





                table tr.odd * {background: #EEE;}

                td.profit, td.neg {color: #000; background: #FFF;}

                </style>



                Figure 3.11. Extending row highlighting and removing color highlights.




                We've managed to remove the background and foreground colors from the profit and negative figures, but a close look at Figure 3.11 reveals another problem. The bottom border of each cell in the Profit column is white, whereas the bottom border of regular cells is still light gray. This made sense when the profit cells had background colors, but now it looks kind of ugly.



                Background Printing

                Even if you define a background color to be printed, there is no guarantee that it actually will be. Most browsers come preconfigured to not print backgrounds, largely as a way to save on ink or toner. The user can change this configuration to enable printing of element backgrounds, but you as the author cannot.




                Because we have the alternate rows highlighted, we have the option to remove the borders between rows altogether, but instead we'll make them consistent with the highlight color used for alternate rows.





                table tr.odd * {background: #EEE;}

                tr.odd *, tr.even * {border-bottom: 1px solid #EEE;}

                td.profit, td.neg {background: #FFF;}



                This will ensure that, even if backgrounds aren't printed, the rows will have some visual separation. We should also drop in the column separators called for in the design goals.





                tr.odd *, tr.even * {border-bottom: 1px solid #EEE;}

                td {border-right: 1px solid #CCC;}

                td.profit, td.neg {color: #000; background: #FFF;}



                By placing the border on the right side of every td element, we get column separators. In cases like the profit cells, there is already a right border defined by a rule with a more specific selector (td.profit), so this latest rule won't change them.



                Speaking of the Profit column, we still need to make the profit figures stand out in a visual sense since that's one of the design goals. We've taken away the backgrounds, so let's boldface the numbers instead. We'll also italicize the negative numbers, as the goals require. This is illustrated in Figure 3.12.





                td.profit, td.neg {color: #000; background: #FFF;}

                td.profit {font-weight: bold;}

                td.neg {font-style: italic;}

                </style>



                Figure 3.12. Drawing attention to both the profits and negative numbers.




                The Totals Row



                The last thing we'll do is clean up the Totals row. We're doing this mostly to make the final result look better, not because it's part of the explicit design goals. In examining Figure 3.12, we can see that a quick way to make the Totals row stand out a little more would be to add a solid top border. We'll make sure this applies to both td and th elements in the row.





                td.neg {font-style: italic;}

                tr.totals * {border-top: 1px solid gray;}

                </style>



                It might also be a good touch to remove the bottom border from the "Totals" cell since it's left sort of hanging in midair. And, as a last little touch, let's use uppercase to the word "TOTALS."





                tr.totals * {border-top: 1px solid gray;}

                tr.totals th {border-bottom: none; text-transform: uppercase;}

                </style>



                Thanks to text-transform, we've changed the capitalization of the text without having to touch the HTML source. In this case, we can make use of it because the cell in question contains actual letters�uppercasing numbers generally doesn't have any useful effect. We can see the results in Figure 3.13.



                Figure 3.13. Putting on the finishing touches.




                With that done, we're ready to have these styles apply only when printing. All we need to do is go back to the beginning of our second style sheet and change screen to print, as previously described. This last change is shown in Listing 3.4, which shows both style sheets we've created.



                Styles in All Media

                The first style sheet in Listing 3.4 applies in all media because the default value for the media attribute is all. Thus, the first style sheet is combined with the second when printing.




                Listing 3.4. Both Style Sheets Together






                <style type="text/css">

                h2, h3 {margin: 0; border: 1px solid gray;}

                h2 {border-width: 0 0 0 1px; padding: 0 0 0 0.25em}

                h3 {border-width: 1px 1px 0 0; padding: 0.1em 0.33em;}

                th, td {text-align: right; padding: 0 0.5em;

                border-bottom: 1px solid #DDD;}

                td {font: small Verdana, "Andale Mono", Courier, "Courier New",

                monospace;}

                thead th {vertical-align: bottom; border: 1px solid gray;

                border-width: 0 1px 1px 0;

                white-space: normal;}

                th {border-right: 1px solid gray; border-bottom-style: dotted;

                white-space: nowrap;}

                td {letter-spacing: -1px;}

                td.profit {background: #CEC; border-bottom-color: white;

                border-right: 1px solid gray;}

                td.neg {background: #FF3; color: red;}

                tr.totals td {font-weight: bold; border-bottom: 1px solid gray;}

                tr.totals td.profit {border: 1px solid black;}

                tr.totals th {border-bottom-style: solid;}

                </style>

                <style type="text/css" media="print">

                table tr.odd * {background: #EEE;}

                tr.odd *, tr.even * {border-bottom: 1px solid #EEE;}

                td {border-right: 1px solid #CCC;}

                td.profit, td.neg {color: #000; background: #FFF;}

                td.profit {font-weight: bold;}

                td.neg {font-style: italic;}

                tr.totals * {border-top: 1px solid gray;}

                tr.totals th {border-bottom: none; text-transform: uppercase;}

                </style>













                   < Day Day Up >