package org.apache.pivot.scala.log import scala.reflect.BeanProperty import io.Source import org.apache.pivot.wtk.content.ListViewItemRenderer import java.lang.String import org.apache.pivot.wtkx.{WTKX, WTKXSerializer} /*为了避免和scala.Application的名称冲突,这里修改了别名*/ import org.apache.pivot.wtk.{ Application => PivotApplication, _} import org.apache.pivot.collections.{ArrayList, Map} /** * Created by IntelliJ IDEA. * User: Administrator * Date: 2010-8-26 * Time: 10:36:45 * To change this template use File | Settings | File Templates. */ /*日志记录Bean对象,由于Scala标准生成的字段不使用getter/setter的格式, 但是提供了注解 @scala.reflect.BeanProperty ,使得编译器可以生成标准的JavaBean对象的getter/setter接口 val 只生成了getter var 同时生成了getter和setter */ class LogRecord ( @BeanProperty val threadName : String, @BeanProperty val date : String, @BeanProperty val time : String, @BeanProperty val module : String, @BeanProperty val level : String, @BeanProperty val content : String){ /* 重载了 Any的 toString接口 override关键字是必须的,在java中使用的是注解 @override,但是java中@override并不是必须的。 省略了 函数还回值,由编译器进行类型推演得到 */ override def toString() = { threadName +" "+date +" "+ time +" "+module +" "+level+" "+content } } /* LogRecord 类的半生对象 定义了 scala中的魔术接口 apply ,使得可以使用 LogRecord("sting 文本") 可以创建一个class LogRecord对象。 apply方法的调用由编译器自动调用,我们只负责定义即可 我们要解析的日志格式 threadName date time module Level content DVOSMAIN 08/26/10 10:17:17 LOGINFO : INFO - Debug level: 2 DVOSMAIN 08/26/10 10:17:17 LOGINFO : INFO - *=ERROR WARNING EXCEPT DVOSMAIN 08/26/10 10:17:17 LOGINFO : INFO - LM=* */ object LogRecord { def apply( line : String ) : LogRecord = { /*生成一个 Regex对象,用于模式匹配*/ val logRegex = """([A-Za-z0-9]+) +([0-9/]*) +([0-9:]*) +([A-Z]*) +: *([A-Z_]+).*""".r line match { /*如果模式匹配成功,threadName,date,time,module,level 分配按次序绑定到模式匹配表达式中()的内容 */ case logRegex(threadName,date,time,module,level) => val logRecord: LogRecord = new LogRecord( threadName, date, time, module, level,line) logRecord /*模式匹配通配符,在没有匹配到的情况下,做通用处理。如果不添加,在匹配不到时会抛出 MatchError异常*/ case _ => val logRecord: LogRecord = new LogRecord("N/A","N/A","N/A","N/A","N/A","N/A") logRecord } } } /* Apache Pivot ListView ItemRenderer 重新定义了如何显示 LogRecord对象的 列表项目的渲染。 如果使用默认的,那么ListView显示对象时,直接调用对象的toString获得其字符串表示 */ class LogListViewItemRenderer extends ListViewItemRenderer { imageView.setVisible(false) override def render(item: AnyRef, index: Int, listView: ListView, selected: Boolean, checked: Boolean, highlighted: Boolean, disabled: Boolean) = { if ( item != null && item.isInstanceOf[LogRecord]) { val log = item.asInstanceOf[LogRecord] label.setText(log.content) } } } /** 定义主窗口界面代码,必须继承自 org.apache.pivot.Application 使用了 @WTKX注解,该注解属于 wtkx的命名对象的绑定语法,在从wtkx文件加载GUI时, 调用bind接口可以自动和wtkx文件中声明的wtkx:id对象进行绑定,无需在掉吗中调用 get("name") */ class MainWindow extends PivotApplication { var window : Window = null @WTKX var textInputFilePath : TextInput = null @WTKX var browsePushButton : PushButton = null @WTKX var loadPushButton : PushButton = null @WTKX var textInputThreadName :TextInput = null @WTKX var textInputModule : TextInput = null @WTKX var textInputLevel : TextInput = null @WTKX var textInputContent : TextInput = null @WTKX var logListView : ListView = null def resume = {} def suspend = {} def shutdown(optional: Boolean) = { if ( window != null) { window.close true } false } def startup(display: Display, properties: Map[String, String]) = { val wtkxSerializer = new WTKXSerializer() var matchString : String = null /*从xml(wtkx)文件加载GUI*/ window = wtkxSerializer.readObject(this,"MainWindow.xml").asInstanceOf[Window] wtkxSerializer.bind(this) if ( properties containsKey "logfile") { textInputFilePath setText ( properties get "logfile") } /*给 Button添加事件处理函数*/ browsePushButton.getButtonPressListeners.add( function2Listener (browseButtonPressed ) ) loadPushButton.getButtonPressListeners.add( function2Listener(loadButtonPressed )) window.open(display) } /*浏览按钮事件处理,打开一个文件浏览窗口,让用户选择文件,并在用户关闭对话框时,捕获用户选择的文件名*/ def browseButtonPressed( button : Button ) : Unit = { val dialog : FileBrowserSheet = new FileBrowserSheet(FileBrowserSheet.Mode.OPEN) dialog.open( window, new SheetCloseListener() { def sheetClosed(sheet: Sheet) = { if ( sheet.getResult) { val fileBrowseSheet = sheet.asInstanceOf[FileBrowserSheet] textInputFilePath.setText( fileBrowseSheet.getSelectedFile.getPath.toString) } } }) } /*从log文件加载内容,每一行是一个日志记录 for中使用了 if过滤器,只有条件符合了,才会进入for循环体。 scala没有提供continu,而是在 for中提供了条件过滤来替代 */ def loadButtonPressed( button : Button ) : Unit = { val logFile = Source.fromFile(textInputFilePath.getText) val list = new ArrayList[LogRecord] for ( line <- logFile.getLines ; logRecord = LogRecord(line.trim); if ( textInputThreadName.getText == "" || textInputThreadName.getText.contains(logRecord.threadName) ); if ( textInputModule.getText == "" || textInputModule.getText.contains(logRecord.module)); if ( textInputLevel.getText == "" || textInputLevel.getText.contains(logRecord.level))){ list add logRecord } logListView.setListData( list) } /*按钮事件辅助接口,用于把一个 事件处理函数转换为ButtonPressListener对象,也可以采取更高级的内容,使用implicit,这里没有使用*/ def function2Listener( fun : Button => Unit ) :ButtonPressListener = { val listener = new ButtonPressListener() { def buttonPressed(button: Button) = { fun(button) } } listener } } /* 主函数 符合Pivot主函数入口规则 */ object LogAnalyse { def main ( args : Array[String]) : Unit = { DesktopApplicationContext.main( classOf[MainWindow], args) } }
run:
使用 java时:
java -classpath scala-library.jar;pivot-core-1.5.jar;pivot-tools-1.5.jar;pivot-wtk-1.5.jar;pivot-wtk-terra-1.5.jar;. org.apache.pivot.scala.log.LogAnalyse
使用 scala时
java -classpath pivot-core-1.5.jar;pivot-tools-1.5.jar;pivot-wtk-1.5.jar;pivot-wtk-terra-1.5.jar;. org.apache.pivot.scala.log.LogAnalyse