Feeling

    三人行,必有我师焉

   ::  :: 新随笔 :: 联系 ::  :: 管理 ::
  185 随笔 :: 0 文章 :: 392 评论 :: 0 Trackbacks

2007年4月4日 #

     摘要: 很多网上下载的PDF文件都包含各种形式的水印,本文主要阐述如何使用易转换一键删除PDF文件中的各种图片水印和文字水印  阅读全文
posted @ 2021-03-09 20:29 三人行,必有我师焉 阅读(390) | 评论 (0)编辑 收藏

Spark源代码下载地址: http://spark.apache.org/downloads.html

下载后,直接用 Scala IDE 通过已存在的项目导入到Eclipse workspace中去,然后Eclipse会自动进行编译。第一次编译会报很多错误,不过总的来说,导致编译错误的源头有三个:
1、Scala编译器版本错误
2、Eclipse Maven插件不能自动识别spark project的一些pom,报Plugin execution not covered by lifecycle configuration异常
3、一些项目,maven会自动生成scala和java文件,但是这些自动生成的代码文件没有配置在eclipse项目的classpath里。

针对第一种错误,比较简单,对于每个scala项目,右键属性选择spark对应的scala编译器版本。



当然spark代码里的项目有几十个,只能手工一个个设置了,比较傻,没办法,还不停的弹出对话框,不停地回车吧。

编译的难点主要在第二种错误上,比如spark-sql项目的pom, 里面有个build-helper-maven-plugin,它下面的execution,eclipse maven插件无法识别,报Plugin execution not covered by lifecycle configuration异常,解决方案参见 https://www.eclipse.org/m2e/documentation/m2e-execution-not-covered.html,先使用 Eclipse quick-fix选项自动修复,忽略此 maven goal,Eclipse 会为 pom.xml自动添加一段xml代码,包含在 pluginManagement section中,里面有一段 <action><ignore/></action>,此处手动修改成
<action>
    <execute>
        <runOnIncremental>false</runOnIncremental>
    </execute>
</action>
然后右键 maven update project 就OK了。

一共有5个project需要修改pom,如图


修改pom后重新编译,依旧会报一些错误,这些错误都是由于maven自动生成的java和scala代码没有添加到classpath里导致的编译错误,只需要手工添加一下即可,需要手工添加项目有 spark-streaming-flume-sink 的 src_managed\main\compiled_avro 目录 和 spark-sql 项目的 test\gen-java 目录。

全部编译好以后的截图:


修改完以后,Spark代码全部编译下来大概耗时25分钟左右(CPU 双核 I7 4600)

原文地址:http://www.blogjava.net/cnfree/archive/2016/11/08/431965.html
posted @ 2016-11-08 13:12 三人行,必有我师焉 阅读(2231) | 评论 (0)编辑 收藏

  Spark简介

  Spark是整个BDAS的核心组件,是一个大数据分布式编程框架,不仅实现了MapReduce的算子map 函数和reduce函数及计算模型,还提供更为丰富的算子,如filter、join、groupByKey等。是一个用来实现快速而同用的集群计算的平台。

  Spark将分布式数据抽象为弹性分布式数据集(RDD),实现了应用任务调度、RPC、序列化和压缩,并为运行在其上的上层组件提供API。其底层采用Scala这种函数式语言书写而成,并且所提供的API深度借鉴Scala函数式的编程思想,提供与Scala类似的编程接口

  Sparkon Yarn

  

  从用户提交作业到作业运行结束整个运行期间的过程分析。

  一、客户端进行操作

  1. 根据yarnConf来初始化yarnClient,并启动yarnClient

  2. 创建客户端Application,并获取Application的ID,进一步判断集群中的资源是否满足executor和ApplicationMaster申请的资源,如果不满足则抛出IllegalArgumentException;

  3. 设置资源、环境变量:其中包括了设置Application的Staging目录、准备本地资源(jar文件、log4j.properties)、设置Application其中的环境变量、创建Container启动的Context等;

  4. 设置Application提交的Context,包括设置应用的名字、队列、AM的申请的Container、标记该作业的类型为Spark;

  5. 申请Memory,并最终通过yarnClient.submitApplication向ResourceManager提交该Application。

  当作业提交到YARN上之后,客户端就没事了,甚至在终端关掉那个进程也没事,因为整个作业运行在YARN集群上进行,运行的结果将会保存到HDFS或者日志中。

  二、提交到YARN集群,YARN操作

  1. 运行ApplicationMaster的run方法;

  2. 设置好相关的环境变量。

  3. 创建amClient,并启动;

  4. 在Spark UI启动之前设置Spark UI的AmIpFilter;

  5. 在startUserClass函数专门启动了一个线程(名称为Driver的线程)来启动用户提交的Application,也就是启动了Driver。在Driver中将会初始化SparkContext;

  6. 等待SparkContext初始化完成,最多等待spark.yarn.applicationMaster.waitTries次数(默认为10),如果等待了的次数超过了配置的,程序将会退出;否则用SparkContext初始化yarnAllocator;

  7. 当SparkContext、Driver初始化完成的时候,通过amClient向ResourceManager注册ApplicationMaster

  8. 分配并启动Executeors。在启动Executeors之前,先要通过yarnAllocator获取到numExecutors个Container,然后在Container中启动Executeors。

      那么这个Application将失败,将Application Status标明为FAILED,并将关闭SparkContext。其实,启动Executeors是通过ExecutorRunnable实现的,而ExecutorRunnable内部是启动CoarseGrainedExecutorBackend的。

  9. 最后,Task将在CoarseGrainedExecutorBackend里面运行,然后运行状况会通过Akka通知CoarseGrainedScheduler,直到作业运行完成。

  Spark节点的概念

  一、Spark驱动器是执行程序中的main()方法的进程。它执行用户编写的用来创建SparkContext(初始化)、创建RDD,以及运行RDD的转化操作和行动操作的代码。

  驱动器节点driver的职责:

  1. 把用户程序转为任务task(driver)

      Spark驱动器程序负责把用户程序转化为多个物理执行单元,这些单元也被称之为任务task(详解见备注)

  2. 为执行器节点调度任务(executor)

      有了物理计划之后,Spark驱动器在各个执行器节点进程间协调任务的调度。Spark驱动器程序会根据当前的执行器节点,把所有任务基于数据所在位置分配给合适的执行器进程。当执行任务时,执行器进程会把缓存的数据存储起来,而驱动器进程同样会跟踪这些缓存数据的位置,并利用这些位置信息来调度以后的任务,以尽量减少数据的网络传输。(就是所谓的移动计算,而不移动数据)。

  二、执行器节点

  作用:

  1. 负责运行组成Spark应用的任务,并将结果返回给驱动器进程;

  2. 通过自身的块管理器(blockManager)为用户程序中要求缓存的RDD提供内存式存储。RDD是直接缓存在执行器进程内的,因此任务可以在运行时充分利用缓存数据加快运算。

  驱动器的职责:

  所有的Spark程序都遵循同样的结构:程序从输入数据创建一系列RDD,再使用转化操作派生成新的RDD,最后使用行动操作手机或存储结果RDD,Spark程序其实是隐式地创建出了一个由操作组成的逻辑上的有向无环图DAG。当驱动器程序执行时,它会把这个逻辑图转为物理执行计划。

  这样 Spark就把逻辑计划转为一系列步骤(stage),而每个步骤又由多个任务组成。这些任务会被打包送到集群中。

  Spark初始化

  1. 每个Spark应用都由一个驱动器程序来发起集群上的各种并行操作。驱动器程序包含应用的main函数,并且定义了集群上的分布式数据集,以及对该分布式数据集应用了相关操作。

  2. 驱动器程序通过一个SparkContext对象来访问spark,这个对象代表对计算集群的一个连接。(比如在sparkshell启动时已经自动创建了一个SparkContext对象,是一个叫做SC的变量。(下图,查看变量sc)

      

  3. 一旦创建了sparkContext,就可以用它来创建RDD。比如调用sc.textFile()来创建一个代表文本中各行文本的RDD。(比如vallinesRDD = sc.textFile(“yangsy.text”),val spark = linesRDD.filter(line=>line.contains(“spark”),spark.count())

      执行这些操作,驱动器程序一般要管理多个执行器,就是我们所说的executor节点。

  4. 在初始化SparkContext的同时,加载sparkConf对象来加载集群的配置,从而创建sparkContext对象。

      从源码中可以看到,在启动thriftserver时,调用了spark- daemon.sh文件,该文件源码如左图,加载spark_home下的conf中的文件。

      

      (在执行后台代码时,需要首先创建conf对象,加载相应参数, val sparkConf = newSparkConf().setMaster("local").setAppName("cocapp").set("spark.executor.memory","1g"), val sc: SparkContext = new SparkContext(sparkConf))

  RDD工作原理:

  RDD(Resilient DistributedDatasets)[1] ,弹性分布式数据集,是分布式内存的一个抽象概念,RDD提供了一种高度受限的共享内存模型,即RDD是只读的记录分区的集合,只能通过在其他RDD执行确定的转换操作(如map、join和group by)而创建,然而这些限制使得实现容错的开销很低。对开发者而言,RDD可以看作是Spark的一个对象,它本身运行于内存中,如读文件是一个RDD,对文件计算是一个RDD,结果集也是一个RDD ,不同的分片、数据之间的依赖、key-value类型的map数据都可以看做RDD。

  主要分为三部分:创建RDD对象,DAG调度器创建执行计划,Task调度器分配任务并调度Worker开始运行。

  SparkContext(RDD相关操作)→通过(提交作业)→(遍历RDD拆分stage→生成作业)DAGScheduler→通过(提交任务集)→任务调度管理(TaskScheduler)→通过(按照资源获取任务)→任务调度管理(TaskSetManager)

  Transformation返回值还是一个RDD。它使用了链式调用的设计模式,对一个RDD进行计算后,变换成另外一个RDD,然后这个RDD又可以进行另外一次转换。这个过程是分布式的。

  Action返回值不是一个RDD。它要么是一个Scala的普通集合,要么是一个值,要么是空,最终或返回到Driver程序,或把RDD写入到文件系统中

  转换(Transformations)(如:map, filter, groupBy, join等),Transformations操作是Lazy的,也就是说从一个RDD转换生成另一个RDD的操作不是马上执行,Spark在遇到Transformations操作时只会记录需要这样的操作,并不会去执行,需要等到有Actions操作的时候才会真正启动计算过程进行计算。

  操作(Actions)(如:count, collect, save等),Actions操作会返回结果或把RDD数据写到存储系统中。Actions是触发Spark启动计算的动因。

  它们本质区别是:Transformation返回值还是一个RDD。它使用了链式调用的设计模式,对一个RDD进行计算后,变换成另外一个RDD,然后这个RDD又可以进行另外一次转换。这个过程是分布式的。Action返回值不是一个RDD。它要么是一个Scala的普通集合,要么是一个值,要么是空,最终或返回到Driver程序,或把RDD写入到文件系统中。关于这两个动作,在Spark开发指南中会有就进一步的详细介绍,它们是基于Spark开发的核心。

  RDD基础

  1. Spark中的RDD就是一个不可变的分布式对象集合。每个RDD都被分为多个分区,这些分区运行在集群的不同节点上。创建RDD的方法有两种:一种是读取一个外部数据集;一种是在群东程序里分发驱动器程序中的对象集合,不如刚才的示例,读取文本文件作为一个字符串的RDD的示例。

  2. 创建出来后,RDD支持两种类型的操作:转化操作和行动操作

      转化操作会由一个RDD生成一个新的RDD。(比如刚才的根据谓词筛选)

      行动操作会对RDD计算出一个结果,并把结果返回到驱动器程序中,或把结果存储到外部存储系统(比如HDFS)中。比如first()操作就是一个行动操作,会返回RDD的第一个元素。

      注:转化操作与行动操作的区别在于Spark计算RDD的方式不同。虽然你可以在任何时候定义一个新的RDD,但Spark只会惰性计算这些RDD。它们只有第一个在一个行动操作中用到时,才会真正的计算。之所以这样设计,是因为比如刚才调用sc.textFile(...)时就把文件中的所有行都读取并存储起来,就会消耗很多存储空间,而我们马上又要筛选掉其中的很多数据。

      这里还需要注意的一点是,spark会在你每次对它们进行行动操作时重新计算。如果想在多个行动操作中重用同一个RDD,那么可以使用RDD.persist()或RDD.collect()让Spark把这个RDD缓存下来。(可以是内存,也可以是磁盘)

  3. Spark会使用谱系图来记录这些不同RDD之间的依赖关系,Spark需要用这些信息来按需计算每个RDD,也可以依靠谱系图在持久化的RDD丢失部分数据时用来恢复所丢失的数据。(如下图,过滤errorsRDD与warningsRDD,最终调用union()函数)

      

  RDD计算方式

  

  RDD的宽窄依赖

  

  窄依赖 (narrowdependencies) 和宽依赖 (widedependencies) 。窄依赖是指 父 RDD 的每个分区都只被子 RDD 的一个分区所使用 。相应的,那么宽依赖就是指父 RDD 的分区被多个子 RDD 的分区所依赖。例如, map 就是一种窄依赖,而 join 则会导致宽依赖

  这种划分有两个用处。首先,窄依赖支持在一个结点上管道化执行。例如基于一对一的关系,可以在 filter 之后执行 map 。其次,窄依赖支持更高效的故障还原。因为对于窄依赖,只有丢失的父 RDD 的分区需要重新计算。而对于宽依赖,一个结点的故障可能导致来自所有父 RDD 的分区丢失,因此就需要完全重新执行。因此对于宽依赖,Spark 会在持有各个父分区的结点上,将中间数据持久化来简化故障还原,就像 MapReduce 会持久化 map 的输出一样。

  SparkExample

  

  步骤 1 :创建 RDD 。上面的例子除去最后一个 collect 是个动作,不会创建 RDD 之外,前面四个转换都会创建出新的 RDD 。因此第一步就是创建好所有 RDD( 内部的五项信息 ) 。

  步骤 2 :创建执行计划。Spark 会尽可能地管道化,并基于是否要重新组织数据来划分 阶段 (stage) ,例如本例中的 groupBy() 转换就会将整个执行计划划分成两阶段执行。最终会产生一个 DAG(directedacyclic graph ,有向无环图 ) 作为逻辑执行计划。

  步骤 3 :调度任务。 将各阶段划分成不同的 任务 (task) ,每个任务都是数据和计算的合体。在进行下一阶段前,当前阶段的所有任务都要执行完成。因为下一阶段的第一个转换一定是重新组织数据的,所以必须等当前阶段所有结果数据都计算出来了才能继续。

  假设本例中的 hdfs://names 下有四个文件块,那么 HadoopRDD 中 partitions 就会有四个分区对应这四个块数据,同时 preferedLocations 会指明这四个块的最佳位置。现在,就可以创建出四个任务,并调度到合适的集群结点上。

  Spark数据分区

  1. Spark的特性是对数据集在节点间的分区进行控制。在分布式系统中,通讯的代价是巨大的,控制数据分布以获得最少的网络传输可以极大地提升整体性能。Spark程序可以通过控制RDD分区方式来减少通讯的开销。

  2. Spark中所有的键值对RDD都可以进行分区。确保同一组的键出现在同一个节点上。比如,使用哈希分区将一个RDD分成了100个分区,此时键的哈希值对100取模的结果相同的记录会被放在一个节点上。

      (可使用partitionBy(newHashPartitioner(100)).persist()来构造100个分区)

  3. Spark中的许多操作都引入了将数据根据键跨界点进行混洗的过程。(比如:join(),leftOuterJoin(),groupByKey(),reducebyKey()等)对于像reduceByKey()这样只作用于单个RDD的操作,运行在未分区的RDD上的时候会导致每个键的所有对应值都在每台机器上进行本地计算。

  SparkSQL的shuffle过程

  

  Spark SQL的核心是把已有的RDD,带上Schema信息,然后注册成类似sql里的”Table”,对其进行sql查询。这里面主要分两部分,一是生成SchemaRD,二是执行查询。

  如果是spark-hive项目,那么读取metadata信息作为Schema、读取hdfs上数据的过程交给Hive完成,然后根据这俩部分生成SchemaRDD,在HiveContext下进行hql()查询。

  SparkSQL结构化数据

  1. 首先说一下ApacheHive,Hive可以在HDFS内或者在其他存储系统上存储多种格式的表。SparkSQL可以读取Hive支持的任何表。要把Spark SQL连接已有的hive上,需要提供Hive的配置文件。hive-site.xml文件复制到spark的conf文件夹下。再创建出HiveContext对象(sparksql的入口),然后就可以使用HQL来对表进行查询,并以由行足证的RDD的形式拿到返回的数据。

  2. 创建Hivecontext并查询数据

      importorg.apache.spark.sql.hive.HiveContext

      valhiveCtx = new org.apache.spark.sql.hive.HiveContext(sc)

      valrows = hiveCtx.sql(“SELECT name,age FROM users”)

      valfitstRow – rows.first()

      println(fitstRow.getSgtring(0)) //字段0是name字段

  3. 通过jdbc连接外部数据源更新与加载

      Class.forName("com.mysql.jdbc.Driver")

      val conn =DriverManager.getConnection(mySQLUrl)

      val stat1 =conn.createStatement()

      stat1.execute("UPDATE CI_LABEL_INFO set DATA_STATUS_ID = 2 , DATA_DATE ='" + dataDate +"' where LABEL_ID in ("+allCreatedLabels.mkString(",")+")")

      stat1.close()

      //加载外部数据源数据到内存

      valDIM_COC_INDEX_MODEL_TABLE_CONF =sqlContext.jdbc(mySQLUrl,"DIM_COC_INDEX_MODEL_TABLE_CONF").cache()

      val targets =DIM_COC_INDEX_MODEL_TABLE_CONF.filter("TABLE_DATA_CYCLE ="+TABLE_DATA_CYCLE).collect

  SparkSQL解析

  

  首先说下传统数据库的解析,传统数据库的解析过程是按Rusult、Data Source、Operation的次序来解析的。传统数据库先将读入的SQL语句进行解析,分辨出SQL语句中哪些词是关键字(如select,from,where),哪些是表达式,哪些是Projection,哪些是Data Source等等。进一步判断SQL语句是否规范,不规范就报错,规范则按照下一步过程绑定(Bind)。过程绑定是将SQL语句和数据库的数据字典(列,表,视图等)进行绑定,如果相关的Projection、Data Source等都存在,就表示这个SQL语句是可以执行的。在执行过程中,有时候甚至不需要读取物理表就可以返回结果,比如重新运行刚运行过的SQL语句,直接从数据库的缓冲池中获取返回结果。在数据库解析的过程中SQL语句时,将会把SQL语句转化成一个树形结构来进行处理,会形成一个或含有多个节点(TreeNode)的Tree,然后再后续的处理政对该Tree进行一系列的操作。

  Spark SQL对SQL语句的处理和关系数据库对SQL语句的解析采用了类似的方法,首先会将SQL语句进行解析,然后形成一个Tree,后续如绑定、优化等处理过程都是对Tree的操作,而操作方法是采用Rule,通过模式匹配,对不同类型的节点采用不同的操作。SparkSQL有两个分支,sqlContext和hiveContext。sqlContext现在只支持SQL语法解析器(Catalyst),hiveContext支持SQL语法和HiveContext语法解析器。

原文地址:http://mt.sohu.com/20160522/n450849016.shtml

posted @ 2016-09-08 13:11 三人行,必有我师焉 阅读(246) | 评论 (0)编辑 收藏

spark中有partition的概念(和slice是同一个概念,在spark1.2中官网已经做出了说明),一般每个partition对应一个task。在我的测试过程中,如果没有设置spark.default.parallelism参数,spark计算出来的partition非常巨大,与我的cores非常不搭。我在两台机器上(8cores *2 +6g * 2)上,spark计算出来的partition达到2.8万个,也就是2.9万个tasks,每个task完成时间都是几毫秒或者零点几毫秒,执行起来非常缓慢。在我尝试设置了 spark.default.parallelism 后,任务数减少到10,执行一次计算过程从minute降到20second。

参数可以通过spark_home/conf/spark-default.conf配置文件设置。

eg.

spark.master  spark://master:7077 

spark.default.parallelism  10 

spark.driver.memory  2g 

spark.serializer  org.apache.spark.serializer.KryoSerializer 

spark.sql.shuffle.partitions  50

 

下面是官网的相关描述:

from:http://spark.apache.org/docs/latest/configuration.html

Property NameDefaultMeaning
spark.default.parallelism For distributed shuffle operations like reduceByKey and join, the largest number of partitions in a parent RDD. For operations likeparallelize with no parent RDDs, it depends on the cluster manager:
  • Local mode: number of cores on the local machine
  • Mesos fine grained mode: 8
  • Others: total number of cores on all executor nodes or 2, whichever is larger
Default number of partitions in RDDs returned by transformations like joinreduceByKey, and parallelize when not set by user.

from:http://spark.apache.org/docs/latest/tuning.html

Level of Parallelism

Clusters will not be fully utilized unless you set the level of parallelism for each operation high enough. Spark automatically sets the number of “map” tasks to run on each file according to its size (though you can control it through optional parameters to SparkContext.textFile, etc), and for distributed “reduce” operations, such as groupByKey and reduceByKey, it uses the largest parent RDD’s number of partitions. You can pass the level of parallelism as a second argument (see the spark.PairRDDFunctions documentation), or set the config propertyspark.default.parallelism to change the default. In general, we recommend 2-3 tasks per CPU core in your cluster.


原文地址:http://www.cnblogs.com/wrencai/p/4231966.html

posted @ 2016-09-08 13:07 三人行,必有我师焉 阅读(2191) | 评论 (0)编辑 收藏

Eclipse Class Decompiler是一款Eclipse插件,整合了多种反编译器,和Eclipse Class Viewer无缝集成,能够很方便的使用插件查看类库源码,进行Debug调试。
同时还提供了在线自动查找源代码,查看Class二进制字节码的功能。
 

Eclipse Class Decompiler对JDK的最低要求为JDK1.6, 能反编译和debug各版本的Class文件,支持JDK8的Lambda语法,同时支持中文等非Ascii码字符集的解析,支持Eclipse 3.6及以上所有版本的Eclipse。

本插件支持Windows,Linux,Macosx 32位及64位操作系统。

Github项目地址为:https://github.com/cnfree/Eclipse-Class-Decompiler

请通过以下地址选择一个可用的源在线安装:

http://cnfree.github.io/Eclipse-Class-Decompiler/update
http://raw.githubusercontent.com/cnfree/eclipse/master/decompiler/update/
http://www.cpupk.com/decompiler/update/

离线包下载地址:
https://github.com/cnfree/Eclipse-Class-Decompiler/releases/download/v2.10.0/eclipse-class-decompiler-update_v2.10.0.zip

 
插件使用说明:

下图为Eclipse Class Decompiler的首选项页面,可以选择缺省的反编译器工具,并进行反编译器的基本设置。缺省的反编译工具为JD-Core,JD-Core更为先进一些,支持泛型、Enum、注解等JDK1.5以后才有的新语法。

首选项配置选项:
1.重用缓存代码:只会反编译一次,以后每次打开该类文件,都显示的是缓存的反编译代码。
2.忽略已存在的源代码:若未选中,则查看Class文件是否已绑定了Java源代码,如果已绑定,则显示Java源代码,如果未绑定,则反编译Class文件。若选中此项,则忽略已绑定的Java源代码,显示反编译结果。
3.显示反编译器报告:显示反编译器反编译后生成的数据报告及异常信息。
4.使用Eclipse代码格式化工具:使用Eclipse格式化工具对反编译结果重新格式化排版,反编译整个Jar包时,此操作会消耗一些时间。
5.使用Eclipse成员排序:使用Eclipse成员排序对反编译结果重新格式化排版,反编译整个Jar包时,此操作会消耗大量时间。
6.以注释方式输出原始行号信息:如果Class文件包含原始行号信息,则会将行号信息以注释的方式打印到反编译结果中。
7.根据行号对齐源代码以便于调试:若选中该项,插件会采用AST工具分析反编译结果,并根据行号信息调整代码顺序,以便于Debug过程中的单步跟踪调试。
8.设置类反编译查看器作为缺省的类文件编辑器:默认为选中,将忽略Eclipse自带的Class Viewer,每次Eclipse启动后,默认使用本插件提供的类查看器打开Class文件。



插件提供了系统菜单,工具栏,当打开了插件提供的类反编译查看器后,会激活菜单和工具栏选项,可以方便的进行首选项配置,切换反编译工具重新反编译,以及导出反编译结果。






类反编译查看器右键菜单包含了Eclipse自带类查看器右键菜单的全部选项,并增加了一个“导出反编译源代码”菜单项。



打开项目路径下的Class文件,如果设置类反编译查看器为缺省的查看器,直接双击Class文件即可,如果没有设置为缺省查看器,可以使用右键菜单进行查看。




同时插件也支持直接将外部的Class文件拖拽到Eclipse编辑器中进行反编译。


Eclipse Class Decompiler插件也提供了反编译整个Jar文件或者Java包的反编译。该操作支持Package Explorer对包显示布局的操作,如果是平铺模式布局,则导出的源代码不包含子包,如果是层级模式布局,则导出选中的包及其所有的子包。




Debug调试:可以在首选项选中对齐行号进行单步跟踪调试,和普通的包含源代码时的调试操作完全一致,同样的也可以设置断点进行跟踪。当透视图为Debug时,插件自动生成行号并进行对齐方便调试代码,无需进行任何设置。


博文地址:http://www.blogjava.net/cnfree/archive/2012/10/30/390457.html
posted @ 2016-05-13 14:23 三人行,必有我师焉 阅读(1298) | 评论 (5)编辑 收藏

Java应用定制工厂(以下简称为JCB,Java Customization Builder)是一个针对Java轻量级桌面应用进行精简优化的小工具,使用它可以精简你的jar包,并自动生成一个精简的JRE,也可以使用它生成一个Exe启动引导程序,并且能够对你的Java应用自动做Pack200和Unpack200处理。使用本工具定制的Java桌面应用通常不会超过10M(包含JRE),SWT客户端程序相对于Swing客户端程序更小,一般不会超过5M。

JCB是一个Java应用,所以目标机器上必须安装1.5以上版本的JDK用以启动JCB,但是JCB可以用来精简1.4版的JRE,并且JRE1.4精简后的体积远小于1.5以上的版本。

1.新建JCB项目
精简JRE的步骤比较繁琐,有可能精简失败,为了不重复之前的步骤,JCB提供一个项目文件用来保存精简配置信息,扩展名为jcprj。这里我们创建一个项目,名为JCB


Wizard需要输入一个工程名和指定工程位置,至于下面的应用程序位置和定制JRE位置由JCB自动指定,这儿显示出来仅供参考。

此时最好Ctrl+S保存一下项目,否则退出后你之前的配置信息会全部丢失,因为你并没有制定一个可用的项目配置文件。

2. 配置JCB项目


首先指定项目需要的jar文件,然后依次选择项目的main class,启动路径默认为空,一般来说无需指定。然后设定应用程序参数和虚拟机参数。最后选定需要精简的JRE,JCB当前支持1.4-1.7版本的JRE,未来可能会支持更高版本的JRE。

右下角有2个单选按钮:全部重新运行和增量运行。全部重新运行就会放弃之前的运行结果,增量运行就是会保留以前的运行结果。

然后点击“以Verbose模式运行”按钮。Verbose模式运行Java程序,会显示JVM加载的全部类信息,JCB需要这些类信息进行JRE的精简,所以请尽可能的把应用所有的功能尽可能的跑一遍,跑的越全面,导致精简出错的可能性就越低。



Verbose运行结果,这个页面的显示信息仅供参考,无实际用处。

3. 分析项目的类依赖项


分析类依赖模式有2个选项:重新完全分析和增量分析。完全分析会花费较多的时间。当使用verbose模式增量运行后,可以使用增量模式分析类依赖项,这样可以节约大量的时间。类依赖分析会反编译所有运行的类,分析类引用关系,但是无法获取Class.forName这类动态类加载信息,所以需要Verbose模式运行的尽量全面,以避免这些动态加载的类的缺失。

为什么需要分析类依赖关系呢?因为不同的操作系统,不同的硬件配置,JRE可能会采取策略模式加载不同的类,或者一些异常,Verbose模式一般不会加载,这样换个硬件环境,仅仅使用Verbose模式的类可能会导致ClassNotFound这样的异常,导致Java程序崩溃。


4. 精简JRE


精简JRE有两种模式:使用Verbose运行结果和使用类依赖分析结果。前者只包含Verbose分析出来的类,精简出来的JRE包很小,但是基本不具备跨平台性。所以一般来说推荐选择后者。

如果你的程序包含Swing的客户端,并且比较复杂的话,最好选中包含Swing选项。因为Swing的设计完全是动态化的加载,全部使用Class.forName方式,类依赖分析对Swing是无效的。当然选中该选项后,JRE的体积会增加许多。比较好的解决方案,是使用SWT替代Swing进行开发,或者尽量把你的程序跑全面,包括各种异常界面都跑出来。

右下角有两个按钮,是用来自定义类和资源文件的,比如移除JAR包的MD5文件或者无用的文件。或者测试运行发现ClassNotFound异常,手动把缺少的类加进去,然后JCB会自动运行增量类依赖分析加载所有可能需要的类。

选择左上角的“精简Jar包”按钮,就可以对JRE进行精简了,精简完毕后可以点击“查看精简结果”按钮进行查看。

5.定制JRE


上图显示了JRE精简结果,JCB会自动分析所有的Class,生成精简版JRE,包括需要的JAR,DLL和资源文件。一般来说精简出来的JRE,普通功能都能正确完成,但是不排除有些功能不能正常使用,比如缺少某个资源文件或者DLL,需要手工添加。

为了保证精简的正确性,你需要进行运行测试,这一步是必须的,而且最好和Verbose运行模式一样,把所有的功能都跑一遍,确认精简无误。



如果测试运行有误的话,请根据运行错误报告进行分析,如果缺少类,请使用Verbose模式重新运行相应的功能,或者在步骤四手工添加需要的类,然后重新生成依赖的JRE。如果缺少相关的DLL或者资源文件,也请手工添加,并且取消步骤四的“清理工作区选项”,否则每次精简JRE都需要重新手工添加。

到此为止,精简JRE部分就算全部完成了,你最好使用Ctrl+S保存一下结果,以避免下次重做项目。

JCB项目下载地址:http://www.sourceforge.net/projects/jcb
posted @ 2013-03-03 17:25 三人行,必有我师焉 阅读(5202) | 评论 (13)编辑 收藏

1. 40亿个无符号整数,找出一个不在这40亿个整数中的数。可以换个方向思考, 99个小于100的数,找出一个不在这99个数中的小于100的数。
首先把这99个数分为10组,按高位为0-9分,然后计算每组的数量,数量最少的那个肯定就是缺失的那个,然后递归……找最少的那个,组合起来的数肯定是缺失的。答案是按位运算找,和这个类似。

2. 43亿个无符号整数,找出一个重复的整数。也就是101个小于100的数,找出重复的那个数来。
首先把这99个数分为10组,按高位为0-9分,然后计算每组的数量,数量最多的那组,肯定有重复的,一次类推找第二位……
posted @ 2012-11-24 22:21 三人行,必有我师焉 阅读(392) | 评论 (0)编辑 收藏

When a object creates a new object, please use the dependency.

When a object just uses a object, please use the association. 
posted @ 2012-11-19 13:16 三人行,必有我师焉 阅读(277) | 评论 (0)编辑 收藏

comparator 

Decorator Pattern and Adapter Pattern have the same alias name: wrapper. But they face different aspects. Decorator pattern changes the object function, but the adapter pattern changes the interface.

The typical decorator pattern is the java OutputStream, you can use the BufferedOutputStream to wrap it, then get the extra function.
The typical adapter pattern in the BIRT is the ElementAdapter, it can convert any object to an other object.

Decorator pattern must extend the class which you want to wrap, but the adapter class must implements the interface using by the client.


FlyWeight pattern extracts the same part of some different objects, and the part doesn't be changed when these objects changed. String class uses the FlyWeight pattern, jface 
ImageRegistry also uses it. 
FlyWeight can have a interface to get external data, and change the external data's status, but FlyWeight internal status shouldn't be changed.

The Collections.sort() method implementation contains template method design pattern and strategy design pattern, but it doesn't contain the visitor design pattern. The Collections.sort() method uses the merge sort algorithm, you can't change it, but you can change the comparator logic, it's one step of the sort algorithm. So it's a template method pattern, but not a classic implementation, it uses the callback method to implement the pattern, but not extending the parent template class. The comparator class use the strategy design pattern, it not a visitor pattern, visitor pattern have a accept method to operate the element to deal some logic. 



posted @ 2012-11-14 00:22 三人行,必有我师焉 阅读(317) | 评论 (0)编辑 收藏

1 归并排序(MergeSort)

归并排序最差运行时间是O(nlogn),它是利用递归设计程序的典型例子。

归并排序的最基础的操作就是合并两个已经排好序的序列。

假设我们有一个没有排好序的序列,那么首先我们使用分割的办法将这个序列分割成一个一个已经排好序的子序列。然后再利用归并的方法将一个个的子序列合并成排序好的序列。分割和归并的过程可以看下面的图例。



从上图可以看出,我们首先把一个未排序的序列从中间分割成2部分,再把2部分分成4部分,依次分割下去,直到分割成一个一个的数据,再把这些数据两两归并到一起,使之有序,不停的归并,最后成为一个排好序的序列。

如何把两个已经排序好的子序列归并成一个排好序的序列呢?可以参看下面的方法。

假设我们有两个已经排序好的子序列。
序列A:1 23 34 65
序列B:2 13 14 87
那么可以按照下面的步骤将它们归并到一个序列中。

(1)首先设定一个新的数列C[8]。
(2)A[0]和B[0]比较,A[0] = 1,B[0] = 2,A[0] < B[0],那么C[0] = 1
(3)A[1]和B[0]比较,A[1] = 23,B[0] = 2,A[1] > B[0],那么C[1] = 2
(4)A[1]和B[1]比较,A[1] = 23,B[1] = 13,A[1] > B[1],那么C[2] = 13
(5)A[1]和B[2]比较,A[1] = 23,B[2] = 14,A[1] > B[2],那么C[3] = 14
(6)A[1]和B[3]比较,A[1] = 23,B[3] = 87,A[1] < B[3],那么C[4] = 23
(7)A[2]和B[3]比较,A[2] = 34,B[3] = 87,A[2] < B[3],那么C[5] = 34
(8)A[3]和B[3]比较,A[3] = 65,B[3] = 87,A[3] < B[3],那么C[6] = 65
(9)最后将B[3]复制到C中,那么C[7] = 87。归并完成。

如果我们清楚了上面的分割和归并过程,那么我们就可以用递归的方法得到归并算法的实现。

    public class MergeSorter
    {
        
private static int[] myArray;
        
private static int arraySize;

        
public static void Sort( int[] a )
        {
            myArray 
= a;
            arraySize 
= myArray.Length;
            MergeSort();
        }

        
/// <summary>
        
/// 利用归并的方法排序数组,首先将序列分割
        
/// 然后将数列归并,这个算法需要双倍的存储空间
        
/// 时间是O(nlgn)
        
/// </summary>
        private static void MergeSort()
        {
            
int[] temp = new int[arraySize];
            MSort( temp, 
0, arraySize - 1);
        }

        
private static void MSort(int[] temp, int left, int right)
        {
            
int mid;

            
if (right > left)
            {
                mid 
= (right + left) / 2;
                MSort( temp, left, mid); 
//分割左边的序列
                MSort(temp, mid+1, right);//分割右边的序列
                Merge(temp, left, mid+1, right);//归并序列
            }
        }

        
private static void Merge( int[] temp, int left, int mid, int right)
        {
            
int i, left_end, num_elements, tmp_pos;

            left_end 
= mid - 1;
            tmp_pos 
= left;
            num_elements 
= right - left + 1;

            
while ((left <= left_end) && (mid <= right)) 
            {
                
if (myArray[left] <= myArray[mid]) //将左端序列归并到temp数组中
                {
                    temp[tmp_pos] 
= myArray[left];
                    tmp_pos 
= tmp_pos + 1;
                    left 
= left +1;
                }
                
else//将右端序列归并到temp数组中
                {
                    temp[tmp_pos] 
= myArray[mid];
                    tmp_pos 
= tmp_pos + 1;
                    mid 
= mid + 1;
                }
            }

            
while (left <= left_end) //拷贝左边剩余的数据到temp数组中
            {
                temp[tmp_pos] 
= myArray[left];
                left 
= left + 1;
                tmp_pos 
= tmp_pos + 1;
            }
            
while (mid <= right) //拷贝右边剩余的数据到temp数组中
            {
                temp[tmp_pos] 
= myArray[mid];
                mid 
= mid + 1;
                tmp_pos 
= tmp_pos + 1;
            }

            
for (i=0; i < num_elements; i++//将所有元素拷贝到原始数组中
            {
                myArray[right] 
= temp[right];
                right 
= right - 1;
            }
        }
    }


归并排序算法是一种O(nlogn)的算法。它的最差,平均,最好时间都是O(nlogn)。但是它需要额外的存储空间,这在某些内存紧张的机器上会受到限制。

归并算法是又分割和归并两部分组成的。对于分割部分,如果我们使用二分查找的话,时间是O(logn),在最后归并的时候,时间是O(n),所以总的时间是O(nlogn)。

2 堆排序(HeapSort)

堆排序属于百万俱乐部的成员。它特别适合超大数据量(百万条记录以上)的排序。因为它并不使用递归(因为超大数据量的递归可能会导致堆栈溢出),而且它的时间也是O(nlogn)。还有它并不需要大量的额外存储空间。

堆排序的思路是:

(1)将原始未排序的数据建成一个堆。
(2)建成堆以后,最大值在堆顶,也就是第0个元素,这时候将第零个元素和最后一个元素交换。
(3)这时候将从0到倒数第二个元素的所有数据当成一个新的序列,建一个新的堆,再次交换第一个和最后一个元素,依次类推,就可以将所有元素排序完毕。

建立堆的过程如下面的图所示:


堆排序的具体算法如下:

public class HeapSorter 
    {
        
private static int[] myArray;
        
private static int arraySize;

        
public static void Sort( int[] a )
        {
            myArray 
= a;
            arraySize 
= myArray.Length;
            HeapSort();
        }

        
private static void HeapSort()
        {
            BuildHeap();            
//将原始序列建成一个堆

            
while ( arraySize > 1 )
            {
                arraySize
--;
                Exchange ( 
0, arraySize );//将最大值放在数组的最后
                DownHeap ( 0 );  //将序列从0到n-1看成一个新的序列,重新建立堆
            } 
        }

        
private static void BuildHeap()
        {
            
for (int v=arraySize/2-1; v>=0; v--)
                DownHeap ( v );
        }

        
//利用向下遍历子节点建立堆
        private static void DownHeap( int v )
        {
            
int w = 2 * v + 1;                     // 节点w是节点v的第一个子节点

            
while (w < arraySize)
            {
                
if ( w+1 < arraySize )        // 如果节点v下面有第二个字节点
                    if ( myArray[w+1> myArray[w] ) 
                        w
++;                        // 将子节点w设置成节点v下面值最大的子节点

                 
// 节点v已经大于子节点w,有了堆的性质,那么返回
                if ( myArray[v] >= myArray[w] ) 
                    
return;   
                
                Exchange( v, w );     
// 如果不是,就交换节点v和节点w的值
                v = w;        
                w 
= 2 * v + 1;            // 继续向下找子节点
            }
        }

        
//交换数据
        private static void Exchange( int i, int j )
        {
            
int t = myArray[i];
            myArray[i] 
= myArray[j];
            myArray[j] 
= t;
        }
    }    


 

堆排序主要用于超大规模的数据的排序。因为它不需要额外的存储空间,也不需要大量的递归。

3 几种O(nlogn)算法的初步比较

我们可以从下表看到几种O(nlogn)算法的效率的区别。所有的数据都使用.Net的Random类产生,每种算法运行100次,时间的单位为毫秒。


500随机整数5000随机整数20000随机整数
合并排序0.31251.56257.03125
 Shell排序0.31251.256.875
堆排序0.468752.18756.71875
快速排序0.156250.6252.8125

从上表可以明显地看出,快速排序是最快的算法。这也就给了我们一个结论,对于一般的应用来说,我们总是选择快速排序作为我们的排序算法,当数据量非常大(百万数量级)我们可以使用堆排序,如果内存空间非常紧张,我们可以使用Shell排序。但是这意味着我们不得不损失速度。 

/******************************************************************************************
 *【Author】:flyingbread
 *【Date】:2007年2月2日
 *【Notice】:
 *1、本文为原创技术文章,首发博客园个人站点(http://flyingbread.cnblogs.com/),转载和引用请注明作者及出处。
 *2、本文必须全文转载和引用,任何组织和个人未授权不能修改任何内容,并且未授权不可用于商业。
 *3、本声明为文章一部分,转载和引用必须包括在原文中。
 ******************************************************************************************/
posted @ 2012-11-10 23:18 三人行,必有我师焉 阅读(587) | 评论 (2)编辑 收藏

1 快速排序(QuickSort)

快速排序是一个就地排序,分而治之,大规模递归的算法。从本质上来说,它是归并排序的就地版本。快速排序可以由下面四步组成。

(1) 如果不多于1个数据,直接返回。
(2) 一般选择序列最左边的值作为支点数据。
(3) 将序列分成2部分,一部分都大于支点数据,另外一部分都小于支点数据。
(4) 对两边利用递归排序数列。

快速排序比大部分排序算法都要快。尽管我们可以在某些特殊的情况下写出比快速排序快的算法,但是就通常情况而言,没有比它更快的了。快速排序是递归的,对于内存非常有限的机器来说,它不是一个好的选择。 

2 归并排序(MergeSort)

归并排序先分解要排序的序列,从1分成2,2分成4,依次分解,当分解到只有1个一组的时候,就可以排序这些分组,然后依次合并回原来的序列中,这样就可以排序所有数据。合并排序比堆排序稍微快一点,但是需要比堆排序多一倍的内存空间,因为它需要一个额外的数组。

3 堆排序(HeapSort)

堆排序适合于数据量非常大的场合(百万数据)。

堆排序不需要大量的递归或者多维的暂存数组。这对于数据量非常巨大的序列是合适的。比如超过数百万条记录,因为快速排序,归并排序都使用递归来设计算法,在数据量非常大的时候,可能会发生堆栈溢出错误。

堆排序会将所有的数据建成一个堆,最大的数据在堆顶,然后将堆顶数据和序列的最后一个数据交换。接下来再次重建堆,交换数据,依次下去,就可以排序所有的数据。

4 Shell排序(ShellSort)

Shell排序通过将数据分成不同的组,先对每一组进行排序,然后再对所有的元素进行一次插入排序,以减少数据交换和移动的次数。平均效率是O(nlogn)。其中分组的合理性会对算法产生重要的影响。现在多用D.E.Knuth的分组方法。

Shell排序比冒泡排序快5倍,比插入排序大致快2倍。Shell排序比起QuickSort,MergeSort,HeapSort慢很多。但是它相对比较简单,它适合于数据量在5000以下并且速度并不是特别重要的场合。它对于数据量较小的数列重复排序是非常好的。

5 插入排序(InsertSort)

插入排序通过把序列中的值插入一个已经排序好的序列中,直到该序列的结束。插入排序是对冒泡排序的改进。它比冒泡排序快2倍。一般不用在数据大于1000的场合下使用插入排序,或者重复排序超过200数据项的序列。

6 冒泡排序(BubbleSort)

冒泡排序是最慢的排序算法。在实际运用中它是效率最低的算法。它通过一趟又一趟地比较数组中的每一个元素,使较大的数据下沉,较小的数据上升。它是O(n^2)的算法。

7 交换排序(ExchangeSort)和选择排序(SelectSort)

这两种排序方法都是交换方法的排序算法,效率都是 O(n2)。在实际应用中处于和冒泡排序基本相同的地位。它们只是排序算法发展的初级阶段,在实际中使用较少。

8 基数排序(RadixSort)

基数排序和通常的排序算法并不走同样的路线。它是一种比较新颖的算法,但是它只能用于整数的排序,如果我们要把同样的办法运用到浮点数上,我们必须了解浮点数的存储格式,并通过特殊的方式将浮点数映射到整数上,然后再映射回去,这是非常麻烦的事情,因此,它的使用同样也不多。而且,最重要的是,这样算法也需要较多的存储空间。

9 总结

下面是一个总的表格,大致总结了我们常见的所有的排序算法的特点。
排序法 平均时间最差情形稳定度额外空间备注
冒泡 O(n2)  O(n2) 稳定O(1)n小时较好
交换  O(n2)  O(n2)不稳定O(1)n小时较好
选择 O(n2) O(n2)不稳定O(1)n小时较好
插入 O(n2) O(n2)稳定O(1)大部分已排序时较好
基数O(logRB)O(logRB)稳定O(n)

B是真数(0-9),

R是基数(个十百)

ShellO(nlogn)O(ns) 1<2不稳定O(1)s是所选分组
快速O(nlogn)O(n2)不稳定O(nlogn)n大时较好
归并O(nlogn)O(nlogn)稳定O(1)n大时较好
O(nlogn)O(nlogn)不稳定O(1)n大时较好

posted @ 2012-11-10 22:30 三人行,必有我师焉 阅读(331) | 评论 (0)编辑 收藏

Eclipse Class Decompiler是一款Eclipse插件,整合了多种反编译器,和Eclipse Class Viewer无缝集成,能够很方便的使用插件查看类库源码,进行Debug调试。
同时还提供了在线自动查找源代码,查看Class二进制字节码的功能。 


Eclipse Class Decompiler对JDK的最低要求为JDK1.6, 能反编译和debug各版本的Class文件,支持JDK8的Lambda语法,同时支持中文等非Ascii码字符集的解析,支持Eclipse 3.6及以上所有版本的Eclipse。

本插件支持Windows,Linux,Macosx 32位及64位操作系统。

Github项目地址为:https://github.com/cnfree/Eclipse-Class-Decompiler

请通过以下地址选择一个可用的源在线安装:

http://cnfree.github.io/Eclipse-Class-Decompiler/update
http://raw.githubusercontent.com/cnfree/eclipse/master/decompiler/update/
http://www.cpupk.com/decompiler/update/

离线包下载地址:
https://github.com/cnfree/Eclipse-Class-Decompiler/releases/download/v2.10.0/eclipse-class-decompiler-update_v2.10.0.zip
 
插件使用说明:

下图为Eclipse Class Decompiler的首选项页面,可以选择缺省的反编译器工具,并进行反编译器的基本设置。缺省的反编译工具为JD-Core,JD-Core更为先进一些,支持泛型、Enum、注解等JDK1.5以后才有的新语法。

首选项配置选项:
1.重用缓存代码:只会反编译一次,以后每次打开该类文件,都显示的是缓存的反编译代码。
2.忽略已存在的源代码:若未选中,则查看Class文件是否已绑定了Java源代码,如果已绑定,则显示Java源代码,如果未绑定,则反编译Class文件。若选中此项,则忽略已绑定的Java源代码,显示反编译结果。
3.显示反编译器报告:显示反编译器反编译后生成的数据报告及异常信息。
4.使用Eclipse代码格式化工具:使用Eclipse格式化工具对反编译结果重新格式化排版,反编译整个Jar包时,此操作会消耗一些时间。
5.使用Eclipse成员排序:使用Eclipse成员排序对反编译结果重新格式化排版,反编译整个Jar包时,此操作会消耗大量时间。
6.以注释方式输出原始行号信息:如果Class文件包含原始行号信息,则会将行号信息以注释的方式打印到反编译结果中。
7.根据行号对齐源代码以便于调试:若选中该项,插件会采用AST工具分析反编译结果,并根据行号信息调整代码顺序,以便于Debug过程中的单步跟踪调试。
8.设置类反编译查看器作为缺省的类文件编辑器:默认为选中,将忽略Eclipse自带的Class Viewer,每次Eclipse启动后,默认使用本插件提供的类查看器打开Class文件。



插件提供了系统菜单,工具栏,当打开了插件提供的类反编译查看器后,会激活菜单和工具栏选项,可以方便的进行首选项配置,切换反编译工具重新反编译,以及导出反编译结果。






类反编译查看器右键菜单包含了Eclipse自带类查看器右键菜单的全部选项,并增加了一个“导出反编译源代码”菜单项。



打开项目路径下的Class文件,如果设置类反编译查看器为缺省的查看器,直接双击Class文件即可,如果没有设置为缺省查看器,可以使用右键菜单进行查看。




同时插件也支持直接将外部的Class文件拖拽到Eclipse编辑器中进行反编译。


Eclipse Class Decompiler插件也提供了反编译整个Jar文件或者Java包的反编译。该操作支持Package Explorer对包显示布局的操作,如果是平铺模式布局,则导出的源代码不包含子包,如果是层级模式布局,则导出选中的包及其所有的子包。




Debug调试:可以在首选项选中对齐行号进行单步跟踪调试,和普通的包含源代码时的调试操作完全一致,同样的也可以设置断点进行跟踪。当透视图为Debug时,插件自动生成行号并进行对齐方便调试代码,无需进行任何设置。


博文地址:http://www.blogjava.net/cnfree/archive/2012/10/30/390457.html
posted @ 2012-10-30 13:48 三人行,必有我师焉 阅读(92435) | 评论 (43)编辑 收藏

The original author of the JadClipse project maintains it no more, and the latest build 3.3.0 doesn't support eclipse 4.x, so I download the source code and update it.

JadClipse for Eclipse 4.x also support Eclipse 3.x, and provides several new features:
 
1. Integrate jad.exe into the plugin, don't need to set jad path in the preference page again.
2. Add two options in the JadClipse main preference page:
    (1) Use Eclipse member sorter
    (2) Show decompiler report
3. Update the formatting preference default settings, the "Output fields before methods" setting's default value changes to true.

JadClipse for Eclipse 4.x Update Site: http://feeling.sourceforge.net/update

Offline Archive Update File Download: 
1. http://feeling.sourceforge.net/downloads/org.sf.feeling.decompiler_1.0.3.zip
2. http://www.blogjava.net/Files/cnfree/org.sf.feeling.decompiler_1.0.3.zip
posted @ 2012-10-15 17:45 三人行,必有我师焉 阅读(7435) | 评论 (10)编辑 收藏

http://www.open-open.com/lib/view/1326265166952

http://blog.chinaunix.net/uid-22342564-id-3183018.html
posted @ 2012-05-31 02:42 三人行,必有我师焉 阅读(469) | 评论 (0)编辑 收藏

com\maxmpz\audioplayer\widget\listwrappers\D800DC00 这个package 主要用于 PlayList 模型的操作。

com\maxmpz\audioplayer\widget\listwrappers\D800DC00\D803DC04.java

里面有个
    private static int D801DC01(Activity activity, int i)
    {
        TypedArray typedarray 
= activity.obtainStyledAttributes(null, com.maxmpz.audioplayer.j.true.p, 00);
        
int j = typedarray.getResourceId(i, 0);
        typedarray.recycle();
        
return j;
    }

Context.obtainStyledAttributes 实现控件属性与XML定义绑定的代码。 

TypedArray其实就是一个存放资源的Array,首先从上下文中获取到R.styleable。。。这个属性资源的资源数组。 attrs是构造函数传进来,应该就是对应attrs.xml文件。 a.getString(R.styleable。。。);这句代码就是获取attrs.xml中定义的属性,并将这个属性的值传给本控件的mValue.最后,返回一个绑定结束的信号给资源:a.recycle();绑定结束

相关学习文章:
http://blog.csdn.net/aomandeshangxiao/article/details/7449973

com.maxmpz.audioplayer.widget.listwrappers.0xE9 这个类,用于显示文件夹列表,右上方有2个自定义的RadioButton,用来设置是平铺模式显示还是层级显示。
定义了一个ID为:flat_hier_group 的RadioGroup,里面有个2个自定义的RadioButton。

<RadioGroup android:gravity="right" android:orientation="horizontal" android:id="@id/flat_hier_group" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true"
  xmlns:android
="http://schemas.android.com/apk/res/android">
    
<RadioButton android:id="@id/flat_folders_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="0.0dip" android:button="@drawable/matte_flat_folders_selector" />
    
<RadioButton android:id="@id/hier_folders_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="-8.0dip" android:button="@drawable/matte_hier_folders_selector" />
</RadioGroup>

matte_flat_folders_selector的XML定义为:
 

<selector
  
xmlns:android="http://schemas.android.com/apk/res/android">
    
<item android:state_checked="true" android:drawable="@drawable/matte_flat_folders_selected" />
    
<item android:state_checked="false" android:drawable="@drawable/matte_flat_folders" />
</selector>

自定义的RadioButton实际上就是张背景透明的图片罢了。


播放器列表的Layout布局文件为 list_with_big_header.xml。

里面有个android:ellipsize属性:
EidtText和textview中内容过长的话自动换行,使用android:ellipsize与android:singleine可以解决,使只有一行。EditText不支持marquee

关于android:ellipsize属性更详细的文章:http://www.cnblogs.com/chiao/archive/2011/08/20/2147250.html


里面还有个 android:textAppearance 属性,这里涉及到了Android的theme和style设置了,更详细的文章参见:http://jiayanjujyj.iteye.com/blog/1392541
posted @ 2012-05-23 11:59 三人行,必有我师焉 阅读(419) | 评论 (0)编辑 收藏

获取屏幕Display: Activity.getWindowManager().getDefaultDisplay();
获取扩展存储目录:Environment.getExternalStorageDirectory()
通过文件获取Uri:Uri.fromFile(File)
根据文件路径获取图片:BitmapFactory.decodeFile(imageFilePath, bmpFactoryOptions)
获取相机Intent:new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
获取相机拍照后的图片:
Bundle extras = intent.getExtras();
Bitmap bmp = (Bitmap) extras.get("data");
触摸事件:onTouchEvent(MotionEvent ev)
媒体播放器:android.media.MediaPlayer
媒体控制器:android.widget.MediaController(和播放器不在同一个package下)
SurfaceView是视图(View)的继承类,这个视图里内嵌了一个专门用于绘制的Surface,类似于Canvas,但感觉比Canvas更高级。
android.provider.MediaStore里包含了相关的Image,Video,Audio信息,可通过managedQuery方法来查询和遍历。
Android中的AdapterView使用Adapter来获取数据,和JFace中的ContentProvider对应。
根据字符串路径获取Uri:
Uri.parse((String)Path)
封装好的视频View:android.widget.VideoView
视频录制:android.media.MediaRecorder
相机高画质:CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);


设置透明度(这是窗体本身的透明度,非背景)

WindowManager.LayoutParams lp=getWindow().getAttributes();
                lp.alpha=0.3f;
              getWindow().setAttributes(lp);
                
alpha在0.0f到1.0f之间。1.0完全不透明,0.0f完全透明


设置黑暗度

                WindowManager.LayoutParams lp=getWindow().getAttributes();
                lp.dimAmount=0.5f;
                getWindow().setAttributes(lp);
                getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);

dimAmount在0.0f和1.0f之间,0.0f完全不暗,1.0f全暗


设置背景模糊

getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,     
           WindowManager.LayoutParams.FLAG_BLUR_BEHIND);



//调用浏览器 
Uri uri = Uri.parse(""); 
Intent it = new Intent(Intent.ACTION_VIEW,uri); 
startActivity(it); 

//显示某个坐标在地图上 
Uri uri = Uri.parse("geo:38.899533,-77.036476"); 
Intent it = new Intent(Intent.Action_VIEW,uri); 
startActivity(it); 

//显示路径 
Uri uri = Uri.parse("http://maps.google.com/maps?f=d&saddr=startLat%20startLng&daddr=endLat%20endLng&hl=en"); 
Intent it = new Intent(Intent.ACTION_VIEW,URI); 
startActivity(it); 

//拨打电话 
Uri uri = Uri.parse("tel:10086"); 
Intent it = new Intent(Intent.ACTION_DIAL, uri); 
startActivity(it); 

Uri uri = Uri.parse("tel.10086"); 
Intent it =new Intent(Intent.ACTION_CALL,uri); 
//需要添加 <uses-permission id="android.permission.CALL_PHONE" /> 这个权限到androidmanifest.xml 

//发送短信或彩信 
Intent it = new Intent(Intent.ACTION_VIEW); 
it.putExtra("sms_body", "The SMS text"); 
it.setType("vnd.android-dir/mms-sms"); 
startActivity(it); 

//发送短信 
Uri uri = Uri.parse("smsto:10086"); 
Intent it = new Intent(Intent.ACTION_SENDTO, uri); 
it.putExtra("sms_body", "cwj"); 
startActivity(it); 

//发送彩信 
Uri uri = Uri.parse("content://media/external/images/media/23"); 
Intent it = new Intent(Intent.ACTION_SEND); 
it.putExtra("sms_body", "some text"); 
it.putExtra(Intent.EXTRA_STREAM, uri); 
it.setType("image/png"); 
startActivity(it); 

//发送邮件 
Uri uri = Uri.parse("mailto:android123@163.com"); 
Intent it = new Intent(Intent.ACTION_SENDTO, uri); 
startActivity(it); 

Intent it = new Intent(Intent.ACTION_SEND); 
it.putExtra(Intent.EXTRA_EMAIL, android123@163.com); 
it.putExtra(Intent.EXTRA_TEXT, "The email body text"); 
it.setType("text/plain"); 
startActivity(Intent.createChooser(it, "Choose Email Client")); 

Intent it=new Intent(Intent.ACTION_SEND); 
String[] tos={"me@abc.com"}; 
String[] ccs={"you@abc.com"}; 
it.putExtra(Intent.EXTRA_EMAIL, tos); 
it.putExtra(Intent.EXTRA_CC, ccs); 
it.putExtra(Intent.EXTRA_TEXT, "The email body text"); 
it.putExtra(Intent.EXTRA_SUBJECT, "The email subject text"); 
it.setType("message/rfc822"); 
startActivity(Intent.createChooser(it, "Choose Email Client")); 

//播放媒体文件 
Intent it = new Intent(Intent.ACTION_VIEW); 
Uri uri = Uri.parse("file:///sdcard/cwj.mp3"); 
it.setDataAndType(uri, "audio/mp3"); 
startActivity(it); 

Uri uri = Uri.withAppendedPath(MediaStore.Audio.Media.INTERNAL_CONTENT_URI, "1"); 
Intent it = new Intent(Intent.ACTION_VIEW, uri); 
startActivity(it); 

//卸载APK 
Uri uri = Uri.fromParts("package", strPackageName, null); 
Intent it = new Intent(Intent.ACTION_DELETE, uri); 
startActivity(it); 

//卸载apk 2 
Uri uninstallUri = Uri.fromParts("package", "xxx", null); 
returnIt = new Intent(Intent.ACTION_DELETE, uninstallUri); 

//安装APK 
Uri installUri = Uri.fromParts("package", "xxx", null); 
returnIt = new Intent(Intent.ACTION_PACKAGE_ADDED, installUri); 

//播放音乐 
Uri playUri = Uri.parse("file:///sdcard/download/sth.mp3"); 
returnIt = new Intent(Intent.ACTION_VIEW, playUri); 

//发送附近 
Intent it = new Intent(Intent.ACTION_SEND); 
it.putExtra(Intent.EXTRA_SUBJECT, "The email subject text"); 
it.putExtra(Intent.EXTRA_STREAM, "file:///sdcard/cwj.mp3"); 
sendIntent.setType("audio/mp3"); 
startActivity(Intent.createChooser(it, "Choose Email Client")); 

//market上某个应用信,pkg_name就是应用的packageName 
Uri uri = Uri.parse("market://search?q=pname:pkg_name"); 
Intent it = new Intent(Intent.ACTION_VIEW, uri); 
startActivity(it); 

//market上某个应用信息,app_id可以通过www网站看下 
Uri uri = Uri.parse("market://details?id=app_id"); 
Intent it = new Intent(Intent.ACTION_VIEW, uri); 
startActivity(it); 

//调用搜索 
Intent intent = new Intent(); 
intent.setAction(Intent.ACTION_WEB_SEARCH); 
intent.putExtra(SearchManager.QUERY,"android123") 
startActivity(intent); 

//调用分享菜单 
Intent intent=new Intent(Intent.ACTION_SEND); 
intent.setType("text/plain"); //分享的数据类型 
intent.putExtra(Intent.EXTRA_SUBJECT, "subject"); //主题 
intent.putExtra(Intent.EXTRA_TEXT, "content"); //内容 
startActivity(Intent.createChooser(intent, "title")); //目标应用选择对话框的标题


获取Location:
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_COARSE);
criteria.setPowerRequirement(Criteria.POWER_LOW);
LocationManager locManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
if(locManager.getBestProvider(criteria, true) != null)
myLocation = locManager.getLastKnownLocation(locManager.getBestProvider(criteria, true));
else {
myLocation = new Location("gps");
myLocation.setLatitude(47.100301);
myLocation.setLongitude(-119.982465);
}
posted @ 2012-05-05 19:41 三人行,必有我师焉 阅读(843) | 评论 (0)编辑 收藏


3.1以下版本升级到最新版最好先还原到初始档,然后重新备份一下初始档。

如果不希望重新开局,以下提供正确的操作步骤:
1、进入备份与还原界面。
2、选择“备份当前游戏数据“进行备份。
3、选择“ 还原游戏至初始档状态“进行还原。
4、选择“设置当前游戏数据作为游戏初始档”进行备份。
5、在还原备份数据的列表中选择步骤2备份的数据存档进行还原

就可以正常进入游戏,并且更新了原始档。


3.9版更新内容:
1、修正了若干已知Bug。
2、象兵及战车数据使用兵种第二防御数据。
3、全面更新地图坐标算法,防止无法进入游戏或者武将位于山地无法移动。
4、增加了切换游戏势力功能,可以无需开档游玩任意势力。
5、增加了东州兵和骆驼兵模的防跳补丁。


3.8版更新内容:
1、增加了解锁朝廷、在野、乱军势力的功能。
2、增加了解除诸葛亮外出云游状态的脚本补丁,玩家可以使用任何势力收买诸葛亮,并且激活三顾茅庐技能。
3、增加了全势力官爵升级的脚本补丁。
4、增加了部分武将特殊技能全势力激活的脚本补丁。
5、增加了创建新兵种功能。


3.7版更新内容:
1、修正了一些细节上的bug。
2、增加了雾隐版吕玲绮卫队女兵模型的导入。
3、增加了武将模型作为骑兵模型的导入,并且可自由移除已导入的模型。
4、步兵的士兵模型可以选择将军模型,骑兵的士兵模型可以选择已导入的将军模型和雾影女兵模型。

3.6版更新内容:
1、修正了导入弩兵陷阵营战斗跳出的bug。
2、修正了收买武将修改器发生异常的bug。
3、修正了更换异族武将势力游戏跳出的bug。
4、修改了一些2种势力都有的武将相关的bug。
5、新建武将后清空武将编辑页面状态。
6、编辑武将能力页面新增了编辑武将卫队经验选项。
7、基本修改页面增加了所有兵种生产回合、费用下调的修改。
8、基本修改页面增加了所有城市建筑生产回合、费用下调的修改。

3.5版更新内容:
1、修正了兵种修改页面中兵种名称显示错乱的bug,现在很容易分清雇佣兵和城市招募了。
2、增加了乱军刷新概率的修改。
3、增加导入弩骑高顺卫队和弩兵陷阵营的功能。

3.4版更新内容:
1、修正了编辑大众卫队武将名字时会改变大众卫队名称的bug。
2、增加了编辑势力地图颜色的功能。
3、增加了降低敌方所有武将忠诚度的功能。
4、解决游戏中部分武将心灰意冷状态下无法被收买的bug。

3.3版更新内容:
1、修正了一些bug,比如编辑武将坐标会发生变化的bug。
2、创建新武将页面的爵位增加了自定义功能。
3、难度修改页面中,增加了禁用电脑驿站加成,禁止电脑生产刺客,以及能够编辑电脑太守加成几率的新功能。

3.2版更新内容:
1、增加了1.9a中特有的马匹,1.9a特有的马匹一般冲量都比较大,老版马匹冲量较小。
2、修正了武将地图坐标自动计算错误的bug。我把RGB颜色值写错了,另外遗漏了森林颜色。
3、修正了编辑新武将坐标和兵模无效生效的bug。
4、增加了孙刘曹中特殊武将不能被交换到其他势力的注释。

3.1版更新内容:
1、修正了未对掌旗官旗帜,城市旗帜,援军,盟军旗帜做修改的bug。
2、修正了编辑武将人物列传未繁体化,换行的bug。
3、增加了修改势力后代武将姓氏的功能。

3.0.1版更新内容:
1、更新了压缩武将图片的算法,让武将图片显示的更加清晰。
2、修正了解压缩更新包,仅支持GBK编码的bug。

3.0版更新内容:
1、新增编辑势力功能。
2、修正编辑武将坐标可能导致游戏异常的bug。
3、修正禁止电脑驿站暴兵的bug(此处bug是由于1.9和1.7的驿站代码不一样导致的)。
4、增加了添加势力兵种对兵营的要求,提高游戏的可玩性。
5、增加了对城墙生命值的修改。
6、增加了武将身份设置功能,方便玩家自定义君主或者继承人。
7、增加了修改器的自动更新功能,3.0及其后续版本若发现修改器有新版本,将会自动更新到最新版本。

注意事项:
因为3.0版改动较大,若使用编辑势力功能,请首先还原游戏数据到初始状态,重新做一次原始备份档,否则编辑势力后,无法还原到游戏原始状态。


说明:
1、修改器安装文件夹路径最好不要包含中文或者空格(有个别用户因为中文和空格路径问题无法启动修改器,调试器会提示:
Error occurred during initialization of VM
java.lang.UnsatisfiedLinkError: no zip in java.library.path


2、正常情况下,请使用“三国全面战争1.9a修改器”运行修改器。

3、非正常情况下,比如修改器无法启动成功,或者一直处于系统初始化状态,或者弹出错误窗口(不包括修改失败),请使用“三国全面战争1.9a修改器(调试器)”运行修改器。调试器启动时会显示一个黑色的dos窗口,如运行时发生错误,错误信息会打印到黑色dos窗口,请截图或者复制错误信息,发送到:http://www.1mod.org/thread-37918-1-1.html,我看见后会及时修正错误。

4、游戏原始备份档下载地址:http://feeling.sourceforge.net/patch/1.9a/default.zip
如果你需要恢复原始数据,而又未作原始档备份,可以从此地址下载。
恢复原始数据的2种方法:
1、解压缩后,复制data目录下的数据文件到游戏中,替换游戏数据文件。
2、复制压缩文件到游戏目录下的/patch/bak目录下,替换掉你自己的原始备份档,然后通过修改器恢复原始备份档。

5、关于杀毒软件误报问题:
(1)如果是国产杀毒软件报病毒,请你不要抱怨修改器,去抱怨那些垃圾杀毒软件吧,技术不过关,老是误报。
(2)如果是国外知名杀毒软件报病毒,比如卡巴斯基,麦咖啡,微软MSE等等,你可以截图发给我。
(3)推荐使用微软MSE,口碑不错,完全免费。


6、修改需理智,请谨慎修改,方能提高游戏的可玩性。










下载地址:http://feeling.sourceforge.net/patch/1.9a/patch_1.9a_3.9.zip

修改器简易教程:http://tieba.baidu.com/p/1418490788


小技巧:
1.如果希望新建武将成为势力君主,可以在创建后和武将势力君主交换。
2.能够更换所属势力的武将不能有后代,也不能是势力君主或者继承人,如果希望更换这些武将的势力,可以先和势力内的没有后代的垃圾武将交换一下,让他们成为自由身,就可以更换武将所属势力了。
posted @ 2012-01-25 22:57 三人行,必有我师焉 阅读(118872) | 评论 (85)编辑 收藏

关于PaletteData的生成:
case Gdip.PixelFormat16bppARGB1555:                                        
case Gdip.PixelFormat16bppRGB555: 
    paletteData = new PaletteData(0x7C00, 0x3E0, 0x1F); 
break;
case Gdip.PixelFormat16bppRGB565: 
    paletteData = new PaletteData(0xF800, 0x7E0, 0x1F); 
break;
case Gdip.PixelFormat24bppRGB: 
    paletteData = new PaletteData(0xFF, 0xFF00, 0xFF0000); 
break;
case Gdip.PixelFormat32bppRGB:
case Gdip.PixelFormat32bppARGB: 
    paletteData = new PaletteData(0xFF00, 0xFF0000, 0xFF000000); 
break;

32位ImageData中的data是以RGBA的顺序存储的。data[0]:red,data[1]:green,data[2]:blue,data[3]:alpha

从byte[]中读取RGB pixel:
public static int getPixelFromRGBA( int depth, byte[] data )
{
        switch ( depth )
        {
            case 32 :
                return ( ( data[0] & 0xFF ) << 24 )
                        + ( ( data[1] & 0xFF ) << 16 )
                        + ( ( data[2] & 0xFF ) << 8 )
                        + ( data[3] & 0xFF );
            case 24 :
                return ( ( data[0] & 0xFF ) << 16 )
                        + ( ( data[1] & 0xFF ) << 8 )
                        + ( data[2] & 0xFF );
            case 16 :
                return ( ( data[1] & 0xFF ) << 8 ) + ( data[0] & 0xFF );
            case 8 :
                return data[0] & 0xFF;
        }
        SWT.error( SWT.ERROR_UNSUPPORTED_DEPTH );
        return 0;
}

从pixel中取出RGB值:
RGB rgb = imagedata.palette.getRGB( pixel );

生成一个空的32位图片:
ImageData dest = new ImageData( width,
                height,
                32,
                new PaletteData( 0xFF00, 0xFF0000, 0xFF000000 ) );

24位透明图片转成32位透明图片:
    public static ImageData convertToRGBA( ImageData src )
    {
        ImageData dest = new ImageData( src.width,
                src.height,
                32,
                new PaletteData( 0xFF00, 0xFF0000, 0xFF000000 ) );

        for ( int x = 0; x < src.width; x++ )
        {
            for ( int y = 0; y < src.height; y++ )
            {
                int pixel = src.getPixel( x, y );
                RGB rgb = src.palette.getRGB( pixel );

                byte[] rgba = new byte[4];

                rgba[0] = (byte) rgb.red;
                rgba[1] = (byte) rgb.green;
                rgba[2] = (byte) rgb.blue;

                if ( pixel == src.transparentPixel )
                {
                    rgba[3] = (byte) ( 0 );
                }
                else
                {
                    rgba[3] = (byte) ( 255 );
                }
                dest.setPixel( x, y, getPixelFromRGBA( 32, rgba ) );
            }
        }
        return dest;
    }

posted @ 2012-01-15 13:49 三人行,必有我师焉 阅读(3552) | 评论 (1)编辑 收藏

SourceForge最近实在太慢了,忍无可忍,每天浪费我大量时间……终于让我不得不投向GitHub的怀抱……
posted @ 2012-01-14 16:33 三人行,必有我师焉 阅读(2266) | 评论 (0)编辑 收藏

JDK1.6的File.createTempFile方法有bug,在我的机器上第一次调用该方法需要耗时5秒时间,换了好几个1.6的版本均有该问题。JDK1.4,1.5则无此问题。

不一定所有的机器都有此问题,不过这儿肯定是有问题的,起码在我的机器上有问题。
posted @ 2012-01-13 15:51 三人行,必有我师焉 阅读(1625) | 评论 (2)编辑 收藏

Java应用定制工厂(以下简称为JCB,Java Customization Builder)是一个针对Java轻量级桌面应用进行精简优化的小工具,使用它可以精简你的jar包,并自动生成一个精简的JRE,也可以使用它生成一个Exe启动引导程序,并且能够对你的Java应用自动做Pack200和Unpack200处理。使用本工具定制的Java桌面应用通常不会超过5M(包含JRE),SWT客户端程序相对于Swing客户端程序更小,一般不会超过3M。

JCB1.0.3主要功能是可以支持
添加Exe的版本信息,并且能够更细节的定义Exe的启动行为,比如是否显示一个splash窗口,是否优先使用精简版的jre,以及增加了对unpack操作的优化,让应用程序第一次运行启动的更快。同时也增加了对系统权限的支持,不再要求需要管理员权限才能运行软件,Guest用户一样的使用。

下一个版本考虑增加一个Au3的编辑器,具有语法高亮和智能辅助功能,可以让高级用户定制自己的Exe行为。

软件主页:http://jcb.sourceforge.net
JCB1.0.3下载地址:http://sourceforge.net/projects/jcb/files/JCB_1.0.3.zip/download


posted @ 2011-12-26 22:13 三人行,必有我师焉 阅读(1599) | 评论 (3)编辑 收藏

在一个线程中启动了一个线程钩子,然后死活拿不到主线程中的消息,全局钩子就没问题。折腾了一下午才发现这个线程钩子是在子线程中启动的,GetCurrentThreadId 方法拿到的不是主线程的threadId,自然也就获取不到主线程的系统消息。Google了好多文章,都没有提到这一点,真TMD郁闷,完全浪费我时间,还以为是我的类库写错了,闹了半天是调用的参数传的不对。
posted @ 2011-12-24 18:58 三人行,必有我师焉 阅读(1775) | 评论 (1)编辑 收藏

同样的API, IShellFolder遍历控制面板里面节点的children,所有的.net代码都能获取,所有的非.net代码都无法获取???

本来还以为是代码的问题,debug一天死活没找到问题,最后在codeproject上找了十几个例子,发现都一样的结果,why? 

难道仅仅对.net的才开放遍历的权限?
posted @ 2011-12-14 12:35 三人行,必有我师焉 阅读(1726) | 评论 (1)编辑 收藏

1、安装VS2008
2、安装 Microsoft Windows SDK for Windows 7 and .NET Framework 3.5 SP1
3、修改SDK的SetEnv.cmd的第146行 
Set "VCTools=%VCRoot%\VC" 为 Set "VCTools=%VCRoot%\VC\Bin"
4、修改build.bat的环境配置
call "C:\Program Files\Microsoft SDKs\Windows\v6.1\Bin\SetEnv" /xp /x86 /Release (不是%PROGRAMFILES%目录,编译字幕为绿色,PROGRAMFILES%目录编译出来的dll有400多k。)
call "%PROGRAMFILES%\Microsoft Visual Studio 9.0\VC\vcvarsall.bat"
posted @ 2011-12-13 13:16 三人行,必有我师焉 阅读(370) | 评论 (0)编辑 收藏

     摘要: Java应用定制工厂(以下简称为JCB,Java Customization Builder)是一个针对Java轻量级桌面应用进行精简优化的小工具,使用它可以精简你的jar包,并自动生成一个精简的JRE,也可以使用它生成一个Exe启动引导程序,并且能够对你的Java应用自动做Pack200和Unpack200处理。使用本工具定制的Java桌面应用通常不会超过10M(包含JRE),SWT客户端程序相对于Swing客户端程序更小,一般不会超过5M。  阅读全文
posted @ 2011-12-12 16:27 三人行,必有我师焉 阅读(6217) | 评论 (12)编辑 收藏

GreenJVMMake 是一个精简JRE的小工具,详细信息请参见项目:

http://code.google.com/p/greenvm/

javaonepackage 是一个集成了GreenJVMMake的IDE,可以方便的生成自定义的JRE,详细信息请参见项目:

http://code.google.com/p/javaonepackage/

比较遗憾的是javaonepackage的作者遗失了代码,导致项目无法进一步的更新,影响了使用。

用以上工具生成的精简JRE通常不超过2M,可是用exe4j将Java应用转换成exe的时候,却会抛出Couldn't load main class,原因是因为exe4j使用自己的jar来加载用户的Jar包,这其中用到了一些反射机制,精简JRE里面当然是不含有多余的class文件的,所以加载必然失败。我们需要做的就是把这些相关的class添加到精简JRE中,这些class包含在 java\lang, java\util, sun\reflect 这三个包中。将这些class添加到精简jre中,大小也仅仅增加数百K而已,在我们可以的接受范围之内。

PS:由于GreenJVMMake的机制是检查运行时加载的class文件,所以它很可能遗失Jar运行所需要的exception class,这会导致运行时JVM的崩溃,用户需手动加载所有可能会产生的exception class,包含runtime的和非runtime的。
posted @ 2010-09-02 10:53 三人行,必有我师焉 阅读(4008) | 评论 (1)编辑 收藏

现在网络上越来越流行.net和java写的客户端的小应用程序,而且后缀是exe。本文讨论的是如何从exe4j封装的exe文件中将自己想要的jar抽取出来。

exe4j一直是一种比较通用的java exe封装工具,但是其并没有将jar转换为本地文件,而是将jar文件通过特殊处理后,封装成的一个exe文件。因此只要我们了解了exe4j的原理,就可以将jar文件从exe文件中提取出来,并通过反编译工具来查看程序代码。

1. 分析Exe4J,得知其在添加文件到.exe时,使用0x88将文件内容Xor,所以第一步,我们需要将原始的数据提取出来:
import java.io.*;
import java.util.*;

public class gen {
    
public static void main(String args[]) throws IOException {
        FileInputStream fin 
= new FileInputStream(args[0]); // 可以将整个exe文件解码
        FileOutputStream fout = new FileOutputStream(args[1]);
        BufferedInputStream bin 
= new BufferedInputStream(fin);
        BufferedOutputStream bout 
= new BufferedOutputStream(fout);
        
int in = 0;
        
do {
            in 
= bin.read();
            
if (in == -1)
                
break;
            in 
^= 0x88;
            bout.write(in);
        } 
while (true);
        bin.close();
        fin.close();
        bout.close();
        fout.close();
    }
}

2.分析提取出来的数据文件,使用WinHex查看其16进制代码。由于Jar文件的开头总是PK开头,并且总包含有manifest.mf文件,并且结尾总是有3个00,同时结尾段有整个Jar包文件的索引,我们可以根据这一特性来分析我们需要的片段。

1、搜索Jar的manifest,然后往前找,找到的第一个PK段,即为一个Jar的开头。
2、查看片段里Jar里的每个class信息,直到最后的文件索引片段。
3、一个Jar的结束片段位于索引片段之后,仍然包含着PK段,并且最后包含着3个00,且这3个00距离PK大概20个字节左右

根据以上3条准则,足以提取整个Jar数据段,然后导入新文件中,并且以zip字段命名,尝试用ZIP解压缩软件打开,看看是否抽取正确。

需要注意的是WinHex非注册版,只能保存280K大小的文件,更大的Jar文件,需要注册版的WinHex才行。
posted @ 2010-08-22 01:03 三人行,必有我师焉 阅读(6767) | 评论 (4)编辑 收藏

1、调用截图工具:

http://iecapt.sourceforge.net/

2、使用Java类库,通过Render生成Java2D图像:

http://www.ldotc.com/Web+Page+Thumbnails+in+Java.html

方法1的优点在于,图像不会失真,速度快,但是缺点是依赖于服务器端的UI,无UI的话,则无法使用。
方法2的优点是不依赖于服务器端的UI,但是图像容易失真,且速度相对较慢……
posted @ 2010-08-17 12:50 三人行,必有我师焉 阅读(1438) | 评论 (0)编辑 收藏

     摘要: TGA or TARGA format is a format for describing bitmap images, it is capable of representing bitmaps ranging from black and white, indexed colour, and RGB colour, the format also supports various compr...  阅读全文
posted @ 2010-03-29 13:02 三人行,必有我师焉 阅读(1989) | 评论 (0)编辑 收藏

Eclipse 是一个集成开发环境,同时又是一个产品平台。这样有时候我们就会碰到一个问题,在开发Debug项目的时候没有问题,打包发布的时候就有问题了,这可如何是好?由于Debug时候和发布后plugin的ClassLoader机制不尽相同,出现这个问题的几率还有会有的。

Java 在这一点上为我们提供了方法,那就是远程Debug。远程Debug一般用于Web开发,或者客户端无法负载大规模的应用时才会运用到,所以Desktop developer 很少会涉及到这个概念。不过Eclipse 的产品平台却让我再次体会到了Java的强大。

关于Eclipse Remote Debug的文章,大家可以从此处学习:

http://www.ibm.com/developerworks/cn/opensource/os-eclipse-javadebug/index.html

Remote Debug 需要2方面的设置,一个是产品平台JVM启动参数的设置,需要让平台以远程Debug的模式启动。然后是在开发端监听产品平台的运行状态。当产品平台运行到断点代码时,Eclipse开发端就会进入Debug界面,像普通debug一样正常debug了。

posted @ 2009-09-10 16:59 三人行,必有我师焉 阅读(2401) | 评论 (1)编辑 收藏

网上关于Eclipse Fragment的资料比较少,引用Eclipse Wiki的一段话:

An Eclipse Fragment is a way of putting your own classes into the "class loader" of another package (basically, it's as though your class was actually in the other package). If you combine this ability of a Fragment with the notion of a plugin's classpath ordering, then you can force your class to load before a like-named class in the original package.

简而言之,Fragment可以利用Eclipse平台的ClassLoader机制替换原有Plugin的某些文件,以便实现自己的功能。如果仅仅是因为Plugin扩展,而需要替换自己项目的某些Plugin,可以参考文章:

http://wiki.eclipse.org/Steps_to_use_Fragments_to_patch_a_plug-in  (来之不易,感兴趣的可以收藏下)

读完这篇文章,你大概就应该能够了解到Fragment的实现分为两部分:Host 和 Patch。这两部分对应的plugin的manifest.mf文件都需要做特殊处理,对于Patch的build方式也要特殊处理,那就是build出来的plugin jar里放置的不是松散的class文件,而是一个特殊的jar文件,这个 jar 文件定义在Host plugin的manifest.mf 的classpath里面。

通常情况下,按照这篇文章的做法是没有问题的。但是在开发阶段,有一种情况可能无法实现class的替换。

我公司的项目是使用perforce进行项目版本控制的,但是perforce比较傻,有些重要的功能没有实现,而又很关键,因此我想自己针对perforce的eclipse plugin做一个fragment,添加自己想要的功能。但是这个plugin没有source code,而我自己的hack也是反编译class文件进行的。所以在我的work space里,并没有Host plugin的 project。结果按照这篇文章的做法,始终不能在workbench debug的状态下,正确load我hack过的class。因为在代码模式下面是可以正确load的,而现在没有代码,在数次检验无果之后,只能针对ClassLoader去思考了。Host文件里要求一个jar文件,我就用PDE 将 fragment export出来,把Fragment plugin jar 包里包含的那个 jar 文件解压出来,放到 patch project 里,然后重新Debug, OK,这次果然没问题了。一个小小的Class Loader问题,真的能够要人命呀……这应当算是Eclipse的一个bug吧,除非是对一个Plugin进行hack,否则一般也不会碰到这种情况。普通的项目开发,肯定会包含Host Plugin的Project。

我的经历权且当做饭后谈资,不足为虑。我这儿想说的是Fragment机制非常好用,也易于Plugin扩展。比如你的项目分为Open Source 和 Commercial 2种的话, Commercial 部分也可以通过Fragment来实现,不一定需要走Extension Point路线。由于网上相关文章不多,还需要自己多多研究,了解其机制。

posted @ 2009-09-10 16:42 三人行,必有我师焉 阅读(1731) | 评论 (0)编辑 收藏

自定义控件通常是从一个Composite或者Canvas继承而来,但是缺省状态下,这两个控件都无法通过键盘的Tab键得到焦点。通过对SWT的debug,我发现要实现该事件,必须满足一个必要条件:为自定义控件安装一个KeyEvent的监听器

实际上我个人认为这出自于SWT的实现者自己的考虑,可能认为如果没有KeyListener,也就意味着没有Key的操作,那么也无需通知Travserse事件,Travserse事件的前提就是Key操作。但是在某些特定情况下我们不需要KeyListener,也可以模拟出KeyEvent的效果,比如通过TraverseListener的keyTraversed方法。总而言之,想通过键盘为某一个自定义控件获取焦点,就老老实实的给控件加一个KeyListener吧。

此处附加一些和Traverse相关的小知识:

1、如何通过键盘的Tab键跳出 Multiple Style 的Text?
        请使用 Ctrl+Tab 组合键。

2、如何通过键盘操作让上一个控件获取焦点?
        请使用 Shift+Tab 或者 Ctrl+Shift+Tab 组合键。

3、Button 可以通过回车键和空格键激活。所以如果有些地方无法使用回车键(比如按钮在Dialog中),可以考虑使用空格键。

4、一些特殊的KeyCode:
        回车键:SWT.KEYPAD_CR
        小键盘的回车键:SWT.TRAVERSE_RETURN
        方向键:SWT.ARROW_UP,SWT.ARROW_DOWN,SWT.ARROW_LEFT,SWT.ARROW_RIGHT
posted @ 2009-04-07 11:22 三人行,必有我师焉 阅读(2232) | 评论 (2)编辑 收藏

项目地址:http://findbugs.sourceforge.net/

用于分析项目代码,自动发现项目潜在Bug,万中无一的好东西,绝对值得下载一试,有兴趣的自己研究。
TeamLeader和PM 强烈推荐,用于Code Review。
posted @ 2009-02-16 00:02 三人行,必有我师焉 阅读(2868) | 评论 (5)编辑 收藏

做不下去了,Vista快把我逼疯了,啥都不支持,随意取消n多API,开发人员能做的事情太有限了,Vista你到底想干什么?

看一看MSDN,全是抱怨Vista的。管理员给出的答案就是按照兼容XP的方式运行,这算哪门子解决方案呀。

Have you tried running your application elevated? (Right Click->Run As Administrator) If this doesn't work try applying an XP SP2 Compatibility shim from the Compatibility Tab in the properties dialog. (Right Click->Properties | Compatibility).

Let me know if this works.

Thanks!


怒呀!!!!!!!

从Win3.1 到 Vista,没有哪个版本比Vista更失败的,无论是从用户角度,还是从开发角度。微软是不是想倒闭不做了?
posted @ 2008-12-05 18:16 三人行,必有我师焉 阅读(2295) | 评论 (5)编辑 收藏

沉寂了一段时间,现在继续SWT Win32 Extension的开发,说实话,最近的进展挺失败的。Black Glossy效果我发现在某些机器上的显示效果非常的卡,我自己的机器却没有任何问题。另外就是我最近在XP下实现了Window Mixer API,用来管理系统声音。Win98,2000,XP都没有问题,结果Vista让我郁闷了,Vista居然取消了Mixer,我哭呀。以下是微软员工给出的答案:

That's because the mixer APIs are virtualized on Windows Vista - you don't get to see the real audio hardware by default, only a virtualized version.  We did this because the vast majority of applications that used the mixer APIs were using them to control their own volume, which is quite rude (it says "I own the box, no other sounds on the system matter").

 You have two choices.  The first is to run your application in XP compatibility mode, in which case you'll be able to access the real audio hardware (please note: you'll see exactly what the hardware provides, which may lead to surprising results).

 The other choice is to use the new Vista audio engine APIs.  either the IAudioEndpointVolume API which allows you access to the master volume for each of the audio endpoints on the machine.  If you really need to access the actual audio controls the IDeviceTopology interface will allow you direct access to the various controls on the audio hardware.

没脾气了,只能专门为Vista实现一套简单的API了。
posted @ 2008-10-23 18:25 三人行,必有我师焉 阅读(2379) | 评论 (5)编辑 收藏

最近做了一个可视化编辑器相关的项目,采用了GMF。现在项目即将进入尾声,以后可能不再接触这个东西,so在还没有忘掉之前,将经验记录下来以供大家参考。 当然做这个项目之前,我对GMF,EMF一无所知,只是对GEF有所了解,所以可能会有些囫囵吞枣的感觉,但是相信我的理解还是会对各位有所帮助。

GMF其实是一个整合了GEF,EMF的自动化生成代码的项目。使用GMF,可以快速的生成一个包含可视化编辑器的项目,这一点网上有文章介绍:15分钟学会GMF。15分钟是夸张了一点,不过15天完成一个可视化项目,对一个熟练的GMF程序员来说,却绝对不是什么难事。但是既然使用了GMF框架,你就不得不面对以下几个问题:

一、既然是框架,自然要遵守框架的规则,GMF是模式驱动设计的,也就是说必须建好模型,才能进行下一步的开发工作。但是国内很多项目,需求总是不断更新,这种情况下,不要轻易使用GMF。
二、使用GMF框架,自然不具备GEF的灵活性,很多地方都被限制住了,不适合做灵活性非常大的图形设计。
三、不得不忍受GMF里大量的bug。

我比较过GMF1.0,2.0,2.1三个版本,其中1.0完全不能容忍,2.0比较傻,2.1还过得去,所以GMF还是值得大家期待的,毕竟是越做越好。


一个比较简单的GMF流程编辑器

个人感觉GMF非常适合做流程编辑器,主要是图形要求简单,并且适合GMF自动布局,兼之对模型要求不高。

在学习GMF之前,有必要研究一下GEF和EMF,其中GEF是必须要有所了解的,而对EMF要求不算太高,能建一个ecore模型,了解emf的commandstack就够了(其实我本人不太喜欢EMF,我更喜欢用自己的模型框架)。

GMF的学习周期大概2周左右,上手到熟练大概需要1个月的时间(我自己的学习周期),当然这期间会碰到各种各样的技术问题,针对不同的case,碰到的问题也会不一样,而我这个系列的文章,主要就是把我所遇到的问题陈列出来,并提供一个解决之道。

附GMF相关资料:
八进制:GMF常见问题
GMF Newsgroup Q and A
posted @ 2008-09-04 14:52 三人行,必有我师焉 阅读(2535) | 评论 (4)编辑 收藏

在Birt Designer中,Binding 是无处不在的,如何正确的是用Birt的Binding呢?首先我们需要知道Birt的Binding Type。

Birt的Binding type随着Birt的版本的升级而越来越丰富,早期的Birt版本只有2种类型:为自己创建一个Data Column Binding,和使用Container的Data Binding,随着CrossTab的出现,进而出现了Cube,ReportItem Reference Binding的概念。

普通的Binding,一般是通过属性编辑器的BindingPage来创建,可以set一个Data set,然后自动创建一个Binding列表。Crosstab和Chart两种类型的Report Item 可以不依赖于Data set,而采用Cube来作为Bingding源。而ReportItem Reference 的概念更是简便了Binding的生成,我们可以让一个ReportItem 直接引用另外一个ReportItem的Binding,而非仅仅是Container的Binding,当然既然是引用,那么你是无法编辑这些Binding的,而且被引用的ReportItem必须包含一个名字,有些ReportItem比如Table本身是可以不设名字的,但在这个地方你就要加上了。

再来说说Binding的设置,我们可以通过Binding Dialog和Binding Page来设置,这两种设置是不同的,如果在Binding Dialog上添加一个Binding,那么这个Binding是添加到这个Report Item的BindingHolder身上,如果在 Binding Page上设置,则Bindnig会添加到自身,让自己成为BindingHolder。
posted @ 2008-07-04 11:47 三人行,必有我师焉 阅读(2603) | 评论 (1)编辑 收藏

通过打开Birt透视图,然后Reset至缺省的Layout,我们能够看到基本的一些View和一个主要的报表可视化编辑器。

先来说一下View,Birt主要的View包含7块:

左上角包含3个视图,Palette,Data Explorer和Resource Explorer,Palette里放置了报表常用的可视化组件,直接将这些组件拖到报表设计器的时候,这些组件并没有作特殊的初始化处理,而从Data Explorer里向设计器拖入一个Dataset会自动生成一个Table,拖入一个Cube会生成一个Crosstab,拖入一个Dataset Column会生成一个DataItem。Data Explorer主要是用来管理和显示数据源。Resource Explorer 老版本里是Library Explorer,新版本则变更为了Resource Explorer,用来特别显示Library,CSS文件,其他文件则不进行特殊处理。

左下角有2个视图,包含Navigator视图和Online视图,Navigator视图是用来建立Birt项目用的,如果是Birt Rcp版本,我们则看不到这个视图,这是IDE版本专有的一个视图,在Rcp版本里没有Project这个概念,直接以文件的形式进行管理。Outline是Birt里较为重要的视图,所有的报表部件都会在这个View里显示并会随着报表的变化实时刷新。

右下角包含了Property Editor 和 Problems两个视图, Property Editor 用来编辑每个可视化报表元素的属性,一般比较常用的属性都会在前几个Tab页里,但是有些属性前几个Tab页里都没有,这时候需要选择Advanced这个Tab页,它里面包含了这个元素所有可用的属性,如果连这儿也没有,那么说明该元素不存在你想要的属性。Problems视图则用来显示报表收集到的一些问题,如果报表校验的时候发生错误,会在此处显示出来。

以上的那些视图属于缺省视图,但还有几个视图也比较有用,一个是Error log视图,一个是Example视图。Error log视图主要是开发用的,当你使用Birt进行二次开发的时候,难免会碰到一些bug,当你感觉有问题的时候,不妨打开error log视图,只要Birt捕捉到了异常,一般都会显示在这个视图里。而Example视图里提供了各种各样的视图,可以Open 和 Save, Open的时候会自动帮你在workspace里建立一个项目,以便你浏览该项目文件。Save则是把这个Example保存到本地某个目录。

说完视图,再来看看Birt可视化的报表设计器,这个设计器包含了五个部分:Layout,Master Page,Script,XML Source,Preview。

Layout为设计器的主要部分,只要通过可视化的拖拽,一个报表就会被自动生成出来,当然要想灵活运用报表设计器,就必须对各个组件的属性了如指掌,Birt提供了丰富灵活的属性供用户选择。MasterPage主要用来设置页眉页脚,以及打印显示之类的功能。Script页面,当你在Layout页面里选中一个元素之后,切换到Script页面,就可以对这个元素进行脚本编码,主要用来监听各种事件,使用Javascript,在采用Web显示里,这些脚本会生效。XML Source则是将这张报表背后的XML source显示出来,用户如果觉得自己对Birt很熟,可以直接在这儿手工修改代码。Preview则是预览Birt报表,Birt会启动Tomcat显示Web运行效果。

基本上Birt还是比较强大的,基本的功能一应俱全。可能你会发现缺少一些更高级花哨的功能,比如flash之类的,其实怎么说呢,不是Birt没有,而是开源版的没有,这个功能在Birt商业版里,可以在 http://www.actuatechina.com/download.php 下载专业版试用。如同IBM,这是这类公司特有的策略,免费上面做收费。喜欢的话,可以试一下专业版,呵呵,可惜网上找不到破解版。

posted @ 2008-06-20 11:48 三人行,必有我师焉 阅读(3817) | 评论 (1)编辑 收藏

Eclipse3.4马上就要Release了,相信Eclipse的fans都已经开始翘首以待,望穿秋水了。不过现在的RC版本用得很不爽呀,性能非常差,Eclipse的惯例就是最后一个月的工作基本上就是对性能做优化,以达到最佳使用效果。

随着Plugin的增多,Eclipse采用了特殊的策略,增加了一个子目录dropins,用来放用户新增加的plugin,而原有的plugins目录,则基本用于系统基本功能,2者的区别就是,前者可以任意添加删除,后者则基本上是一个ReadOnly的状态,添加了就不能再作修改了,Eclipse会将每一个添加的plugin记录下来,以后启动就不再检查这些plugin了。

不过对于我来说,我一直都习惯于使用plugins目录,下了一个插件直接解压,就直接覆盖安装到plugins目录了,而且有一些plugin不支持dropins目录,必须在plugins目录下才能正常工作。不过一旦插件安装失败,想再reset就比较麻烦了。Eclipse不会自动恢复到初始安装状态,经过测试,找到了一个解决方案,用原始的eclipse的文件替代2个目录:configuration和p2目录。plugins文件位置记录在configuration\org.eclipse.equinox.simpleconfigurator\bundles.info里,p2目录里则记录了更多的初始化信息。要想Reset Eclipse3.4,这两个目录必须被恢复到初始化状态,然后就可以正常使用了。

posted @ 2008-06-17 22:30 三人行,必有我师焉 阅读(7807) | 评论 (5)编辑 收藏

最近的项目需要使用报表,因为是RCP应用,所以选择了Birt,用了一下,感觉还可以,就是网上资料少了点,不过以前也研究过一些Eclipse相关技术,这些都不重要了,找了SDK版本Debug,啥研究不出来?

BIRT是一个Eclipse-based开放源代码报表系统。它主要是用在基于Java与J2EE的Web应用程序上。BIRT主要由两部分组成:一个是基于Eclipse的报表设计和一个可以加到你应用服务的运行期组件。BIRT同时也提供一个图形报表制作引擎。

官方主页:http://www.eclipse.org/birt
官方BBS支持:http://www.actuatechina.com/forum2.html

基本上来说Birt功能还是很强大的,支持时下比较流行的WebService,Ajax技术,既可用于Web,也可以用于桌面,更新也算稳定,基本上遵循Eclipse的开发步骤,一个一个大版本,同时支持脚本调用,debug开发等等。唯一不足的就是中国的国情支持得还不够完善,毕竟中国比较特殊,我以前给公司做党务报表,要按照纸质报表画,一分一毫都不能变差,那个变态呀,在电脑上画报表还是拿尺子量。

刚刚开始用,慢慢研究,看了下Birt自带的Example,的确是很强大,做得也很漂亮,自己试着创建一个报表也很简单,希望能够比较快的上手吧。

在网上找了一些资源:
http://blogger.org.cn/blog/more.asp?name=sixsun&id=13933 BIRT 中文指南
http://www.springside.org.cn/docs/reference/Birt.htm BIRT报表
http://www-128.ibm.com/developerworks/cn/opensource/os-ecl-birt/ Birt的IBM DW的中文教程
http://download.eclipse.org/birt/downloads/demos/FirstReport/MyFirstReport.html Birt Flash Demo.
posted @ 2008-06-12 12:02 三人行,必有我师焉 阅读(6191) | 评论 (8)编辑 收藏

  最近很多人问我SWT Extension 项目上的那个不需要的JREExample是如何做出来的。我以前也会执着于这个问题,毕竟如果不依赖于JRE的话,就不需要为用户准备一个容量极大的安装包,但是这种做法看似有利,实则有利有弊。

就我所知,目前把Java程序编译成本机可执行程序的方法有两种,一种是GCJ,免费的,一种是Excelsior JET,商业的。我已经很久没有碰过GCJ了,因为当初用起来实在是非常麻烦,现在的版本如何,我不太清楚。我自己使用的是Excelsior JET,版本为3.7。有一点要注意的的是,Excelsior JET的后续版本好像已经不支持这个功能了,3.7是我所知的最后一个版本,能支持当前所有的Win32平台和早期的Linux(当前比较流行的Ubuntu不支持,因为内核版本过高,不过企业版Redhat没有问题)。不过我是很久以前从0day当下来的,由于0day仓储只保留一年,故现在已经找不到了,我自己的机器上也没有安装包了(有一次大意之下,把整个Download目录全给删掉了,事后悔之晚矣)。

Excelsior JET无非就是用自己的Runtime来代替JRE,只是比JRE更加灵活,根据Java程序具体的依赖来生成对应的Runtime。其实这个Runtime也挺大的,通常10M左右,不过比起JRE,那要小很多了。SWT Extension上的那个例子只有6M,是因为我用ASPack把所有的DLL文件全部压缩过了,体积小了一半。

就我的感觉,Excelsior JETGCJ更加灵活,也更好用,毕竟是商业版的东西,它的网站上曾经有例子将Eclipse 3.0编译成本机程序,不过我当初照着例子试了一遍,没有成功。Excelsior JET的编译过程极为耗时,我上大学的时候,当时机器只有128M内存,编译了一天JRE也没有完成,后来找同学借了根256的内存,这才得以完成。

JAVA代码编译成本机程序的弊端也是有的,那意味着你将无法在线升级,GCJ也许可以,但是Excelsior JET是绝对不行的,这是因为它最后一步要对所有DLL进行链接,如果更换了DLL文件,它会检测出来并报错。

各位看官如果哪位有兴趣,可以自行在网上查找Excelsior JET3.7或其他版本。由于安装包我自己也没有,故无法提供下载,见谅。

posted @ 2008-05-18 15:38 三人行,必有我师焉 阅读(6781) | 评论 (7)编辑 收藏

在SWT Extension中,引入了Function这个类。基本上所有的Win32 JNI库都有这个类,用来直接操纵Win32 的部分API。有了这个Class,我们不用编写JNI,就可以实现某些简单的,甚至是较复杂的Win32 API。这里我们就以EnumWindows这个API举例,看看怎么Java来执行这个Win32 API。
    private static final String FUNTION_ENUMWINDOWS = "EnumWindows";
    
private static final String USER32_LIB = "user32";
    
private static List windowsList = new ArrayList();
    
    
public static int[] enumWindows()
    {
        windowsList.clear();
        Callback callback 
= new Callback(Windows.class"enumWindowsProc"2);
        
int address = callback.getAddress();
        
if (address != 0)
        {
            
try
            {
                Function function 
= new Function(USER32_LIB, FUNTION_ENUMWINDOWS);
                function.invoke_I(address, 
0);
                function.close();
            } 
catch (Exception e)
            {
                SWT.error(SWT.ERROR_INVALID_ARGUMENT);
            }
            callback.dispose();
        }
        
int[] handles = new int[windowsList.size()];
        
for (int i = 0; i < windowsList.size(); i++)
            handles[i] 
= ((LONG) windowsList.get(i)).value;
        
return handles;
    }

    
private static int enumWindowsProc(int hwnd, int lParam)
    {
        windowsList.add(
new LONG(hwnd));
        
return 1;
    }
EnumWindows是用来遍历Windows窗口的API,它需要传入一个返回boolean值的callback的地址作为参数。实际上在C里面,一个boolean值无非就是是否非0,如果为0,则为false,不为0,则为true。我们只需要new 一个function实例,传入这个API所在的Lib和API名字,然后执行invoke方法就OK了,在Function里面,可以最多执行含有4个简单类型参数的API。

让我们再来看看FindWindowEx这个API,它需要传入2个int变量和2个字符串指针,根据SWT的设计,我们是可以将Java的字符串转换为指针的,因此通过Function我们也可以实现这个API:
    private static final String FUNTION_FINDWINDOWEX = Extension.IsUnicode ? "FindWindowExW"
            : 
"FindWindowExA";
    
private static final String USER32_LIB = "user32";
    
    
public static int findWindowEx(int parent, int hwndChildAfter, String className,
            String windowName)
    {
        
int result = 0;
        
int lpClassName = 0;
        
int lpWindowName = 0;
        
int hHeap = Extension.GetProcessHeap();

        
if (className != null)
        {
            TCHAR buffer 
= new TCHAR(0, className, true);
            
int byteCount = buffer.length() * TCHAR.sizeof;
            lpClassName 
= Extension.HeapAlloc(hHeap, Extension.HEAP_ZERO_MEMORY, byteCount);
            Extension.MoveMemory(lpClassName, buffer, byteCount);
        }
        
if (windowName != null)
        {
            TCHAR buffer 
= new TCHAR(0, windowName, true);
            
int byteCount = buffer.length() * TCHAR.sizeof;
            lpWindowName 
= Extension.HeapAlloc(hHeap, Extension.HEAP_ZERO_MEMORY, byteCount);
            Extension.MoveMemory(lpWindowName, buffer, byteCount);
        }

        
try
        {
            Function function 
= new Function(USER32_LIB, FUNTION_FINDWINDOWEX);
            result 
= function.invoke_I(parent, hwndChildAfter, lpClassName, lpWindowName);
            function.close();
        } 
catch (Exception e)
        {
            SWT.error(SWT.ERROR_INVALID_ARGUMENT);
        }
        
if (lpClassName != 0) Extension.HeapFree(hHeap, 0, lpClassName);
        
if (lpWindowName != 0) Extension.HeapFree(hHeap, 0, lpWindowName);
        
return result;
    }
其实像这种简单参数类型的API,Win32 里还有很多,我们完全不必为其专门编写JNI,只需使用熟悉的Java即可。虽然不是调用全部的API,但大部分常用的API都是没有问题的,关键是如何灵活运用。现在的大型商业RCP应用中,其实多多少少都参和了JNI,用于提升对用户的友好性和软件的执行性能,毕竟Java天生就是客户端开发的矮子。对于JNI,我们既不能一味排斥,也不能滥用,要把握一个平衡点,使之成为Java客户端开发的利器。
posted @ 2008-05-11 19:31 三人行,必有我师焉 阅读(5823) | 评论 (7)编辑 收藏

网上有一篇关于JNI中文问题的文章,写得很详细,http://www.vckbase.com/document/viewdoc/?id=1611

我在这里主要是想说说我碰到的一些问题,并且希望能从各位老大身上获得答案。

因为一直从事Java编程,基本上没有涉及过C++的开发,最近因为开源项目SWT Extension,不得已需要用JNI来实现一些系统Native功能。但是总是需要一些Java字符串对应C++的字符串的问题。一边情况下我都是使用SWT的TCHAR来解决问题,少部分情况需要传递Java String到JNI。然而少部分的这些Case总是在某些问题下出现乱码或者异常。我一直使用的是网上比较流行的中文编码解决方案:
char* jstringToNative( JNIEnv  *env, jstring jstr )
{
  
int length = env->GetStringLength(jstr );
  
const jchar* jcstr = env->GetStringChars(jstr, 0 );
  
char* rtn = (char*)malloc( length*2+1 );
  
int size = 0;
  size 
= WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)jcstr, length, rtn,(length*2+1), NULL, NULL );
  
if( size <= 0 )return NULL;
  env
->ReleaseStringChars(jstr, jcstr );
  rtn[size] 
= 0;
  
return rtn;
}

jstring nativeTojstring( JNIEnv
* env, char* str )
{
  jstring rtn 
= 0;
  
int slen = strlen(str);
  unsigned 
short * buffer = 0;
  
if( slen == 0 )
    rtn 
= env->NewStringUTF( str ); 
  
else
  {
    
int length = MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str, slen, NULL, 0 );
    buffer 
= (unsigned short *)malloc( length*2 + 1 );
    
if( MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str, slen, (LPWSTR)buffer, length ) >0 )
      rtn 
= env->NewString(  (jchar*)buffer, length );
  }
  
if( buffer )
  free( buffer );
  
return rtn;
}

一般情况下,这两个函数能够很好的工作。但是在读写注册表时,如果一个key的名字或者value的名字中包含了中文,jstringToNative的解决方案是不正确的,我在网上查了一下其它的关于Java访问注册表的开源项目,发现虽然它们都对字符串进行了处理,但依然存在着中文问题。我进行了数次尝试,但都没有成功。最后到了已经绝望的时候,用开头我提到的那篇文章中里说的最不可能用到的方法将问题成功地解决了:
char* jstringToNative( JNIEnv  *env, jstring jstr )
{
  
const char* pstr = env->GetStringUTFChars(jstr, false);
  
int nLen = MultiByteToWideChar( CP_UTF8, 0, pstr, -1, NULL, NULL );
  LPWSTR lpwsz 
= new WCHAR[nLen];    
  MultiByteToWideChar( CP_UTF8, 
0, pstr, -1, lpwsz, nLen );
  
int nLen1 = WideCharToMultiByte( CP_ACP, 0, lpwsz, nLen, NULL, NULL, NULL, NULL );    
  LPSTR lpsz 
= new CHAR[nLen1];
  
int size = 0;
  size 
= WideCharToMultiByte( CP_ACP, 0, lpwsz, nLen, lpsz, nLen1, NULL, NULL );
  
if( size <= 0 ){
      delete [] lpwsz;
      
return NULL;
  }
  env
->ReleaseStringUTFChars(jstr, pstr );
  delete [] lpwsz;
  
return lpsz;
}
问题虽然解决了,但是我却不求甚解,为什么直接通过env拿到unicode字串,然后转成多字节串不行,但是通过env拿到utf-8字串,然后转成unicode字串,再将这个unicode字串转成多字节串就能工作?

如果大家有兴趣的话,不妨试试,用JNI调用RegOpenKeyEx这个API,就能验证我说的这个Case。哪位老大对JNI比较在行的话,可以在评论中告诉我,不甚感激。
posted @ 2008-05-04 13:17 三人行,必有我师焉 阅读(4022) | 评论 (2)编辑 收藏

Glossy 效果,顾名思义,就是玻璃质的光泽透明的效果,在Windows平台下的应用越来越广泛,从Media Player10开始,它的button已经运用上了此效果。现在但凡是微软新发布的软件,十有八九都带有glossy特效。Glossy 效果使用了Gdi Plus的API,因此在Win98和Win2000下,必须安装gdiplus.dll才能使用,此动态链接库不大,只有700多K,但是想要在自己的应用程序中画出绚丽多彩的效果,那是少不了这个小东西的。关于Glossy效果的描述,可以参见CodeProject上的一片文章WindowsVistaRenderer,http://www.codeproject.com/KB/vista/WindowsVistaRenderer.aspx

Glossy特效有一个重要的组成部分,就是椭圆的光晕,此效果在Linux下可能并没有实现(并未下定论,我还没有深入研究过Linux下的图形库), 所以SWT的Gdip并没有将其公开出来,而是放入custom的API里,也就是说,你可以自行调用此效果的API,但是SWT并不负责为你提供封装, 因此你并不能使用GC来实现该特效,这对我们的界面开发极为不利,自己调用Gdip的API,繁琐不说,还很容易导致JVM退出。

为了能够方便的使用GC来画出此特效,我们不得不采用一些非常规的手段:反射。利用反射我们可以拿到GC的一些内部数据,在这个地方,我们只需要拿到GCData就可以,它包含了画图所需要具备的元素。Glossy效果需要使用PathGradientBrush,我们把这个刷子赋给GCData,就可以使用GC来画出glossy特效了。
 1 public class GCExtension {
 2 
 3     private GC gc;
 4 
 5     private GCData data;
 6 
 7     public GCExtension(GC gc) {
 8         this.gc = gc;
 9         data = getGCData(gc);
10     }
11 
12     public void fillGradientPath(Path path, float[] centerPoint,
13             Color centerColor, int centerColorAlpha, Color[] surroundColors,
14             int[] surroundColorAlphas) {
15         if (gc == null || gc.handle == 0)
16             SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
17         if (path == null || centerPoint == null || centerColor == null
18                 || surroundColorAlphas == null)
19             SWT.error(SWT.ERROR_NULL_ARGUMENT);
20         if (path.handle == 0 || centerPoint.length < 2
21                 || centerColor.handle == 0
22                 || surroundColors.length != surroundColorAlphas.length)
23             SWT.error(SWT.ERROR_INVALID_ARGUMENT);
24         for (int i = 0; i < surroundColors.length; i++) {
25             if (surroundColors[i] == null || surroundColors[i].handle == 0)
26                 SWT.error(SWT.ERROR_INVALID_ARGUMENT);
27         }
28 
29         int brush = Gdip.PathGradientBrush_new(path.handle);
30         if (brush == 0)
31             SWT.error(SWT.ERROR_NO_HANDLES);
32         PointF point = new PointF();
33         point.X = centerPoint[0];
34         point.Y = centerPoint[1];
35         Gdip.PathGradientBrush_SetCenterPoint(brush, point);
36 
37         int colorRef = centerColor.handle;
38         int rgb = ((colorRef >> 16& 0xFF| (colorRef & 0xFF00)
39                 | ((colorRef & 0xFF<< 16);
40         int color = Gdip.Color_new(centerColorAlpha << 24 | rgb);
41         if (color == 0)
42             SWT.error(SWT.ERROR_NO_HANDLES);
43         Gdip.PathGradientBrush_SetCenterColor(brush, color);
44         Gdip.Color_delete(color);
45 
46         int[] colors = new int[surroundColors.length];
47         for (int i = 0; i < surroundColors.length; i++) {
48             colorRef = surroundColors[i].handle;
49             rgb = ((colorRef >> 16& 0xFF| (colorRef & 0xFF00)
50                     | ((colorRef & 0xFF<< 16);
51             colors[i] = Gdip.Color_new(surroundColorAlphas[i] << 24 | rgb);
52             if (colors[i] == 0)
53                 SWT.error(SWT.ERROR_NO_HANDLES);
54         }
55         Gdip.PathGradientBrush_SetSurroundColors(brush, colors,
56                 new int[] { colors.length });
57         for (int i = 0; i < surroundColors.length; i++) {
58             Gdip.Color_delete(colors[i]);
59         }
60         data.gdipBrush = brush;
61         boolean advanced = gc.getAdvanced();
62         if (!advanced)
63             gc.setAdvanced(true);
64         int mode = Extension.GetPolyFillMode(gc.handle) == Extension.WINDING ? Gdip.FillModeWinding
65                 : Gdip.FillModeAlternate;
66         Gdip.GraphicsPath_SetFillMode(path.handle, mode);
67         Gdip.Graphics_FillPath(data.gdipGraphics, data.gdipBrush, path.handle);
68         if (!advanced)
69             gc.setAdvanced(false);
70         if (data.gdipBrush != 0) {
71             Gdip.PathGradientBrush_delete(data.gdipBrush);
72             data.gdipBrush = 0;
73         }
74     }
75 
76     private GCData getGCData(GC gc) {
77         GCData data = null;
78         try {
79             Object obj = null;
80             Field field = gc.getClass().getDeclaredField("data");
81             if (field != null) {
82                 field.setAccessible(true);
83                 obj = field.get(gc);
84             }
85             if (obj != null && obj instanceof GCData)
86                 data = (GCData) obj;
87         } catch (Exception e) {
88 
89         }
90         return data;
91     }
92 }

特效截图:

posted @ 2008-04-30 15:54 三人行,必有我师焉 阅读(3540) | 评论 (3)编辑 收藏

SWT Win32 Extension写到现在的状况,在win32 natvie上面已经没有太多花样了,常用的一些功能我都已经做得差不多了,现在主要是做一些自定义的控件,就目前的进度,还只是完成了Shell,Menu,ToolBar 3个部分,还有很多内容可以慢慢完善。不过自从发布了自定义的菜单以后,SWT Win32 Extension的用户群大增,也对我提出了更高的要求。不过现在的主要任务是实现功能,因此代码的质量上肯定是差了点。现有的接口都是我自己通过Example的需求来加的,以后等功能做的完善上,再将现有的架构进行较大的重构,我想应该是一个不错的步骤。毕竟就我一个人做这个东西,还要兼职写Example,Document,测试,网站维护,虽然每天都在加班加点,但还是感觉时间不够用。每天都有用户发邮件来催进度,所以维护这个项目现在真的是让我废寝忘食了,但总体来说还是物有所值,毕竟辛辛苦苦的努力,还是有所回报的。开源嘛,本来就是一种奉献精神,回馈社会,让所有人都来分享自己的成果。

这些天一直忙着写新的Feature,今天写的差不多了,于是回过头来整理Example。本来上个版本我就想接管Eclipse Native的菜单,不过没能如愿,因为Eclipse的菜单都是LazyLoad的。今天又尝试了一下,终于成功的实现了这个功能。做完了才知道其实很简单,所遇到的重重障碍只不过是因为自己的框架老是蹦出新的bug。唉,自己测试自己开发的东西总是有盲点存在,实在是无能为力呀。

从本质上来说,我自定义的菜单和标准菜单控件的代码及事件上的实现基本一致,所以接管Eclipse原生的菜单并不是一件很难的事情,当自定义的菜单接收到一个事件的时候,只需将这个事件转发给Eclipse的原生菜单就好了,一切就是这么简单。重点就是Notify SWT.Selected 和 SWT.Show 事件,前者用来触发Action的行为,后者用来触发Eclipse原生菜单的LazyLoad。

截图如下:
posted @ 2008-04-20 20:37 三人行,必有我师焉 阅读(3371) | 评论 (4)编辑 收藏


The idea is from DotnetMagic, I copied its style, but different implement methods. DotnetMagic uses shell self message circulation, but I use swt event listener. I want to implement the custom style menu for all platforms initially, but it's impossible. It has to use a lot of advanced OS funcitions. If I use pure swt public functions, I can't implement  some features. For example, if I click the menu, the window shell will be deactivated, I click window shell's titlebar, swt event manager doesn't send messages to me. I must use WND Message hook to deal these messages. So I have to add the feature into SWT Win32 Extension, but not a independent project.

Some beautiful snapshots:


Office 2003 Style Menu


VS 2005 Style Menu


Project Download: http://www.swtui.cn/downloads/org.eclipse.swt.win32.extension.zip
JNLP Online Demo: http://www.swtui.cn/jws/example.jnlp

If you don't have installed Java Runtime, you can access it via http://www.swtui.cn/downloads/org.eclipse.swt.win32.extension.example.independence_native.zip

Eclipse Plugin Update Site URL: http://www.swtui.cn/update

 

posted @ 2008-04-02 11:25 三人行,必有我师焉 阅读(3129) | 评论 (5)编辑 收藏

Add Flash Control to SWT Win32 Extension, now you can check out the latest code from CVS and run it.

Project Main Page: http://www.swtui.cn

cvs -d:pserver:anonymous@feeling.cvs.sourceforge.net:/cvsroot/feeling login



Flash Control Listener   


Flash Control Hook Interceptor

 

posted @ 2008-03-14 22:00 三人行,必有我师焉 阅读(2650) | 评论 (0)编辑 收藏

在SWT Win32 Extension 中新添加了窗口系统菜单管理功能,现在可以自定义窗口系统菜单了。
posted @ 2008-03-10 20:38 三人行,必有我师焉 阅读(2262) | 评论 (0)编辑 收藏

窗口是一个应用程序的门面,有一个好看的窗口,用户的评价自然也会大大提高,经过几天的努力,终于在SWT Win32 Extension中加入了自定义的Window Theme,当然目前只完成了一些基本的实现,高级实现依然有待于研究。


Windows XP Theme


Custom Theme

  目前已完成了任意SWT Shell wrapper,系统菜单管理,不规则边框的切边等功能,尚未完成的功能还有很多,比如窗口菜单。未来准备加入用户自定义Theme的接口,只要符合规范都可以进行自动切换。由于功能仍然还有很多地方尚未完成,暂时还没有提供打包下载,有兴趣的话,可以从项目CVS上Checkout出来看看效果。

cvs -d:pserver:anonymous@feeling.cvs.sourceforge.net:/cvsroot/feeling login
posted @ 2008-01-15 14:25 三人行,必有我师焉 阅读(2805) | 评论 (0)编辑 收藏

做Java UI的人应该都很熟悉Look and Feel,Swing拥有的这个功能的确是相对于SWT的一个巨大优势。不过SWT的GC也可以画出自己的UI,前提是这个控件是Custom的,而不是系统级的。Eclipse Presentation 就是对eclipse本身UI提供的一个扩展。本来我还对这个扩展很友好的,不过现在觉得真是一锅粥里掉了个老鼠屎,完全变了味道。

由于闲来无视,把一个1年半前一个德国人写的Eclipse VS L&F Plugin down了下来,无奈bug太多,用户体验也和我个人感觉不一致,索性就把代码check out 出来,作了一些本地修改。不过让我吐血的地方就是,如果我从eclipse default L&F 切换到这个L&F,就问题一堆,从其它的L&F切换就没有问题。Debug了半天,毫无进展,只是发现很多地方都是Null Exception。于是把Eclipse 2.2 L&F的代码翻了出来,经过仔细对照,还是没有找到解决的方案,我就感觉怪怪的,也不知道哪儿出了问题,觉得大概是自己没有把Presentation的代码吃透的原因。于是又回头开始一行行的从有问题的代码处开始Debug,看看我的代码和2.2L&F的代码在运行时到底有什么区别,终于功夫不负有心人,我发现这个代码片断:
    /**
     * Sets the minimized state for this stack. The part may call this method to
     * minimize or restore itself. The minimized state only affects the view
     * when unzoomed.
     *
     * This implementation is specific to the 3.3 presentation's
     * min/max story; otherwise it just forwards the call.
     
*/

    
public void setMinimized(boolean minimized) {
        
// 'Smart' minimize; move the stack to the trim

        Perspective persp = getPage().getActivePerspective();
        
if (Perspective.useNewMinMax(persp)) 
{
原来3.3的L&F做了专门处理,而我的代码和3.3是一致的,和 2.2L&F是不一致的,不过我找了半天,也没有在2.2L&F的代码里找出异样之处,晕的不行。唯一的线索就是
boolean useNewMinMax = preferenceStore.getBoolean(IWorkbenchPreferenceConstants.ENABLE_NEW_MIN_MAX);

可恶的是,IWorkbenchPreferenceConstants.ENABLE_NEW_MIN_MAX 这个静态常量是无法在项目里找到eclipse自身的引用。2.2L&F plugin里也没有,该死的eclipse肯定是写死在代码里了。于是翻出editplus,对eclipse ui workbench的代码多文件搜索了一把,然后开始吐血,它居然把所有的L&F的配置都写在UI Workbench的Preference Page里,这还算什么插件,根本就没有把扩展的接口给出来,还是很重要的一个配置。其实2.2L&F以前只是它的一个内部package,后来重构成一个plugin,3.0L&F到现在依然还是一个package。不过我想既然2.2L&F做成插件了,怎么也改和系统独立开来呀,现在这样就成了一个半吊子的plugin.

Eclipse终于被我bs了一把^_^,林子大了,什么鸟都有。


改过之后L&F自己觉得好用了不少

 

posted @ 2007-12-25 19:19 三人行,必有我师焉 阅读(3549) | 评论 (5)编辑 收藏

新增了4个Low Level Hook:Mouse_LL,Keyboard_LL, JournalRecord,JournalPlayback。由于是Low Level Hook,因此Hook是不依赖于dll,所以可以直接将HookProc在Java程序中编写。这四个钩子都是全局的,而且都很有用处。Mouse_LL,Keyboard_LL,自不必说,用来监听鼠标和键盘的。Journal的2个Hook则是所谓的日志钩子,WH_JOURNALPLAYBACK Hook使应用程序可以插入消息到系统消息队列。可以使用这个Hook回放通过使用WH_JOURNALRECORD Hook记录下来的连续的鼠标和键盘事件。只要WH_JOURNALPLAYBACK Hook已经安装,正常的鼠标和键盘事件就是无效的。WH_JOURNALPLAYBACK Hook是全局Hook,它不能象线程特定Hook一样使用。WH_JOURNALPLAYBACK Hook返回超时值,这个值告诉系统在处理来自回放Hook当前消息之前需要等待多长时间(毫秒)。这就使Hook可以控制实时事件的回放。

基本上现在用SWT-Extension来实现这四个Hook还是很容易的,做了一下简单的数据封装和事件封装,而且加入了结合体对象和JNI的handle互相转换的函数。用来做C++的一些事情还是比较得心应手的。最新版本的Example提供了一个简单的系统Record/Playback例子,可以记录和回放系统事件。

 

最新的build已经发布到 http://feeling.sourceforge.net 上了,有兴趣的可以下载看看,并且可以作为Eclipse插件使用,支持 eclipse 3.2 以上版本。

PS: Journal的2个Hook Vista已经停止支持了,所以这个例子在Vista 下是看不到的:-(
posted @ 2007-12-12 18:18 三人行,必有我师焉 阅读(1512) | 评论 (2)编辑 收藏

SWT-Extension这个项目做了很久,但一直都没有realease,只是个人做着玩玩,很重要的一个原因是对Windows System Hook的机制没有能够很好地实现出来。Hook本身不算是很难的技术,在C++,C#里都能够很容易的实现,为什么运用Java就那么困难呢?

首先当然主要还是我个人对C++并不在行了,其次就是Java和C++交互的问题了。要想通过C++把数据传给Java,就要通过JNI标准的接口来实现,也就是要通过 JNIENV 来实现,但是HookProc 这个CallBack 是给系统进程调用的,不是给你Java调用的,你说系统进程调用了 HookProc 之后,没法把这个事件传递给Java,那么还有一个方法,用Java不间断的轮循Hook里的数据,这倒是能实现,网上也有一个老外的例子,但不好的地方就是当我系统没工作的时候,你Java还在那儿轮循我干嘛?这不是浪费资源吗?所以呢,这解铃还需系铃人,系统的事件还得让系统来通知你才好。在Java里,有一个IO阻塞,比如当调用System.in.read()的时候,系统就是等待你的输入,如果你不输入,系统就一直等着不工作。还有线程,有wait方法,非要等着其他的线程通过notify把你唤醒你才能工作。在C++里也有这么一套机制:CreateEvent 和WaitForSingleObject,也就是说我先创建一个事件,然后将这个事件置于未激活状态,让它一直等待,将线程阻塞住,当HookProc被系统进程调用的时候,就将这个事件激活,通知Java程序你可以开始干活了,干完活以后再次被阻塞,直到这个Hook被uninstall掉。当然这其中还有一些 C++ 代码的细节性问题,比如怎么让不同的进程共享同一个事件,这里要说明的就是不同的进程可以共享同一个事件,但是不能共享同一个事件句柄,同一个事件,在不同的进程里有不同的句柄,句柄是不能跨进程的。 

我个人认为Hook应当是SWT-Extension里一个很重要的组成部分,SWT本身只能实现线程钩子,对于系统级的钩子无能为力。因为系统机钩子需要实现数据共享操作,还需要DLL入口句柄,这些我已都在SWT-Extension中实现了。唯一让我遗憾的是没有办法实现日志钩子,这是一个很有用的钩子,可以用来记入当前用户行为的操作,然后重新演示,我想如果做自动化测试这个会很有用,或者给游戏软件练功什么的,呵呵。之所以不能实现是因为这个钩子很特别,它要的不是DLL的句柄,而是应用程序的句柄,这没有办法从Java程序里获得,我试过javaw.exe,但是也不行,会导致系统假死。以后有时间在研究吧。

做完Hook,终于可以松一口气,发一个小小的realease了,剩下的就是document工作要做了,一个枯燥无味的工作,就当练习一下英语好了。

这里发一个Hook的截图:




没有了标题栏的Eclipse
最新的Build和代码也可以在 http://feeling.sf.net 上下载了。
posted @ 2007-12-07 15:08 三人行,必有我师焉 阅读(2443) | 评论 (17)编辑 收藏

1. Change priorities when it became apparent that items with major market impact didn't take much effort, or when it became apparent that items with minor market impact wuld take much more effort than they worth.
2. Prioritize the task list based on their presentation of the feature's importance.
3. Maintain a list of what is needed in the product.
4. Iterative, incremental development. Each iteration is called a Sprint, and the results of the iteration is called a Product Increment.
5. Whoever writes code owns it forever.
6. produce an updated produce technical illustration with each Sprint(and release)that could be used to understand the product design and code.
7. Institute a quick, daily meeting where the team would report what it is doing.
8. Product Backlog: A list, list all of the things that the system should include and address, including functionality, features, and technology.
9. The Product Backlog is a prioritized list of all product requirements. and it 's never finalized. Product backlog content can come from anywhere: users, customers, sales, marketing, customer service, and engineering can all submit items to the backlog. However, only the Product Owner can prioritize the backlog.
10. Scrum relies on team initiative and integrity.
11. The Scrum Team meets daily for a short status meeting, called the Daily Scrum.
12. At the end of the Sprint, the team gets together with management at a Spring Review Meeting to inspect the product increment the team has built.
posted @ 2007-09-24 13:44 三人行,必有我师焉 阅读(416) | 评论 (1)编辑 收藏

Since 19th century, human has been changing the earth continuously. They began to use various energies to server themselves. The most important application is electricity. If the electric power is cutted, wo even couldn't do anything. Air conditioner, fridge, wash matchine, computer and oven all need electric power. We use coal,water power,wind,biology and nuclear power to generate electric power. Generally, when we convert a power to another power, the efficiency is not perfect, we will lose some energy. Most of the lost energy is changed as hot energy. So when we touch the machine used electric power, we can feel it's hot.

Except electric power, we also use another kind of power, that is chemical power. We can get it by burning coal and oil. This power is used broadly. For example, the car, the plane and some other traffic tools. But when we generate the chemical power, there will cause lots of waste gas. Some kind gases in the waste gas can let earth become a greenhouse. Then we generate a mass of hot energy but these greenhouse gases prevent it to run away to the universe. The hot energy stays at our planet, and the temperature becomes high little by little.

Now the global warming is obvious, the ice of the south earth pole is melting little by little, the drought and the hurricane appears more and more. Each person can feel the earth is warming now.

Now the big energy countries start to decrease the greenhouse gas releasing and increase the efficiency of power conversion.For example, we use water power, wind, nuclear power to generate electric power as much as possible, but not use coal and oil. Each people has the responsibility to protect our home.

posted @ 2007-09-19 12:28 三人行,必有我师焉 阅读(248) | 评论 (0)编辑 收藏

Everyone knows that smoking is harmful for health, but why do so many people still smoke? It’s a complex society problem. There are several reasons that caused it.

 

Firstly, cigar contains some matters which can let people depend on them. Nicotine is one of the most harmful matters in the cigar. The nicotine contained in one cigar can kill one mouse by poison. And some other matters of cigar can let people get cancer. Smoking also can damage liver and lung. In short, smoking is very dangerous.


 

Secondly, lots of people smoking is caused by the social fashion. Generally, most of people started to smoke when they were teenager. They have a strong emulous mind, and they like to imitate the movie stars’ smoking behavior. The environment that the teenagers lives is bad for their growth.

 

Lastly, it’s caused by economy. The tax of cigar is very huge, each government couldn’t ignore it. It will generate a big benefit, so most of countries don’t forbid selling cigar. Fortunately, some of them begin to forbid selling cigar to the underage people.

 

Lots of parents don’t allow children to smoke, but it’s not very effective. Because they don’t let children smoke, but they still smoke. Children’s growth needs a clear and fresh environment, but not an environment full of smoking. The government must carry out more measures about forbidding smoking, and adult would better to give up smoking also.

posted @ 2007-09-18 12:36 三人行,必有我师焉 阅读(1017) | 评论 (0)编辑 收藏

Grammar Website: http://www.windsn.com/main/grammar/
Dictionary Online: http://www.godict.com
Google Translator: http://www.google.com/language_tools?hl=zh-CN
English Studying Fourm:http://www.maplesky.net/bbs/index.php (Can download a lot of resource from here)
English Movie:
Family Album U.S.A(走遍美国) 很好的英语口语学习教材
Speed(生死时速) 练习听力,语速很慢

posted @ 2007-09-05 13:30 三人行,必有我师焉 阅读(279) | 评论 (0)编辑 收藏

在你看来,下面图像的运动方向是顺时针呢还是逆时针呢??
每个人看来都是不一样的 
 
顺时针的话,属于是用右脑较多的类型
逆时针属于是用左脑较多的类型
大部分人的眼里是逆时针方向转动,但也有人看来是顺时针方向转动的。
顺时针的情况,女性比男性多 ~~
试试吧!~ 

我第一眼看上去是逆时针,第二眼又变成了顺时针。

怎么说呢,以不同的视角看,就会形成不同的旋转路线,可能是逆时针也可能是顺时针,我现在已经是忽左忽右,快暴走了。

自己找到了一个比较好的解决方法,脑袋贴近屏幕向右偏转45度看,很容易形成逆时针,向左偏转45度看,很容易形成顺时针,主要是人和图片的视角问题。这图片设计的也太巧妙了。

Team里的人大部分看都是顺时针,只有一个左撇子看是逆时针。
posted @ 2007-07-25 17:11 三人行,必有我师焉 阅读(1841) | 评论 (6)编辑 收藏

  中新网7月13日电 综合报道,一名犯有重罪的罗马尼亚犯人近日向上帝提出控诉,地方法院12日对此予以驳回。

  据悉,该名罗马尼亚犯人是2005年7月因受贿罪被捕的。他被判处入狱20年,在狱中更是抱怨上帝对他不公,在2006年甚至向地方法院控告上帝。

  这名犯人说,早在他出生时在教堂受洗的时候就与上帝订立了契约,让他能够快乐生活,但现在“上帝打破了这份契约,因此有必要控告他”。

  地方法院12日发布的判决书称,“由于无法获知上帝的家庭住址,因此无法向其传达法院的意见,”并最终对囚犯的要求予以驳回。

posted @ 2007-07-13 18:19 三人行,必有我师焉 阅读(301) | 评论 (0)编辑 收藏

昨晚赶工为SF上的项目做了个首页:http://feeling.sf.net 。各位兄弟有空可以看看,帮忙提点意见,不过现在铺的好像就有点大了,这么多页面,不知道何时才能做完,打算就先这么搁一个首页,以后有时间再说吧。

SWT Extension Example我今天打包了一下,已经可以下载了,但是源代码我暂时还没打算开放下载,因为有些功能还没做好,需要一段时间,最重要的是我打算对现有代码进行重构,API可能有比较重大的调整,现在提供下载,对想要使用的兄弟来说是一种不负责任的态度。不过Code还是可以从CVS Checkout,地址可以在项目首页上找到。

SWT Extension Example下载地址:

Java 版: http://feeling.sourceforge.net/downloads/example.zip
Native版:http://feeling.sourceforge.net/downloads/example_native.zip (如果上网的机器上还没有安装JRE的兄弟请选择这个)




SWT Extension extends the Eclipse library SWT.

It is a software development kit enabling you to work with native code from Java programs without using JNI. With SWT Extension, you don't need to create native libraries to call a function of the operating system API or a function from any dynamic library. You write code in the Java language only, and SWT Extension does the rest. SWT Extension provides quite a number of integration features to make your Java application look and behave like a Win32 citizen.

  • Window Decorations: making windows always-on-top, transparent, flashing on the taskbar, etc.
  • Custom Shape Window: creating non-rectangular windows using custom Regions.
  • Access to Windows Registry.
  • Shell Folders: getting paths and icons of the user folders (Favorites, My Pictures, etc)
  • Shell Links: managing the system link files.
  • System Info: gathering CPU and memory information.
  • Specially, you can get a lot of functions via SWT, because SWT Extension extends SWT.
  • posted @ 2007-06-28 17:10 三人行,必有我师焉 阅读(1328) | 评论 (7)编辑 收藏

    大概因为开发环境是英文的缘故吧,做了这么久时间的SWT-Extension,直到今天才发现存取中文都是乱码。不过显而易见的是Test Case做得太少了,毕竟是自己的开源项目,在上面投入的是兴趣,而不是精力。虽然一直在弄,但动辄就几个月没有commit,而且到现在也没有一个正式版发布。本来可以积累一点user的,现在估计也都跑光了。

    下面这段代码用于JNI中jstring和Window char之间转换:

    char* jstringToNative( JNIEnv  *env, jstring jstr )
    {
      
    int length = env->GetStringLength(jstr );
      
    const jchar* jcstr = env->GetStringChars(jstr, 0 );
      
    char* rtn = (char*)malloc( length*2+1 );
      
    int size = 0;
      size 
    = WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)jcstr, length, rtn,(length*2+1), NULL, NULL );
      
    if( size <= 0 )return NULL;
      env
    ->ReleaseStringChars(jstr, jcstr );
      rtn[size] 
    = 0;
      
    return rtn;
    }

    jstring nativeTojstring( JNIEnv
    * env, char* str )
    {
      jstring rtn 
    = 0;
      
    int slen = strlen(str);
      unsigned 
    short * buffer = 0;
      
    if( slen == 0 )
        rtn 
    = env->NewStringUTF( str ); 
      
    else
      {
        
    int length = MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str, slen, NULL, 0 );
        buffer 
    = (unsigned short *)malloc( length*2 + 1 );
        
    if( MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str, slen, (LPWSTR)buffer, length ) >0 )
          rtn 
    = env->NewString(  (jchar*)buffer, length );
      }
      
    if( buffer )
      free( buffer );
      
    return rtn;
    }



    JNI 用起来实在太麻烦了,比我做Java开发效率实在低得太多,各种各样的类型转换,我头都晕了…… 另外JNI好像是SUN中国研究院搞的,怎么就没有提供一个好的中文解决方案?

    Eclipse SWT Extension snapshot:













    posted @ 2007-06-25 12:43 三人行,必有我师焉 阅读(943) | 评论 (2)编辑 收藏

    最近一段时间真是生逢不幸,屋漏偏逢连夜雨,老天爷处处和我作对,每天只能长吁短谈,至于怨天尤人,那还不至于成为我的作风,学习的动力也因此而来。人嘛,总是在安逸中堕落,逆境中求生。从大学毕业到现在,除了头年的奋斗,后面的几年基本上就是在堕落中度过,而且愈演愈烈。

    工作的几年,经验长了不少,大公司,小公司,国内的,国外的,甚至连皮包公司都呆过,还是现在的这个最爽。不过Manager因为移民澳大利亚马上就要离开公司了,我的好日子也要到头了。这几年时间,说实在话,成就不大,基本上就在原地踏步,也不知道工资怎么就翻了10倍。这期间也看过一些书,不过说实在话,收获不大。现在想回过头来潜心研究一些基础的东西,虽说基础,但是没有以前的积累,是无法透彻领悟的。

    我想(I think that if I want to)弥补自己的漏洞,在网上看看别人的面试题,然后自己做做,心里就应该有个底了。想当年考研的时候,第一次拿着历年的考试题做,居然150分只拿了40分,那个汗呀,最后强攻了3个月,最后考了个135,其实我自己都不知道怎么能考这么多分,最后2个大题没做,这就20分没了(出得太变态了,居然出魔方,这个规律性太强,我只知道有6个规律,背不下来,难道要自己临场琢磨,我当场就直接白卷放弃,本来也没打算上研。不过学校小考的时候也考过这个,我是抄的,也只能怪自己了。)

    设计模式,UML,J2EE,三道难题摆在我面前。外加 Spoken English。Japanese? I'm very sorry,日企我还没这个雅兴。

    这里主要说设计模式了,我看过很多遍,以前没什么经验,很多架构自己都没有用到过,设计模式这个东西,也就是看了白看。这几天系统地看了一下,其实其中的大部分,我已经从平常阅读别人的代码中学过并且已经用过了,现在回头再看看,自己比较比较,仔细领悟,以后就不用再看了。领悟了以后就是自己的了,还管别人的干什么,自己的就是最好的。这年头连社会主义都是有自己的特色的,设计模式当然也要有自己的特色,吸众家之所长,取各方之精华。

    UML慢慢搞吧,去年搞了搞,没啥进展。

    J2EE我不知道怎么说,除了EJB,其他的好像都搞过,JSP,Servlet,JMS,RMI,JNDI(LDAP),JDBC……不过好像是前两年搞的,而且都是些小项目。最近在做Eclipse Plugin的开发,一年多没碰了,心虚的不行呀。就说最近几年流行的Spring,Hibernate,Ajax,我压根就不会,也就是搞了一会iBatis,感觉有点落伍了。说白了就是我个人已经厌恶B/S了,已经转向C/S的怀抱了,没什么兴趣在搞这些玩意。

    看看网上的招聘信息,很搞笑,某外企,英文要求写的是熟练掌握书面英语,口语流利。最后中文附注只要求看懂文档就行了,俄的神呀!是不是所有的外企都这样?我的印象外语还是蛮重要的,最近努力加强中……看来我以后的工作性质只能向C/S靠齐了,B/S方向已经严重落伍。

    其实作为技术而言,只要工作上要用,学起来都会很快。但是有些技术之外的东西却需要时间来沉淀,比如Design Pattern,UML,English,System Architecture,还是每天花时间搞搞这些玩意来的实际。

    今年下半年的主要任务就是查漏补缺,系统总结了。明年公司合同就到期了,到时候看看情况再决定是走是留吧……留当然容易,不过还要看看发展前景再说:-(
    posted @ 2007-06-20 19:36 三人行,必有我师焉 阅读(1519) | 评论 (15)编辑 收藏

    想真正领悟这首曲子感人的地方,就不能不去玩《英雄传说6》这个游戏。

    星之所在口琴版(游戏中的音乐):
     
    下载地址:http://www.blogjava.net/Files/cnfree/xzszkqb.mp3

    星之所在完整版:
     
    下载地址:http://www.blogjava.net/Files/cnfree/xzszwzb.mp3

    FC结局视频:


    《星之所在》歌词

    一秒的喜悦,一秒来幻灭
    不意闯入流光飞舞的世界
    轮廓再真切,情感越发强烈
    就暂时停留这天上宫阙

    左手很鲜艳,右手在凋谢
    庆幸至今谁都没想过妥协
    一千零一夜,竟是一千零一劫
    劫后余生何尝不是破灭

    你早不是你,而我不是我
    两个名字,靠得那么近

    前生的不满,来世再偿还
    此刻只想逃避千万别责怪
    或许是今晚,明月繁星都不在
    不正好沉寂自做主张的愉快


    幕布拉不开,忘掉了对白
    世人不复昨日的百无聊赖
    空旷的舞台,没有谁人会理睬
    不正好独享光辉灿烂的存在
    再一次重来,又怎么才能重来
    请别计较遗忘和铭记的胜败

     


    翻译二:
    遥远的地方,是谁在歌唱,
    踏着梦的足迹,来到我身旁,
    失去你的黑夜,我心仍徬徨,
    期待你有天会出现我身旁;

    微风在轻扬,诉说着忧伤,
    乘着爱的翅膀,找寻你方向,
    就算受伤情愿和你去流浪,
    我依然向往和你一起飞翔,

    静静守候相约的誓言,
    等候明天太阳的光芒,

    让爱去徜徉,让心去飘荡,
    就让泪光融化寒冷和冰凉,
    有你陪伴的夜我不再迷惘,
    看星光依然,雪花飞舞飘扬。

    依然等你在相遇的地方。

    posted @ 2007-05-05 02:34 三人行,必有我师焉 阅读(1955) | 评论 (0)编辑 收藏

    假如你是一个Leader,那么你敢对你的自己的项目Refactor吗?当然我这儿所说的Refactor不是仅仅修改几个Class而已,而是将旧有的框架完全抛弃,而建立一个全新的框架。你能面对Release的压力,还有项目成败的挑战吗?

    当一个Project越来越大,Logic越来越复杂的时候,就有的框架体系往往不能满足新Feature的要求,于是程序员们有两种选择,要么重构,要么打补丁。对于后者,如果开发人员水平高一点,补丁的痕迹还不会很明显,如果水平一般的话,这段代码往往就会形成一个恶梦。久而久之,整个项目都会积重难返,直至崩溃。

    很幸运的是,我所在的Team从一开始就定位于坚持Refactor。基本上每个MileStone,都会有1-2个人手上的活不是new feature,而是refactor。也许刚刚开始refactor的时候会无从下手,毕竟很大的一块,不是说动就动的。但是不管怎么样,refactor之后的效果是显而易见的,新的扩展很容易实现,往往只要覆写某个方法就可以实现一个新的feature。磨刀不误砍柴工,refactor很好的诠释了这一点。

    看过《重构》这本书的人,都会知道重构须从小处做起,不断坚持,但这样的重构也只仅仅局限于某些功能点的重用性而已。真正的重构,是需要大刀阔斧的。一个项目,你很难知道后期的行为,因此代码框架也很难一直适应新的需求。当需求不断变更的同时,如果固步自封,浑身打上狗皮膏药,补丁越多,维护越累。当量变达到质变的时候,也就是项目崩溃的时候。只有坚持对框架进行调整,才能够不断的满足新的需求。

    说到这儿就不得不说到团队间的合作问题,一个产品,往往是由几个Team共同协作完成的。基本上每个Team都只需要负责自己的模块,并且根据工作量的大小有相应的人手。那么你认为在这儿Team之间,大家工作的感觉会想差不多吗?实际上,每个Team内部的情况完全不一样,有的Team,一个人平均每天只能该1个Bug,有的Team能够该3-5个。归根结底,还是由于框架的问题。如果框架结构清晰明了,改起来自然简单,往往一行代码的修改就能解决问题。框架结构复杂的话,那就不好收拾了。框架的作用就是增加重用性,降低耦合度。我们这儿有一个Team,框架3年都没有什么改变了,而且由于人员的更迭,很多代码都和黑盒一样,没有人能够看明白。我敢说,我一天改10个Bug都不在话下,他们能说吗?

    一个Leader要维护Team之间的平衡真得很累,结构好了,自然就做的快了,可那又不是自己的错,做得慢的Team不但拖累自己,到头来还硬要说你出风头。开发人员第一个需要拥有的素质就是能够不断自省,要学会先怀疑自己。把所有的责任都推卸出去了,到最后问题没解决那还是自己的。一个项目的成败也往往是由Leader的管理水平来决定的。如果Leader都怕失败,不敢去承担责任,那么手下的人自然也没有这个义务了。

    我只想说一句,不敢对自己现有的框架体系做出挑战的,不能够自省的Leader,都是对自己的项目,自己的手下不负责任。一个项目最终的成败,也可能就毁在这些人手上。
    posted @ 2007-05-02 18:51 三人行,必有我师焉 阅读(842) | 评论 (4)编辑 收藏

    DataSet Joint
    一个简单的Dataset Joint Example

    一般来说,Eclipse插件开发用到GEF的机会并不是很多,大概也就是结构设计,数据管理,流程控制等应用罢了。看了一下网上的例子,大部分都是基于数据库管理的,我想这应该是因为数据库设计的Dataset Joint是程序开发最常见的吧。

    GEF的一个简单Example可以参加GEF自带的例子Logic,功能非常强大,了解了Logic,就能够了解相应的GEF开发。在网上这方面的教程并不多,我也基本上没开,我个人始终认为看书不如看代码。当然我以前也没有接触过GEF,毕竟要完全掌握这个东西并非一日之功,要想在上面有所造诣不通过一个大型项目的加强是不可能的。上面的这个小东西也是我花了半个月,还请教了一些人帮忙debug才研究出来的,还是花费了相当功夫。

    不过GEF是一套框架,上面的这个小东西,麻雀虽小,五脏俱全,而且基本上可以算一个不依赖于Eclipse平台的小应用程序。不过GEF(Ver 3.3)这个项目依赖于Eclipse OSGI,如果想完全独立于Eclipse,需要自己做一些小小的改变,也不算太麻烦。最后基本上SWT+JFACE+GEF基本上就可以自己做应用了。

    独立于Eclipse的GEF简单教程可以参见:
    http://www13.plala.or.jp/observe/GEF/GEF_StandAlone.html
    http://www13.plala.or.jp/observe/GEF/GEF_Tool_StandAlone.html

    日文写的,我看不懂,只看代码。

    这里我只说几点:
    1、如果面板需要滚动条,并且能够自由伸缩,显示的话,请选择ScrollingGraphicalViewer,相应的RootEditPart请选择ScalableFreeformRootEditPart。

    2、GraphicalViewer是通过EditPartFactory拿到子EditPart的,有些类似于JFace TreeViewer的ContentProvider,根据特定的Element拿到对应的EditPart,不同于TreeViewer的是,GEF的getChildren方式是写在EditPart里的,每一个EditPart都要实现 protected List getModelChildren( ) 方法,而TreeViewer的getChilder是在ContentProvider内部实现的。因此EditPart更为灵活,因为EditPart还可以通过EditPartFactory拿到上下文环境,而TreeViewer ContentProvider脱离了Viewer本身,只能通过Model来取,这样当Model和Viewer不一致的时候,GEF游刃有余,而TreeViewer却举步维艰。

    3、EditPart的FeedBack Figure的背景颜色是和它的背景取异或操作的,因次再拖动EditPart的时候,如果FeedBack Figure覆盖EditPart的时候,Figure的颜色很难看,解决这个问题的办法就是设置GraphicalViewer的背景颜色为白色。

    4、希望EditPart能够拖动,需要实现getDragTracker( )方法:

        public DragTracker getDragTracker( Request req )
        {
            DragEditPartsTracker track 
    = new DragEditPartsTracker( this );
            
    return track;
        }


    5、刷新EditPart的显示需要覆写protected void refreshVisuals( )方法,当Model的模型改变,需要刷新View的时候可以通过事件监听来显示的调用该方法。

    6、设置EditPart在父亲EditPart的位置调用( (GraphicalEditPart) getParent( ) ). setLayoutConstraint(EditPart arg0, IFigure arg1, Object arg2)方法。 

    7、如果是XYLayoutEditPolicy,内部EditPart位置的改变会调用XYLayoutEditPolicy的protected Command createChangeConstraintCommand( EditPart child,
       Object constraint )方法,需要记录EditPart位置可以在这里进行。

    8、EditPart的Selection事件需要注册SelectionEditPolicy,你可以针对不同的EditPart实现不同的SelectionEditPolicy。

    9、内部有自由布局的EditPart需要注册LayoutEditPolicy的子类。而该EditPart的Figure需要设置对应的LayoutManager。

    10、GraphicalViewer监听Key操作需要setKeyHandler(new KeyHandler(viewer))。

    11、进行连接操作的源EditPart需要实现protected List getModelSourceConnections( )方法,目标EditPart需要实现protected List getModelTargetConnections( )方法,创建一个连接需要使用ConnectionDragCreationTool。连接图形的EditPart必须继承AbstractConnectionEditPart。实际上每个连接会被创建出2个EditPart,只有这2个EditPart的Model相等的时候,一个连接才会成立。

    12、如果需要连接,需要注册GraphicalNodeEditPolicy,并且实现protected org.eclipse.gef.commands.Command getConnectionCompleteCommand(
       CreateConnectionRequest request )和protected org.eclipse.gef.commands.Command getConnectionCreateCommand(
       CreateConnectionRequest request )方法。注册代码:

    installEditPolicy( EditPolicy.GRAPHICAL_NODE_ROLE,
                    
    new ConnectionCreationEditPolicy( ) );


     先写到这儿,慢慢再补。

    posted @ 2007-04-30 18:35 三人行,必有我师焉 阅读(3696) | 评论 (4)编辑 收藏

    Eclipse下的插件开发如果需要用到什么字体或其他的工具时,尽量避免使用AWT GraphicsEnvironment ,这会导致Vista Aero效果暂停工作。如果有需要得到Font字体列表的话,可以使用SWT的FontList拿到:

     1    public static String[] getSystemFontNames( Comparator comparator )
     2    {
     3        FontData[] fontDatas = (FontData [])Display.getCurrent( ).getFontList( nullfalse );
     4        SortedSet set = new TreeSet(comparator);
     5        for(int i=0;i<fontDatas.length;i++){
     6            set.add( fontDatas[i].getName( ) );
     7        }

     8        fontDatas = ( FontData [] )Display.getCurrent( ).getFontList( nulltrue );
     9        for(int i=0;i<fontDatas.length;i++){
    10            set.add( fontDatas[i].getName( ));
    11        }

    12        String[] fonts = new String[set.size( )];
    13        set.toArray( fonts );
    14        return fonts;
    15    }

    /**
     * Returns <code>FontData</code> objects which describe
     * the fonts that match the given arguments. If the
     * <code>faceName</code> is null, all fonts will be returned.
     *
     * 
    @param faceName the name of the font to look for, or null
     * 
    @param scalable if true only scalable fonts are returned, otherwise only non-scalable fonts are returned.
     * 
    @return the matching font data
     *
     * 
    @exception SWTException <ul>
     *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
     * </ul>
     
    */

    public FontData [] getFontList (String faceName, boolean scalable)
    posted @ 2007-04-30 16:34 三人行,必有我师焉 阅读(1109) | 评论 (0)编辑 收藏

    规则:每次单挑都有五个候选人可以选择单挑,有人有武器,有人没有。战胜持有武器的武将,得武器,体力回复少许;战胜没有武器的武将,体力回复较前者略大;中间败北可以选择复活一次(只有这一次!)体力全满
    手戟:太史慈93、典韦95、甘宁94(无需斗志即可实行暗器攻击)
    弓:黄忠93(100斗志伪退却,有几率使敌将受伤)
    剑:赵云96(斗志提升速度加快)
    刀:关羽97(攻击力上升大于丈八蛇矛)
    没有武器的武将:颜良94、文丑93、庞德94、马超97、张辽92、许褚96

    首先要注重单挑顺序,其次注重技巧。技巧方面就是尽量多防守,少进攻,必杀技一定要留在最后放,否则敌人会通过你的攻击集气,然后给你个必杀技就得不偿失了。

    首先单挑太史慈,选择攻击,在损失15%的血以后就可以顺利击败,并获得手戟。
    排在第二位的是赵云或者关羽,关羽难度比较大,个人感觉是13人中最强的,建议先选赵云。先攻击几个回合再防御,最后2个必杀技+暗器,PK掉赵云,应该还剩30-40%血,拿到青虹剑,加快斗志提升速度。
    第三位可以选张辽,张辽是武力最低的一个,但是比较难打,因为无论是进攻还是防守,都会费不少血,建议先防守1招,然后攻击几招,最后必杀技+暗器搞定。最后还剩20-25%左右血。
    第四位和第五位选庞德或者文丑(颜良?),这里面庞德、文丑、颜良是有很大机会秒杀的,而且费血很少。这2关打完以后血应该能够恢复到60-70%。
    第六位选择甘宁或者典韦,会费一点血,不过最后应该会超过50%血。
    第七位要看黄忠是否出来了,黄忠出来了立即选黄忠,一开始就进攻,不要防守,在15招之前解决战斗。拿到养由基弓。应该还有40-50%血。
    第八位:庞德、文丑、颜良中剩下的一个,有机会秒杀,不秒杀也要尽量剩70%以上的血。
    第九位:许褚,主防即可。剩75-85%血。
    第十位:关羽,这一仗至关重要。关羽很难打,无论是攻击还是防守,都会制你于死地。建议先防守一招,然后对攻,还剩不到45%血时主防,最后必杀技+暗器+伪退。可能还剩10%-30%血,拿到青龙偃月刀,再次加快斗志提升速度。
    第十一位:如果血比较多,可以选典韦、甘宁中剩下的一个,血少的话选马超。主防即可,打马超基本不费血,最后2必杀技+暗器+伪退。如果是马超,最后血补全满。
    第十二位:如果十一选了马超,那么这一关就要尽量避免失血。一定要保证血大于60%,不要大意哦。
    剩下的就是吕布和项羽了:只要一直防守就可以了,打完吕布之后似乎是不会补血的。所以最后要保证30%以上的血,吕布集气很快,有可能会放必杀技。项羽除了一个暗器以外,很菜的。对付这两人都是3必杀技+暗器+伪退,五个大招一次解决问题。

    太史慈、黄忠、颜良、文丑、庞德,尽量多进攻,张辽、关羽,进攻+防守,剩下的防守就可以了。最后连续的几个必杀技按快一点,一定要保持连续性,不给敌人喘息的机会。如果必杀技放完了,敌人还有一丝血,就马上切换成进攻,给予最后的一击。
    posted @ 2007-04-24 01:28 三人行,必有我师焉 阅读(20157) | 评论 (16)编辑 收藏

    Realease在即,而Mock-up却还在更新,这就是我目前的境况。要命的却是还有一个从来没有涉猎过的领域摆在我面前,那就是GEF,Eclilpse最复杂的框架之一。我一向推崇简单就是美,Java搞了这么多年,但是越搞越复杂,Eclipse也是如此。最令人推崇的Eclipse开发版本还是2.1.2,相对于2.1版本,3.2简直就是蜗牛。而我们却要无休止紧跟着Eclipse的脚步,它走一步,我们就要前进一步。我以前甚至不屑于使用JFace,更何况这个传说中的GEF,玩玩还可以,使用它那还不是要我的小命。

    不过框架自有框架的好处,如果能够熟练使用,可以少写很多代码,因此能够使项目速成。我现在要做的是一个数据库表索引关联编辑器,功能其实不多,但是麻雀虽小,五脏俱全,一个完完整整地GEF应用。拖拉暂且不说,是GEF的基本应用,最麻烦的其实还是各个表初始化的布局,需要写一个自己的布局管理器。如果要自己从头写而不用GEF,估计一个月怎么也够呛。现在采用GEF,我想半个月就差不多了,不过学习成本昂贵呀。我得承认我严重低估了GEF的复杂度,到目前为止,我已经研究了三四天,才刚刚能够进行简单应用。看书,找资料,研究框架的构架,都是扯淡,看了八进制的文章,仍旧是一头雾水。看别人的容易,变成自己的就太难了,什么事情都还要靠自己领悟才行。

    还好我是多条路并行采用了。虽然我眼下的项目可以称得上是最复杂的GEF应用之一(源代码打ZIP包都快30M了),但身边能用GEF开发的高手却屈指可数,Manager估计早就想让我搞这个玩意了。JFace我都是速成的,现在已经很熟练了。顺便说一下TreeViewer这个东西,它的显示逻辑全部都是通过Provider来实现的。显示的时候就会通过getChildren从上往下走,找一个节点的时候则是通过getParent从下往上走,现在就有一个问题了,如果我setInput的Model的内部逻辑和我要显示的外部逻辑相差比较大,那么如何实现?在这儿适配器是不能工作的,因为沟通是双方的,适配器则是单方的。如果用一个虚节点来代替Model实际上没有的显示逻辑,那么虚节点的儿子(一个Model实体)通过getParent是找不到那个虚节点的,它只知道自己的实体父亲。封装所有的Model也是不可取的,要不要Model干什么。我想TreeViewer碰到这样的应用就会无能为力了。

    现在说一下框架速成大法:
    1、问,自然是问高手了。高手会一针见血的把问题找出来,并能告诉你框架的整体结构,通过现场演示,能够让你的脑子对框架有一个整体的认识,这可比看文章接受的快多了。我同事已经被我折磨了一个礼拜了。在问和解答的过程中,大家都能够发现自己的不足,如果两个人在一起编码,又是一个结对编程的过程,这个时候2个人的脑子思维都会很清晰。
    2、Debug,找一个和自己相近的应用。每一个框架,作者一般都会提供一些例子,而且这些例子虽然简单,却基本上包含了框架的方方面面。要想应用框架,最终是需要自己写代码的,代码在哪儿找,就是作者的例子里找。看看例子里有多少应用是自己需要的,找到合适的地方Debug一把,一步一步地跟下去,很快你就能够通过堆栈信息以及源码了解应用的整个步骤,然后用Copy大法,一个自己的应用就创建出来了。

    当然第二点依赖于第一点,初学者是很难寻找合适的断点进行跟踪,所以需要找个高手过来,让他来跟,他演示的过程就是自己学习的过程。有了自己的第一桶金,后面的路就已经很平坦了。一个人对于未知领域的恐惧并不是怕自己不能掌握,而是不知道自己要花多长时间来掌握它。通过3天的速成,虽然对GEF的整体了解是管中窥豹,但我已经心里非常有底了。现在已经能够把Tabel以及里面的Column画出来,而且已经实现了布局,拖拽等基本事件,剩下需要研究的东西不会太多,够用就行。技术这个东西,不怕不了解,就怕不会学习,很多时候,等到要用到的时候再学也不会迟,关键是要掌握正确的学习方法。

    posted @ 2007-04-07 00:22 三人行,必有我师焉 阅读(1183) | 评论 (3)编辑 收藏

    传说中凤凰每隔500年要投入火中以求得新生。有一种恒星在其「临死亡」的剎那,将发生激烈的爆炸,如迴光返照般放出极耀眼的光芒。星球毁灭了自己,却也同时触发了新恒星的诞生。这就是超新星,天上的火凤凰。

    在宇宙中,恒星的分类是按照它们的死亡的方式,一类象我们太阳这种,最终安静的成为白矮星,另一类是比太阳大8倍以上的恒星,它们的死亡是爆炸。恒星越大,寿命就急剧的缩短,质量差3倍,寿命就差750倍,也就是说,一个比我们的太阳大3倍的恒星,它的寿命就只有1300万年,所以,生命的进化是不可能托付给大恒星的。但是,宇宙的物质的丰富和流动,却全靠它们。

    宇宙在过去有过一个非常单调的开端,只有氢元素和少量的氦元素,然而宇宙在成长,而成长的标志就是重元素的增加,这种增加使宇宙越来越丰富,宇宙的所有的奇迹,都是在有了完整的元素制造之后。而制造元素,就是把氢元素以不同的数目聚合,而要完成所有元素的聚合的场所,就是拥有巨大引力的大恒星。从丰富物质角度来说,大恒星是宇宙中的精品,它们不仅能生产所有的元素,而且由于恒星越大,寿命越短,因此周期也短,所以,恒星的巨无霸是宇宙制造元素效率最高的工厂。不过,宇宙中最大的恒星的质量极限是一百个太阳,如果再大,就会因为自身的核反应过猛而解体。

    船底座海山二星(Eta Carinae)可能即将爆炸!但谁也不知道它会发生于何时?一年后,抑或百万年后?海山二星的质量约为太阳的100倍,拥有足够的能量以产生一次非凡的超新星爆炸。根据历史记载,大约150年前一次不平常的爆发,使得海山二星成为南半球夜空中最亮的几颗星之一。位在钥匙孔星云(KeyholeNebula)中的海山二星被认为是目前已知唯一一颗可发射自然激光的恒星。这一张在1996年经由复杂的影像处理后所得的影像,显示出这颗恒星周围云气的细微部分,其中包括两个清楚的圆形突出部分、一个炽热的中央区域,以及一些奇怪的辐射状条纹。
    船底座海山二星(Eta Carinae)可能即将爆炸

    引力制造元素,但也束缚元素,小恒星大约能制造出十来种元素,但这些元素最终不能在宇宙中流动。大恒星能制造更多的元素,一般超过太阳质量 8倍以上的恒星就能使聚变一往无前,其核心达到几十亿度的高温不断的创造不可思议的聚变,每次聚变所产生的能量都使恒星膨胀得更大一些,于是它就象洋葱一样形成令人吃惊的多层核聚变的巨大空间,这个空间可以达到一百亿公里,装下整个的太阳系。在聚变的深入的过程中,恒星变得越来越危险了,因为元素越重,聚变提供的能量越少,而巨大的恒星又必须靠不断释放的核能支撑。然而,当聚变到排列第26位的铁元素时,摇摇欲坠的恒星遭受到最致命的破坏──因为铁元素的结构极其稳定,它在聚变时不释放能量,于是,巨大而膨胀的恒星将会因核心失去支撑而倒塌。

    因此而恒星粉碎性的爆炸,能量的狂飙扫荡天庭,这就是超新星爆发。此刻它的能量相当于正常恒星的一百亿倍,在这个超能量的瞬间,宇宙中所有的元素都被聚变出来了。象金银首饰这种重元素,就是在超新星的爆炸中诞生的,当我们佩戴它们时,要记住宇宙制造高档产品确实是代价很高,它需要报废一颗至少比太阳大8倍以上的恒星,才能使我们披金戴银。

    超新星发生在一个恒星即将结束生命时,亦即在红巨星阶段,核心燃料快要消耗殆尽时,恒星会因为没有额外的燃料而自行崩溃。如果恒星的质量够大,恒星内部的内爆层会在接触核心时反弹,产生巨大的爆裂,爆炸所产生的震波会将恒星的所有物质射入太空中。

    我们的太阳将会在50亿年后衰亡,因它内部提供予核融合的燃料终於消耗殆尽。到时太阳会变成一个主要由碳和氧组成、密度高而「寒冷」的白矮星。 另一方面,一颗比太阳更重的恒星的中心温度更高。这些巨大星体会在经过一次壮观的爆炸后灭亡,这过程称为「超新星爆炸」。爆炸释出的能量非常巨大,超新星爆炸的光度可能相当於1,000亿万颗恒星同时发出的光芒。

    超新星的爆发是在约一秒钟之内完成的。由於高能辐射与爆炸拋射出来的恒星大气相互作用,使得超新星也可能有X射线等辐射。例如SN1987A在爆炸后100多天才被Ginga卫星所探测到它的X射线。而光学波段的突然增亮,首先是由膨胀大气引起的,后来则由Ni56等同位素的衰变提供能量,使得光度下降较为缓慢。图五中给出了典型的超新星光变曲线。超新星爆发的高速拋射物与周围介质相互作用形成的激波引发出电波辐射,而对星周尘埃的加热则可以产生红外辐射。但这些只有周围有稠密的星际物质的II型或Ib、Ic型超新星才能观测得到。

    在不到一秒钟时间内释放出1051~1053erg的能量(相当於90个太阳在其一生所释放能量之总和)的天体,它的前身星是什么?产生如此巨大能量的机制是什么?这些是天文学家首先面临的问题。

    首先我们来看看Ia型超新星。在它的光谱中缺少氢谱线,而且根据统计它在不同类型的星系中都有可能出现。据此天文学家提出了Ia型超新星是密近双星演化到晚期的终极结果的想法。设想有一密近双星系统,其两个成员星的质量均小於8M¤ ,其中质量大的那一个演化得比较快,在其核心燃烧完氢后,接著燃烧氦,而变成中心为碳和氧的白矮星。这时初始质量较小的那颗成员星的物质就被它吸积。假如物质转移速度小於每年10-8M¤ 的话,在白矮星周围形成氢壳,当它达到核融合点火的温度时,其表面就产生核融合点火爆发,这就是新星爆发的现象,其规模比超新星要小得多。

    当转移速率在每年10-6M¤ ~10-8M¤ 之间的话,表面同样会产生核融合,而形成氦,氦形成碳,逐步使其碳核心质量增加,直到钱氏 (Chandrasekhar) 极限的1.4 M¤ 。其中心密度可达到3×109g/cm3,而且中心达到碳点火的温度。碳被点燃,并且融合过程从中心往外迅速传播,在不到一秒钟之内传到白矮星的最外层。其爆炸将产生1053erg的能量,而且爆炸规模巨大无比,以至於将这颗白矮星完全「炸飞」了。由於白矮星中的氢已经燃烧殆尽,所以它的光谱中没有氢线,同时因为它是一种「老年」的恒星,因此会出现在不同的星系之中。

    II型的超新星则不同。它的光谱中以氢线为主,而且往往出现在螺旋星系的旋臂上,在那裡往往有恒星正在形成。一个目前被广泛接受的II型超新星爆炸的模型是:一个大质量的恒星(质量大过10M¤ ),在其最初的3000万年甚至更短的时间内,它的核心首先是氢融合为氦,然后氦变为碳和氧,碳变为氖和镁,氧和镁变为硅和硫,直到最终硅和硫融合为铁属元素。上述每种融合过程都释放出大量的能量,维持著恒星的「生命」,而且其核心变得愈来愈密,温度则愈来愈高,以致能够抵抗恒星引力的收缩。但到了核心变为铁心后,由於铁属元素的核束缚能最小,融合无法继续为恒星提供能量,反而要吸收能量。引力收缩就开始,中心的密度和温度继续增大,到 1010K和1010g/cm3时,电子就被压到原子核内而形成富含中子的同位素,而高能辐射又将原子核「撕」成a粒子。这两个过程都要吸收能量,使得重力塌缩变得更快。当中心密度超过2.7×1014g/cm3时,塌缩不能继续,产生反弹而引发超新星爆发。它将外层核融合的剩余物,包括最外层的氢向外拋,而留下一个核核心,也就是中子星。所以在光谱中有强的氢线,同时因为大质量恒星(寿命短;因此我们看到的都是不久前形成的)是和恒星形成区相关的,所以他们往往出现在螺旋星系的旋臂上。至於Ib和Ic型超新星,目前也认为是一种称为「沃夫─瑞叶星」 (Wolf-Rayet stars; W-R stars) 的大质量恒星演化到晚期的结果。由於W-R星有大规模的恒星风,质量流失很大,因此表层已失去了氢甚至氦,所以其光谱中没有氢线(或甚至於氦线)。

    超新星1987A(1987年发现的第一个超新星)是近代爆炸的超新星中,最靠近地球的一个,位於169,000光年外(我们银河系的伴星系)的大麦哲伦星系。它也是自从克卜勒在1604年於银河系中观测到超新星以来最明亮的一个;同时是自1885年以来第一个肉眼看得见的超新星。那原来是一个蓝超巨星的位置,其质量约为太阳的20倍。天文学家相信这个星球先是膨胀成红超巨星,在吹开一部份的星球体后,经过收缩与再加热,成为一个蓝超巨星。之后,在短短不到一秒钟,整个星球的中心突然就崩垮了,一阵微中子将中心加热至100亿度。这个过程引爆出震波,将此星球炸散掉,并喷出大量的微中子到太空中。

    直至1987年5月,国际紫外线探索号已在超新星的碎片中发现了许多化学元素,显示出这个始祖星球已经过了红巨星期,证实了原来的理论。到了7月,一个日本的人造卫星和德国的望远镜都侦测到从碎片中发射出来的X光线。自8月到11月,更有其他的研究团队侦测到高能的伽玛射线,这是在即将死去的星球中心出现核反应所产生的放射性元素,衰变时所放射出来的。此资料证实了大家所相信的理论,即超新星会产生组成地球大部分的重化学元素。

    超新星1987A影像 
    超新星1987A影像

    哈伯太空望远镜先进巡天相机 (ACS) 所拍摄的超新星1987A影像,在其四周包围著一串如珍珠项链般的气体环,这些「珍珠」其实是超新星爆发所产生的冲击波,以超过每小时6千万公里的速度追撞上了“恒星在爆炸前数万年所喷出, 膨胀速度较慢的气体”。爆震波追上了这个环,由於碰撞作用,气体受到衝击,温度升高到了数百万至1千万度,因而发出了红外辐射。环中的尘埃是在星风中形成的,而不是在超新星爆发中形成的。光环直径约一光年,光环中央的长椭圆形黯淡星体就是超新星残骸,主要受超新星爆炸时所产生放射性元素鈦 44 衰变辐射加热而发光,未来数十年都还将持续发光。天文学家在 1996 年首次在 SN 1987A 的外圈发现一个亮点,现在则可看出数十个。天文学家推测,未来几年中还将陆续出现更多类似的光点,这些亮点的光会将周围照亮,天文学家届时将可推测超新星爆炸前是如何喷发物质至太空中。当震波逐渐往外移时,产生的紫外线和X射线辐射将加热更多周围过去所喷出的物质。就如同参与钱卓研究计画的科学家理查、麦克雷所说:「超新星1987A将会点亮它自己的过去」。

    超新星的爆炸使物质摆脱了引力的束缚,但铁元素的核却坠入引力的深渊,巨大的塌方把电子都压进了质子,于是质子全变成了中子,而中子之间没有电磁力的排斥,原子核可以相互紧紧的挨在一起,这就形成了最致密的物质──中子星,它一立方厘米的质量能达到十亿吨,而它引力强大到让光都要成抛物线才能挣脱。把一个几百万公里直径的物体压缩成只有30公里的直径,就是中子星,而同时被压缩的还有磁场,这是一个匪夷所思的超高能核电站,它可以把表面附着的电子象高压水柱一样喷射出去,它们所具有强烈的方向性可以成为宇宙定位的灯塔。十几年前,人类寻访外星生命的一艘飞行器上所携带的人类的自我介绍,就是用多颗中子星为地球做定位。一些大的超新星爆炸之后,将会产生引力的奇迹──黑洞,巨大的引力把物质化为无形,因为连光都要被吸回它的表面,如果把地球压缩成一个核桃,就是黑洞,因为地球其实是一个强力和电磁力支撑的物体,如果把原子核都毁灭了,地球就将成为几厘米直径的浓缩引力的载体,黑洞的存在已经被证实。

    超新星是宇宙中4种力配合的杰作,它们共同建造一个巨大的原子锅炉,然后以锅炉的崩溃所激发的能量完成所有元素的制造,并且在最后的瞬间把元素都彻底的抛洒出去,正因为有这种抛洒,物质才有可能演化,否则,就象有钱不去投资,再多的财富也将没有任何意义。恒星以自身的毁灭造就了宇宙中最伟大的新生。 在超新星的物质弥漫之后,引力将会再次把这些物质凝聚成天体,大的塌缩成恒星,小的形成行星,如果这颗恒星有较长的寿命,而它的周围有若干合适的行星围绕,那么这个长寿的核能和比较靠近它的行星上丰富的宇宙元素的光和热交流,就可能最终产生宇宙中最复杂的物质形态──生命。

    宇宙中最丰富的十种元素
    posted @ 2007-04-05 13:07 三人行,必有我师焉 阅读(512) | 评论 (1)编辑 收藏

        超新星是最激烈的天体物理现象,它的爆发过程只延续大约一秒鐘,但是释放出极大的能量,超新星爆炸的光度可能相当於1,000万亿颗恆星同时发出的光芒。爆炸时產生的高能粒子是地面上任何加速器都不能达到的, 它提供一个在极端条件下进行的核融合,以及与高能粒子相互作用的实验,包括爆炸过程在内,这样的条件在地面上是永远无法实现的。在周期表中原子序数比铁更高的元素(如锌、金或铅)全都是在超新星爆炸中產生的。超新星爆炸标示了一颗恆星壮烈的死亡,但是也触发了新一代的恆星诞生。

    超新星Supernova 1994D (表示是1994年里第4个发现的超新星,第二十六个以后的则是用aa、ab、ac等等)
    超新星Supernova 1994D

    天文学家把超新星按它们光谱上的不同元素的吸收线来分成数个类型:
    I型:没有氢吸收线。
    Ia型:没有氢、氦吸收线,有硅吸收线。
    Ib型:没有氢吸收线,有氦吸收线。
    Ic型:没有氢、氦、硅吸收线。
    II型:有氢吸收线。

    I型的超新星一般都比II型超新星亮。一般学生最先知道的超新星是II型(Type II)超新星, 是大质量恆星死亡后, 成為黑洞或中子星前的超新星爆炸產生的。 Ia型超新星(Type Ia supernova, Ia唸成one-a, 不是i-a).一般相信(会写一般相信, 就表示并非百分之百有定论)是来自含有白矮星与巨星的双星系统, 白矮星从巨星的外层大气中逐渐吸收质量, 待白矮星的质量超过所谓"钱的限制(Chandrasehkar's limit)"后, 会引发重力塌缩及超新星爆炸。

    这种双星系统的爆炸分为两种,一种是新星的爆炸,另外一种则是更剧烈的超新星爆炸。

    新星 (Nova) 爆炸:

    Nova(复数Novae)在拉丁文中代表「新的」,在天文学中「新星」指的是看来像是新產生的星星。新星会在天空中突然变亮,维持几天后,逐渐变暗,至数月后才看不见。但是事实上「新星」并非一个新诞生的星星,而是一颗年老的白矮星爆炸所形成。

    新星爆炸是由於一颗普通星星的质量经由吸积盘转移到一颗白矮星上。由於这些物质是由一颗普通的星星上来的,所以裡面含有许多未经核融合的成分,其中氢就佔得最多。当这些物质聚集在白矮星的表面时,形成一层未经核融合反应的燃料层。当这层物质愈来愈厚,它也变得愈来愈密、愈来愈热,最后到达可以產生氢的核融合的条件,突然產生爆炸。

    為了明白这些爆炸如何產生,我们要先了解质量如何掉入一颗星球上。

    吸积盘 (Accretion Disks)

    当伴星质量往白矮星掉落时,由於角动量守恆,事实上物质无法直接掉在白矮星上,而是绕著白矮星转。我们用一个日常生活举例︰一个装满水的洗脸槽,槽内的水原本有些轻微的扰动,不过它的旋转并不明显,一旦我们将塞子拔掉,往排水口流出的水由於角动量守恆,所以变成了漩涡。同样的,掉入白矮星的气体也会因同样的效应形成一个旋转盘,称為吸积盘。

    这两颗恒星是如何产生如此奇怪的复杂结构呢?大部分的恆星是属於多星系统的一员。有些紧邻的双星,其中一颗星的物质会掉入环绕著另一颗星的吸积盘上。然而只须扳一扳手指头就可以数出来的紧邻双星系统,是属於中度的极化双星系统,在这个系统中,白矮星的磁场会将内吸积盘向外推出,使得物质只能从磁极附近掉入。上图所示由画家所描绘的中度的极化双星系统,是著名的英仙座DQ (DQ Hercules)系统。在前方的白矮星与另一颗一般的星靠的很近,以至於白矮星会掠夺另一颗的外围大气。当白矮星自转时,被吸入的气柱也跟著一起转起来。所谓的中度极化,是因為它所发出的光的极化程度 是另一种没有吸积盘的极化双星的一半而已。中度的极化双星系统是激变星中的一种类型。
    中度极化双星系统中的吸积盘

    在吸积盘中会发生两件重要的事情︰第一,盘中的气体因為摩擦力及潮汐力而变得十分热。这个吸积盘扮演煞车的角色,让气体旋转速度变慢,掉入白矮星内。靠吸积盘内部的气体温度可以超过100万K,气体会发生强烈的X光。另外,从吸积盘往内掉落至白矮星上的物质会发出巨大的爆炸。

    新星的爆炸将白矮星的外层以每秒几千公里的速度往外炸开。虽然往外炸开的物质质量仅有0.0001倍的太阳质量,但是它的光度可达太阳的10万倍。当外层膨胀得愈来愈大,且愈来愈稀薄时,就逐渐变冷,新星看来就逐渐黯淡了。

    这个爆炸几乎不会影响这颗白矮星和它的伴星,所以同样的质量转移的过程又开始进行。白矮星外层的燃料层加厚的速度与质量转移的速度有关。根据这个理论,有些新星需要1,000到10万年来累积足够厚的燃料层来產生爆炸;有些则仅需要几週。再发新星 (recurrent novae)、矮新星 (dwarf novae) 及一些相关的不规则变星 (irregular variable stars) 都经歷类似新星的较小规模的爆炸。虽然这几型星球并不一样,不过它们都经歷质量累积在吸积盘的过程。

    在名为蛇夫座RS (RS Ophiuchi)的双星系统里,壮观的爆炸不停的重复发生。大约每隔20年,随著红巨星倾洩足够的氢气到它的白矮伴星,就会在白矮星的表面引发闪亮的热融合爆炸。离我们有二千光年远的蛇夫座RS星,因新星爆炸而大幅增亮,成為肉眼可见的天体。在上面这幅图示中,右方的天体就是这颗红巨星,白矮星则在左端明亮吸积盘的中心。随著恆星相互绕行,云气不断地由红巨星流向白矮星。天文学家认为在接下来十万年的某个时间点,当足够的质量累积在白矮星上,让它的质量超过钱氏极限 (Chandrasekhar Limit)时,就会造成更强烈的超新星爆炸。事实上宇宙中有一半以上的恆星都是双星系统。大部分的双星系统两颗星星都分得很开,所以当其中一颗膨胀并塌缩时不会影响它的伴星。但是有些双星距离很近,当质量较大的星星开始膨胀时,会与它的伴星有些特别的交互作用。
    不断发生爆炸的蛇夫座RS (RS Ophiuchi)的双星系统

    超新星爆炸:

    经典的观点认为,热核爆炸超新星——也就是Ia型超新星——爆炸发生在白矮星——一种燃烧完核燃料(Nuclear Fuel)并且全部由碳(Carbon)和氧(Oxygen)组成的星体——从一个邻近的伴星吸积物质的时候发生。在吸积的同时白矮星会收缩从而导致密度和温度上升。这个过程一直进行到白矮星的质量达到质量极限——也就是所谓的Chandrasekhar质量,大概等于1.4倍的太阳质量。当达到这个状态的时候,由于热核反应不稳定性导致核聚变放出大量的能量,将白矮星外层的物质以很高的速度喷射出去,速度可以达到光速的百分之几。核反应可以将大概0.6个太阳质量的白矮星物质变成一种同位素:放射性的镍56(Nickel-56)。这种同位素的衰变——先是衰变到钴56(Cobalt-56),然后再衰变到铁56(Iron-56)——提供了一个延迟能量来源,这可以维持喷射出去的物质处于高温,导致超新星获得比十亿个太阳更强的峰值光度(光度的定义为单位时间内辐射出来的能量)。

    天文学家对于Ia型超新星具有浓厚的兴趣,因为它们可以被用来探索宇宙的膨胀历史。这种超新星的光度很大,这就意味著能够在很远的地方看到——由于光的传播速度有限,这同时也意味著可以看到遥远的过去——而它们的相对视亮度则可以被用来推测它们的距离。超新星光变曲线和峰值光度之间的经验关系可以用来很精确地确定超新星的光度。

    所有的Ia型超新星, 当它们的亮度达最高点时,都有著同样的绝对亮度。因为它们发生爆炸的原因都完全相同,起始于白矮星吸收伴星物质的过程一直进行到白矮星的质量达到质量极限,由于热核反应不稳定性导致核聚变放出大量的能量。

    但是1996年后, 这一点被新观测给修正了。由Howell等人发现的超新星是SNLS-03D3bb(或者SN2003fg)在光学波段具有发射和吸收谱,由这些信息可以确定这颗超新星是Ia型的。这就意味著它的爆炸是由前面描述的失控热核反应驱动的,而不是驱动其它类型超新星的引力塌缩。但是这颗超新星的峰值光度是典型Ia型超新星爆炸事例的2.2倍。超新星爆炸的光度取决于镍56的质量,在这个案例中,产生这么大的光度需要有1.3倍太阳质量的镍56。产生这么多的镍要求初始喷射物质的质量远远超过Chandrasekhar极限允许的1.4倍的太阳质量。这是因为核聚变不仅产生镍,而且还稳定的铁系同位素,而且SN2003fg的光学谱显示存在更轻元素比如硅(Silicon)、硫磺(Sulphur)和钙(Calcium)的存在。同时还可能存在没有燃烧完全的碳和氧。把这些都考虑在一起,Howell等人估计喷射物的质量达到了2.1个太阳质量。

    但是为什么白矮星可以如此之重呢?一种可能是两个邻近的白矮星相互绕转最后融合。这种情况可以通过由引力波导致的星体角动量损失产生。但是这种情况下通常会产生的是中子星而不是超新星爆发。一个可能性更大的解释是,从普通伴星那里被白矮星吸积过来的物质导致白矮星的角动量增加,从而使得白矮星高速转动,可以克服引力的吸引,从而使得白矮星在爆炸之前具有超过极限的质量。

    在这种情况下白矮星可以具有多大的质量取决于角动量在星体内部如何分布,也就是说白矮星作为一个整体转动还是各不同部位的转动不一样。较差转动(Differential Rotation)可以使得白矮星的质量达到四倍太阳质量之巨,考虑到从伴星吸积物质有一定限度,白矮星的质量可能被限制在大概两倍太阳质量。

    由于多普勒效应的结果——移动物体发出的辐射谱发生变化——SN2003fg的光谱被展宽,而光谱变化的程度显示喷射物质的速度比起典型Ia型超新星来要低。这和超极限质量白矮星是符合的,因为虽然在这种情况下核聚变产生的能量更多,而同时也造成物质脱离引力束缚需要具有更高的能量。高束缚能造成较低的喷射速度。

    为了更好地了解Ia型超新星,确定喷射物质的质量分布是非常关键的。比如Ia型超新星是否普遍具有超极限的质量?它们的质量在1.4到2.1倍太阳质量之间有平滑的分布?Howell等人对超新星样例所作的一项分析表明情况可能确实如此。目前的数据和位于质量极限附近的典型Ia型超新星是相容的,而SN2003fg则显得比较例外。这种解释主要是受到了不同以往的超大光度以及对于光度-光变关联关系的破坏这两种异常现象的启发。虽然这种Ia型超新星的亮度非常大,光变曲线的形状则是典型的。

    但是这种Ia型超新星爆发现象的发现并不意味著用Ia型超新星作为宇宙学距离指示器有问题。如果假设SN2003fg符合光度-光变形状经验关系,就有可能极大地低估它的光度,从而低估它的距离。但是由于这颗超新星是如此地奇特,在一项宇宙学研究中已经将其排除。光度-光变形状关系是经验性的,并且对Ia型超新星的质量分布没有人为假设。这就已经意味著这个经验关系可以容纳白矮星质量对质量极限有少许偏离,但这并不包括SN2003fg这种情形。

    无论如何, 我们可以透过观测Ia型超新星而得知它们的绝对亮度. 一但有了绝对亮度, 和观测到的亮度比较后, 透过平方反比律, 我们就可以算出该超新星的距离, 也就是它的母星系的距离。
    posted @ 2007-04-04 17:40 三人行,必有我师焉 阅读(2095) | 评论 (6)编辑 收藏

    GitHub |  开源中国社区 |  maven仓库 |  文件格式转换