【トピック】 ちょっとしたトピックを扱います。

2006年07月19日

yGuard で曖昧化する

Java クラスの内容を曖昧化するオブファスケータの yGuard を使ってみました。
yGuard は Ant のタスクとして提供されるオブファスケータです。次のページから取得することができます。

●yGuard

以下、実際に使ってみるまでの手順を記述してみました。

1. タスクの定義方法
yGuard のタスクは Ant の taskdef 要素で定義します。
yGuard に用意されている Ant タスク用のクラス名を指定します。

<taskdef name="yguard" classname="com.yworks.yguard.YGuardTask" classpath="yguard.jar"/>


2. タスクの定義
yGuard のタスクを定義したら、yGuard 要素を使用できます。
yGuard 要素には次の子要素を定義することができます。

● inoutpair
● externalclasses
● attribute
● shrink
● rename

2-1. inoutpair
yGuard では少なくとも1つの inoutpair 要素を指定する必要があります。この要素では in と out の jar のパスを指定します。

<inoutpair in="${jar}" out="${obfjar}"/>

2-2. externalclasses
yGuard によって実行される jar が外部のライブラリに依存している場合にはこの要素で指定します。ここで指定されたライブらいについては、サイズの縮小も曖昧化も行われません。

<externalclasses>
  <pathelement location="lib/external.jar"/>
  <pathelement location="lib/additional/classes/"/>
 </externalclasses>

2-3. attribute
ここで指定した属性については、曖昧化が行われません。カンマで区切って複数の値を指定することができます。

<attribute name="SourceFile, LineNumberTable, LocalVariableTable">
    <patternset>
      <include name="com.mycompany.mylibrary.**"/>
    </patternset>
  </attribute>

2-4. shrink
指定されたエントリポイントから到達しないすべてのクラス、メソッド、フィールドを取り除きます。

<shrink logfile="${shrinklog}">
    <keep>
      <class classes="protected" methods="protected" fields="protected">
        <patternset>
          <include name="com.mycompany.publicapi.**.*"/>
          <exclude name="com.mycompany.publicapi.private.*"/>
          <include name="com.mycompany.menu.reflection.**.*"/>
        </patternset>
      </class>
    </keep>
  </shrink>

2-5. rename
keep 要素で指定されたクラス、メソッド、フィールドを除くすべての対象の名前を変更します。

<rename mainclass="${mainclass}" logfile="${renamelog}">
    <property name="error-checking" value="pedantic"/>
    <keep>
      <class classes="protected" methods="protected" fields="protected">
        <patternset>
          <include name="com.mycompany.publicapi.**.*"/>
          <exclude name="com.mycompany.publicapi.private.*"/>
        </patternset>
      </class>
    </keep>
  </rename>

3. サンプルの実行
それでは早速 yGuard を使って、曖昧化した jar ファイルを作成してみます。
今回は2つのパッケージを持つプロジェクトを作成しました。
フォルダ構成は以下のとおりです。

/ (ルート)
  src/
  com.smartdez.yguard/
   Item1.java
   Imte2.java
   YguardSample.java
  lib/
   yguard.jar
  build.xml

Item1 クラスではすべてのメソッド、属性が public なメソッドです。一方の Item2 クラスでは private な属性と protected なメソッドを持つ package-private なクラスです。
ここでは yGuard で public な可視性であるクラス、メソッド、属性の名前をそのままにして、
それ以外のクラス、メソッド、属性の名前は変更してみます。

package com.smartdez.yguard;
  
/**
 * 商品情報を保持するクラス
 */
public class Item1 {
  /** 単価 */
  public int price;
  /** ディスカウント */
  public int discount;
  /** 個数 */
  public int count;
  
  public void setCount(int count) {
    this.count = count;
  }
  public void setDiscount(int discount) {
    this.discount = discount;
  }
  public void setPrice(int price) {
    this.price = price;
  }
  public int calc() {
    // 10個以上なら特別価格
    if (count > 10) {
      return (price * count) - discount;
    }
    return price * count;
  }
}
package com.smartdez.yguard;
  
/**
 * 商品情報を保持するクラス
 */
class Item2 {
  /** 単価 */
  private int price;
  /** ディスカウント */
  private int discount;
  /** 個数 */
  private int count;
  
  protected void setCount(int count) {
    this.count = count;
  }
  protected void setDiscount(int discount) {
    this.discount = discount;
  }
  protected void setPrice(int price) {
    this.price = price;
  }
  protected int calc() {
    // 10個以上なら特別価格
    if (count > 10) {
      return (price * count) - discount;
    }
    return price * count;
  }
}

次のような build.xml を用意します。

<?xml version="1.0" encoding="UTF-8" ?>
<project name="Samples" default="yguard" basedir=".">
	
	<target name="init">
	    <property name="project_name" value="yGuardSample"/>
	    <property name="src.dir" value="src"/>
	    <property name="class.dir" value="classes"/>
		<property name="build.dir" value="build" />
	    <property name="jar" value="${build.dir}/${project_name}.jar"/>
	    <property name="obfjar" value="${build.dir}/${project_name}_obf.jar"/>
	    <property name="renamelog" value="${build.dir}/${project_name}_renamelog.xml"/>
	    <property name="shrinklog" value="${build.dir}/${project_name}_shrinklog.xml"/>
	    <property name="mainclass" value="com.smartdez.yguard.YguardSample"/>
	    <mkdir dir="${class.dir}" />
	    <mkdir dir="${build.dir}" />
	</target>
    
    <target name="yguard" depends="jar">
    	<!-- yGuardのタスクを定義 -->
		<taskdef name="yguard" classname="com.yworks.yguard.YGuardTask"
	      classpath="lib/yguard.jar"/>
   
    	<!-- yGuardのタスクを実行 -->
		<yguard>
        <inoutpair in="${jar}" out="${obfjar}"/>
	    <shrink logfile="${shrinklog}">
	        <keep>
	        	<class classes="public" methods="public" fields="public">
		            <patternset>
		            	<include name="com.smartdez.yguard.**"/>
		            </patternset>
		        </class>
		    </keep>
	    </shrink>
		<rename mainclass="${mainclass}" logfile="${renamelog}">
	        <property name="error-checking" value="pedantic"/>
			<keep>
	        	<class classes="public" methods="public" fields="public">
	            <patternset>
	            	<include name="com.smartdez.yguard.**"/>
	            </patternset>
	            </class>
	        </keep>
	    </rename>
	    </yguard>
    </target>
    
    <!-- compile -->
    <target name="compile" depends="init">
      <javac srcDir="${src.dir}" includes="com/smartdez/**/*.java"
        destdir="${class.dir}">
      </javac>
    </target>
    
    <!-- create .jar -->
    <target name="jar" depends="compile">
      <jar jarfile="${jar}"
        basedir="${class.dir}"
        includes="com/smartdez/**">
        <fileset dir="${src.dir}">
          <include name="com/mycompany/resources/*.properties"/>
        </fileset>
      </jar>
    </target>
    
	<!-- run project -->
	<target name="run" depends="yguard">
		<java classname="${mainclass}" fork="true">
		    <classpath>
		    	<pathelement location="${obfjar}"/>
		    </classpath>
	    </java>
	</target>
    
    <!-- removes all that has been built -->
    <target name="clean" depends="init">
	    <delete dir="${class.dir}" includeEmptyDirs="true" />
	</target>
</project>

用意ができたら、Ant の yGuard タスクを実行します。
そうすると次のようなメッセージが表示されて、shrink および rename された jar ファイルが生成されます。

Buildfile: D:\Workspace\yGuardDemo\build.xml
init:
    [mkdir] Created dir: D:\Workspace\yGuardDemo\build
compile:
jar:
      [jar] Building jar: D:\Workspace\yGuardDemo\build\yGuardSample.jar
yguard:
   [shrink] yGuard Shrinker v2.0.1 - http://www.yworks.com/products/yguard
   [shrink] parsing D:\Workspace\yGuardDemo\build\yGuardSample.jar
   [shrink] writing shrinked D:\Workspace\yGuardDemo\build\yGuardSample.jar 
              to D:\Workspace\yGuardDemo\build\yguard_temp_955.jar.
   [shrink] shrinked D:\Workspace\yGuardDemo\build\yGuardSample.jar BY -14.44%.
   [shrink] size before: 2 KB, size after: 2 KB.
   [shrink] removed 0 classes, 3 methods, 0 fields, 0 resources.
   [shrink] 3 classes remaining of 3 total.
   [rename] yGuard Obfuscator v2.0.1 - http://www.yworks.com/products/yguard
Parsing jar D:\Workspace\yGuardDemo\build\yguard_temp_955.jar
Obfuscating Jar D:\Workspace\yGuardDemo\build\yguard_temp_955.jar to yGuardSample_obf.jar
BUILD SUCCESSFUL
Total time: 2 seconds

build ディレクトリに yGuardSample_obf.jar が作成されます。そのファイルを展開して、そこにあるクラスファイルの内容を確認してみてください。Item1 クラスの内容はすべてそのままに保たれていますが、Item2 クラスの内容は A とか B とか内容が曖昧化されて何を意味するか分からなくなっています。

このように jar ファイルを相手に渡すのだけど、中身を知られたくないというときにはオブファスケータを利用すると便利です。

投稿者 thatanaka : 07:05 | コメント (4654)

2006年07月06日

java2htmlでハイライト表示されたHTMLを作成する

Javaのソースコードを HTML として公開するときに、例えば pre タグとか利用して記述するということもできますが、予約語のキーワードとかをハイライト表示するのは面倒くさいですよね。

java2html というライブラリを利用すれば、Javaのソースコードからハイライト表示されたHTMLを簡単に作成することができます。java2htmlではAntタスクも用意されているので、ビルドプロセスの一環として組み込むことも可能です。

ここではjava2htmlのAntタスクを利用して作成したいと思います。

●環境
 Windows-XP Professional SP2
 JDK1.5.0
 Eclipse 3.2
 java2html 5.0

●手順
 1.Eclipse で Java プロジェクトを作成し、適当な Java プログラムを作成してください。またjava2html.jarを lib ディレクトリに配置します。
  プロジェクトの構成
  /src
  /lib
   java2html.jar

 2.プロジェクトのルートディレクトリに build.xml を作成します。build.xml の内容は以下のとおりです。

<?xml version="1.0" encoding="UTF-8" ?>
<project name="Samples" default="help" basedir=".">
  <property name="app.name" value="Samples" />
  <property name="app.version" value="0.9" />
  <property name="src.dir" value="src" />
  <property name="class.dir" value="bin" />
  <property name="build.dir" value="build" />
  <target name="help">
    <echo>
<![CDATA[
${app.name} build file:
java2html - Java ソースファイルからカラーハイライトされた HTML を作成します。
]]>
    </echo>
  </target>
  <target name="clean">
    <delete dir="${build.dir}" />
  </target>
  <target name="init">
    <mkdir dir="${build.dir}" />
  </target>
  <taskdef name="java2html"
   classname="de.java2html.anttasks.Java2HtmlTask"
   classpath="${class.dir}"
  />
  <target name="java2html">
    <java2html
     srcdir="${src.dir}"
     destdir="${build.dir}"
     includes="**/*.java"
     style="eclipse"
     showLineNumbers="true"
     showFileName="true"
     showTableBorder="true"
    />
  </target>
</project>

 3.build.xml を右クリックして、[Run As] - [Ant build...] をクリックします。

 4.[Classpath] タブで java2html.jar を追加します。

 5.[Targets] タブで init, java2html を順にクリックし、[Run] ボタンをクリックします。

 6.BUILD SUCCESSFUL と表示されたら、プロジェクトに作成された build ディレクトリ配下に html ファイルが作成されていることを確認できます。HTML を開いて確認してください。

投稿者 thatanaka : 06:49 | コメント (10)

2006年05月17日

SQL*PlusのAUTOTRACE機能

OracleでSQLのパフォーマンスチューニングなどを行うときに、SQL*PlusのAUTOTRACE機能を使用すると、画面上で確認できて便利です。ここではWindowsプラットフォームで設定する方法についてまとめています。

【環境】
 OS:WindowsXP Professional SP2
 DB:Oracle 9i R2
 スクリプト:%ORACLE_HOME%\sqlplus\admin

1. sysユーザでデータベースに接続。

SQL > sqlplus /nolog
SQL >  connect / as sysdba

2. PLUSTRACEロールの作成

SQL > @%ORACLE_HOME%\sqlplus\admin\plustrce.sql

3. SQLを実行するユーザにロールを付与

SQL > grant plustarce to <username>;

4. PLAN_TABLEの作成

SQL > connect <username>/<password>@<servicename>
SQL > @%ORACLE_HOME%\rdbms\admin\utlxplan.sql

以上でAUTOTRACE機能の設定が完了です。
後は、SQL*Plus にログイン後、以下のコマンドを実行すれば、AUTOTRACE機能が有効になります。

SET AUTOTRACE ON

また検索処理を実行せずに実行プランだけを表示させたい場合は、次のコマンドを実行します。

SET AUTOTRACE TRACEONLY EXPLAIN

投稿者 thatanaka : 23:29 | コメント (0)

2006年01月23日

StrutsTestCase

StrutsTestCaseは、Strutsアプリケーションのテスト用に作成されたテスティング フレームワークです。JUnit を拡張し、さらに Struts の Action の動作や戻り値などをテストすることができます。
StrutsTestCase では、MockObjectでコンテナ不要の Mock アプローチとコンテナを動作させてテストする Cactus アプローチがあります。
今回プロジェクトで Sun Java Studio Enterprise を使用しています。そこでの StrutsTestCase とライブラリの設定などをまとめてみました。

○Sun Java Studio Enterprise での StrutsTestCase (Mock Approach)

テスト対象のアクションクラスは次のようなクラスです。
クライアントから送信されてきたパラメータに応じた挨拶を返すアクションです。

public class GreetAction extends Action {  
  private static Map map = new HashMap();
  static {
    map.put("morning", "おはようございます");
    map.put("afternoon", "こんにちは");
    map.put("night", "こんばんは");
  }
  
  public ActionForward execute(ActionMapping mapping, 
      ActionForm form, 
      HttpServletRequest request, 
      HttpServletResponse response) 
  throws Exception {
    GreetForm gform = (GreetForm)form;
    String[] items = gform.getItems();
    List list = new ArrayList();
    for (int i=0; i<items.length; i++) {
      list.add(map.get(items[i]));
    }
    request.setAttribute("result", list);
    return mapping.findForward("success");
  }   
}

このアクションが動作する Struts アプリケーションを作成し、web.xml や struts-config.xml などを設定します。ちなみにこのアプリケーションのフォルダ階層は次のとおりです。

/src
  /sample
    GreetAction.java
    GreetForm
/test
  /sample
    GreetActionStrutsTest.java
/web
  /WEB-INF
    web.xml
    struts-config.xml
    /lib
      ・struts関係のライブラリ

Strutsアプリケーションを構築した状態で、次の手順で行いました。

1.次のライブラリを[プロジェクトプロパティ]-[ライブラリ]の[コンパイル]タブで追加します。
  servlet.jar
  commons-collection.jar
  strutstest-2.1.x.jar
  ※struts 関係のライブラリはあらかじめライブラリに追加されていることが前提です。

2.WEB-INF が存在するディレクトリを[プロジェクトプロパティ]-[ライブラリ]の
[テスト実行時]ライブラリに追加します。
例えば /web/WEB-INF/web.xml である場合、「/web」フォルダをライブラリに追加します。
※WEB-INF直下にはあらかじめ struts 関係のコンフィグレーションが存在していることが前提です。

3.MockStrutsTestCase を継承するテストケースを作成します。

 package sample;
 
 import java.util.List;
 import servletunit.struts.MockStrutsTestCase;
 
 /**
  * StrutsTestCase を使用したサンプル
  */
 public class GreetActionStrutsTest extends MockStrutsTestCase {
   
   public void setUp() throws Exception {
     super.setUp();
   }
 
   public void tearDown() throws Exception {
     super.tearDown();
   }
 
   
   /** Creates a new instance of GreetActionStrutsTest */
   public GreetActionStrutsTest() {
   }
   
   public GreetActionStrutsTest(String name) {
     super(name);
   }
   
   public void testGreet001() {
     // Strutsアクションパスの指定
     setRequestPathInfo("/greet");
     // Requestパラメータの追加
     addRequestParameter("items", "morning");
     // アクションの実行
     actionPerform();
     // mapping.forwardの戻り値チェック
     verifyForward("success");
     // request属性の値をチェック
     Object object = getRequest().getAttribute("result");
     assertNotNull("結果が取得できません。", object);
     assertTrue(object instanceof List);
     List list = (List)object;
     assertEquals("挨拶が正しくありません。", 
         "おはようございます", list.get(0));
   }
 }

4.Shift + F6 でテストを実行します。

そうすると下記のようなメッセージが表示され、テストが成功したことが確認できます。

Testsuite: sample.GreetActionStrutsTest
Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.28 sec

投稿者 thatanaka : 18:15 | コメント (25)