Thursday, October 29, 2009

Hack 66. Generate Statistics on Your C# Code











 < Day Day Up > 





Hack 66. Generate Statistics on Your C# Code





You'll write a lot of code in

Visual Studio. Now, learn about a free tool that lets you view

assorted statistics and information about your C# Visual Studio

Projects
.





Have you ever wondered how

many files, classes, or lines of code exist in one or more of your

Visual Studio Projects? While you can certainly count these metrics

manually, there is a free Visual Studio add-in that will provide

these statistics (and more!) in a flash. Once installed, this add-in,

called devMetrics,

adds an Analyze menu option to the Visual Studio Tools menu. When

selected, the projects in the currently loaded Visual Studio Solution

are examined, and their statistics are presented in an easy-to-read

report. (Unfortunately, devMetrics generates reports for only C#

Projects.)





The devMetrics reports provide useful information at the click of a

mouse. The report's statistics include information

that can be used to measure the progress of a code project, show what

classes are undercommented, and point out what classes and methods

are exceedingly complex and in need of refactoring.







7.9.1. Download and Install devMetrics





Before you can generate

statistical reports on your code, you'll first need

to download and install the devMetrics add-in, which is a free

product from Anticipating Minds (http://www.anticipatingminds.com) and is

available at http://www.anticipatingminds.com/Content/Products/devMetrics/devMetrics.aspx.

Download the devMetrics installer to your computer, and then

double-click the file to begin the installation process.





Once installed, devMetrics can be run in two ways:






From Visual Studio





To view the statistics for a C# Project through Visual Studio, open

Visual Studio and load the solution or project to analyze. Then, from

the Tools menu, choose the devMetrics submenu, and select the Analyze

menu option, as shown in Figure 7-36. Once the

project(s) have been analyzed, the statistical report will be

automatically displayed in Visual Studio.






From the command line





To run the devMetrics analyzer from the command line, navigate to the

Program Files\Anticipating Minds\devMetrics

directory and run the devMetrics.exe executable,

specifying the directory that contains the C# Projects that you want

to analyze, such as: devMetrics "C:\My Projects\Some Visual

Studio Project Folder
". (devMetrics will recursively

iterate through the directory's subdirectories and

include reports on all C# Projects found.) After completing,

devMetrics will automatically launch Internet Explorer, displaying

the report.











Figure 7-36. devMetrics Analyze menu option











7.9.2. Study the Report





After

analyzing either a Visual Studio Project or Solution, devMetrics

displays the resulting project report (see Figure 7-37). This report lists each C Project analyzed,

along with the following metrics:






Files





The number of C# files in the project.






Types





The number of classes, interfaces, and structures in the project.






Members





The number of









fields, properties,

events, methods, and constructors.






Lines





The total number of lines of code in the project, including

blank lines and comments.






Statements





The total number of statements in the project.






Average and maximum code complexity





devMetrics uses the cyclomatic code

complexity algorithm as defined by the

Software Engineering Institute (see

http://www.sei.cmu.edu/str/descriptions/cyclomatic_body.html).

The complexity is a measure of linearly independent paths through a

program module and is calculated for each member that contains

statements. The code complexity measurement results in a numerical

evaluation, with lower values meaning less complex code. The maximum

code complexity is the highest complexity value for all members in

the project; the average code complexity is the average complexity of

all members.









In addition to showing these metrics for each project, the project

report also displays a summary row.







Figure 7-37. devMetrics project report







As Figure 7-37 shows, the name of each project in

the report is displayed as a hyperlink. Clicking on the link will

expand the project node and show you a list of the

types in that particular project. For each

type in the project, the number of statements and members are shown

along with the cyclomatic complexity. Figure 7-38

shows the report with the project node expanded.







Figure 7-38. devMetrics member report







From the Type Declaration list, you can expand the node of each type

and view a list of the type members, including the number of

statements and complexity of each member.





The devMetrics add-in can provide quick summary data about your C#

code on a project-by-project level as well as a member-by-member

level. The cyclomatic code complexity, statements/member, and

members/class metrics can assess what portions of your code are

unduly verbose and what portions would benefit from being refactored.





Scott Mitchell



















     < Day Day Up > 



    16.5 Replication











     < Day Day Up > 





    16.5 Replication



    MySQL supports replication capabilities that allow the contents of databases on one server to be made available on another server. MySQL replication uses a master/slave architecture:



    • The server that manages the original databases is the master.

    • Any server that manages a copy of the original databases is a slave.

    • A given master server can have many slaves, but a slave can have only a single master.



    A replication slave is set up initially by transferring an exact copy of the to-be-replicated databases from the master server to the slave server. Thereafter, each replicated database is kept synchronized to the original database. The basis for communication is the master server's binary log:



    • When the master server makes modifications to its databases, it records the changes in its binary log files.

    • Changes recorded in the binary log are sent to each slave server, which makes the changes to its copy of the replicated databases. Slave servers that aren't connected to the master when a statement is recorded receive the statement the next time they connect.



    By default, the master server logs updates for all databases, and the slave server replicates all updates that it receives from the master. For more fine-grained control, it's possible to tell a master which databases to log updates for, and to tell a slave which of those updates that it receives from the master to apply. You can either name databases to be replicated (in which case those not named are ignored), or you can name databases to ignore (in which case those not named are replicated). The master host options are --binlog-do-db and --binlog-ignore-db. The slave host options are --replicate-do-db and --replicate-ignore-db.



    The following example illustrates how this works, using the options that enable replication for specific databases. Suppose that a master server has three databases named a, b, and c. You can elect to replicate only databases a and b when you start the master server by placing these options in an option file read by that server:










    [mysqld]

    binlog-do-db = a

    binlog-do-db = b




    With those options, the master server will log updates only for the named databases to the binary log. Thus, any slave server that connects to the master will receive information only for databases a and b.



    A slave that wants to filter the updates received may do so. A slave that takes no such action will replicate databases a and b. For a slave that should replicate only database a, you can start it with these lines in an option file:










    [mysqld]

    replicate-do-db = a




    For a slave that should replicate only database b, you can start it with these lines in an option file:










    [mysqld]

    replicate-do-db = b




    Note that these options apply only when the given database happens to be the default database. Statements that name a database explicitly are always written to the binary log.













       < Day Day Up > 



      24.4 TCP Out-of-Band Data Recap



      [ Team LiB ]






      24.4 TCP Out-of-Band Data Recap


      All our examples using out-of-band data so far have been trivial. Unfortunately, out-of-band data gets messy when we consider the timing problems that may arise. The first point to consider is that the concept of out-of-band data really conveys three different pieces of information to the receiver:


      1. The fact that the sender went into urgent mode. The receiving process can be notified of this with either the SIGURG signal or with select. This notification is transmitted immediately after the sender sends the out-of-band byte, because we saw in Figure 24.11 that TCP sends the notification even if it is stopped by flow control from sending any data to the receiver. This notification might cause the receiver to go into some special mode of processing for any subsequent data that it receives.

      2. The position of the out-of-band byte, that is, where it was sent with regard to the rest of data from the sender: the out-of-band mark.

      3. The actual value of the out-of-band byte. Since TCP is a byte stream protocol that does not interpret the data sent by the application, this can be any 8-bit value.


      With TCP's urgent mode, we can think of the URG flag as being the notification, the urgent pointer as being the mark, and the byte of data as itself.


      The problems with this concept of out-of-band data are that: (i) there is only one TCP urgent pointer per connection; (ii) there is only one out-of-band mark per connection; and (iii) there is only a single one-byte out-of-band buffer per connection (which is an issue only if the data is not being read inline). We saw with Figure 24.12 that an arriving mark overwrites any previous mark that the process has not yet encountered. If the data is being read inline, previous out-of-band bytes are not lost when new out-of-band data arrives, but the mark is lost.


      One common use of out-of-band data is with rlogin, when the client interrupts the program that it is running on the server (pp. 393�394 of TCPv1). The server needs to tell the client to discard all queued output because up to one window's worth of output may be queued to send from the server to the client. The server sends a special byte to the client, telling it to flush all output, and this byte is sent as out-of-band data. When the client receives the SIGURG signal, it just reads from the socket until it encounters the mark, discarding everything up through the mark. (Pages 398�401 of TCPv1 contain an example of this use of out-of-band data, along with the corresponding tcpdump output.) In this scenario, if the server sent multiple out-of-band bytes in quick succession, it wouldn't affect the client, as the client just reads up through the final mark, discarding all the data.


      In summary, the usefulness of out-of-band data depends on why it is being used by the application. If the purpose is to tell the peer to discard the normal data up through the mark, then losing an intermediate out-of-band byte and its corresponding mark is of no consequence. But if it is important that no out-of-band bytes be lost, then the data must be received inline. Furthermore, the data bytes that are sent as out-of-band data should be differentiated from normal data since intermediate marks can be overwritten when a new mark is received, effectively mixing out-of-band bytes with the normal data. telnet, for example, sends its own commands in the normal stream of data between the client and server, prefixing its commands with a byte of 255. (To send this value as data then requires two successive bytes of 255.) This lets it differentiate its commands from normal user data, but requires that the client and server process each byte of data looking for commands.






        [ Team LiB ]



        Part IV: Client-Side JavaScript Reference










        Part IV: Client-Side JavaScript Reference



        This part of the book is a complete reference to all of the objects, properties, functions, methods, and event handlers in client-side JavaScript. See the sample entry at the beginning of Part III for an explanation of how to use this reference.


        Classes and objects documented in this part include:


        Anchor
        DOMException
        JSObject
        Table
        Applet
        DOMImplementation
        KeyEvent
        TableCell
        Attr
        DOMParser
        Link
        TableRow
        Canvas
        Element
        Location
        TableSection
        CanvasGradient
        Event
        MimeType
        Text
        CanvasPattern
        ExternalInterface
        MouseEvent
        Textarea
        CanvasRenderingContext2D
        FlashPlayer
        Navigator
        UIEvent
        CDATASection
        Form
        Node
        Window
        CharacterData
        Frame
        NodeList
        XMLHttpRequest
        Comment
        History
        Option
        XMLSerializer
        CSS2Properties
        HTMLCollection
        Plugin
        XPathExpression
        CSSRule
        HTMLDocument
        ProcessingInstruction
        XPathResult
        CSSStyleSheet
        HTMLElement
        Range
        XSLTProcessor
        Document
        IFrame
        RangeException
        DocumentFragment
        Image
        Screen
        DocumentType
        Input
        Select













        Chapter 17 Triggers

        Team-Fly
         

         

        Oracle® PL/SQL® Interactive Workbook, Second Edition
        By
        Benjamin Rosenzweig, Elena Silvestrova
        Table of Contents

        Appendix D. 
        Answers to Test Your Thinking Sections



        Chapter 17 Triggers

        1)

        Create the following trigger: Create or modify a trigger on the ENROLLMENT table that fires before an INSERT statement. Make sure all columns that have NOT NULL and foreign key constraints defined on them are populated with their proper values.

        A1:

        Answer: Your trigger should look similar to the following:


        CREATE OR REPLACE TRIGGER enrollment_bi
        BEFORE INSERT ON ENROLLMENT
        FOR EACH ROW
        DECLARE
        v_valid NUMBER := 0;
        BEGIN
        SELECT COUNT(*)
        INTO v_valid
        FROM student
        WHERE student_id = :NEW.STUDENT_ID;

        IF v_valid = 0 THEN
        RAISE_APPLICATION_ERROR (-20000, 'This is not a
        valid student');
        END IF;

        SELECT COUNT(*)
        INTO v_valid
        FROM section
        WHERE section_id = :NEW.SECTION_ID;

        IF v_valid = 0 THEN
        RAISE_APPLICATION_ERROR (-20001, 'This is not a
        valid section');
        END IF;

        :NEW.ENROLL_DATE := SYSDATE;
        :NEW.CREATED_BY := USER;
        :NEW.CREATED_DATE := SYSDATE;
        :NEW.MODIFIED_BY := USER;
        :NEW.MODIFIED_DATE := SYSDATE;
        END;

        Consider this trigger. It fires before the INSERT statement on the ENROLLMENT table. First, you validate new values for student ID and section ID. If one of the IDs is invalid, the exception is raised and the trigger is terminated. As a result, the INSERT statement causes an error. If both student and section IDs are found in the STUDENT and SECTION tables, respectively, the ENROLL_DATE, CREATED_ DATE, and MODIFIED_DATE are populated with current date, and columns CREATED_BY and MODIFIED_BY are populated with current user name.

        Consider the following INSERT statement:


        INSERT INTO enrollment (student_id, section_id)
        VALUES (777, 123);

        The value 777, in this INSERT statement does not exist in the STUDENT table and therefore is invalid. As a result, this INSERT statement causes the following error:


        INSERT INTO enrollment (student_id, section_id)
        *
        ERROR at line 1:
        ORA-20000: This is not a valid student
        ORA-06512: at "STUDENT.ENROLLMENT_BI", line 10
        ORA-04088: error during execution of trigger
        'STUDENT.ENROLLMENT_BI'
        2)

        Create the following trigger: Create or modify a trigger on the SECTION table that fires before an UPDATE statement. Make sure that the trigger validates incoming values so that there are no constraint violation errors.

        A2:

        Answer: Your trigger should look similar to the following:


        CREATE OR REPLACE TRIGGER section_bu
        BEFORE UPDATE ON SECTION
        FOR EACH ROW
        DECLARE
        v_valid NUMBER := 0;
        BEGIN
        IF :NEW.INSTRUCTOR_ID IS NOT NULL THEN
        SELECT COUNT(*)
        INTO v_valid
        FROM instructor
        WHERE instructor_id = :NEW.instructor_ID;
        IF v_valid = 0 THEN
        RAISE_APPLICATION_ERROR (-20000,
        'This is not a valid instructor');
        END IF;
        END IF;

        :NEW.CREATED_BY := USER;
        :NEW.CREATED_DATE := SYSDATE;
        :NEW.MODIFIED_BY := USER;
        :NEW.MODIFIED_DATE := SYSDATE;
        END;

        This trigger fires before the UPDATE statement on the SECTION table. First, you check if there is a new value for an instructor ID with the help of an IF-THEN statement. If the IF-THEN statement evaluates to TRUE, the instructor's ID is checked against the INSTRUCTOR table. If a new instructor ID does not exist in the INSTRUCTOR table, the exception is raised, and the trigger is terminated. Otherwise, all columns with NOT NULL constraints are populated with their respected values.

        Consider the following UPDATE statement:


        UPDATE section
        SET instructor_id = 220
        WHERE section_id = 79;

        The value 220 in this UPDATE statement does not exist in the INSTRUCTOR table and therefore is invalid. As a result, this UPDATE statement when run causes an error:


        UPDATE section
        *
        ERROR at line 1:
        ORA-20000: This is not a valid instructor
        ORA-06512: at "STUDENT.SECTION_BU", line 11
        ORA-04088: error during execution of trigger
        'STUDENT.SECTION_BU'





          Team-Fly
           

           
          Top
           


          13.1 Index Optimization and Index Usage











           < Day Day Up > 





          13.1 Index Optimization and Index Usage



          When you create a table, consider whether it should have indexes, because they have important benefits:



          • Indexes contain sorted values. This allows MySQL to find rows containing particular values faster. The effect can be particularly dramatic for joins, which have the potential to require many combinations of rows to be examined.

          • Indexes result in less disk I/O. The server can use an index to go directly to the relevant table records, which reduces the number of records it needs to read. Furthermore, if a query displays information only from indexed columns, MySQL might be able to process it by reading only the indexes and without accessing data rows at all.



          13.1.1 Types of Indexes



          MySQL supports four types of indexes:



          • A nonunique index is one in which any key value may occur multiple times. This type of index is defined with the keyword INDEX or KEY.

          • A UNIQUE index is unique-valued; that is, every key value is required to be different than all others. (The exception is that NULL values may occur multiple times.)

          • A PRIMARY KEY also is a unique-valued index. It is similar to a UNIQUE index, but has additional restrictions:

            • A table may have multiple UNIQUE indexes, but at most one PRIMARY KEY.

            • A UNIQUE index can contain NULL values, whereas a PRIMARY KEY cannot.

          • A FULLTEXT index is specially designed for text searching.



          To define indexes when you're initially creating a table, use CREATE TABLE. To add indexes to an already existing table, use ALTER TABLE or CREATE INDEX. To drop indexes, use ALTER TABLE or DROP INDEX.



          ALTER TABLE can add or drop several indexes in the same statement, which is faster than processing each one separately. CREATE INDEX and DROP INDEX allow only one index to be added or dropped at a time.



          Index creation using the INDEX, UNIQUE, and PRIMARY KEY keywords is discussed in the "Core Study Guide." FULLTEXT indexes are not covered there because they are a more specialized kind of index. Instead, FULLTEXT indexing is discussed in section 13.1.4, "FULLTEXT Indexes Indexes."



          13.1.2 Obtaining Table Index Information



          To find out what indexes a table has, use SHOW CREATE TABLE to display the CREATE TABLE statement that corresponds to the table structure, including its indexes.



          For more detailed information about the indexes, use SHOW INDEX. For example, SHOW INDEX produces the following output for the Country table of the world database:










          mysql> SHOW INDEX FROM Country\G

          *************************** 1. row ***************************

          Table: Country

          Non_unique: 0

          Key_name: PRIMARY

          Seq_in_index: 1

          Column_name: Code

          Collation: A

          Cardinality: NULL

          Sub_part: NULL

          Packed: NULL

          Null:

          Index_type: BTREE

          Comment:




          The output indicates that the table has a single index, a primary key on the Code column. The output for the City table is similar except that it indicates the ID column is the primary key:










          mysql> SHOW INDEX FROM City\G

          *************************** 1. row ***************************

          Table: City

          Non_unique: 0

          Key_name: PRIMARY

          Seq_in_index: 1

          Column_name: ID

          Collation: A

          Cardinality: NULL

          Sub_part: NULL

          Packed: NULL

          Null:

          Index_type: BTREE

          Comment:




          For the CountryLanguage table, the output has two rows because the primary key includes two columns, Country and Language:










          mysql> SHOW INDEX FROM CountryLanguage\G

          *************************** 1. row ***************************

          Table: CountryLanguage

          Non_unique: 0

          Key_name: PRIMARY

          Seq_in_index: 1

          Column_name: Country

          Collation: A

          Cardinality: NULL

          Sub_part: NULL

          Packed: NULL

          Null:

          Index_type: BTREE

          Comment:

          *************************** 2. row ***************************

          Table: CountryLanguage

          Non_unique: 0

          Key_name: PRIMARY

          Seq_in_index: 2

          Column_name: Language

          Collation: A

          Cardinality: NULL

          Sub_part: NULL

          Packed: NULL

          Null:

          Index_type: BTREE

          Comment:




          The Seq_in_index values show the order of the columns within the index. They indicate that the primary key columns are Country first and Language second. This information corresponds to the following PRIMARY KEY declaration:










          PRIMARY KEY (Country, Language)




          13.1.3 Using Indexes



          An index helps MySQL perform retrievals more quickly than if no index is used. But indexes can be used with varying degrees of success, so you should keep several index-related considerations in mind when designing tables:



          • Declare an indexed column NOT NULL if possible. Although NULL values can be indexed, NULL is a special value that requires additional decisions when performing comparisons on key values. An index without NULL can be processed more simply and thus faster.

          • Avoid overindexing; don't index a column just because you can. If you never refer to a column in comparisons (such as in WHERE, ORDER BY, or GROUP BY clauses), there's no need to index it. Another reason to avoid unnecessary indexing is that every index you create slows down table updates. If you insert or delete a row, an entry must be added to or removed from each of the table's indexes. If you update a row, any change to indexed columns require the appropriate indexes to be updated as well.

          • One strategy the MySQL optimizer uses is that if it appears an index will return a large percentage of the records in the table, it will be just as fast to scan the table as to incur the overhead required to process the index. As a consequence, an index on a column that has very few distinct values is unlikely to do much good. Suppose that a column is declared as ENUM('Y','N') and the values are roughly evenly distributed such that a search for either value returns about half of the records. In this case, an index on the column is unlikely to result in faster queries.

          • Choose unique and nonunique indexes appropriately. The choice might be influenced by the type of a column. If the column is declared as an ENUM, there is a fixed number of distinct column values that can be stored in it. This number is equal to the number of enumeration elements, plus one for the '' (empty string) element that is used when you attempt to store an illegal value. Should you choose to index an ENUM column, you likely should create a nonunique index. A PRIMARY KEY allows only as many rows as the number of distinct enumeration values. A UNIQUE index enforces a similar restriction, except that unless the column is declared NOT NULL, the index allows NULL values.

          • Index a column prefix rather than the entire column. MySQL caches index blocks in memory to avoid whenever possible reading them from disk repeatedly. Shortening the length of indexed values can improve performance by reducing the amount of disk I/O needed to read the index and by increasing the number of key values that fit into the key cache. This technique is discussed further in section 13.1.3.1, "Indexing Column Prefixes."

          • Avoid creating multiple indexes that overlap (have the same initial columns). This is wasteful because MySQL can use a multiple-column index even when a query uses just the initial columns for lookups. For more information, see section 13.1.3.2, "Leftmost Index Prefixes."



          13.1.3.1 Indexing Column Prefixes


          Short index values can be processed more quickly than long ones. Therefore, when you index a column, it's worth asking whether it's sufficient to index partial column values rather than complete values. This technique, known as indexing a column prefix, can be applied to string column types.



          Suppose that you're considering creating a table using this definition:










          CREATE TABLE t

          (

          name CHAR(255),

          INDEX (name)

          );




          If you index all 255 bytes of the values in the name column, index processing will be relatively slow:



          • It's necessary to read more information from disk.

          • Longer values take longer to compare.

          • The index cache is not as effective because fewer index values fit into it at a time.



          It's often possible to overcome these problems by indexing only a prefix of the column values. For example, if you expect column values to be distinct most of the time in the first 15 bytes, index only that many bytes of each value, not all 255 bytes.



          To specify a prefix length for a column, follow the column name in the index definition by a number in parentheses. The following table definition is the same as the previous one, except that the index uses just the first 15 bytes of each column value:










          CREATE TABLE t

          (

          name CHAR(255),

          INDEX (name(15))

          );




          Indexing a column prefix can speed up query processing, but works best when the prefix values tend to have about the same amount of uniqueness as the original values. Don't use such a short prefix that you produce a very high frequency of duplicate values in the index. It might require some testing to find the optimal balance between long index values that provide good uniqueness versus shorter values that compare more quickly but have more duplicates. To determine the number of records in the table, the number of distinct values in the column, and the number of duplicates, use this query:










          SELECT

          COUNT(*) AS 'Total Rows',

          COUNT(DISTINCT name) AS 'Distinct Values',

          COUNT(*) - COUNT(DISTINCT name) AS 'Duplicate Values'

          FROM t;




          That gives you an estimate of the amount of uniqueness in the name values. Then run a similar query on the prefix values:










          SELECT

          COUNT(DISTINCT LEFT(name,n)) AS 'Distinct Prefix Values',

          COUNT(*) - COUNT(DISTINCT LEFT(name,n)) AS 'Duplicate Prefix Values'

          FROM t;




          That tells you how the uniqueness characteristics change when you use an n-byte prefix of the name values. Run the query with different values of n to determine an acceptable prefix length.



          Note that when an index on a full column is a PRIMARY KEY or UNIQUE index, you might have to change the index to be nonunique if you decide to index prefix values instead. If you index partial column values and require the index to be unique, that means the prefix values must be unique, too.



          13.1.3.2 Leftmost Index Prefixes


          In a table that has a composite (multiple column) index, MySQL can use leftmost index prefixes of that index. A leftmost prefix of a composite index consists of one or more of the initial columns of the index. MySQL's capability to use leftmost index prefixes enables you to avoid creating unnecessary indexes.



          The CountryLanguage table in the world database provides an example of how a leftmost prefix applies. The table has a two-part primary key:










          mysql> SHOW INDEX FROM CountryLanguage\G

          *************************** 1. row ***************************

          Table: CountryLanguage

          Non_unique: 0

          Key_name: PRIMARY

          Seq_in_index: 1

          Column_name: CountryCode

          Collation: A

          Cardinality: 246

          Sub_part: NULL

          Packed: NULL

          Null:

          Index_type: BTREE

          Comment:

          *************************** 2. row ***************************

          Table: CountryLanguage

          Non_unique: 0

          Key_name: PRIMARY

          Seq_in_index: 2

          Column_name: Language

          Collation: A

          Cardinality: 984

          Sub_part: NULL

          Packed: NULL

          Null:

          Index_type: BTREE

          Comment:




          The index on the CountryCode and Language columns allows records to be looked up quickly based on a given country name and language. However, MySQL also can use the index given just a country code. Suppose that you want to determine which languages are spoken in France:










          SELECT * FROM CountryLanguage WHERE CountryCode = 'FRA';




          MySQL can see that CountryCode is a leftmost prefix of the primary key and use it as though it were a separate index. This means there's no need to define a second index on the CountryCode column alone.



          On the other hand, if you want to perform indexed searches using just the Language column of the CountryLanguage table, you do need to create a separate index because Language is not a leftmost prefix of the existing index.



          Note that a leftmost prefix of an index and an index on a column prefix are two different things. A leftmost prefix of an index consists of leading columns in a multiple-column index. An index on a column prefix indexes the leading bytes of values in the column.



          13.1.4 FULLTEXT Indexes



          FULLTEXT indexes are designed to make text searching fast and easy. They have the following characteristics:



          • FULLTEXT indexes currently are supported only for MyISAM tables.

          • Each column must be either CHAR or VARCHAR without the BINARY option, or one of the TEXT types. You cannot use a binary string column type such as CHAR BINARY, VARCHAR BINARY, or BLOB.

          • FULLTEXT indexes are not case sensitive. This is a consequence of the fact that the index can include only nonbinary string columns.

          • The syntax for defining a full-text index is much like that for other indexes: An index-type keyword (FULLTEXT), an optional index name, and a parenthesized list of one or more column names to be indexed. A FULLTEXT index may be created with CREATE TABLE, added to a table with ALTER TABLE or CREATE INDEX, and dropped from a table with ALTER TABLE or DROP INDEX. The following are all legal statements for FULLTEXT index manipulation:








            CREATE TABLE t (name CHAR(40), FULLTEXT (name));

            ALTER TABLE t ADD FULLTEXT name_idx (name);

            ALTER TABLE t DROP INDEX name_idx;

            CREATE FULLTEXT INDEX name_idx ON t (name);

            DROP INDEX name_idx ON t;


          • Column prefixes are not applicable for FULLTEXT indexes, which always index entire columns. If you specify a prefix length for a column in a FULLTEXT index, MySQL ignores it.

          • FULLTEXT index indexes can be constructed on multiple columns, allowing searches to be conducted simultaneously on all the indexed columns. However, leftmost index prefixes are not applicable for FULLTEXT indexes. You must construct one index for every column or combination of columns you want to search. Suppose that you want to search for text sometimes only in column c1 and sometimes in both columns c1 and c2. You must construct two FULLTEXT indexes: one on column c1 and another on columns c1 and c2.



          To perform a FULLTEXT search, use MATCH and AGAINST(). For example, to search the table t for records that contain 'Wendell' in the name column, use this query:










          SELECT * FROM t WHERE MATCH(name) AGAINST('Wendell');




          The MATCH operator names the column or columns you want to search. As mentioned earlier, there must be a FULLTEXT index on exactly those columns. If you want to search different sets of columns, you'll need one FULLTEXT index for each set. If a table people has name and address columns and you want to search them either separately or together, three FULLTEXT indexes are needed:










          CREATE TABLE people

          (

          name CHAR(40),

          address CHAR(40),

          FULLTEXT (name), # index for searching name only

          FULLTEXT (address), # index for searching address only

          FULLTEXT (name,address) # index for searching name and address

          );




          The indexes allow queries such as the following to be formulated:










          SELECT * FROM people WHERE MATCH(name) AGAINST('string');

          SELECT * FROM people WHERE MATCH(address) AGAINST('string');

          SELECT * FROM people WHERE MATCH(name,address) AGAINST('string');




          The preceding discussion summary of FULLTEXT indexing and searching is very brief. More information may be found in the MySQL Reference Manual.













             < Day Day Up > 



            Recipe 9.5. Avoiding Naming Collisions with Namespaces










            Recipe 9.5. Avoiding Naming Collisions with Namespaces





            Problem


            You want to define a class or module whose name conflicts with an existing class or module, or you want to prevent someone else from coming along later and defining a class whose name conflicts with yours.




            Solution


            A Ruby module can contain classes and other modules, which means you can use it as a namespace.


            Here's some code from a physics library that defines a class called String within the StringTheory module. The real name of this class is its fully-qualified name: StringTheory::String. It's a totally different class from Ruby's built-in String class.



            module StringTheory
            class String
            def initialize(length=10**-33)
            @length = length
            end
            end
            end

            String.new # => ""

            StringTheory::String.new
            # => #<StringTheory::String:0xb7c343b8 @length=1.0e-33>





            Discussion


            If you've read Recipe 8.17, you've already seen
            namespaces in action. The constants defined in a module are qualified with the module's name. This lets Math::PI have a different value from Greek::PI.


            You can qualify the name of any Ruby object this way: a variable, a class, or even another module.
            Namespaces let you organize your libraries, and make it possible for them to coexist alongside others.


            Ruby's standard library uses namespaces heavily as an organizing principle. An excellent example is REXML, the standard XML library. It defines a REXML namespace that includes lots of XML-related classes like REXML::Comment and REXML::Instruction. Naming those classes Comment and Instruction would be a disaster: they'd get overwritten by other librarys' Comment and Instruction classes. Since nothing about the genericsounding names relates them to the REXML library, you might look at someone else's code for a long time before realizing that the Comment objects have to do with XML.


            Namespaces can be nested: see for instance rexml's REXML::Parsers module, which contains classes like REXML::Parsers::StreamParser. Namespaces group similar classes in one place so you can find what you're looking for; nested namespaces do the same for namespaces.


            In Ruby, you should name your top-level module after your software project (SAX), or after the task it performs (XML::Parser). If you're writing Yet Another implementation of something that already exists, you should make sure your namespace includes your project name (XML::Parser::SAX). This is in contrast to Java's namespaces: they exist in its package structure, which follows a naming convention that includes a domain name, like org.xml.sax.


            All code within a module is implicitly qualified with the name of the module. This can cause problems for a module like StringTheory, if it needs to use Ruby's built-in String class for something. This should be fixed in Ruby 2.0, but you can also fix it by setting the built-in String class to a variable before defining your StringTheory::String class. Here's a version of the StringTheory module that can use Ruby's builtin String class:



            module StringTheory2
            RubyString = String
            class String
            def initialize(length=10**-33)
            @length = length
            end
            end

            RubyString.new("This is a built-in string, not a StringTheory2::String")
            end
            # => "This is a built-in string, not a StringTheory2::String"





            See Also


            • qRecipe 8.17, "Declaring Constants"

            • Recipe 9.7, "Including
              Namespaces"













            11.6 Internationalization Actions








             

             










            11.6 Internationalization Actions



            The JSTL internationalization (I18N) actions help you internationalize your Web applications. Three configuration settings support these actions.



            Overview of JSTL Internationalization Actions



            Table 11.13 lists the JSTL I18N actions.





































































            Table 11.13. Internationalization Actions


            Action





            Description





            <fmt:setLocale>





            Sets the FMT_LOCALE configuration setting, which is used for resource bundle lookups; those resource bundles are used by <fmt:message> actions.



            The FMT_LOCALE configuration setting is also used by JSTL formatting actions; see page 509.





            <fmt:setBundle>





            Searches for a resource bundle identified with the required basename attribute. <fmt:setBundle> stores that resource bundle (and the locale used to locate that resource bundle) in the FMT_LOCALIZATION_CONTEXT configuration setting.





            <fmt:bundle>





            Searches for a resource bundle identified with the required basename attribute, using the same search algorithm used by <fmt:setBundle>. That resource bundle is only used by <fmt:message> actions and formatting actions in the body of the <fmt:bundle> action.





            <fmt:message>





            Retrieves a localized message from a resource bundle. That message is sent to the current JspWriter, or if the var attribute is specified, the message is stored in a scoped variable.



            <fmt:message> searches for a resource bundle in:





            1. Its bundle attribute



            2. Its enclosing <fmt:bundle> action



            3. The FMT_LOCALIZATION_CONTEXT configuration setting





            <fmt:param>





            Specifies a single parameter for a compound message. That parameter is used by an enclosing <fmt:message> action.





            <fmt:requestEncoding>





            Sets the character encoding for an HTTP request. This action is necessary because most browsers do not specify the Content-Type header, making it impossible for applications to determine the encoding of request parameters that were encoded with a charset other than ISO-8859-1.







            JSTL Internationalization Configuration Settings



            The following configuration settings support JSTL internationalization:





            • FMT_LOCALE



            • FMT_FALLBACK_LOCALE



            • FMT_LOCALIZATION_CONTEXT





            FMT_LOCALE


            The FMT_LOCALE configuration setting is listed in Table 11.14.





















































            Table 11.14. FMT_LOCALE


            Config Constant





            FMT_LOCALE





            Name





            javax.servlet.jsp.jstl.fmt.locale





            Type





            java.lang.String or java.util.Locale





            Set by





            <fmt:setLocale>, Deployment Descriptor, Config class





            Used by





            <fmt:bundle>, <fmt:setBundle>, <fmt:message>,<fmt:formatNumber>, <fmt:parseNumber>, <fmt:formatDate>, <fmt:parseDate>





            The FMT_LOCALE configuration setting specifies a locale for both internationalization and formatting actions. If you set this configuration setting, internationalization and formatting actions will ignore your browser's locale preferences. See "<fmt:setLocale>" on page 496 for more information about the <fmt:setLocale> action, which is the only JSTL action that directly sets the FMT_LOCALE configuration setting.



            You can also set the FMT_LOCALE configuration setting with a context initialization parameter or in a business component. See "Configuration Settings" on page 230 for more information on how to do that.





            FMT_FALLBACK_LOCALE


            The FMT_FALLBACK_LOCALE configuration setting is listed in Table 11.15.





















































            Table 11.15. FMT_FALLBACK_LOCALE


            Config Constant





            FMT_FALLBACK_LOCALE





            Name





            javax.servlet.jsp.jstl.fmt.fallbackLocale





            Type





            java.lang.String or java.util.Locale





            Set by





            Deployment Descriptor, Config class





            Used by





            <fmt:bundle>, <fmt:setBundle>, <fmt:message>,

            <fmt:formatNumber>, <fmt:parseNumber>, <fmt:formatDate>, <fmt:parseDate>





            In the quest for a resource bundle or a formatting locale, JSTL I18N and formatting actions will resort to the locale stored in the FMT_FALLBACK_LOCALE configuration setting if the user's preferred locales do not yield a resource bundle.





            FMT_LOCALIZATION_CONTEXT


            The FMT_LOCALIZATION_CONTEXT configuration setting is listed in Table 11.16.





















































            Table 11.16. FMT_LOCALIZATION_CONTEXT


            Config Constant





            FMT_LOCALIZATION_CONTEXT





            Name





            javax.servlet.jsp.jstl.fmt.localizationContext





            Type





            java.lang.String or javax.servlet.jsp.jstl.fmt.LocalizationContext





            Set by





            <fmt:setBundle>, Deployment Descriptor, Config class





            Used by





            <fmt:message>, <fmt:formatNumber>, <fmt:parseNumber>, <fmt:formatDate>, <fmt:parseDate>





            <fmt:message> actions retrieve localized messages from a resource bundle. That resource bundle is stored in a read-only object known as a localization context, which also keeps track of the locale that yielded the resource bundle. The localization context's resource bundle is used by <fmt:message> and its locale is used by JSTL formatting actions.



            When a <fmt:message> action searches for a resource bundle, it turns to the FMT_LOCALIZATION_CONTEXT configuration setting if you don't specify the <fmt:message> bundle attribute and if the <fmt:message> action doesn't reside in the body of a <fmt:bundle> action. <fmt:setBundle> is the only JSTL action that sets the FMT_LOCALIZATION_CONTEXT configuration setting. You can temporarily override that configuration setting with <fmt:bundle>, which creates a localization context of its own. (<fmt:bundle> does not set the FMT_LOCALIZATION_CONTEXT configuration setting.)



            The value of the FMT_LOCALIZATION_CONTEXT configuration setting can be a string representing a resource bundle base name, or it can be an instance of javax.servlet.jsp.jstl.fmt.LocalizationContext.



            See "Localization Context Lookup" on page 268 for more information about <fmt:setBundle> and the FMT_LOCALIZATION_CONTEXT configuration setting.







            JSTL Internationalization Actions





            <fmt:setLocale>



            Configures a locale for <fmt:message> and formatting actions





            Syntax:[14]



            [14] Items in brackets are optional.





            <fmt:setLocale value [scope] [variant]/>



            Description:



            The <fmt:setLocale> action sets the FMT_LOCALE configuration setting, which is used by I18N and formatting actions to locate resource bundles and formatting locales. You specify the locale by setting the required value attribute, with a string or an instance of java.util.Locale.



            Attributes:























































            Attribute[a]





            Type





            Description





            value





            String or java.util.Locale





            A value that specifies a locale. That value can be a Locale object or a string consisting of a two-letter language code and an optional two-letter country code. The language and country codes can be separated by either a hyphen or an underscore.





            variant





            String





            A string representing a vendor- or browser-specific variant, such as WIN for Windows or MAC for Macintosh.





            scope





            String





            The scope of the scoped variable whose name is specified by the value attribute; default is page scope.





            [a] static | dynamic



            Constraints and Error Handling:





            • If you specify null or an empty string for the value attribute, the associated <fmt:setLocale> action will store the default locale in the javax.servlet.jsp.jstl.fmt.locale configuration variable.



            • If you specify an invalid value attribute, <fmt:setLocale> will throw an IllegalArgumentException.





            In a Nutshell:



            The <fmt:setLocale> action sets a locale for any action that establishes a localization context and disables browser-based locale settings for those actions. Place this action at the beginning of a JSP page, before any action that establishes a localization context.



            You specify a locale with the value attribute, which can be a string or an instance of java.util.Locale. That string represents a language and, optionally, a country. The language and country are separated by a hyphen or an underscore; for example, you can specify value='es' for Spanish or either value='es-MX' or value='es_MX' for Mexican Spanish.



            If a locale is stored in the FMT_LOCALE configuration variable, JSTL uses that locale for formatting actions and also to locate a resource bundle for <fmt:message> actions. The <fmt:setLocale> action, given a valid value attribute, stores a locale in that configuration variable, like this:





            <fmt:setLocale value='en-US' scope='session'/>



            Optionally, you can set the value of the FMT_LOCALE configuration setting in a business component, such as a servlet, life-cycle listener, custom action, or bean; for example, a custom action could set the locale for session scope like this:





            import javax.servlet.jsp.jstl.core.Config;

            ...

            Config.set(pageContext, Config.FMT_LOCALE,

            new java.util.Locale("en-US"),

            PageContext.SESSION_SCOPE);

            ...



            The preceding code fragment, which uses the Config class to set the FMT_LOCALE configuration setting, is functionally equivalent to the <fmt:setLocale> action used above. You can also set a locale for your application by specifying a context initialization parameter in your deployment descriptor (WEB-INF/web.xml) for the FMT_LOCALE configuration setting like this:





            <web-app>

            ...

            <context-param>

            <param-name>

            javax.servlet.jsp.jstl.fmt.locale

            </param-name>



            <param-value>

            en-US

            </param-value>

            </context-param>

            ...

            </web-app>





            <fmt:setBundle>



            Creates a localization context for <fmt:message> and JSTL formatting actions





            Syntax:[15]



            [15] Items in brackets are optional.



            <fmt:setBundle basename [var] [scope]/>



            Description:



            The <fmt:setBundle> action does three things:













            1. Searches for a resource bundle, using the basename attribute.





            2. Stores that resource bundle, along with the locale used to locate it, in a localization context.





            3. Stores that localization context in the FMT_LOCALIZATION_CONTEXT configuration setting, or if you specify the var attribute, stores the localization context in a scoped variable whose name is specified by the var attribute.





            Subsequently, <fmt:message> actions and formatting actions access the localization context: <fmt:message> uses its resource bundle to localize messages, whereas formatting actions use its locale to format and parse numbers, currencies, percents, and dates.



            Attributes:























































            Attribute[a]





            Type





            Description





            basename





            String





            The base name of a resource bundle; for example if a resource bundle is specified by the properties file com/acme/resources/Resources_fr.properties, then the base name is com.acme.resources.Resources.





            var





            String





            The name of a scoped variable that references a localization context that contains a reference to the resource bundle loaded by the <fmt:setBundle> action.





            scope





            String





            The scope of the variable whose name is specified by the var attribute, or if var is not specified, the scope of the FMT_LOCALIATION_CONTEXT configuration setting. The default scope is page.





            [a] static | dynamic





            Constraints and Error Handling:





            • If the basename attribute is null or empty or <fmt:setBundle> cannot find a resource bundle, <fmt:setBundle> creates an empty localization context, meaning a localization context with a null resource bundle and locale.





            In a Nutshell:



            You use the <fmt:setBundle> action to specify a resource bundle that <fmt:message> actions use to localize their messages. You specify a resource bundle base name with the basename attribute, like this:





            <fmt:setBundle basename='messages' scope='request'/>



            The <fmt:setBundle> action in the preceding line of code locates a resource bundle from information in the action's mandatory basename attribute (messages) and the user's preferred locale and stores that resource bundle in the FMT_LOCALIZATION_CONTEXT configuration setting for request scope. Subsequently, in the absence of other <fmt:setBundle> actions, <fmt:message> actions in the same request will use the messages resource bundle to localize their messages, as long as those <fmt:message> actions do not specify their bundle attribute.



            You can also use <fmt:setBundle> to store a localization context in a scoped variable by specifying the var and scope attributes, like this:





            <fmt:setBundle basename='messages' var='msgs' scope='request'/>



            The <fmt:setBundle> action in the preceding line of code, like the first code fragment in this section, locates a resource bundle using the value of the action's mandatory basename attribute (messages) and stores that resource bundle in a localization context. The difference between the two uses of <fmt:setBundle> is that the preceding line of code stores the localization context in a scoped variable whose name is msgs. That scoped variable is stored in request scope. Subsequently, <fmt:message> actions in the same request can access that localization context like this:





            <fmt:message key='login.page.title' bundle='${msgs}'/>



            The <fmt:message> action in the preceding code fragment accesses the msgs localization context by specifying that scoped variable for the <fmt:message> bundle attribute.



            If you specify the var attribute, but not the scope attribute, the localization context created by <fmt:setBundle> is stored in page scope.





            <fmt:bundle>



            Creates a localization context for <fmt:message> actions and JSTL formatting actions that reside in the body of the action





            Syntax:[16]



            [16] Items in brackets are optional.





            <fmt:bundle basename [prefix]>

            body content, presumably with other I18N and formatting actions that use the

            bundle specified with the mandatory basename attribute

            </fmt:bundle>



            Description:



            The <fmt:bundle> action does three things:













            1. Searches for a resource bundle, using the basename attribute





            2. Stores that resource bundle in a localization context





            3. Stores that localization context in the <fmt:bundle> action's tag handler





            Subsequently, only <fmt:message> actions and formatting actions within the body of the <fmt:bundle> action will use the localization context created by the <fmt:bundle> action.



            Attributes:













































            Attribute[a]





            Type





            Description





            basename





            String





            The base name of a resource bundle; for example if a resource bundle is specified by the properties file com/acme/resources/Resources_fr.properties, then the base name is com.acme.resources.Resources.





            prefix





            String





            A prefix that's prepended to message keys specified by <fmt:message> actions that reside in the body of the <fmt:bundle> action that specified the prefix attribute.





            [a] static | dynamic





            Constraints and Error Handling:





            • If the basename attribute is null or empty or <fmt:bundle> cannot find a resource bundle, <fmt:bundle> creates an empty localization context.





            In a Nutshell:



            The <fmt:bundle> action finds a resource bundle specified by the basename attribute and stores that resource bundle in a localization context. The localization context is used by <fmt:message> actions and formatting actions only within the body of the <fmt:bundle> action; for example,





            <fmt:bundle basename='app'>

            <fmt:message key='login.title'/>

            <fmt:message key='login.welcome'/>

            <fmt:formatNumber value='10000' type='currency'/>

            </fmt:bundle>



            In the preceding code fragment, both the <fmt:message> actions and the <fmt:formatNumber> action use the localization context created by their enclosing <fmt:bundle> action. The <fmt:message> actions look up localized messages in the localization context's resource bundle, whereas the <fmt:formatNumber> action uses the localization context's locale as its formatting locale.



            You can also specify a prefix for <fmt:bundle> actions that have a body. Prefixes are used for long keys; for example, the code fragment below specifies a prefix:





            <fmt:bundle basename='app' prefix='com.Acme.application.'>

            <fmt:message key='login.title'/>

            <fmt:message key='login.welcome'/>

            </fmt:bundle>



            Prefixes are prepended to message keys for <fmt:message> actions in the body of the <fmt:bundle> action, so the preceding code fragment is equivalent to the code fragment listed below:





            <fmt:bundle basename='app'>

            <fmt:message key='com.Acme.application.login.title'/>

            <fmt:message key='com.Acme.application.login.welcome'/>

            </fmt:bundle>





            <fmt:message



            Retrieves a localized message from a resource bundle





            Syntax:[17]



            [17] Items in brackets are optional.



            Syntax #1: Without a body





            <fmt:message key [bundle] [var] [scope]/>



            Syntax #2: With a body that specifies message parameters





            <fmt:message key [bundle] [var] [scope]>

            <fmt:param> actions

            </fmt:message>



            Syntax #3: With a body that specifies a message key and, optionally, message parameters





            <fmt:message [bundle] [var] [scope]>

            key

            optional <fmt:param> actions

            </fmt:message>



            Description:



            The <fmt:message> action extracts a localized message from a resource bundle and sends it to the current JspWriter (which in most cases displays the message in the browser) or stores it in a scoped variable specified with the var attribute, and optionally, the scope attribute.



            Attributes:

































































            Attribute[a]





            Type





            Description





            key





            String





            The message key used by <fmt:message> to extract localized messages from a resource bundle.





            bundle





            LocalizationContext





            <fmt:message> actions extract localized messages from a resource bundle stored in an instance of LocalizationContext.





            var





            String





            The name of a scoped variable that references a localized message.





            scope





            String





            The scope of the scoped variable whose name is specified by the var attribute; default is page scope.





            [a] static | dynamic





            Constraints and Error Handling:





            • If you specify the scope attribute, you must also specify the var attribute.



            • If you specify a null or empty key, the <fmt:message> action will generate an error message of the form ??????.



            • If the <fmt:message> action cannot locate a valid localization context, an error message of the form ???<key>??? is generated, where <key> represents the value of the key attribute.





            In a Nutshell:



            You can specify message keys with the key attribute, like this�





            <fmt:message key='messages.loginPage.title'/>



            �or within the body of <fmt:message> actions, like this:





            <fmt:message>

            messages.loginPage.title

            </fmt:message>



            The resource bundle used by the <fmt:message> actions in the two preceding code fragments is the resource bundle stored in the localization context that is stored in the FMT_LOCALIZATION_CONTEXT configuration setting (See "<fmt:setBundle>" on page 498 for more information about that configuration setting). You can also specify a localization context explicitly, with the bundle attribute, like this:





            <fmt:message key='msgs.greeting' bundle='${aLocalizationContext}'/>



            The <fmt:message> action in the preceding code fragment specifies a localization context stored in a scoped variable named aLocalizationContext. That localization context can be created with <fmt:setBundle> or a business component, such as a servlet, life-cycle listener, or custom action.



            If a <fmt:message> action resides in the body of a <fmt:bundle> action, that <fmt:message> action extracts localized messages from the resource bundle stored in the localization context established by its enclosing <fmt:bundle> action. If the enclosing <fmt:bundle> action specifies a prefix attribute, enclosed <fmt:message> actions prepend that prefix to their message keys. See "<fmt:bundle>" on page 500 for more information about the <fmt:bundle> action.



            <fmt:message> actions can also display compound messages. A compound message is a message that contains parameters that are specified at runtime. Those parameters are specified with <fmt:param>, like this:





            <jsp:useBean id='now' class='java.util.Date'/>



            <fmt:message key='footer.messages.todaysDate'>

            <fmt:param value='${now}'/>

            </fmt:message>



            The preceding code fragment specifies a date as a parameter to the compound message corresponding to footer.messages.todaysDate. That compound message is specified like this in a properties file:





            footer.messages.todaysDate=Today is: {0}





            <fmt:param>



            Supplies a parameter for an enclosing <fmt:message>





            Syntax:



            Syntax #1: Without a body





            <fmt:param value/>



            Syntax #2: With a body





            <fmt:param>

            value

            </fmt:param>



            Description:



            The <fmt:param> action specifies a parameter for an enclosing <fmt:message> action.



            Attributes:



































            Attribute[a]





            Type





            Description





            value





            Object





            This attribute specifies a parameter for an enclosing <fmt:message> action. You can also specify parameters in the body of <fmt:param> actions.





            [a] static | dynamic





            Constraints and Error Handling:





            • <fmt:param> actions must reside in the body of a <fmt:message> action.





            In a Nutshell:



            Each <fmt:param> action specifies a single parameter for a compound message. That compound message is retrieved from a resource bundle by an enclosing <fmt:message> action. The first <fmt:param> action contained in the body of a <fmt:message> action specifies the first parameter for that compound message, the second <fmt:param> action specifies the second parameter, and so on; for example, for this compound message in a resource bundle�





            message=There are {0} parameters in this message: the second is \

            {1} and the third is {2}.



            � if you specify parameters like this�





            <fmt:message key='message'>

            <fmt:param value='THREE'/>

            <fmt:param value='THE SECOND PARAMETER'/>

            <fmt:param value='THE THIRD PARAMETER'/>

            </fmt:message>



            �then the <fmt:message> action in the preceding code fragment will generate the following text: There are THREE parameters in this message: the second is THE SECOND PARAMETER and the third is THE THIRD PARAMETER.



            You do not have to specify a <fmt:param> action for every parameter in a compound message, but it is recommended that you do so. If you do not specify a <fmt:param> action for every parameter, no substitution is made for unspecified parameters; for example, if you specify only two parameters for the compound message in the code fragment above, like this�





            <fmt:message key='message'>

            <fmt:param value='TWO'/>

            <fmt:param value='THE SECOND PARAMETER'/>

            </fmt:message>



            �then the <fmt:message> action in the preceding code fragment will generate the following text: There are TWO parameters in this message: the second is THE SECOND PARAMETER and the third is {2}.



            JSP 1.2 does not support JSTL Expression Language (EL) expressions, so you cannot specify an EL expression in the body of a <fmt:param> action (or any action, for that matter). For example, that means you can do this:





            <fmt:param value='${param.amount}'/>



            but you cannot do this:





            <fmt:param>

            ${param.amount}

            </fmt:param>



            Instead, you must do this:





            <fmt:param>

            <c:out value='${param.amount}'/>

            </fmt:param>



            JSP 2.0 will support the JSTL Expression Language, which means you will be able to specify EL expressions directly within the body of a <fmt:param> action.





            <fmt:requestEncoding>



            Sets the request's character encoding





            Syntax:[18]



            [18] Items in brackets are optional.





            <fmt:requestEncoding [value]/>



            Description:



            The <fmt:requestEncoding> action sets an HTTP request's character encoding.



            Attributes:



































            Attribute[a]





            Type





            Description





            value





            String





            The character encoding that the servlet container uses to decode request parameters.





            [a] static | dynamic





            In a Nutshell:



            Imagine that you have two JSP pages: one that contains an HTML form, which we'll call the form page, and another that is specified as the form's action, which we'll call the action page. Now imagine that your form page is localized for Chinese, and that you set the response charset for that page to Mainland Chinese (charset=GB2312).



            When the form is submitted, the action page is loaded and accesses the request parameters to find out what the user entered in the form. Will those request parameters be decoded properly? The answer for most browsers is no, because most browsers do not specify the Content-Type request header and therefore the application cannot determine the request encoding. To force your browser to properly decode those request parameters, you must specify the action page's request encoding so that it matches the form page's response encoding. That's exactly what <fmt:requestEncoding> does. All you have to do is use the <fmt:requestEncoding> action at the top of your action page before you access request parameters.



            There are two ways to use the <fmt:requestEncoding> action. If you know the response encoding of the form page, you can specify that charset with the <fmt:requestEncoding> action's value attribute. If you don't know the response encoding of the form page, don't specify the value attribute and the <fmt:requestEncoding> action will figure out what to do.



            At this point you may wonder how the <fmt:requestEncoding> action knows the charset to use if you don't specify it with the value attribute. The answer is that <fmt:requestEncoding> retrieves that charset from a session attribute. That attribute was created by the JSTL internationalization actions in the form page; therefore, for <fmt:requestEncoding> to work properly, you must use JSTL internationalization actions in the form page if you don't specify the <fmt:requestEncoding> action's value attribute.





            Exposed Classes



            JSTL exposes two classes for internationalization:





            • javax.servlet.jsp.jstl.fmt.LocaleSupport



            • javax.servlet.jsp.jstl.fmt.LocalizationContext





            The LocaleSupport class lets you extract localized messages from resource bundles; LocalizationContext objects store a resource bundle and the locale used to locate that resource bundle.





            LocaleSupport



            A class that lets you retrieve localized messages from a resource bundle





            Definition:





            class LocaleSupport {

            public static String getLocalizedMessage(PageContext, String key)

            public static String getLocalizedMessage(PageContext, String key,

            String basename)

            public static String getLocalizedMessage(PageContext, String key,

            Object[] args)

            public static String getLocalizedMessage(PageContext, String key,

            Object[] args, String basename)

            }



            Description:



            The four methods of the LocaleSupport class let you extract localized messages from resource bundles, just like <fmt:message> actions do. You can use those methods in a custom action; for example see "I18N Custom Actions" on page 293 for a discussion of a custom action that uses the LocaleSupport class to localize error messages.





            LocalizationContext



            A class that stores a resource bundle and a locale





            Definition:





            class LocalizationContext {

            public LocalizationContext()

            public LocalizationContext(ResourceBundle bundle, Locale locale)

            public LocalizationContext(ResourceBundle bundle)



            public Locale getLocale()

            public ResourceBundle getResourceBundle()

            }



            Description:



            In all likelihood, you will never have to deal with an instance of LocalizationContext directly, although you may want to create one in a business component, such as a servlet, servlet filter, or life-cycle listener.



            The LocalizationContext class provides three constructors. The no-argument constructor creates an empty LocalizationContext instance with a null resource bundle and a null locale. JSTL uses that constructor when <fmt:bundle> or <fmt:setBundle> cannot find a resource bundle.



            You can also create a localization context with a resource bundle and a locale. The constructor that takes those two arguments simply assigns the resource bundle and locale to the localization context's member variables. The constructor that just takes a resource bundle stores the resource bundle and its locale in the localization context.