( ! ) Deprecated: Function WP_Dependencies-&gt;add_data() was called with an argument that is <strong>deprecated</strong> since version 6.9.0! IE conditional comments are ignored by all supported browsers. in /var/www/html/wp-includes/functions.php on line 6131
Call Stack
#TimeMemoryFunctionLocation
10.0000484224{main}( ).../index.php:0
20.0006484576require( '/var/www/html/wp-blog-header.php ).../index.php:17
30.32114311984require_once( '/var/www/html/wp-includes/template-loader.php ).../wp-blog-header.php:19
40.32754341304include( '/var/www/html/wp-content/themes/twentyfifteen/archive.php ).../template-loader.php:125
50.32754341304get_header( $name = ???, $args = ??? ).../archive.php:19
60.32754341520locate_template( $template_names = [0 => 'header.php'], $load = TRUE, $load_once = TRUE, $args = [] ).../general-template.php:48
70.32754341616load_template( $_template_file = '/var/www/html/wp-content/themes/twentyfifteen/header.php', $load_once = TRUE, $args = [] ).../template.php:749
80.32784342160require_once( '/var/www/html/wp-content/themes/twentyfifteen/header.php ).../template.php:814
90.32814349568wp_head( ).../header.php:18
100.32814349568do_action( $hook_name = 'wp_head' ).../general-template.php:3197
110.32814349784WP_Hook->do_action( $args = [0 => ''] ).../plugin.php:522
120.32814349784WP_Hook->apply_filters( $value = '', $args = [0 => ''] ).../class-wp-hook.php:365
130.32834352768wp_enqueue_scripts( '' ).../class-wp-hook.php:341
140.32834352768do_action( $hook_name = 'wp_enqueue_scripts' ).../script-loader.php:2311
150.32834352984WP_Hook->do_action( $args = [0 => ''] ).../plugin.php:522
160.32834352984WP_Hook->apply_filters( $value = '', $args = [0 => ''] ).../class-wp-hook.php:365
170.32844354872twentyfifteen_scripts( '' ).../class-wp-hook.php:341
180.32864356392wp_style_add_data( $handle = 'twentyfifteen-ie', $key = 'conditional', $value = 'lt IE 9' ).../functions.php:440
190.32864356392WP_Styles->add_data( $handle = 'twentyfifteen-ie', $key = 'conditional', $value = 'lt IE 9' ).../functions.wp-styles.php:245
200.32864356392WP_Dependencies->add_data( $handle = 'twentyfifteen-ie', $key = 'conditional', $value = 'lt IE 9' ).../class-wp-styles.php:385
210.32864475176_deprecated_argument( $function_name = 'WP_Dependencies->add_data()', $version = '6.9.0', $message = 'IE conditional comments are ignored by all supported browsers.' ).../class-wp-dependencies.php:317
220.32864481128wp_trigger_error( $function_name = '', $message = 'Function WP_Dependencies->add_data() was called with an argument that is <strong>deprecated</strong> since version 6.9.0! IE conditional comments are ignored by all supported browsers.', $error_level = 16384 ).../functions.php:5925
230.32874481880trigger_error( $message = 'Function WP_Dependencies-&gt;add_data() was called with an argument that is <strong>deprecated</strong> since version 6.9.0! IE conditional comments are ignored by all supported browsers.', $error_level = 16384 ).../functions.php:6131

( ! ) Deprecated: Function WP_Dependencies-&gt;add_data() was called with an argument that is <strong>deprecated</strong> since version 6.9.0! IE conditional comments are ignored by all supported browsers. in /var/www/html/wp-includes/functions.php on line 6131
Call Stack
#TimeMemoryFunctionLocation
10.0000484224{main}( ).../index.php:0
20.0006484576require( '/var/www/html/wp-blog-header.php ).../index.php:17
30.32114311984require_once( '/var/www/html/wp-includes/template-loader.php ).../wp-blog-header.php:19
40.32754341304include( '/var/www/html/wp-content/themes/twentyfifteen/archive.php ).../template-loader.php:125
50.32754341304get_header( $name = ???, $args = ??? ).../archive.php:19
60.32754341520locate_template( $template_names = [0 => 'header.php'], $load = TRUE, $load_once = TRUE, $args = [] ).../general-template.php:48
70.32754341616load_template( $_template_file = '/var/www/html/wp-content/themes/twentyfifteen/header.php', $load_once = TRUE, $args = [] ).../template.php:749
80.32784342160require_once( '/var/www/html/wp-content/themes/twentyfifteen/header.php ).../template.php:814
90.32814349568wp_head( ).../header.php:18
100.32814349568do_action( $hook_name = 'wp_head' ).../general-template.php:3197
110.32814349784WP_Hook->do_action( $args = [0 => ''] ).../plugin.php:522
120.32814349784WP_Hook->apply_filters( $value = '', $args = [0 => ''] ).../class-wp-hook.php:365
130.32834352768wp_enqueue_scripts( '' ).../class-wp-hook.php:341
140.32834352768do_action( $hook_name = 'wp_enqueue_scripts' ).../script-loader.php:2311
150.32834352984WP_Hook->do_action( $args = [0 => ''] ).../plugin.php:522
160.32834352984WP_Hook->apply_filters( $value = '', $args = [0 => ''] ).../class-wp-hook.php:365
170.32844354872twentyfifteen_scripts( '' ).../class-wp-hook.php:341
180.34964482984wp_style_add_data( $handle = 'twentyfifteen-ie7', $key = 'conditional', $value = 'lt IE 8' ).../functions.php:444
190.34964482984WP_Styles->add_data( $handle = 'twentyfifteen-ie7', $key = 'conditional', $value = 'lt IE 8' ).../functions.wp-styles.php:245
200.34964482984WP_Dependencies->add_data( $handle = 'twentyfifteen-ie7', $key = 'conditional', $value = 'lt IE 8' ).../class-wp-styles.php:385
210.34964482984_deprecated_argument( $function_name = 'WP_Dependencies->add_data()', $version = '6.9.0', $message = 'IE conditional comments are ignored by all supported browsers.' ).../class-wp-dependencies.php:317
220.34964483304wp_trigger_error( $function_name = '', $message = 'Function WP_Dependencies->add_data() was called with an argument that is <strong>deprecated</strong> since version 6.9.0! IE conditional comments are ignored by all supported browsers.', $error_level = 16384 ).../functions.php:5925
230.34974483528trigger_error( $message = 'Function WP_Dependencies-&gt;add_data() was called with an argument that is <strong>deprecated</strong> since version 6.9.0! IE conditional comments are ignored by all supported browsers.', $error_level = 16384 ).../functions.php:6131

Java SE 6 新特性: Java DB 和 JDBC 4.0

2006 年底,Sun 公司发布了 Java Standard Edition 6(Java SE 6)的最终正式版,代号 Mustang(野马)。跟 Tiger(Java SE 5)相比,Mustang 在性能方面有了不错的提升。与 Tiger 在 API 库方面的大幅度加强相比,虽然 Mustang 在 API 库方面的新特性显得不太多,但是也提供了许多实用和方便的功能:在脚本,WebService,XML,编译器 API,数据库,JMX,网络和 Instrumentation 方面都有不错的新特性和功能加强。 本系列 文章主要介绍 Java SE 6 在 API 库方面的部分新特性,通过一些例子和讲解,帮助开发者在编程实践当中更好的运用 Java SE 6,提高开发效率。

本文是系列文章的第 5 篇,介绍了 Java SE 6 在数据库编程方面的新特性。

长久以来,由于大量(甚至几乎所有)的 Java 应用都依赖于数据库,如何使用 Java 语言高效、可靠、简洁地访问数据库一直是程序员们津津乐道的话题。新发布的 Java SE 6 也在这方面更上层楼,为编程人员提供了许多好用的新特性。其中最显著的,莫过于 Java SE 6 拥有了一个内嵌的 100% 用 Java 语言编写的数据库系统。并且,Java 6 开始支持 JDBC 4.0 的一系列新功能和属性。这样,Java SE 在对持久数据的访问上就显得更为易用和强大了。

Java DB:Java 6 里的数据库

新安装了 JDK 6 的程序员们也许会发现,除了传统的 bin、jre 等目录,JDK 6 新增了一个名为 db 的目录。这便是 Java 6 的新成员:Java DB。这是一个纯 Java 实现、开源的数据库管理系统(DBMS),源于 Apache 软件基金会(ASF)名下的项目 Derby。它只有 2MB 大小,对比动辄上 G 的数据库来说可谓袖珍。但这并不妨碍 Derby 功能齐备,支持几乎大部分的数据库应用所需要的特性。更难能可贵的是,依托于 ASF 强大的社区力量,Derby 得到了包括 IBM 和 Sun 等大公司以及全世界优秀程序员们的支持。这也难怪 Sun 公司会选择其 10.2.2 版本纳入到 JDK 6 中,作为内嵌的数据库。这就好像为 JDK 注入了一股全新的活力:Java 程序员不再需要耗费大量精力安装和配置数据库,就能进行安全、易用、标准、并且免费的数据库编程。在这一章中,我们将初窥 Java DB 的世界,来探究如何使用它编写出功能丰富的程序。

Hello, Java DB:内嵌模式的 Derby

既然有了内嵌(embedded)的数据库,就让我们从一个简单的范例(代码在 清单 1 中列出)开始,试着使用它吧。这个程序做了大多数数据库应用都可能会做的操作:在 DBMS 中创建了一个名为 helloDB 的数据库;创建了一张数据表,取名为 hellotable;向表内插入了两条数据;然后,查询数据并将结果打印在控制台上;最后,删除表和数据库,释放资源。

清单 1. HelloJavaDB 的代码

public class HelloJavaDB {
public static void main(String[] args) {
try { // load the driver
Class.forName("org.apache.derby.jdbc.EmbeddedDriver").newInstance();
System.out.println("Load the embedded driver");
Connection conn = null;
Properties props = new Properties();
props.put("user", "user1");
props.put("password", "user1");
//create and connect the database named helloDB
conn=DriverManager.getConnection("jdbc:derby:helloDB;create=true", props);
System.out.println("create and connect to helloDB");
conn.setAutoCommit(false);
// create a table and insert two records
Statement s = conn.createStatement();
s.execute("create table hellotable(name varchar(40), score int)");
System.out.println("Created table hellotable");
s.execute("insert into hellotable values(`Ruth Cao`, 86)");
s.execute("insert into hellotable values (`Flora Shi`, 92)");
// list the two records
ResultSet rs = s.executeQuery(
"SELECT name, score FROM hellotable ORDER BY score");
System.out.println("name\t\tscore");
while(rs.next()) {
StringBuilder builder = new StringBuilder(rs.getString(1));
builder.append("\t");
builder.append(rs.getInt(2));
System.out.println(builder.toString());
}
// delete the table
s.execute("drop table hellotable");
System.out.println("Dropped table hellotable");
rs.close();
s.close();
System.out.println("Closed result set and statement");
conn.commit();
conn.close();
System.out.println("Committed transaction and closed connection");
try { // perform a clean shutdown
DriverManager.getConnection("jdbc:derby:;shutdown=true");
} catch (SQLException se) {
System.out.println("Database shut down normally");
}
} catch (Throwable e) {
// handle the exception
}
System.out.println("SimpleApp finished");
}
}

随后,我们在命令行(本例为 Windows 平台,当然,其它系统下稍作改动即可)下键入以下命令:

清单 2. 运行 HelloJavaDB 命令

                java –cp .;%JAVA_HOME%\db\lib\derby.jar HelloJavaDB

程序将会按照我们预想的那样执行,图 1 是执行结果的一部分截屏:

图 1. HelloJavaDB 程序的执行结果
图 1. HelloJavaDB 程序的执行结果

上述的程序和以往没什么区别。不同的是我们不需要再为 DBMS 的配置而劳神,因为 Derby 已经自动地在当前目录下新建了一个名为 helloDB 的目录,来物理地存储数据和日志。需要做的只是注意命名问题:在内嵌模式下驱动的名字应为 org.apache.derby.jdbc.EmbeddedDriver;创建一个新数据库时需要在协议后加入 create=true。另外,关闭所有数据库以及 Derby 的引擎可以使用以下代码:

清单 3. 关闭所有数据库及 Derby 引擎

                DriverManager.getConnection("jdbc:derby:;shutdown=true");

如果只想关闭一个数据库,那么则可以调用:

清单 4. 关闭一个数据库

                DriverManager.getConnection("jdbc:derby:helloDB;shutdown=true ");

这样,使用嵌入模式的 Derby 维护和管理数据库的成本接近于 0。这对于希望专心写代码的人来说不失为一个好消息。然而有人不禁要问:既然有了内嵌模式,为什么大多数的 DBMS 都没有采取这样的模式呢?不妨做一个小实验。当我们同时在两个命令行窗口下运行 HelloJavaDB 程序。结果一个的结果与刚才一致,而另一个却出现了错误,如 图 2 所示。

图 2. 内嵌模式的局限
图 2. 内嵌模式的局限

错误的原因其实很简单:在使用内嵌模式时,Derby 本身并不会在一个独立的进程中,而是和应用程序一起在同一个 Java 虚拟机(JVM)里运行。因此,Derby 如同应用所使用的其它 jar 文件一样变成了应用的一部分。这就不难理解为什么在 classpath 中加入 derby 的 jar 文件,我们的示例程序就能够顺利运行了。这也说明了只有一个 JVM 能够启动数据库:而两个跑在不同 JVM 实例里的应用自然就不能够访问同一个数据库了。

鉴于上述的局限性,和来自不同 JVM 的多个连接想访问一个数据库的需求,下一节将介绍 Derby 的另一种模式:网络服务器(Network Server)。

网络服务器模式

如上所述,网络服务器模式是一种更为传统的客户端/服务器模式。我们需要启动一个 Derby 的网络服务器用于处理客户端的请求,不论这些请求是来自同一个 JVM 实例,还是来自于网络上的另一台机器。同时,客户端使用 DRDA(Distributed Relational Database Architecture)协议连接到服务器端。这是一个由 The Open Group 倡导的数据库交互标准。图 3 说明了该模式的大体结构。

由于 Derby 的开发者们努力使得网络服务器模式与内嵌模式之间的差异变小,使得我们只需简单地修改 清单 1 中的程序就可以实现。如 清单 5所示,我们在 HelloJavaDB 中增添了一个新的函数和一些字符串变量。不难看出,新的代码只是将一些在 上一节中特别指出的字符串进行了更改:驱动类为 org.apache.derby.jdbc.ClientDriver,而连接数据库的协议则变成了 jdbc:derby://localhost:1527/。这是一个类似 URL 的字符串,而事实上,Derby 网络的客户端的连接格式为:jdbc:derby://server[:port]/databaseName[;attributeKey=value]。在这个例子中,我们使用了最简单的本地机器作为服务器,而端口则是 Derby 默认的 1527 端口。

图 3. Derby 网络服务器模式架构
图 3. Derby 网络服务器模式架构

清单 5. 网络服务器模式下的 HelloJavaDB

public class HelloJavaDB {
public static String driver = "org.apache.derby.jdbc.EmbeddedDriver"$$
public static String protocol = "jdbc:derby:"$$
public static void main(String[] args) {
// same as before
}
private static void parseArguments(String[] args) {
if (args.length == 0 || args.length > 1) {
return;
}
if (args[0].equalsIgnoreCase("derbyclient")) {
framework = "derbyclient"$$
driver = "org.apache.derby.jdbc.ClientDriver"$$
protocol = "jdbc:derby://localhost:1527/"$$
}
}
}

当然,仅仅有客户端是不够的,我们还需要启动网络服务器。Derby 中控制网络服务器的类是 org.apache.derby.drda.NetworkServerControl,因此键入以下命令即可。如果想了解 NetworkServerControl 更多的选项,只要把 start 参数去掉就可以看到帮助信息了。关于网络服务器端的实现,都被 Derby 包含在 derbynet.jar 里。

清单 6. 启动网络服务器

java -cp .;"C:\Program Files\Java\jdk1.6.0\db\lib\derby.jar"$$
"C:\Program Files\Java\jdk1.6.0\db\lib\derbynet.jar"
org.apache.derby.drda.NetworkServerControl start

相对应的,网络客户端的实现被包含在 derbyclient.jar 中。所以,只需要在 classpath 中加入该 jar 文件,修改后的客户端就可以顺利地读取数据了。再一次尝试着使用两个命令行窗口去连接数据库,就能够得到正确的结果了。如果不再需要服务器,那么使用 NetworkServerControl 的 shutdown 参数就能够关闭服务器。

更多

至此,文章介绍了 Java SE 6 中的新成员:Java DB(Derby),也介绍了如何在内嵌模式以及网络服务器模式下使用 Java DB。当然这只是浅尝辄止,更多高级的选项还需要在 Sun 和 Derby 的文档中寻找。在这一章的最后,我们将简单介绍几个 Java DB 的小工具来加快开发速度。它们都位于 org.apache.derby.tools 包内,在开发过程中需要获取信息或者测试可以用到。

  • ij:一个用来运行 SQL 脚本的工具;
  • dblook:为 Derby 数据库作模式提取(Schema extraction),生成 DDL 的工具;
  • sysinfo:显示系统以及 Derby 信息的工具类;


回页首

JDBC 4.0:新功能,新 API

如果说上一章介绍了 Java 6 中的一个新成员,它本来就存在,但是没有被加入进 JDK。那么这一章,我们将关注在 JDBC 4.0 中又增加了哪些新功能以及与之相对应的新 API。

自动加载驱动

在 JDBC 4.0 之前,编写 JDBC 程序都需要加上以下这句有点丑陋的代码:

清单 7. 注册 JDBC 驱动

                Class.forName("org.apache.derby.jdbc.EmbeddedDriver").newInstance();

Java.sql.DriverManager 的内部实现机制决定了这样代码的出现。只有先通过 Class.forName 找到特定驱动的 class 文件,DriverManager.getConnection 方法才能顺利地获得 Java 应用和数据库的连接。这样的代码为编写程序增加了不必要的负担,JDK 的开发者也意识到了这一点。从 Java 6 开始,应用程序不再需要显式地加载驱动程序了,DriverManager 开始能够自动地承担这项任务。作为试验,我们可以将 清单 1 中的相关代码删除,重新编译后在 JRE 6.0 下运行,结果和原先的程序一样。

好奇的读者也许会问,DriverManager 为什么能够做到自动加载呢?这就要归功于一种被称为 Service Provider 的新机制。熟悉 Java 安全编程的程序员可能对其已经是司空见惯,而它现在又出现在 JDBC 模块中。JDBC 4.0 的规范规定,所有 JDBC 4.0 的驱动 jar 文件必须包含一个 java.sql.Driver,它位于 jar 文件的 META-INF/services 目录下。这个文件里每一行便描述了一个对应的驱动类。其实,编写这个文件的方式和编写一个只有关键字(key)而没有值(value)的 properties 文件类似。同样地,‘#’之后的文字被认为是注释。有了这样的描述,DriverManager 就可以从当前在 CLASSPATH 中的驱动文件中找到,它应该去加载哪些类。而如果我们在 CLASSPATH 里没有任何 JDBC 4.0 的驱动文件的情况下,调用 清单 8 中的代码会输出一个 sun.jdbc.odbc.JdbcOdbcDriver 类型的对象。而仔细浏览 JDK 6 的目录,这个类型正是在 %JAVA_HOME%/jre/lib/resources.jar 的 META-INF/services 目录下的 java.sql.Driver 文件中描述的。也就是说,这是 JDK 中默认的驱动。而如果开发人员想使得自己的驱动也能够被 DriverManager 找到,只需要将对应的 jar 文件加入到 CLASSPATH 中就可以了。当然,对于那些 JDBC 4.0 之前的驱动文件,我们还是只能显式地去加载了。

清单 8. 罗列本地机器上的 JDBC 驱动

Enumeration<Driver> drivers = DriverManager.getDrivers();
while(drivers.hasMoreElements()) {
System.out.println(drivers.nextElement());
}

RowId

熟悉 DB2、Oracle 等大型 DBMS 的人一定不会对 ROWID 这个概念陌生:它是数据表中一个“隐藏”的列,是每一行独一无二的标识,表明这一行的物理或者逻辑位置。由于 ROWID 类型的广泛使用,Java SE 6 中新增了 java.sql.RowId 的数据类型,允许 JDBC 程序能够访问 SQL 中的 ROWID 类型。诚然,不是所有的 DBMS 都支持 ROWID 类型。即使支持,不同的 ROWID 也会有不同的生命周期。因此使用 DatabaseMetaData.getRowIdLifetime 来判断类型的生命周期不失为一项良好的实践经验。我们在 清单 1 的程序获得连接之后增加以下代码,便可以了解 ROWID 类型的支持情况。

清单 9. 了解 ROWID 类型的支持情况

DatabaseMetaData meta = conn.getMetaData();System.out.println(meta.getRowIdLifetime());

Java SE 6 的 API 规范中,java.sql.RowIdLifetime 规定了 5 种不同的生命周期:ROWID_UNSUPPORTED、ROWID_VALID_FOREVER、ROWID_VALID_OTHER、ROWID_VALID_SESSION 和 ROWID_VALID_TRANSACTION。从字面上不难理解它们表示了不支持 ROWID、ROWID 永远有效等等。具体的信息,还可以参看相关的 JavaDoc。读者可以尝试着连接 Derby 进行试验,会发现运行结果是 ROWID_UNSUPPORTED ,即 Derby 并不支持 ROWID。

既然提供了新的数据类型,那么一些相应的获取、更新数据表内容的新 API 也在 Java 6 中被添加进来。和其它已有的类型一样,在得到 ResultSet 或者 CallableStatement 之后,调用 get/set/update 方法得到/设置/更新 RowId 对象,示例的代码如 清单 10 所示。

清单 10. 获得/设置 RowId 对象

// Initialize a PreparedStatement
PreparedStatement pstmt = connection.prepareStatement(
"SELECT rowid, name, score FROM hellotable WHERE rowid = ?");
// Bind rowid into prepared statement.
pstmt.setRowId(1, rowid);
// Execute the statement
ResultSet rset = pstmt.executeQuery();
// List the records
while(rs.next()) {
RowId id = rs.getRowId(1);
// get the immutable rowid object
String name = rs.getString(2);
int score = rs.getInt(3);
}

鉴于不同 DBMS 的不同实现,RowID 对象通常在不同的数据源(datasource)之间并不是可移植的。因此 JDBC 4.0 的 API 规范并不建议从连接 A 取出一个 RowID 对象,将它用在连接 B 中,以避免不同系统的差异而带来的难以解释的错误。而至于像 Derby 这样不支持 RowId 的 DBMS,程序将直接在 setRowId 方法处抛出 SQLFeatureNotSupportedException。

SQLXML

SQL:2003 标准引入了 SQL/XML,作为 SQL 标准的扩展。SQL/XML 定义了 SQL 语言怎样和 XML 交互:如何创建 XML 数据;如何在 SQL 语句中嵌入 XQuery 表达式等等。作为 JDBC 4.0 的一部分,Java 6 增加了 java.sql.SQLXML 的类型。JDBC 应用程序可以利用该类型初始化、读取、存储 XML 数据。java.sql.Connection.createSQLXML 方法就可以创建一个空白的 SQLXML 对象。当获得这个对象之后,便可以利用 setString、setBinaryStream、setCharacterStream 或者 setResult 等方法来初始化所表示的 XML 数据。以 setCharacterStream 为例,清单 11 表示了一个 SQLXML 对象如何获取 java.io.Writer 对象,从外部的 XML 文件中逐行读取内容,从而完成初始化。

清单 11. 利用 setCharacterStream 方法来初始化 SQLXML 对象

SQLXML xml = con.createSQLXML();
Writer writer = xml.setCharacterStream();
BufferedReader reader = new BufferedReader(new FileReader("test.xml"));
String line= null;
while(
(line = reader.readLine() != null) {
writer.write(line);
}

由于 SQLXML 对象有可能与各种外部的资源有联系,并且在一个事务中一直持有这些资源。为了防止应用程序耗尽资源,Java 6 提供了 free 方法来释放其资源。类似的设计在 java.sql.Array、Clob 中都有出现。

至于如何使用 SQLXML 与数据库进行交互,其方法与其它的类型都十分相似。可以参照 RowId 一节 中的例子在 Java SE 6 的 API 规范中找到 SQLXML 中对应的 get/set/update 方法构建类似的程序,此处不再赘述。

SQLExcpetion 的增强

在 Java SE 6 之前,有关 JDBC 的异常类型不超过 10 个。这似乎已经不足以描述日渐复杂的数据库异常情况。因此,Java SE 6 的设计人员对以 java.sql.SQLException 为根的异常体系作了大幅度的改进。首先,SQLException 新实现了 Iterable<Throwable> 接口。清单 12 实现了 清单 1 程序的异常处理机制。这样简洁地遍历了每一个 SQLException 和它潜在的原因(cause)。

清单 12. SQLException 的 for-each loop

// Java 6 code
catch (Throwable e) {
if (e instanceof SQLException) {
for(Throwable ex : (SQLException)e ){
System.err.println(ex.toString());
}
}
}

此外,图 4 表示了全部的 SQLException 异常体系。除去原有的 SQLException 的子类,Java 6 中新增的异常类被分为 3 种:SQLReoverableException、SQLNonTransientException、SQLTransientException。在 SQLNonTransientException 和 SQLTransientException 之下还有若干子类,详细地区分了 JDBC 程序中可能出现的各种错误情况。大多数子类都会有对应的标准 SQLState 值,很好地将 SQL 标准和 Java 6 类库结合在一起。

图 4. SQLException 异常体系
图 4. SQLException 异常体系

在众多的异常类中,比较常见的有 SQLFeatureNotSupportedException,用来表示 JDBC 驱动不支持某项 JDBC 的特性。例如在 Derby 下运行 清单 10 中的程序,就可以发现 Derby 的驱动并不支持 RowId 的特性。另外值得一提的是,SQLClientInfoException 直接继承自 SQLException,表示当一些客户端的属性不能被设置在一个数据库连接时所发生的异常。


回页首

小结:更多新特性与展望

在本文中,我们已经向读者介绍了 Java SE 6 中 JDBC 最重要的一些新特性:它们包括嵌在 JDK 中的 Java DB (Derby)和 JDBC 4.0 的一部分。当然,还有很多本文还没有覆盖到的新特性。比如增加了对 SQL 语言中 NCHAR、NVARCHAR、LONGNVARCHAR 和 NCLOB 类型的支持;在数据库连接池的环境下为管理 Statement 对象提供更多灵活、便利的方法等。

此外,在 Java SE 6 的 beta 版中,曾经将 Annotation Query 的特性包含进来。这项特性定义了一系列 Query 和 DataSet 接口,程序员可以通过撰写一些 Annotation 来自定义查询并获得定制的数据集结果。但是,由于这一特性的参考实现最终不能满足 JDK 的质量需求,Sun 公司忍痛割爱,取消了在 Java SE 6 中发布其的计划。我们有理由相信,在以后的 JDK 版本中,这一特性以及更多新的功能将被包含进来,利用 Java 语言构建数据库的应用也会变得更为自然、顺畅。

参考资料

How to fix “java.lang.OutOfMemoryError: unable to create new native thread”


I recently came across this exception on a couple of java systems that use many threads  java.lang.OutOfMemoryError: unable to create new native thread. The strange thing was that the JVM had been assigned a lot of memory (1.5GB) and that it had at least half the memory available. Michele found this article that points out that the more memory you give to the JVM the more likely you are to get java.lang.OutOfMemoryError: unable to create new native thread exceptions when you have many threads.


Which makes perfect sense when you think about it. Each 32 bit process on Windows has 2GB “available” memory as 2GB is reserved to Windows. In my case the JVM grabbed 1.5 GB leaving 500MB. Part of the 500MB was used to map system dlls etc in memory so less than 400 MB was left. Now to the crucial point: When you create a thread in java it creates a Thread object in the JVM memory but it also creates a operating system thread. The operating system creates the thread with a thread stack in the 400MB that is left, not in the 1.5 GB allocated in the JVM. Java 1.4 uses a default stack size of 256kb but Java 1.5 uses a 1MB stack per thread. So, in the 400MB left to process I could only generate ~400 threads. Absurd but true: to create more threads you have to reduce the memory allocated to the JVM. Another option is to host the JVM in your own process using JNI.


This formula gives a decent estimate for the number of threads you can create: 
(MaxProcessMemory – JVMMemory – ReservedOsMemory) / (ThreadStackSize) = Number of threads


For Java 1.5 I get the following results assuming that the OS reserves about 120MB:
1.5GB allocated to JVM: (2GB-1.5Gb-120MB)/(1MB) = ~380 threads
1.0GB allocated to JVM: (2GB-1.0Gb-120MB)/(1MB) = ~880 threads


Java 1.4 uses 256kb for the thread stack which lets you create a lot more threads:
1.5GB allocated to JVM: ~1520 threads
1.0GB allocated to JVM: ~3520 threads


I have not tried the 3GB switch but it should in theory let you create more threads.

NOD32最新升級ID nod32升级服务器 nod32下载 nod32破解版 nod32注册码


2007年9月6號

 

UserName: AV-6476241
Password: n1d7xtk7ko

UserName: AV-6488086
Password: it9gqnd33a

UserName: AV-6471366
Password: 3gufs98wcq

UserName: AV-6258073
Password: y17dhcb1f4

UserName: AV-6454441
Password: 2mo24goes2

UserName: AV-6360500
Password: 73ec6ds05r

UserName: AV-6069610
Password: p96wc7bfbh

UserName: AV-6516992
Password: ise0qj9a8y

STRUTS ACTION – AGGREGATING ACTIONS IN STRUTS

If you are a Struts developer then you might have experienced the pain of writing huge number of Action classes for your project. The latest version of struts provides classes using which you can aggregate a related set of actions into a single unified action. In this article we will see how to achieve this. Struts provides four important classes for this purpose. These classes are called as Dispatchers. The important Dispatchers that struts provides includes : DispatchAction, ActionDispatcher , LookupDispatchAction and MappingDispatchAction.

All these classes can be found in the package org.apache.struts.actions. Let us look in to each of these in detail. Our examples use the simple CRUD actions.

DispatchAction: In this type of aggregation, the action class must extend DispatchAction class as shown.

public final class CRUDDispatchAction extends DispatchAction {

public ActionForward create(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) throws Exception {
return (mapping.findForward(“success”));
}
… 


and the action mapping will be as 

<action path=”/crudDispatchAction” type=”com.companyname.projname.CRUDDispatchAction” name=”formName” scope=”request” input=” homeDef” parameter=”methodToCall”>
<forward name=”success” path=”targetDefName”/>
</action>


in your jsp you can call this action as 

<html:link action=”crudDispatchAction?methodToCall=create”>Create</html:link>
… 


Observe that the above class extends DispatchAction and so you cannot use this method if your class already extends your (some) super class (eg., the class where the session is validated/invalidated). Here the user has to send a query string variable (methodToCall) to set the action name to call.

ActionDispatcher: This flavor of aggregation is same as DispatchAction except that we need not extend ActionDispatcher, so we can use this method even if our class extends a super class. The following code snippet shows this scenario.


public final class CRUDActionDispatcher extends Action {

protected ActionDispatcher dispatcher = new ActionDispatcher(this, ActionDispatcher.DEFAULT_FLAVOR);

public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) throws Exception {
return dispatcher.execute(mapping, form, request, response);
}
The DEFAULT_FLAVOR field suggests that the default parameter is “method” if none is specified as parameter in struts-config.xml (eg,. methodToCall).
ActionDispatcher flavor also needs methodToCall parameter to be set (using hidden variable or a query string) as in case of DispatchAction.

LookupDispatchAction: This type of aggregation is useful in situations where in you have multiple submit buttons in a single form. The class must extend LookupDispatchAction. However, the great thing about this type is that its java script free. That means, you need not set any hidden variables or pass query string however, you must use submit buttons as shown.

<html:submit property=”submit”><bean:message key=”button.create”/></html: submit >
<html:submit property=”submit”><bean:message key=”button.read”/></html: submit >
… 
The example Action class will be as follows 

public class CRUDLookUpDispatchAction extends LookupDispatchAction {
protected Map getKeyMethodMap() {
Map map = new HashMap();
map.put(“button.create”, “create”);
?nbsp;
return map;
}
public ActionForward create(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) throws Exception {
return (mapping.findForward(“success”));
}
Observe the getKeyMethodMap() method. The submit button names are specified in a Map and their keys comes from MessageResources file. Struts picks up the name from this file and redirects it to the value specified in the Map. The calling code in jsp however has multiple submit buttons only differing in their names.

MappingDispatchAction: This aggregation extends MappingDispatchAction class. This is the most useful type among the four types available. But as seen in other cases, you can use this type only when your action does not extend any other action. The good thing about this type is that the action mappings can differ and so need not be the same as in all other cases. To illustrate this consider the below mappings.

<action path=”/createMappingAction” type=”com.bodhtree.CRUDMappingDispatchAction” scope=”request” input=”homeDef” parameter=”create”>
<forward name=”success” path=”targetDef”/>
</action>
<action path=”/readMappingAction” type=”com.bodhtree.CRUDMappingDispatchAction” name=” formName” scope=”request” input=”homeDef” parameter=” read”>
<forward name=”success” path=”targetDef”/>
</action> 


Notice that in the first action mapping, there is no form bean while in the second the bean name is specified. This means that the user has the flexibility to change the mapping according to his needs and hence not been contained to use a constant mapping for all the CRUD actions. Note that in all the other types of aggregations, we must use the same mapping for all the CRUD actions.

Conclusion: Each of these types has their own pros and cons. DispatchAction is the default type which uses java script and we must extend DispatchAction to use it, ActionDispatcher is same as DispathAction except that we do not extend any action , LookupDispatchAction gives the flexibility to use multiple submit buttons while MappingDispatchAction allows us to change the action mappings according to our need. So each one of these has a particular usage and which one to use depends on the user requirement.

Configuring Struts DataSource Manager on Tomcat 5

This tutorial shows you how you can configure Struts DataSource Manager on the Tomcat 5.5.9 server. We will use struts 1.2.7 in this tutorial. In this tutorial we will configure Struts DataSource Manager to use MySQL Database and use the connection provided by Struts DataSource in action class.


Downloading and Installing Tomcat 5.5.9
Download jakarta-tomcat-5.5.9 from http://jakarta.apache.org/tomcat/. Install it on your machine. Run and test the pages that comes with the tomcat.


Download Struts
Download Struts struts-1.2.7 from http://struts.apache.org/download.cgi and unzip it to your favorite directory. Go to the struts-1.2.7\webapps directory and then unzip struts-blank.war file. We will use this file to write our tutorial.


Download MySQL JDBC Driver
Download mysql-connector-java-3.0.16-ga-bin.jar from here mysql-connector-java-3.0.16-ga-bin.jar or you can download and use the latest version of mysql jdbc driver. Copy the JDBC driver file (mysql-connector-java-3.0.16-ga-bin.jar or latest version) to the jakarta-tomcat-5.5.9\common\lib directory of your tomcat installation. This will add the MySQL JDBC driver to the tomcat server.


Creating MySQL Database
In this tutorial I am using MySQL server installed on my local machine. You can download and install MySQL on your local machine and use for this tutorial. If you already have MySQL server then you can use the existing MySQL server.


Create database “strutsdatabase” on the MySQL server and then run the following query to create test table.






CREATE TABLE `test` (
`username` varchar(20) NOT NULL default ”
) TYPE=MyISAM;

/*Data for the table `test` */

insert into `test` values (‘rajesh’),(‘George’),(‘Vikas’),(‘Prakash’),(‘Mahesh’);


Above query creates test table and then populates the table with data.


Configuring Struts Application
Now create a directory “strutsdatabase” in the jakarta-tomcat-5.5.9\webapps\ directory and copy the content of struts-blank application (unzipped above) in the strutsdatabase directory.


Now start the tomcat and try to access the strutsdatabase application by typing the url http://localhost:8080/strutsdatabase in browser. Your browser should display the welcome page. After testing shutdown the tomcat server.


Configuring Struts DataSource Manager
The Struts DataSource manager makes it easy for your Action class get the database connection. To configure the Stuts DataSource Manager we will uncomment the <data-sources> entry in the struts-config.xml.


Uncomment and then <data-sources> entry in the struts-config.xml and then change the line


org.apache.commons.dbcp.BasicDataSource” to “org.apache.tomcat.dbcp.dbcp.BasicDataSource“. In tomcat 5.5.9 dbcp classes are packaged in naming-factory-dbcp.jar archieve, so we are using “org.apache.tomcat.dbcp.dbcp.BasicDataSource” instead of “org.apache.commons.dbcp.BasicDataSource”. After this change the database dirver, database url and passwor in the <data-sources> tag.


You <data-source> element should look like:






<data-sources>
<data-source type=”org.apache.tomcat.dbcp.dbcp.BasicDataSource“>
<set-property
property=”driverClassName”
value=”com.mysql.jdbc.Driver” />
<set-property
property=”url”
value=”jdbc:mysql://localhost:3306/strutsdatabase?autoReconnect=true” />
<set-property
property=”username”
value=”root” />
<set-property
property=”password”
value=”” />
<set-property
property=”maxActive”
value=”10″ />
<set-property
property=”maxWait”
value=”5000″ />
<set-property
property=”defaultAutoCommit”
value=”false” />
<set-property
property=”defaultReadOnly”
value=”false” />
<set-property
property=”validationQuery”
value=”SELECT COUNT(*) FROM test” />
</data-source>
</data-sources>

Create action Class to Test the DataSource
Now we will write the code of Action class for getting the connection form DataSource:





package test;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import java.sql.*;

public class TestDataSource extends Action
{
  public ActionForward execute(
    ActionMapping mapping,
    ActionForm form,
    HttpServletRequest request,
    HttpServletResponse responsethrows Exception{

       javax.sql.DataSource dataSource;
       java.sql.Connection myConnection=null;
       try {
        dataSource = getDataSource(request);
        myConnection = dataSource.getConnection();
        Statement stmt=myConnection.createStatement();
        ResultSet rst=stmt.executeQuery(“select username from test”);
        System.out.println(“******************************************”);
        System.out.println(“********Out Put from TestDataSource ******”);
        while(rst.next()){
        System.out.println(“User Name is: ” + rst.getString(“username”));
        }
        System.out.println(“******************************************”);
        rst.close();
        stmt.close();
        // do what you wish with myConnection
       catch (SQLException sqle) {
        getServlet().log(“Connection.process”, sqle);
       finally {
        //enclose this in a finally block to make
        //sure the connection is closed
        try {
           myConnection.close();
        catch (SQLException e) {
           getServlet().log(“Connection.close”, e);
        }
         }


      return mapping.findForward(“success”);
  }

Following code is used to get the data source and then connection from Struts DataSource:


dataSource = getDataSource(request);
myConnection = dataSource.getConnection();


Save this file(TestDataSource.java)  into jakarta-tomcat-5.5.9\webapps\strutsdatabase\WEB-INF\src\java\test directory. Add the servlet API into class path. Then open dos prompt and navigate to jakarta-tomcat-5.5.9\webapps\strutsdatabase\WEB-INF\src\ directory and issue run ant. This will compile the action class (TestDataSource.java) and copy it to the classes directory of the webapplication.


Creating Action Mapping struts-config.xml
Now add the following action mapping into the struts-config.xml:






<action
      path=”/DataSource”
      type=”test.TestDataSource”>
      <forward name=”success” path=”/success.jsp”/>
</action>

Running and testing
Start tomcat and browse the url http://localhost:8080/strutsdatabase/DataSource.do. Your browser should show the following output.



Now check tomcat console, it should display records fetched from database.


You can download my struts-config.xml from here.


Note: The DataSource manager is being retained in Struts 1.x for backward compatibility but may not be retained in Struts 2.x or later.

STRUTS INTERNATIONALIZATION

In this tutorial we shall see how to implement Internationalization (abbreviated as I18N) in Struts.

The Multinational Corporations have their branches in various parts of the world. so, they must provide products and services to their clients and customers in their traditional way. The customers will expect the product to work in their native languages especially the date, time, currency etc.,. So, the we should not make any assumptions about their clients region or language. If such assumptions become invalid, we have to re-engineer the applications.

Internationalization or I18N is the process of designing the software to support multiple languages and regions, so that we don’t need to re-engineer the applications every language or country needs to be supported.

Struts provides various locale sensitive JSP tags which can be used to make the applications simpler. With this short introduction we shall see how to implement i18n in a Simple JSP file of Struts.

g:\>md localedemo
g:\>cd localedemo
g:\localedemo>edit localedemo.jsp

// g:\localedemo\localedemo.jsp

<%@ page language=”java” %>

<%@ taglib uri=”/WEB-INF/struts-html.tld” prefix=”html” %>
<%@ taglib uri=”/WEB-INF/struts-bean.tld” prefix=”bean” %>
<%@ taglib uri=”/WEB-INF/struts-logic.tld” prefix=”logic” %>

<html:html locale=”true”>
<body bgcolor=pink>

<bean:message key=”index.info” />

</body>
</html:html>
————————————–



Next copy struts-blank.war to f:\tomcat41\webapps and start the tomcat with JAVA_HOME as jdk1.4. A folder named struts-blank will be created. Rename the folder as localedemo. Copy the above JSP file to f:\tomcat41\webapps\localedemo.

Now we have to edit the property files for various locales. The struts framework(struts1.1) provides a property file named application.properties. It is present in the folder f:\tomcat41\webapps\localedemo\web-inf\classes\resources. We have to add our own property file in this folder only. Our property file much be named along with the language code

For example the language code of
     1. German – de
     2. Spanish – es
     3. English – en
     4. Korean – ko
     5. French – fr
     6. Italy – it

So, when we write i18n message in German language it must be placed in property file named application_de.properties and all the properties files must be present in the resources folder only. Also when we write the property file of a particular language it need not be of the same language. For example we can create application_de.properties and write the message in french or english. In fact, the message does not depend on any language. It is a simple key value pair. The message we give for the key is just substituted. The property file to locate the value of key depends on the language settings of the browser. For this example, we will write four properties file as follows.

f:\tomcat41\webapps\localedemo\web-inf\classes\resources\ application_de.properties

index.info=GERMANY
———————————————————
f:\tomcat41\webapps\localedemo\web-inf\classes\resources\ application_es.properties

index.info=SPAIN
———————————————————–
f:\tomcat41\webapps\localedemo\web-inf\classes\resources\ application_en.properties

index.info=ENGLISH
———————————————————–
f:\tomcat41\webapps\localedemo\web-inf\classes\resources\ application_fr.properties

index.info=FRANCE
————————————————————
Also append this text in the application.properties file
    index.info=STRUTS TUTORIAL.

Now we have to add entry in the
struts-config.xml file for all the properties files. The entry and its corresponding portion is shown below.

<!– Message Resources Definitions –>

        <message-resources parameter=”resources.application_fr“/>
        <message-resources parameter=”resources.application_es“/>
        <message-resources parameter=”resources.application_en“/>
        <message-resources parameter=”resources.application_de“/>
        <message-resources parameter=”resources.application“/>

Now restart the Tomcat server. Open the Internet Explorer and type the URL as http://localhost:8080/localedemo/localedemo.jsp. We will get the message ‘ENGLAND’. This is because our default browser language is ‘United States English’.

Now we have to change the language settings of the browser to change the locale. For that, Open a new Internet Explorer, goto ‘Tools’ menu and select the ‘Internet Options’. In the ‘Internet Option’ dialog box, select ‘General’ tab and click the ‘Languages…’ button. We will get ‘Language Preference’ dialog box. There click ‘Add…’ button and add the languages. For this example add English, Spanish, German and French. Here we have languages specific to particular region. For example we have, French Belgium, French Canada, French France etc., we can select any one of these in all cases. Next select ‘German’ and by using the ‘Move up’ button, place it on the top. Now type the URL as http://localhost:8080/localedemo/localedemo.jsp. We will get the message ‘GERMAN’ Similarly place ‘Spanish’ and ‘French’ at the top, we will get the message ‘SPAIN’ and ‘FRANCE’ respectively.
—————————————————————————

Developing Struts PlugIn


This article shows you how to develop custom Struts PlugIn and incorporate in your Struts Web Applications. After completing this tutorial you will be able to create your own custom PlugIn for your web application. Struts PlugIn allows the programmer to enhance their web applications. There are many PlugIns available for struts e.g. Struts Tiles PlugIn, Struts Hibernate PlugIn, Struts Spring PlugIn etc. Beside these available PlugIn you can create your own PlugIn.


Understanding PlugIn


Struts PlugIns are configured using the <plug-in> element within the Struts configuration file. This element has only one valid attribute, ‘className’, which is the fully qualified name of the Java class which implements the org.apache.struts.action.PlugIn interface.


For PlugIns that require configuration themselves, the nested <set-property> element is available.


The plug-in tag in the struts-config.xml file is used to declare the PlugIn to be loaded at the time of server start-up. Following example shows how to declare the Tiles PlugIn:


<plug-in className=”org.apache.struts.tiles.TilesPlugin”>
    <set-property
        property=”definitions-config”
           value=”/WEB-INF/tiles-defs.xml”/>
</plug-in>


The above declaration instructs the struts to load and initialize the Tiles plugin for your application on startup. 


 


 


Writing Struts PlugIn Java Code


In this example we write HelloWorld Struts PlugIn example that will give you idea about creating, configuring and checking Struts PlugIn. Our HelloWorld Stuts PlugIn contains a method called Say Hello, which simply returns HelloWorld message.


Here is code of HelloWorld Struts Plugin: 






package roseindia.net.plugin;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import org.apache.struts.action.PlugIn;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.config.ModuleConfig;

/**
@author Deepak Kumar
* @Web http://www.roseindia.net
* @Email [email protected]
*/


public class HelloWorldStrutsPlugin implements PlugIn {


    public static final String PLUGIN_NAME_KEY 
            = HelloWorldStrutsPlugin.class.getName();

   public void destroy() {
      System.out.println(“Destroying Hello World PlugIn”);
   }

   public void init(ActionServlet servlet, ModuleConfig config
throws ServletException {
      System.out.println(“Initializing Hello World PlugIn”);
   ServletContext context = null;
   context = servlet.getServletContext();
   HelloWorldStrutsPlugin objPlugin = new HelloWorldStrutsPlugin();
   context.setAttribute(PLUGIN_NAME_KEY, objPlugin);

   }

  public String sayHello(){
    System.out.println(“Hello Plugin”);
    return “Hello Plugin”;
  }
  
}


Configuring PlugIn


To configure the plugin add the following line your struts-config.xml file.


<plug-in className=”roseindia.net.plugin.HelloWorldStrutsPlugin”>
</plug-in>


Calling PlugIn From JSP Page


Here is the code for calling our PlugIn from jsp page.






<%@page contentType=”text/html” import=”java.util.*,roseindia.net.plugin.*” %>
<%

ServletContext servletContext = this.getServletContext();


HelloWorldStrutsPlugin plugin= (HelloWorldStrutsPlugin) servletContext.getAttribute
(HelloWorldStrutsPlugin.PLUGIN_NAME_KEY);

String strMessage = plugin.sayHello();


%>

Message From Plugin: <%=strMessage%>


Building and Testing


Use ant tool to build the application and then deploy on the server. Enter the url http://localhost:8080/strutstutorial/pages/plugin.jsp in your browser. It display “Hello Plugin” message. Your server console also should display “Hello Plugin” message.


In this section we learnt how to develop simple struts plugin, configure, deploy and test.

Struts nested tag Example

The tag library 忛ested?is included in Struts 1.1. In this tutorial we are going to explain what are the features of nested tag library and how you can use it. We can manage nested beans easily with the help of struts nested tag library. 


Nested tags are used in the nested context. The Nested tags and its supporting classes extends the base struts tags and making them possible to relate to each other in the nested fashion. In case of Nested tags the original logic of the tags does not change and all the references to beans and bean properties is managed in the nested context.


As far as bean is concerned, one is associated with another internally and access to all the beans are  through the current one. The beans that refers to another is the parent and the second related to the first one is its child. Here both ‘parent’ and ‘child’ denotes a hierarchical structure of beans. 
    
For example, Take an object which represents a Author. Each author  related to many book  .If this case was translated to bean objects, 
the author object would have a reference to the book objects he wrote, and each bunch object would hold a reference to
the chapters in the books.

The author object is the parent to the books object, and the books object is a child of the author object. The books object
is parent to its child chapters objects, and the child chapters objects children of the books object. The author is higher in
the hierarchy than the books, and the chapters lower in the hierarchy to the books.



Herbert Schildt
   
Teach Yourself C++
    Java: The Complete Reference, J2SE
    Struts: the complete reference
O’Reilly
   
.NET & XML
    ADO.NET in a Nutshell
    ADO: ActiveX Data Objects

Create a new struts 1.1 project to to understand nested tags.


Object Class Books
Create a class Books with properties id and name in the package roseindia.web.common.
Add a getter and setter method for each property.
Also add  a constructor that initialize the properties.

Books.java






package roseindia.web.common;
public class Books {

private int id;
private String name;

//constructors
public Books(){}

public Books(int id, String name){
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}


Object Class Authors
Create a second java class Authors in the same package roseindia.web.common.
Add two properties, id of type int and name of type String and one property books of type Collection, which holds a list of books.
Add a getter and setter method for each property.
Also add  a constructor that initialize the properties.

Authors.java






package roseindia.web.common;
import java.util.*;
public class Authors {
	private int id;
private String name;
	//books collection
private Collection books;
	//constructors
public Authors() {}
public Authors(int id, String name, Collection books){
this.id = id;
this.name = name;
this.books = books;
}
	public Collection getBooks() {
return books;
}
public void setBooks(Collection books) {
this.books = books;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}


Action form class AuthorsBooksForm
Create a java class AuthorsBooksForm in the package roseindia.web.struts.form, which extends the class ActionForm of struts.
Add a property authors of type Authors .
Add a getter and setter method for the property authors .

Implement the reset() method of the ActionForm class. 

AuthorsBooksForm.java






package roseindia.web.struts.form;
import java.util.*;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import roseindia.web.common.Authors;
import roseindia.web.common.Books;
public class AuthorsBooksForm extends ActionForm {
	Authors authors;

public void setAuthors(Authors authors) {
this.authors = authors;
}
	public Authors getAuthors() {
return authors;
}
	public void reset(ActionMapping mapping,HttpServletRequest request) {
		//initial a dummy collection of books
Collection books = new ArrayList();
		books.add(new Books(1, “Teach Yourself C++”));
books.add(new Books(2, “Java: The Complete Reference, J2SE”));
books.add(new Books(3, “Struts: The Complete Reference”));

//initial a dummy authors
authors = new Authors(1, “Herbert Schildt”, books);

}
}


Action class AuthorsBooksAction 

Create a java class AuthorsBooksAction in the package roseindia.web.struts.action, which extends the class Action of struts.
Return the forward example.

AuthorsBooksAction.java






package roseindia.web.struts.action;
import roseindia.web.struts.form.AuthorsBooksForm;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

public class AuthorsBooksAction extends Action {

public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) {
AuthorsBooksForm booksForm = (AuthorsBooksForm) form;
		return mapping.findForward(“books”);
}
}


The JSP file


Create a new JSP file authorsbooks.jsp.
Add the reference to the tag library nested at the top of the file.


authorsbooks.jsp






<%@ page language=”java”%>
<%@ taglib uri=”/tags/struts-bean” prefix=”bean” %>
<%@ taglib uri=”/tags/struts-html” prefix=”html” %>
<%@ taglib uri=”/tags/struts-logic” prefix=”logic” %>
<%@ taglib uri=”/tags/struts-nested” prefix=”nested”%>
<html>
<head>
<title>Struts nested tag Example</title>
</head>
<body>
<h1>Struts nested tag Example</h1>
	  <b>Author and his books:</b>
<html:form action=”/example” method=”post”>
			<nested:nest property=”authors”>
				<b><nested:write property=”name”/> </b>
<nested:iterate property=”books”>
					<ul><li><nested:write property=”name”/></li></ul>
</nested:iterate>
</nested:nest>

		</html:form>
</body>
</html>


Configure the struts-config.xml


Open the struts-config.xml and add the form bean and action mapping.


struts-config.xml






 <form-beans>
<form-bean name=”AuthorsBooksForm”
type=”roseindia.web.struts.form.AuthorsBooksForm” />
</form-beans>
<action-mappings>
<action
path=”/example”
type=”roseindia.web.struts.action.AuthorsBooksAction”
input=”/pages/user/authorsbooks.jsp”
name=”AuthorsBooksForm”
scope=”request”
validate=”false”>
<forward name=”example” path=”/pages/user/authorsbooks.jsp” />
</action>
</action-mappings>



Output:
To view the output run the authorsbooks.jsp from the browser.

Struts Logic Tags

Struts Logic Tags examples.



  1. Introduction to Struts Logic Tags
    Struts logic tags are conditional tags that replaces scriptlets in the jsp files.
     

  2. Logic Empty and notEmpty Tags
    Tag evaluation of the nested body content occurs only if the specified value is either absent (i.e. null), an empty string (i.e. a java.lang.String with a length of zero)
      

  3. Logic Equal and notEqual Tags
    if the requested variable is equal to the specified value then this tag is used to evaluate the contents contained in the nested body parts of this tag
      

  4. Logic greaterEqual and greaterThan Tags
    This tag compares the variable against the specified constant value. If the variable is greater than or equal to the specified value then the nested body contents of this tag is evaluated
      

  5. Logic lessEqual and lessThan Tags
    This tag compares the variable against the specified constant value. If the variable is less than or equal to the specified value then the nested body contents of this tag is evaluated
      

  6. Logic match and notMatch Tags
    This tag matches the variable specified as a String against the specified constant value. If the value is a substring  then the nested body content of this tag is evaluated.
      

  7. Logic present and notPresent Tags
    This tag checks the current request and depending on which attribute is specified, it evaluates the nested body content of this tag only if the specified value is present.


Struts Logic Tags: An Introduction

Struts logic tags are conditional tags that replaces scriptlets in the jsp files.


This tag library contains tags that do the following things :
    conditional generation of the output text,
    generate iterations to output the text,
    application flow management,
    matching strings and substrings…


Logic tags available in the Struts Framework


























































Tag Name Description
empty  If the requested variable is either null or an empty string then the nested body content of this tag is evaluated
equal  If the requested variable is equal to the specified value then the nested body content of this tag is evaluated
forward  It forwards the control to the page specified by the specified ActionForward entry.
greaterEqual If the value of the requested variable is greater than or equal to the specified value then the nested body content of this tag is evaluated
greaterThan  If the value of the requested variable is greater than the specified value then the nested body content of this tag is evaluated
iterate  It repeats the nested body content of this tag over a specified collection.
lessEqual  If the value of the requested variable is less than or equal to the specified value then the nested body content of this tag is evaluated
lessThan If the value of the requested variable is less than the specified value then the nested body content of this tag is evaluated
match Evaluates the nested body content of this tag if the specified value is an appropriate substring of the requested variable.
messagesNotPresent If the specified message is not present in the request then it generates the nested body content of this tag .
messagesPresent If the specified message is present in this request then it generates the nested body content of this tag .
notEmpty If the requested variable is neither null nor an empty string nor an empty java.util.Collection (tested by the isEmpty() method on the java.util.Collection interface) then the nested body content of this tag is evaluated
notEqual If the requested variable is not equal to the specified value then the nested body content of this tag is evaluated
notMatch If the specified value is not an appropriate substring of the requested variable then the nested body content of this tag is evaluated 
notPresent If the specified value is not present in the request then it generates the nested body content of this tag .
present If the specified value is present in the request then it generates the nested body content of this tag 
redirect It renders an HTTP Redirect request.

Struts logic tags uses equal, greaterEqual, greaterThan, lessEqual, lessThan, notEqual tags to compare the values. There are rules that must be  followed :



  • Initially the specified variable needed to be compared is examined (whether it can be converted to a double or to a long). Then a  numeric (either floating point or integer) type comparison is done. If numeric conversion fails than a String comparison is performed.
  • The variable to be compared is retrieved from the request attribute(s)  that may be a cookie, header, name, parameter or property available to the specified tag. This variable is then converted to the appropriate type needed for the comparison..
  • If the variable or property to be compared returns null, it is converted into a zero-length string before the comparison occurs.
  • If the comparison logic returns a true value then only the specific comparison is performed and subsequently the nested body content is evaluated .

Struts logic tags  can also do the substring matching using the tags (match, notMatch). There are rules that must be  followed :



  • The variable to be compared is retrieved from the request attribute(s)  that may be a cookie, header, name, parameter or property available on this tag. Then this variable is converted to a String, if necessary.
  • If the retrieval of the variable fails or it contains a null value then a request time exception is thrown.  
  • The existence of the variable as a substring is examined at the position specified by the location attribute Location can be specified at the beginning (if location is set to start), at the end (if location is set to end), or anywhere (if location is not specified).

A JspException is thrown at runtime if any tag is utilized incorrectly or any invalid combination of tag attributes are used. To process the actual exception that caused the problem,  a request attribute under key org.apache.struts.action.EXCEPTION  is passed to the error page.


In the subsequent section we will show you the examples of these tags.