定义好规则和配置格式,就可以开始动手写代码了,首先,需要两个class来保存表的信息和字段信息,还需要从表的xml文件中提取出表的信息,代码如下:
Field.java
package com . bang . dev . autocoder ;
public class Field {
private String fieldLabel ; //字段标签
private String fieldComment ; //注释
private String fieldName ; //字段名
private String fieldClassName ; //转换以后的java类名
private String fieldType ; //字段类型
private String fieldClassType ; //转换以后的java类型
private int fieldLen ; //字段长度
private int fieldNull ; //字段空标志
private boolean readOnly ; //只读标志
private String fieldFormType ; //保留,表单类型
private String fieldSeq ; //序列
private String defaultValue ; //默认值
public String getDefaultValue () {
return defaultValue ;
}
public void setDefaultValue ( String defaultValue ) {
this . defaultValue = defaultValue ;
}
public void setFieldType ( String fieldType ) {
this . fieldType = fieldType ;
}
public void setFieldName ( String fieldName ) {
this . fieldName = fieldName ;
}
public void setFieldLen ( int fieldLen ) {
this . fieldLen = fieldLen ;
}
public void setFieldNull ( int fieldNull ) {
this . fieldNull = fieldNull ;
}
public void setReadOnly ( boolean readOnly ) {
this . readOnly = readOnly ;
}
public int getFieldLen () {
return fieldLen ;
}
public String getFieldName () {
return fieldName ;
}
public String getFieldType () {
return fieldType ;
}
public int getFieldNull () {
return fieldNull ;
}
public boolean isReadOnly () {
return readOnly ;
}
public String getFieldClassName () {
return fieldClassName ;
}
public void setFieldClassName ( String fieldClassName ) {
this . fieldClassName = fieldClassName ;
}
public String getFieldClassType () {
return fieldClassType ;
}
public String getFieldLabel () {
return fieldLabel ;
}
public String getFieldFormType () {
return fieldFormType ;
}
public String getFieldSeq () {
return fieldSeq ;
}
public void setFieldClassType ( String fieldClassType ) {
this . fieldClassType = fieldClassType ;
}
public void setFieldLabel ( String fieldLabel ) {
this . fieldLabel = fieldLabel ;
}
public void setFieldFormType ( String fieldFormType ) {
this . fieldFormType = fieldFormType ;
}
public void setFieldSeq ( String fieldSeq ) {
this . fieldSeq = fieldSeq ;
}
public String getFieldComment () {
return fieldComment ;
}
public void setFieldComment ( String fieldComment ) {
this . fieldComment = fieldComment ;
}
}
Table.java
package com . bang . dev . autocoder ;
import java . io . DataInputStream ;
import java . io . FileInputStream ;
import java . util . ArrayList ;
import java . util . HashMap ;
import java . util . List ;
import org . jdom . Document ;
import org . jdom . Element ;
import org . jdom . input . SAXBuilder ;
import com . infinitouch . xiaowei . autocode . Field ;
public class Table {
private String tableName ;
private String tableClassName ;
private String tableShortName ;
private ArrayList tableFields ;
private ArrayList primaryKeys ;
private String display ;
public String getDisplay () {
return display ;
}
public void setDisplay ( String display ) {
this . display = display ;
}
public ArrayList getPrimaryKeys () {
return primaryKeys ;
}
public void setPrimaryKeys ( ArrayList primaryKeys ) {
this . primaryKeys = primaryKeys ;
}
public String getTableClassName () {
return tableClassName ;
}
public void setTableClassName ( String tableClassName ) {
this . tableClassName = tableClassName ;
}
public ArrayList getTableFields () {
return tableFields ;
}
public void setTableFields ( ArrayList tableFields ) {
this . tableFields = tableFields ;
}
public String getTableName () {
return tableName ;
}
public void setTableName ( String tableName ) {
this . tableName = tableName ;
}
public String getTableShortName () {
return tableShortName ;
}
public void setTableShortName ( String tableShortName ) {
this . tableShortName = tableShortName ;
}
public static Table parse ( String fileName ) throws Exception
{
Table t = new Table ();
ArrayList fieldList = new ArrayList ();
HashMap fieldMap = new HashMap ();
ArrayList pkList = new ArrayList ();
SAXBuilder sb = new SAXBuilder (); //建立构造器
DataInputStream in = new DataInputStream ( new FileInputStream ( fileName ));
Document doc = sb . build ( in ); //读入stream流
Element root = doc . getRootElement (); //获得根节点
Element fields = root . getChild ( "fields" );
List list = fields . getChildren ();
for ( int i = 0 ; i < list . size (); i ++)
{
Element e = ( Element ) list . get ( i );
Field f = new Field ();
f . setFieldClassName ( e . getChild ( "class-name" ). getText ());
f . setFieldName ( e . getChild ( "name" ). getText ());
f . setFieldClassType ( e . getChild ( "class-type" ). getText ());
f . setFieldFormType ( e . getChild ( "form-type" ). getText ());
f . setFieldLabel ( e . getChild ( "label" ). getText ());
f . setFieldLen ( Integer . parseInt ( e . getChild ( "length" ). getText ()));
f . setFieldNull ( Integer . parseInt ( e . getChild ( "null" ). getText ()));
f . setFieldType ( e . getChild ( "type" ). getText ());
f . setReadOnly ( Boolean . getBoolean ( e . getChild ( "readonly" ). getText ()));
if ( e . getChild ( "default" ) != null )
f . setDefaultValue ( e . getChild ( "default" ). getText ());
else
f . setDefaultValue ( "" );
if ( e . getChild ( "seq" ) != null )
f . setFieldSeq ( e . getChild ( "seq" ). getText ());
else
f . setFieldSeq ( "" );
if ( e . getChild ( "comment" ) != null )
f . setFieldComment ( e . getChild ( "comment" ). getText ());
else
f . setFieldComment ( e . getChild ( "label" ). getText ()); //默认以label作为注释
fieldList . add ( f );
fieldMap . put ( f . getFieldName (), f );
}
Element pks = root . getChild ( "pks" );
list = pks . getChildren ();
for ( int i = 0 ; i < list . size (); i ++)
{
Element e = ( Element ) list . get ( i );
String name = e . getChild ( "name" ). getText ();
pkList . add ( fieldMap . get ( name ));
}
Element name = root . getChild ( "name" );
t . setTableName ( name . getText ());
Element class_name = root . getChild ( "class-name" );
t . setTableClassName ( class_name . getText ());
Element short_name = root . getChild ( "short-name" );
t . setTableShortName ( short_name . getText ());
Element display = root . getChild ( "display" );
t . setDisplay ( display . getText ());
//设置主键
t . setPrimaryKeys ( pkList );
//设置表字段
t . setTableFields ( fieldList );
return t ;
}
}
另外需要保存读取进来的配置文件的class,代码如下:
AutoCoderConfig.java
package com . bang . dev . autocoder ;
import java . io . DataInputStream ;
import java . io . FileInputStream ;
import java . util . List ;
import java . util . Vector ;
import org . jdom . Document ;
import org . jdom . Element ;
import org . jdom . input . SAXBuilder ;
public class AutoCoderConfig {
private String saveToPath ; //生成代码的保存路径
private String tableFileName ; //读取表名的文件
private String dbDriver ; //数据库驱动
private String dbUrl ; //数据库URL
private String dbUsername ; //数据库用户名
private String dbPassword ; //数据库密码
private Vector tmpVector ;
private Vector otherClass ;
private boolean dbFlag ;
public boolean isDbFlag () {
return dbFlag ;
}
public void setDbFlag ( boolean dbFlag ) {
this . dbFlag = dbFlag ;
}
public String getDbDriver () {
return dbDriver ;
}
public void setDbDriver ( String dbDriver ) {
this . dbDriver = dbDriver ;
}
public String getDbPassword () {
return dbPassword ;
}
public void setDbPassword ( String dbPassword ) {
this . dbPassword = dbPassword ;
}
public String getDbUrl () {
return dbUrl ;
}
public void setDbUrl ( String dbUrl ) {
this . dbUrl = dbUrl ;
}
public String getDbUsername () {
return dbUsername ;
}
public void setDbUsername ( String dbUsername ) {
this . dbUsername = dbUsername ;
}
public Vector getOtherClass () {
return otherClass ;
}
public void setOtherClass ( Vector otherClass ) {
this . otherClass = otherClass ;
}
public String getSaveToPath () {
return saveToPath ;
}
public void setSaveToPath ( String saveToPath ) {
this . saveToPath = saveToPath ;
}
public String getTableFileName () {
return tableFileName ;
}
public void setTableFileName ( String tableFileName ) {
this . tableFileName = tableFileName ;
}
public Vector getTmpVector () {
return tmpVector ;
}
public void setTmpVector ( Vector tmpVector ) {
this . tmpVector = tmpVector ;
}
public static AutoCoderConfig readConfig ( String name ) throws Exception {
AutoCoderConfig config = new AutoCoderConfig ();
SAXBuilder sb = new SAXBuilder (); //建立构造器
DataInputStream in = new DataInputStream ( new FileInputStream (
name ));
Document doc = sb . build ( in ); //读入stream流
Element root = doc . getRootElement (); //获得根节点
Element file_path = root . getChild ( "file-path" );
config . saveToPath = file_path . getText ();
Element table_file = root . getChild ( "table-file" );
config . tableFileName = table_file . getText ();
//数据库配置
Element db_element = root . getChild ( "database" );
Element db_driver = db_element . getChild ( "driver" );
config . dbDriver = db_driver . getText ();
Element db_url = db_element . getChild ( "url" );
config . dbUrl = db_url . getText ();
Element db_username = db_element . getChild ( "username" );
config . dbUsername = db_username . getText ();
Element db_password = db_element . getChild ( "password" );
config . dbPassword = db_password . getText ();
Element db_flag = db_element . getChild ( "dbflag" );
if ( db_flag == null )
config . dbFlag = false ;
else
config . dbFlag = Boolean . parseBoolean ( db_flag . getText ());
//模板配置
Element templates = root . getChild ( "templates" );
List list = templates . getChildren ();
config . tmpVector = new Vector ();
for ( int i = 0 ; i < list . size (); i ++) {
MyTemplate myTmp = new MyTemplate ();
Element tmp = ( Element ) list . get ( i );
myTmp . tmpClassName = tmp . getChild ( "class-name" ). getText ();
myTmp . tmpFile = tmp . getChild ( "template-file" ). getText ();
myTmp . tmpPackage = tmp . getChild ( "java-package" ). getText ();
myTmp . tmpType = tmp . getChild ( "template-type" ). getText ();
config . tmpVector . add ( myTmp );
}
//生成其它class配置
Element table_templates = root . getChild ( "table-templates" );
//Element template = root.getChild("template");
list = table_templates . getChildren ();
config . otherClass = new Vector ();
for ( int i = 0 ; i < list . size (); i ++) {
MyTemplate myTmp = new MyTemplate ();
Element tmp = ( Element ) list . get ( i );
myTmp . tmpClassName = tmp . getChild ( "class-name" ). getText ();
myTmp . tmpFile = tmp . getChild ( "template-file" ). getText ();
myTmp . tmpPackage = tmp . getChild ( "java-package" ). getText ();
myTmp . tmpType = tmp . getChild ( "template-type" ). getText ();
config . otherClass . add ( myTmp );
}
in . close ();
return config ;
}
}
这三个是基本的类,下边的代码都是基于这三个class操作的,需要从数据库提取出表的信息的class,封装了对数据库的操作:
DBUtil.java
package com . bang . dev . autocoder ;
import java . sql . Connection ;
import java . sql . DatabaseMetaData ;
import java . sql . DriverManager ;
import java . sql . ResultSet ;
import java . sql . ResultSetMetaData ;
import java . sql . SQLException ;
import java . sql . Statement ;
import java . util . ArrayList ;
import java . util . HashMap ;
import java . util . StringTokenizer ;
public class DBUtil {
private static DBUtil instance = null ;
private Connection conn = null ;
private AutoCoderConfig config ;
public void openConnection ()
{
try {
Class . forName ( config . getDbDriver ());
conn = DriverManager . getConnection ( config . getDbUrl (), config . getDbUsername (), config . getDbPassword ());
} catch ( Exception ex ) {
ex . printStackTrace ();
conn = null ;
System . out . println ( "db connect error!" );
System . exit (- 1 );
}
}
public void closeConnection ()
{
if ( conn != null )
{
try
{
conn . close ();
} catch ( Exception e )
{
e . printStackTrace ();
}
}
}
private DBUtil ()
{
}
public static DBUtil getInstance ( AutoCoderConfig config )
{
if ( instance == null )
instance = new DBUtil ();
instance . config = config ;
return instance ;
}
public static String getShortName ( String tName ){
String ret = "" ;
for ( int i = 0 ; i < tName . length (); i ++){
if ( tName . charAt ( i ) >= 'A' && tName . charAt ( i ) <= 'Z' ){
ret += tName . charAt ( i );
}
}
return ret . toLowerCase ();
}
public static String dbToClass ( String dbFieldName ){
String ret = "" ;
StringTokenizer token = new StringTokenizer ( dbFieldName , "_" );
while ( token . hasMoreTokens ()){
String t = token . nextToken ();
ret += t . substring ( 0 , 1 ). toUpperCase () + t . substring ( 1 );
}
ret = ret . substring ( 0 , 1 ). toLowerCase () + ret . substring ( 1 );
return ret ;
}
public static String classToDb ( String classFieldName ){
String ret = "" ;
boolean next = false ;
for ( int i = 0 ; i < classFieldName . length (); i ++){
String t = classFieldName . substring ( i , i + 1 );
if ( t . charAt ( 0 )>= 'A' && t . charAt ( 0 )<= 'Z' && i > 0 ){
next = true ;
}
if ( next ){
ret += "_" + t . toLowerCase ();
next = false ;
} else
ret += t ;
}
ret = ret . substring ( 0 , 1 ). toLowerCase () + ret . substring ( 1 );
return ret ;
}
private ArrayList getFieldList ( String tableName ){
ArrayList fieldList = new ArrayList ();
tableName = tableName . toLowerCase ();
try {
Statement stmt = conn . createStatement ();
ResultSet rs = stmt . executeQuery ( "select * from " + tableName );
ResultSetMetaData rsmd = rs . getMetaData ();
int colCount = rsmd . getColumnCount ();
for ( int i = 1 ; i <= colCount ; i ++){
String name = rsmd . getColumnName ( i ). toLowerCase ();
String type = rsmd . getColumnTypeName ( i );
String classType = dbTypeToClassType ( type );
int len = rsmd . getColumnDisplaySize ( i );
int n = rsmd . isNullable ( i );
boolean b = rsmd . isReadOnly ( i );
String fcName = dbToClass ( name );
Field f = new Field ();
f . setFieldLen ( len );
f . setFieldName ( name );
f . setFieldClassName ( fcName );
f . setFieldType ( type );
f . setFieldNull ( n );
f . setReadOnly ( b );
f . setFieldClassType ( classType );
fieldList . add ( f );
}
} catch ( Exception e ){
e . printStackTrace ();
} finally {
}
return fieldList ;
}
public Table getTableInfo ( String tableName ) throws SQLException {
Table t = new Table ();
ArrayList fieldList = getFieldList ( tableName );
ArrayList pList = getPrimaryKeys ( tableName );
t . setTableName ( tableName );
t . setPrimaryKeys ( pList );
t . setTableFields ( fieldList );
t . setTableClassName ( dbToClass ( tableName ). substring ( 0 , 1 ). toUpperCase () + dbToClass ( tableName ). substring ( 1 ));
t . setTableShortName ( getShortName ( t . getTableClassName ()));
return t ;
}
public ArrayList getPrimaryKeys ( String keyTable ) throws SQLException {
keyTable = keyTable . toUpperCase ();
ArrayList fList = getFieldList ( keyTable );
ArrayList pList = new ArrayList ();
DatabaseMetaData dbmd = conn . getMetaData ();
ResultSet rs = dbmd . getPrimaryKeys ( null , null , keyTable );
while ( rs . next ()) {
String fName = rs . getString ( "COLUMN_NAME" ). toLowerCase ();
for ( int i = 0 ; i < fList . size (); i ++){
Field f = ( Field ) fList . get ( i );
if ( f . getFieldName (). toLowerCase (). equals ( fName ))
pList . add ( f );
}
}
return pList ;
}
public String dbTypeToClassType ( String dbType ){
String ret ;
HashMap map = new HashMap ();
dbType = dbType . toUpperCase ();
map . put ( "TINYINT" , "String" );
map . put ( "NVARCHAR" , "String" );
map . put ( "INT" , "int" );
map . put ( "FLOAT" , "float" );
map . put ( "INTEGER" , "int" );
map . put ( "NUMBER" , "int" );
map . put ( "DOUBLE" , "double" );
map . put ( "TINYINT" , "int" );
map . put ( "REAL" , "double" );
map . put ( "TEXT" , "String" );
map . put ( "LONGTEXT" , "String" );
map . put ( "CHAR" , "String" );
map . put ( "DATA" , "java.util.Date" );
ret = ( String ) map . get ( dbType );
if ( ret == null )
ret = "String" ;
return ret ;
}
}
上边的代码中,dbTypeToClassType方法是做数据库和java类型之间的映射,这个本来可以用ResultSetMetaData 来获取的,但这里为了方便,直接做了几个类型的映射。
还有一个辅助的类,保存模板的各种信息,比如文件名、类型等等
MyTemplate.java
package com . bang . dev . autocoder ;
public class MyTemplate {
public String tmpFile ;
public String tmpPackage ;
public String tmpClassName ;
public String tmpType ;
}
接下来是最重要的一个class,生成代码的class
AutoCoder.java
package com . bang . dev . autocoder ;
import java . io .*;
import java . util .*;
import org . apache . velocity . Template ;
import org . apache . velocity . VelocityContext ;
import org . apache . velocity . app . Velocity ;
import org . apache . velocity . exception . ParseErrorException ;
import org . apache . velocity . exception . ResourceNotFoundException ;
public class AutoCoder {
private AutoCoderConfig config ;
private DBUtil db ;
public AutoCoderConfig getConfig () {
return config ;
}
public void setConfig ( AutoCoderConfig config ) {
this . config = config ;
}
public AutoCoder ( String fileName )
{
try {
config = AutoCoderConfig . readConfig ( fileName );
db = DBUtil . getInstance ( config );
} catch ( Exception e ) {
e . printStackTrace ();
}
}
/**
* 检查包的路径是否存在,如果不存在,创建
* @param pkg String
* @param path String
*/
private String checkPackage ( String pkg , String path ) {
File file = new File ( path );
String split = System . getProperty ( "file.separator" );
if (! file . exists ())
file . mkdir ();
StringTokenizer token = new StringTokenizer ( pkg , "." );
String subPath = "" ;
while ( token . hasMoreTokens ()) {
String dir = token . nextToken ();
subPath += ( split + dir );
if ( path . endsWith ( split ))
path += dir ;
else
path += split + dir ;
File newFile = new File ( path );
if (! newFile . exists ())
newFile . mkdir ();
}
return path ;
}
/**
* 读取数据表信息
* @param dbFlag true从数据库中读取 false从文件中读取
* @return
*/
private ArrayList loadTableInfo ()
{
File f = new File ( config . getTableFileName ());
ArrayList tableList = new ArrayList ();
BufferedReader reader ;
try {
reader = new BufferedReader ( new FileReader ( f ));
String line = "" ;
while ( line != null ) {
line = reader . readLine ();
if ( line == null )
break ;
if ( line . startsWith ( "#" ))
continue ;
tableList . add ( line );
}
} catch ( Exception e ) {
e . printStackTrace ();
return null ;
}
ArrayList retList = new ArrayList ();
for ( int i = 0 ; i < tableList . size (); i ++)
{
String tableName = ( String ) tableList . get ( i );
Table table ;
try {
if ( config . isDbFlag ())
{
db . openConnection ();
table = db . getTableInfo ( tableName );
db . closeConnection ();
}
else
table = Table . parse ( "tables/" + tableName + ".xml" );
} catch ( Exception e )
{
e . printStackTrace ();
continue ;
}
retList . add ( table );
}
return retList ;
}
private void makeTablesFile ( List list , String vmFile , String destFile ) throws Exception
{
Velocity . init ();
Template template = Velocity . getTemplate ( vmFile , "gb2312" );
VelocityContext context = new VelocityContext ();
context . put ( "list" , list );
StringWriter s = new StringWriter ();
PrintWriter writer = new PrintWriter ( s , true );
template . merge ( context , writer );
writer . close ();
String ctx = s . getBuffer (). toString ();
String content = "" ;
try {
File file = new File ( destFile );
FileInputStream in = new FileInputStream ( file );
int len = in . available ();
byte [] b = new byte [ len ];
in . read ( b );
content = new String ( b );
} catch ( Exception e ) {
content = ctx ;
}
String fileContent = ctx ;
PrintWriter pw = new PrintWriter ( new FileOutputStream ( destFile ));
pw . print ( fileContent );
pw . close ();
}
public Table makeJavaClass ( Table t , String vmFile , String destFile ,
String basePackage , boolean overWriteFlag ) throws ResourceNotFoundException ,
ParseErrorException , Exception {
Velocity . init ();
Template template = Velocity . getTemplate ( vmFile , "gb2312" );
VelocityContext context = new VelocityContext ();
context . put ( "table" , t );
context . put ( "package" , basePackage );
StringWriter s = new StringWriter ();
PrintWriter writer = new PrintWriter ( s , true );
template . merge ( context , writer );
writer . close ();
String ctx = s . getBuffer (). toString ();
String content = "" ;
try {
File file = new File ( destFile );
FileInputStream in = new FileInputStream ( file );
int len = in . available ();
byte [] b = new byte [ len ];
in . read ( b );
content = new String ( b );
} catch ( Exception e ) {
content = ctx ;
}
if ( content . startsWith ( "//DO NOT CHANGE THIS FILE" ))
return t ;
String fileContent = "" ;
if (! overWriteFlag )
{
String start = "//start your code here/r/n" ;
String end = "//finish your code here/r/n" ;
String endofile = "}//end of file" ; //标志
int index1 = content . indexOf ( start ) + start . length ();
int endindex = ctx . indexOf ( endofile );
if ( endindex < 0 )
endindex = content . length () - 1 ;
if ( index1 <= start . length ()) {
fileContent = ctx . substring ( 0 , endindex );
fileContent += "/r/n/r/n" ;
fileContent += start + "/r/n" ;
fileContent += end + "/r/n" ;
fileContent += "/r/n/r/n" ;
fileContent += endofile ;
} else {
int index2 = content . indexOf ( end );
String yourcode = content . substring ( index1 , index2 );
fileContent = ctx . substring ( 0 , endindex );
fileContent += "/r/n/r/n" ;
fileContent += start ;
fileContent += yourcode ;
fileContent += end ;
fileContent += "/r/n/r/n" ;
fileContent += endofile ;
}
} else
fileContent = ctx ;
PrintWriter pw = new PrintWriter ( new FileOutputStream ( destFile ));
pw . print ( fileContent );
pw . close ();
return t ;
}
public static void main ( String [] arg )
{
String configFile = "config.xml" ;
if ( arg . length > 0 )
configFile = arg [ 0 ];
AutoCoder coder = new AutoCoder ( configFile );
ArrayList list = coder . loadTableInfo ();
AutoCoderConfig config = coder . getConfig ();
List tableVector = config . getTmpVector ();
List templatesVector = config . getOtherClass ();
for ( int i = 0 ; i < list . size (); i ++)
{
Table table = ( Table ) list . get ( i );
for ( int j = 0 ; j < tableVector . size (); j ++)
{
MyTemplate mytmp = ( MyTemplate ) tableVector . get ( j );
String tableClassName = table . getTableClassName ();
String fileName = mytmp . tmpClassName . replaceAll ( "CLASSNAME" , tableClassName );
fileName = fileName . replaceAll ( "TABLENAME" , table . getTableName ());
String filePath = coder . checkPackage ( mytmp . tmpPackage , config . getSaveToPath ());
filePath += System . getProperty ( "file.separator" ) + fileName ;
System . out . print ( "正在为表" + table . getTableName () + "生成文件" + fileName + "..." );
try
{
coder . makeJavaClass ( table , mytmp . tmpFile , filePath , mytmp . tmpPackage ,! mytmp . tmpType . equals ( "java" ));
} catch ( Exception e )
{
e . printStackTrace ();
}
System . out . println ( "OK!" );
}
}
for ( int j = 0 ; j < templatesVector . size (); j ++)
{
MyTemplate mytmp = ( MyTemplate ) templatesVector . get ( j );
String fileName = mytmp . tmpClassName ;
String filePath = coder . checkPackage ( mytmp . tmpPackage , config . getSaveToPath ());
filePath += System . getProperty ( "file.separator" ) + fileName ;
System . out . print ( "正在生成文件" + fileName + "..." );
try
{
coder . makeTablesFile ( list , mytmp . tmpFile , filePath );
} catch ( Exception e )
{
e . printStackTrace ();
}
System . out . println ( "OK!" );
}
}
}