:::
顯示具有 DSpace 標籤的文章。 顯示所有文章

Windows一鍵執行SSH指令:AutoIT、Pietty搭配使用

Windows一鍵執行SSH指令:AutoIT、Pietty搭配使用

image

Linux的命令列畫面讓很多人惟恐避之不及,這對有許多指令需要依賴SSH連線、並在命令列輸入才能執行的DSpace來說,無疑是一大門檻。在此我提出一種可以做到「一鍵指令」的方案:利用AutoIt自動執行機器人,透過PieTTY的命令列模式,用ini設定檔來設定連線參數,來執行捷徑所指定的指令的作法。

這種作法對資安來說非常不理想,僅是一個簡便利用的應急方案而已。


一鍵指令的背景與目的

我現在要做的事情是:

  1. 在Windows的環境下
  2. 透過SSH連線到Linux伺服器
  3. 進行登入動作(以及金鑰確認)
  4. 然後執行一個指令。

而這個方案的目的是將使用者的操作簡化到極限,我希望使用者能夠以滑鼠執行一個檔案,就自動做完上述的所有動作。

一鍵指令方案概述

簡單來說,這個方案的作法是:

  1. 利用PieTTY的命令列模式來輸入登入資訊與要執行的指令
  2. 以ini檔案儲存登入資訊
  3. 在Linux伺服器端配置參數與接收命令的sh腳本
  4. 利用AutoIt來處理連線的細節
  5. 利用Windows的捷徑與捷徑後輸入的參數,將參數輸入給AutoIt

Linux環境配置

要做到這些事情,需要Linux伺服器端與Windows使用者端的環境一起配置才行。這邊先敘述Linux的部份,大致上是要做以下三件事情:

  • 建立帳號、密碼
  • 開啟ssh連線
  • 建立ssh-cmd.sh腳本

Linux伺服器建立帳號、密碼、開啟ssh連線等基本操作請參考鳥哥的Linux思房菜。在此最重要的是要配置接收來自客戶端指令的執行腳本「ssh-cmd.sh」。

在本篇的例子中,我以普通使用者「dspace」跟管理者「root」作為帳號、「password」作為該帳號的密碼來說明。

ssh-cmd.sh:執行指令腳本

因為帳號是使用「dspace」,所以我在「/home/dspace/ssh-cmd.sh」(SkyDrive備份)這個位置建立起腳本。腳本的內容如下:

#!/bin/bash
# Program:
#       Excute command and pause at finish.
## History:
## 2009/11/12    Pudding   First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export JAVA_HOME=/usr/java/jdk1.6.0_06
export PATH
export LC_ALL=en_US
export JAVA_OPTS="-Xmx128M -Xms64M -Dfile.encoding=UTF-8"

ANT_HOME=/opt/apache-ant-1.7.0
JAVA_HOME=/usr/java/jdk1.6.0_06
CATALINA_HOME=/opt/apache-tomcat-6.0.16
PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$ANT_HOME/bin:$PATH:/opt/apache-maven-2.0.9/bin
export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE INPUTRC JAVA_HOME ANT_HOME CATALINA_HOME


if [ "$1" == "/home/dspace/tomcat_restart.sh" ]; then
        at now + 0 minutes < $1
        echo "Tomcat will restart now."
else
        $1
fi

echo ""
echo "====================================="
echo ""
read -p "Please press ENTER to exit. " doExit

這個腳本中設置了相當多參數,請依照你伺服器的實際情況來決定要設置的參數內容。

此外,由於Tomcat的重新啟動無法直接透過這樣的指令來執行,所以我改成以「at」執行一次的方式來執行。必須說明的是,這並不是很理想的作法,有待以後改善。

tomcat_restart.sh:重新啟動Tomcat伺服器腳本

如果你沒有需要重新啟動Tomcat的話,這個步驟是可以省略的。「/home/dspace/tomcat_restart.sh」(SkyDrive備份)是用來重新啟動Tomcat伺服器的腳本,內容如下:

export JAVA_HOME=/usr/java/jdk1.6.0_06
export JAVA_OPTS="-Xmx128M -Xms64M -Dfile.encoding=UTF-8"

/opt/apache-tomcat-6.0.16/bin/shutdown.sh 
sleep 1
/opt/apache-tomcat-6.0.16/bin/startup.sh 

要記得將這些腳本的執行權限開啟,他們才能正常地執行。

Windows使用者端配置

你現在需要在Windows中建立一個資料夾,例如「c:\ssh-cmd\」,然後把以下的檔案放進去:

PieTTY的命令列執行方式

雖然很多人都知道PieTTY是用來作SSH連線的,但是知道PieTTY可以透過命令列與指令檔案來進行連線並執行指令的人就不多了,其實這是基於PieTTY改編自PuTTY原始就有的功能喔。

具體來說,利用命令列來透過PieTTY連線的作法如下:

pietty0327.exe -l [ID] -P [PORT] -pw [PASSWORD] -m [COMMAND] -t [HOST]

裡面的參數中:

  • [ID]是要登入的帳號
  • [PORT]是連接埠
  • [PASSWORD]是密碼
  • [COMMAND]是「存放指令的檔案位置」,注意,不是指令,只是檔案位置喔
  • [HOST]要連線的主機IP
config.ini:連線配置

連線的配置資訊,我將它存放在「config.ini」中。「config.ini」的內容如下:

[ssh-dspace]
login=dspace
pw=password

[ssh-root]
login=root
pw=password

[ssh]
port=22
host=127.0.0.1

在此安排了兩種不同的身分,一種是以普通使用者「dspace」來執行,另一種是以管理者「root」來執行。除了重新啟動伺服器等重大指令之外,一般指令最好是以普通使用者「dspace」的身分來執行會比較安全。

ssh-cmd.exe:執行連線腳本

由於要執行指令必須要以存放在檔案中的形式來執行,所以建立這個檔案、並指引PieTTY來連線的工作,是交給AutoIt的自動腳本ssh-cmd.exe來執行。

ssh-cmd.exe是由ssh-cmd.au3編譯而來的,這是AutoIt的程式語言。內容如下:

Dim $user = "ssh-dspace"
Dim $script = ""
If $CmdLine[0] == 2 Then
	$user = "ssh-" & $CmdLine[1]
	$script = $CmdLine[2]
ElseIf $CmdLine[0] == 1 Then
	$script = $CmdLine[1]
EndIf

Dim $login = IniRead("config.ini",$user, "login", "root")
Dim $pw = IniRead("config.ini",$user, "pw", "password")
Dim $port = IniRead("config.ini","ssh", "port", "22")
Dim $host = IniRead("config.ini","ssh", "host", "127.0.0.1")

If $script == "" Then
	MsgBox(0, "錯誤", "請指定要執行的指令")
	Exit
EndIf

Dim $doExcute = MsgBox(1, "提示","您確定要在伺服器中執行以下命令嗎: " & $script)
If $doExcute == 2 Then
    Exit
EndIf

Dim $sh = "cmd.sh"
Dim $scriptHeader = "~/ssh-cmd.sh "

$file = FileOpen($sh, 2)

; Check if file opened for writing OK
If $file = -1 Then
    MsgBox(0, "錯誤", "無法開啟檔案")
    Exit
EndIf

FileWrite($file, $scriptHeader & $script)
FileClose($file)

Dim $cmd = "pietty0327.exe -l " & $login & " -P " & $port & " -pw " & $pw & " -m " & $sh & " -t " & $host
Run($cmd)
Sleep(1000)
If WinActivate("PieTTY Security Alert") Then
	WinActive("PieTTY Security Alert")
	Send("{ALTDOWN}Y{ALTUP}")
EndIf

這個腳本做了幾件事情:

  1. 接收來自外部的「身分」與「指令」參數(稍後建立Windows捷徑的時候,我會再說明怎麼輸入這邊的參數)
  2. 讀取來自config.ini中的連線資訊,包括「帳號」、「密碼」、「伺服器位置」、「連接埠」
  3. 過濾指令、顯示提示
  4. 將指令寫入「cmd.sh」檔案中
  5. 以命令列執行PieTTY連線
建立Windows捷徑

image

接著要建立到「ssh-cmd.exe」的捷徑,並且在捷徑之後加上「參數」。建立好ssh-cmd.exe並改好名字之後,你可以打開捷徑的「內容」,在「目標」的欄位中設定參數。

舉例來說,我現在要在伺服器上以「dspace」身分執行「/home/dspace/tomcat_restart.sh」的指令,那麼目標裡面的設定如下:

"C:\ssh-cmd\ssh-cmd.exe" dspace /home/dspace/tomcat_restart.sh

目標的值除了指定要執行的程式位置之外,還指定了要執行的身分「dspace」跟要執行的指令「/home/dspace/tomcat_restart.sh」。如此配置之後,就能夠讓使用者直接點選此捷徑,讓他自動執行這些動作了。

你可以利用這個例子舉一反三,建立執行不同身分、不同指令的捷徑,並組成一個操作列表,讓使用者易於選擇。也可以將此捷徑放到「開始」程式集裡面,讓使用者更容易執行各種操作。這些動作我是用InnoSetup在安裝時自動配置而成,不過那又是另一番長篇大論了。


結語

儘管一鍵指令的方案我研究了很久,但是仍有很多不完美之處,希望高手能多多指教。

其實這個是DSpace-DLLL寫書的一部分技術內容。之前寫完書之後就匆忙地投入其他事情中,到最近在使用AutoIt時,又把之前寫的檔案挖出來看。

這時候就會覺得這個Blog對我來說也是很重要的,如果沒有這些記錄,我恐怕很快就會忘記自己之前做過的事情了吧。

(more...)

CentOS中自動啟動Tomcat的亂碼問題

CentOS中自動啟動Tomcat的亂碼問題

image

如果要架設以Java、JSP、Sevlet系列伺服器端程式語言為主的網頁伺服器,Apache Tomcat(簡稱Tomcat)是相當有名的一套解決方案。我研究DSpace時也是使用Tomcat來架設在CentOS作業系統上。

因為Tomcat並不是CentOS內建服務而是我額外安裝的,所以我設定了crontab讓他在開機時自動執行。由於之前的參數沒有配置完善,導致開機自動執行Tomcat時,讓Java讀取檔案的編碼發生錯誤。

研究了老半天終於找到算是可行的解決方案,在這邊記錄一下。

Tomcat啟動腳本規劃考量

安裝好Tomcat之後,一般是以命令列執行[tomcat]/bin/startup.sh ([tomcat]表示Tomcat的安裝目錄),但是如果要以自動啟動的方式來啟動Tomcat,卻會因為沒有先執行/etc/profile中設置Java的參數,而會造成啟動失敗。

/etc/profile中的Java參數

先回顧一下DSpace安裝步驟裡,在/etc/profile設置Java參數的內容:

JAVA_OPTS="-Xmx2048M -Xms2048M -Dfile.encoding=UTF-8"
ANT_HOME=/opt/apache-ant-1.7.1
JAVA_HOME=/usr/java/jdk1.6.0_12
CATALINA_HOME=/opt/apache-tomcat-6.0.13
CLASSPATH=$CATALINA_HOME/common/lib/servlet-api.jar
PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$ANT_HOME/bin:$PATH:/opt/apache-maven-2.0.9/bin
export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE INPUTRC ANT_HOME JAVA_HOME CATALINA_HOME CLASSPATH

其中很重要的是「JAVA_HOME」跟「JAVA_OPTS」這兩項參數。前者是要告訴Tomcat要執行的Java環境必要的套件位置,後者則是執行Java時的參數設定。

Tomcat啟動腳本

如果要自動啟動Tomcat的話,則必須在腳本中加入Java參數設定才行。我建立了一個「/home/dspace/tomcat_startup.sh」的腳本,內容如下:

export JAVA_HOME=/usr/java/jdk1.6.0_12
export JAVA_OPTS="-Xmx2048M -Xms2048M -Dfile.encoding=UTF-8"

/opt/apache-tomcat-6.0.16/bin/startup.sh

這個腳本執行了三件事情:

  1. 設置JAVA_HOME變數為「/usr/java/jdk1.6.0_12 」
  2. 設置JAVA_OPTS變數為「-Xmx2048M -Xms2048M -Dfile.encoding=UTF-8」
  3. 執行「/opt/apache-tomcat-6.0.16/bin/startup.sh 」以啟動Tomcat

如果你也要依樣話葫蘆的話,記得要調整一下這些參數的設定喔。

Tomcat解決亂碼的爭議點

上面在設定JAVA_OPTS的時候,有一個「Dfile.encoding=UTF-8」的編碼參數,這個設定可以讓Java知道要以UTF-8的編碼來開啟檔案,以免他用預設的en_US編碼來處理而造成UTF-8看起來像是亂碼一樣。

但是網路上大部分論壇都主張要將此參數設置在[tomcat]/bin/catalina.sh中,或是一樣在catalina.sh中設定「CATALINA_OPTS=-Dfile.encoding=UTF-8」。前者因為Tomcat版本相差過遠,我找不到要修改的地方;後者還沒試過。

總之,「Dfile.encoding」的參數應該還是有很多其他的地方可以配置,如果大家有更好的方法,也請提出來多多討論吧。

在crontab中開機自動執行Tomcat啟動腳本

開機自動執行的方法有很多種,其中crontab也可以在開機時指定要執行的程式。crontab是Linux中執行例行性工作排程的好用工具,詳細的原理可以參考鳥哥的介紹。以下我僅敘述如何將「/home/dspace/tomcat_startup.sh」加入crontab開機時自動啟動的腳本中。

1. 進入crontab編輯畫面

輸入「crontab -e」就可以進入編輯畫面了。

[dspace@dspace-dlll ~]$ crontab -e
2. 加入開機執行指令

crontab編輯畫面會以一般的vi文字編輯器形式出現,如果你對vi編輯器不熟的話,還是得先請你看一下鳥哥的操作說明。請在crontab檔案最後加入以下設定:

# Startup tomcat
@reboot /home/dspace/tomcat_startup.sh

第一行只是註解。

第二行的「@reboot」參數表示在重新開機時都會執行後面的指令:「/home/dspace/tomcat_startup.sh」。

儲存並離開之後就完成crontab的設定。

3. 重新啟動測試

設置好crontab之後,別忘了reboot重新啟動來測試一下Tomcat是否有自動地啟動喔。


結語

這個編碼問題讓我煩惱了好久。一開始我還以為是Sevlet或JSP在傳送request的時候編碼設定錯誤,沒想到最後居然是根本上的Java編碼就出了問題。希望這次設定完之後,以後不要再出現編碼的問題了啊。

(more...)

DSpace清理已刪除Bitstream的cleanup時出現java.lang.OutOfMemoryError: Java heap space的處理方法

布丁布丁吃布丁

DSpace清理已刪除Bitstream的cleanup時出現java.lang.OutOfMemoryError: Java heap space的處理方法

DSpace中刪除的Bitstream(檔案)只會在資料庫中標示為deleted = 1,並不會從檔案系統中移除。換句話說,檔案還留在伺服器上,佔據硬碟空間。如果要真正地刪除檔案,必須使用[dspace]/bin/cleanup指令,關於Bistream Store(檔案儲存)知識在DSpace的說明書中已經有提及,在此只是稍微回顧一下。

Bistream的清理主要是使用BitstreamStorageManager.cleanup(),他會從資料庫中取出所有被標示為deleted = 1的Bitstream,並一一地從檔案系統中刪除。但是deleted = 1的Bitstream數量太多時,就會出現「java.lang.OutOfMemoryError: Java heap space」錯誤。

簡單來說,這是由於記憶體不足,DSpace無法處理從資料庫取出來的超多資料的錯誤。處理的這個問題的方法有兩種,一種是加大Java可用的記憶體,另一種是變更資料庫查詢的方式。我認為加大Java可用記憶體的方法是治標不治本,因為總是會有挑戰記憶體上限的資料量出現。我建議的是修改查詢資料庫的方法,設定offset跟limit,一次查詢部分資料,然後分多次查詢進行。

因此我修改了BitstreamStorageManager.java,在此也順便提供給有遇到類似問題的人使用:

  1. 下載BitstreamStorageManager.java (注意,這是DSpace 1.5.1的版本,如果你使用不同版本的話,並不建議直接下載覆蓋,而是請參考下面的說明)
  2. 放至[dspace-src]/dspace-api/src/main/java/org/dspace/storage/bitstore/BitstreamStorageManager.java

這個檔案主要是修改了cleanup方法,方法如上述。詳細的程式碼如下:

    /**
     * Clean up the bitstream storage area. This method deletes any bitstreams
     * which are more than 1 hour old and marked deleted. The deletions cannot
     * be undone.
     * 
     * @param deleteDbRecords if true deletes the database records otherwise it
     *                only deletes the files and directories in the assetstore  
     * @exception IOException
     *                If a problem occurs while cleaning up
     * @exception SQLException
     *                If a problem occurs accessing the RDBMS
     */
    public static void cleanup(boolean deleteDbRecords) throws SQLException, IOException
    {
        Context context = null;
        BitstreamInfoDAO bitstreamInfoDAO = new BitstreamInfoDAO();
        int commit_counter = 0;

        try
        {
            context = new Context();        
            
            int queryBitstreamNumber = 10;
            int queryBitstreamIndex = 0;
            int queryBitstreamInterval = 10;
            
            while (queryBitstreamNumber > 0)
            {
                String myQuery = "select * from Bitstream where deleted = '1' offset " + queryBitstreamIndex + " limit " + queryBitstreamInterval;
                
                List storage = DatabaseManager.queryTable(context, "Bitstream", myQuery)
                        .toList();
                queryBitstreamNumber = storage.size();
                if (queryBitstreamNumber == 0)
                    break;

                for (Iterator iterator = storage.iterator(); iterator.hasNext();)
                {
                    TableRow row = (TableRow) iterator.next();
                    int bid = row.getIntColumn("bitstream_id");
                    
                    System.out.println("Ready to Bitsteam (" + bid + ")...");

                    GeneralFile file = getFile(row);

                    // Make sure entries which do not exist are removed
                    if (file == null || !file.exists())
                    {
                        log.debug("file is null");
                        if (deleteDbRecords)
                        {
                            log.debug("deleting record");
                            bitstreamInfoDAO.deleteBitstreamInfoWithHistory(bid);
                            DatabaseManager.delete(context, "Bitstream", bid);
                        }
                        System.out.println("File not exists, continue.");
                        continue;
                    }

                    // This is a small chance that this is a file which is
                    // being stored -- get it next time.
                    if (isRecent(file))
                    {
                        log.debug("file is recent");
                        System.out.println("File is recent.");
                        continue;
                    }

                    if (deleteDbRecords)
                    {
                        log.debug("deleting db record");
                        bitstreamInfoDAO.deleteBitstreamInfoWithHistory(bid);
                        DatabaseManager.delete(context, "Bitstream", bid);
                        System.out.println("Deleting db record.");
                    }

                    if (isRegisteredBitstream(row.getStringColumn("internal_id"))) {
                        System.out.println("do not delete registered bitstreams");
                        continue;            // do not delete registered bitstreams
                    }

                    boolean success = file.delete();

                    if (log.isDebugEnabled())
                    {
                        log.debug("Deleted bitstream " + bid + " (file "
                                + file.getAbsolutePath() + ") with result "
                                + success);
                        System.out.println("Deleted bitstream " + bid + " (file "
                                + file.getAbsolutePath() + ") with result "
                                + success);
                    }

                    // if the file was deleted then
                    // try deleting the parents
                    // Otherwise the cleanup script is set to 
                    // leave the db records then the file
                    // and directories have already been deleted
                    // if this is turned off then it still looks like the
                    // file exists
                    if( success )
                    {
                        deleteParents(file);
                    }
                    
                    // Make sure to commit our outstanding work every 100
                    // iterations. Otherwise you risk losing the entire transaction
                    // if we hit an exception, which isn't useful at all for large
                    // amounts of bitstreams.
                    commit_counter++;
                    if (commit_counter % 100 == 0)
                    {
                        context.commit();
                        System.out.println("commit");
                    }
                }
                
                queryBitstreamIndex = queryBitstreamIndex + queryBitstreamInterval;
                
                
            }    //while (queryBitstreamNumber > 0)

            context.complete();
        }
        // Aborting will leave the DB objects around, even if the
        // bitstreams are deleted. This is OK; deleting them next
        // time around will be a no-op.
        catch (SQLException sqle)
        {
            context.abort();
            throw sqle;
        }
        catch (IOException ioe)
        {
            context.abort();
            throw ioe;
        }
    }
      (more...)

      DSpace-DLLL原始碼

      布丁布丁吃布丁

      DSpace-DLLL原始碼

      image

      繼昨天所說的寫書完成之後,今天繼續把DSpace-DLLL的原始程式碼釋放出來:

      以下簡單地敘述安裝所需的步驟:

      安裝其他軟體

      DSpace-DLLL使用了大量的Media Filter多媒體轉檔,所以您的作業系統內也必須安裝對應的軟體。包括以下軟體:

      • FFmpeg:影片轉檔與截圖工具
      • MEncoder:影片轉檔工具
      • python:Zoomify Image的運行環境
      • Zoomify Image:將圖片切割成Zoomify Express可以瀏覽的工具
      • SWFTools:SWF與PDF、JPEG等轉換的工具
      • Xpdf:處理PDF的工具。CentOS上安裝Xpdf請看這篇
      • OdfConvertor:將docx、pptx、xlsx轉換成Open Document格式的工具
      • OpenOffice:將各種文件轉換成PDF,以便DSpace處理的重要軟體
      • Xvfb:文字介面中控制OpenOffice的工具。

      其他的軟體則已經一同壓縮在dspace-dlll-1.5.0-src-release當中,安裝時就會自動加入,不必另外安裝。

      設定OpenOffice自動啟動與重新啟動指令

      文字介面中控制OpenOffice必須要使用Xvfb,請看我在「用Xvfb讓 OpenOffice開機時自動啟動」這篇的說明。

      然後就可以撰寫script去讓他重新啟動。請寫一個openoffice_restart.sh的檔案放在/home/dspace/當中,執行權限打開。

      檔案內容就只是停止OpenOffice,然後再啟動而已。內容如下:

      /etc/init.d/openoffice stop
      sleep 3
      /etc/init.d/openoffice stop
      sleep 5
      /etc/init.d/openoffice start
      sleep 10

      安裝VNC與phpPgAdmin

      CentOS中安裝的方法請看「VNCserver初始設定與自動啟動」這篇。

       

      phpPgAdmin是PHP的軟體,直接下載之後在Apache執行即可。

      設定config.cfg

      上述軟體安裝完之後,還要到[dspace-source]/dspace/config/config.cfg當中設定這些軟體的相關執行參數。

      主要有兩處,一個是位於檔案中間的filter開頭的設定,請比對上述軟體的安裝位置來作調整。

      filter.exec.ffmpeg = ffmpeg
      filter.exec.mencoder = /usr/bin/mencoder
      filter.exec.python = python
      filter.exec.zoomifyImage = /opt/ZoomifyImage/ZoomifyFileProcessor.py
      filter.exec.imagemagick = convert
      filter.exec.pdf2swf = pdf2swf
      filter.exec.xpdf-pdftotext = pdftotext
      filter.exec.xpdf-pdftohtml = pdftohtml
      filter.exec.odfconverter = OdfConverter
      filter.exec.jpeg2swf = jpeg2swf
      filter.exec.swfcombine = swfcombine

      另一處則是最下方的其他工具,包括vnc、apache的http與phppgadmin。

      vnc.port = 5801
      http.port = 80
      phppgadmin.url = /phpPgAdmin

      其中原本我在DSpace-DLLL中的http.port是使用50080,這是為了避免一般人直接進入phpPgAdmin操作的手段。同時Apache的連接埠也請記得修改。

      開始安裝

      待完成上述步驟之後,正式安裝DSpace主要請見以前我寫的DSpace 1.5.1安裝法。雖然這個DSpace-DLLL是以DSpace 1.5版為主,但跟1.5.1安裝方法是相同的。config.cfg記得要修改喔。


      因為還沒做過測試,所以安裝起來可能會有其他問題。

      如果大家對於安裝有任何疑問,請在這篇下面回應,感謝。

      (more...)

      寫書初稿完成!

      布丁布丁吃布丁

      寫書初稿完成!

       

      image 我現在是研究所三年級下學期,很多人會問我什麼時候畢業,我都這樣回答:「先寫完書,再來寫論文。」而到今天為止,總算是把寫書初稿跟附件光碟全部完成了!

      寫書至今已經一年了,可是我好像沒有在這裡好好談談寫書這件事情。所以在寫書初稿完成的今晚,我就好好地來報告一下寫書的由來與經過吧!


      關於本書

      這本書的書名定為「DSpace開放原始碼數位典藏系統建置技術彙編」,是由陳老師訂定的,雖然我覺得有點饒舌,但也不失學術風味,似乎也不錯。這本書是由陳老師帶領的實驗室底下的助理、學生約12人共同撰寫,其中我規劃了本書內容、製作附件光碟的DSpace-DLLL'、並撰寫了部份章節。

      本書是為了讓需要建置數位典藏系統或是數位典藏教學需求而撰寫,讀者可以從本書第一部份學習數位典藏的相關理論,接著第二部份是附件光碟DSpace-DLLL的操作介紹,而第三部份則介紹三個由DSpace建置而成的數位典藏。DSpace是一個開放原始碼的數位典藏系統,而我將之重整規劃之後,成為一個容易安裝、操作的附件光碟,而且一樣以BSD條款發行供大家使用。

      本書從2009年4月初制定架構到2010年4月中初稿完成,目前已經交由陳老師審查、校稿,老師正在尋求出版商,並希望能在這學期結束之前出版,以便趕在下學期上課時使用。

      本書全部共15章,初稿Word檔案的頁數總共380頁。最後出版時可能會採用比A4更小的紙張,因此頁數會更多。各章概要請見下表:

      本書章節標題 內容摘要
      第一部分 數位典藏導論
      第一章 數位典藏概論 介紹數位典藏的各種定義,釐清讀者對數位典藏的概念,並引領讀者認識數位典藏的相關計畫。
      第二章 數位典藏專案規劃 介紹數位典藏小組需要的成員構成,並從後設資料與系統分析一步一步地規劃數位典藏專案的步驟與細節。
      第三章 網站資訊架構 介紹數位典藏資訊系統網站的組織架構原則。包括組織系統、標籤命名系統、導覽系統、搜尋系統、後設資料與控制詞彙等支援元件等。
      第四章 後設資料Metadata 說明後設資料的原理以及重要性,並介紹數位典藏常用的後設資料規格與其他參考資源。
      第五章 數位資源格式 介紹典藏品數位化與原生數位資源的差異,並解說圖像、聲音、視訊、文件等各種類型的數位資源格式。
      第六章 電子資源授權與權限控管 介紹電子資源的授權方式、各種不同的授權條款、以及數位典藏系統的權限控管的規劃建議。
      第二部分 數位典藏系統DSpace實作
      第七章 DSpace介紹 介紹DSpace的背景,並帶領讀者瀏覽DSpace各種特色功能與網頁使用介面,並介紹以DSpace進行的相關數位典藏應用。
      第八章 系統安裝與設定 詳細介紹DSpace安裝與設定手續,讓讀者能夠利用自己的電腦架設DSpace。
      第九章 資料內容組織架構 介紹DSpcae的資料內容組織架構架構。從社群、類別、文件、檔案集到檔案各層級與管理的介紹,讓讀者能夠學習如何制訂典藏的數位內容。
      第十章 使用者、群組與權限設定 介紹如何建立DSpace的使用者、群組,以及權限控管的設定。
      第十一章 遞交作業與工作流程 介紹DSpace中設計與建立數位典藏獨特的遞交作業與工作流程,其中遞交作業還涉及後設資料規範的設定。
      第十二章 系統架構與版面修改 剖析DSpace的系統架構,並說明如何閱讀DSpace使用的Java程式碼,然後教導讀者修改網頁使用介面。
      第三部分 DSpace數位典藏建置案例
      第十三章 臺灣大學數位典藏 介紹臺灣大學數位典藏計畫發展歷程,包括以DSpace修改而成的臺灣大學典藏數位化計畫入口網站以及各種加值應用。
      第十四章 臺灣百年圖書館史暨數位圖書館先導計畫 介紹由政治大學圖書資訊與檔案學研究所策劃的「台灣百年圖書館史」。詳細地描述數位典藏專案的各個程序,以供讀者作為規劃的參考。
      第十五章 教育部全國通識網課程資料庫 介紹由教育部全國通識網底下的子計畫「課程資料庫」的建置成果。全國通識網課程資料庫含括典藏完整數位課程資料的優質課程資料庫與集合國內各大專院校通識課程資訊的通識課程基本資料庫。

      寫書的由來

      認識我的朋友們都知道,我這個學生最不像學生,老是接了一堆很奇怪又不賺錢的工作在在身上。從進研究所之前我就接了「臺灣百年圖書館史暨數位圖書館先導計畫」,作到碩一下告一段落,這就是我開始碰DSpace的起源。當時對DSpace不懂,嚴格來說,我對撰寫DSpace的Java語言也不熟。而且DSpace用了很多進階程式技巧的設計模式、將物件導向的優點發揮得淋漓盡致,也很靈活地運用MVC架構、讓程式各司其職,但這些對於當時完全不懂的我來說,要控制DSpace著實讓我花了不少時間與精力。在自我摸索、讀書、不斷地嘗試錯誤之後,我也逐漸能夠掌握DSpace系統。

      然後政大圖檔所在2008年暑假舉辦了數位典藏實務與加值服務研習班,這個研習班中也用了DSpace作為教材。當時不僅先幫各個學員預先用虛擬機器安裝好DSpace就已經讓我在實驗室待了好幾個晚上,到教DSpace內容資料架構與metadata遞交表單的設計時,太過複雜的操作方式幾乎讓所有學員都舉了白旗投降。

      除了研習班的學員之外,王梅玲老師與陳老師也會在上課時使用DSpace來授課,尤其是王老師會要求學生利用臺灣百年圖書館史暨數位圖書館網站來上傳資料。由於DSpace原始的操作介面實在是很難讓人使用,學生們用起來也是不少怨言。

      碩二時陳老師接了教育部「教育部通識教育資源平臺建構與永續發展計畫」,這也是用DSpace來架設課程資料庫與教師資料庫這兩個系統。當時我撰寫了許多教學用投影片教導專任助理們DSpace,並配合計畫需求大幅度地開始改造DSpace的功能。這段期間我在Blog中寫了很多DSpace相關的文章,主要都是給助理們用於計畫中。而作到最後乾脆我自己下海操刀,多媒體轉檔、瀏覽搜尋、管理介面的操作工具等許多功能陸續開發出來。

      大概是在碩二下學期時,陳老師提議撰寫本書,而我也覺得這是一個不錯的構想。在歷經各個計畫、授課等經驗之後,我看到了許多需要數位典藏系統的人們。有人需要一個可以用來架設用於機構、計畫使用的數位典藏,有人需要一個可以用來教課、讓學生邊玩邊操作的系統,而我則是有能力將這些需求匯整成一個實際可以用的系統、而且我也希望能將這些年來的成果以一個詳細且實用的方式發佈供人使用,於是就開始了整個寫書的工作。


      寫書的經過(前期)

      從2009年4月初老師提起這個想法之後,就由我來負責實現。以下聊聊一些令我印象比較深刻的經過:

      一開始是制訂整本書的規劃與架構時,還有考慮文學院機構典藏的介紹。但由於文學院機構典藏本身到最後不了了之,最後則刪去不做。

      寫書初期時,理論部份有找老師的一位研究助理幫忙。但是該助理對於此主題不甚熟悉,工作效率低落也讓老師看不下去,最後放棄了。

      寫書前期規劃好大綱之後,其實實際上並沒有什麼進度,大家都在忙著教育部計畫與課業。直到暑假時(約2009年8月後)學弟妹較為空閒,也有新的學弟陸續加入實驗室,於是正式地分配寫書章節給學弟妹與各個助理。

      最先交稿的是第二章數位典藏專案規劃。但由於這個主題其實是相當模糊的概念,與學弟來來往往修改多次之後,在寫書後期才定稿。

      原本第三章是談主題分析與檢索系統,負責學妹很快地整理好之後交給我。但是後來我才知道應該擺資訊架構較為合適,最後一整個改頭換面。

      第四章後設資料匯整的速度很快,而且架構很清楚,即使寫書完檢查時也覺得很漂亮。負責此章的學妹非常厲害。

      第十三章臺灣大學數位典藏也是很快就整理好了。負責此章的研究助理功力一流,資料豐富到讓我覺得擺在這本書裡面似乎有點小廟容不下大佛(?)。

      第一章數位典藏概論也是很快就完成了。

      至此本書進度仍十分緩慢,特別是第二部份幾乎沒有令人滿意的成果。在2009年末時我大學室友進來擔任計畫助理,這時我也逐漸推掉計畫的工作而專心在寫書上,寫書的進度開始推進。


      寫書的經過(中期)

      首先是第九章資料內容組織架構,儘管章節內容規劃得很好,但是我卻大幅度地修改了作者的撰寫內容。能熬過我整章全紅且註解一堆(而且寫得很直接orz)的專任助理,實在是非常辛苦,真是抱歉。最後第九章由其他人接手之後,修改多次才完成,算是第二部份最早完成的章節。

      第十五章的撰寫也被我改了相當多,但由於負責的專任助理本身就有很不錯的文筆,熟悉我的敘述方式之後,一整章寫下來也非常易讀、好懂。

      第十四章原本是由某位專任助理負責,但她整理的方式與效率較低,第一次交稿之後就沒有多大進度。後來交給另一位專任助理完成。至此第三部份大致上完工。

      接著該助理著手撰寫學弟無法完成的第五章電子資源授權與權限控管,也很快地把零散地材料重新組織成具有可讀性的章節,組織資料的能力也相當地厲害。

      再來是我自己負責的第八章系統安裝與設定。本章內容很好撰寫,但這是我大幅改善DSpace操作工具所帶來的成果。這期間強化了語系檔編輯器、遞交表單編輯、重新啟動Tomcat、電子郵件編輯。還經過陳老師學程上課的實驗,讓整個系統趨於完善。而同時附件光碟的內容也漸趨成型。

      接著我進行第十一章遞交作業與工作流程的撰寫,一樣是基於發展了遞交表單編輯器的功能,才能簡單又清楚地把操作方式介紹給讀者。

      至此為止,寫書的進度表中,完成的章節甚至不到一半而已。而此時卻面臨另一個難關:2009年年底兩位專任助理即將離職。不過這兩位離職之後仍被我纏著寫稿,真是夠辛苦的了XD


      寫書的經過(後期)

      第十二章系統架構與版面修改一開始由專任助理負責,但進度十分緩慢。直到2009年底新任教育部助理進來後,我重新制訂了該章大綱,並安排兩人完成。最後再由我統一修整之後完成。

      第十章使用者、群組與權限設定在專任助理離職之後努力完成。這次不像第九章那樣修改很多次,而很快地進入完稿階段。

      第七章DSpace也是在轉成助教的專任助理努力翻譯之後,交由我修整過後才完成。

      這段期間另一位離職的專任助理被我纏著校稿校了好幾章,真是辛苦了。

      在這個時間我毅然地決定將第三章改成資訊架構學,而捨棄原本完成的主題分析。原本請離職的專任助理撰寫,但因為他事務繁忙而放棄,最後我將之完成。

      第二章數位典藏專案規劃中間隔一段時間沒有進度,然後也是在這段期間完成。

      第五章數位資源格式,負責學弟由於事務繁忙,到最後才完稿。

      而在初稿完成之後我就著手將附件光碟完工。在撰寫第八章時我就已經把附件光碟的大部分完成,最後則是修正許多安裝上的Bug、重新清理系統,然後燒錄成光碟。

      這段期間我的工作就是寫書寫書再寫書,我的噗浪三不五時就是[寫書]文,然後每週或隔週就跟老師通信報告寫書進度。而到今天總算完成整本書的初稿與附件光碟了!

      整理與老師寫書進度報告中,從2009年9月14日正式進度報告開始到今天2010年4月17日為止,總共報告了19次。每一次報告由於都會有大量附件,所以得分成多封寄出,Gmail的信件對話串已經長到讓人難以點閱的程度。不過還好有這個進度報告,讓我整理上述的經過時方便許多,也算是一個寶貴的日記吧。


      為什麼要寫書?

      很多人會問我,其他的研究生都在寫論文,為什麼我在寫書?就算都已經碩三下學期了,都已經延畢一年了,為什麼我還是在寫書?為什麼不要先畢業再來寫?

      又有人會問,寫書出版可以賺很多錢吧?版費多少錢啊?做出來的系統可以賣啊,賺大錢。

      一開始我會回答說,因為要趁著專任助理還沒離職之前趕快把書寫完。不過在他們離職之後,他們還是被我纏著繼續寫,可見這個理由不太合理(XD)。

      我也不會贊成畢業之後再來寫,因為畢業之後要當兵,不碰觸這些東西之後,我一定再也無法把他完成。

      書或系統能賣多少錢?這也不是我在乎的問題。事實上,只要這些初稿完成,再怎樣也能找到出版商將之出版成書,所以我不太去煩惱這種問題。

      此外,這本書會以多作者的方式出版。老師的名字應該掛第一個,而我的名字也會掛在上面,但其實第幾順位我也不太在意。畢竟如果這本書能夠幫助老師升等,那對實驗室的學弟妹也會有莫大的幫助。

       

      我只要能夠出書就好了。

       

      以一個還是學生的身份,能夠出一本能在書店裡買得到的書,甚至還能提供給其他學生當教材,或是讓相關領域的專業人員作為參考工具的書,我覺得這是一種自我滿足的成就。

      有些人抱有「用機車、腳踏車或甚至走路環島」之類的目標,他們不太在意這到底能不能賺錢、能不能對自己未來有所幫助,只是單純地想要完成這項成就,而我也是如此。他們在畢業後、就業前的空檔進行這個計畫,而我則是在畢業之前、手上握有大量資源與人力的時候進行。

       

      當然,我很清楚這個選擇是基於夢想的任性,而不是一種對於現實的理智。

      在寫書這段期間,我不計利益得失、也不在乎花費的時間長短,只是努力地讓這本書更豐富、更好閱讀、更容易使用。也許在旁人的眼中這是很笨的行為,而我也很清楚這是事實。這段期間我沒有像其他畢業的同學一樣去工作賺錢,父母還要支付學費給學校。而實驗室內被我佔據的這個角落也一直沒有讓給新進來的學弟妹(雖然我覺得應該也沒人想要坐這邊XD)。老師等著我的標註系統,好多人都在等著我畢業,而我一直辜負著他們的期望。

      換個角度來看,這可說是身為學生的一種任性的特權吧。能夠任性地單純作一件自己想做的事情,我想除了現在之外,往後就不會有這種機會了。


      寫完書之後

      所以寫書告一段落之後,接下來就不會耍任性,好好地努力畢業了嗎?

      這個答案可說是,也可說不是。

      接下來的確會開始著手規劃論文的標註系統,進度也會在這邊報告。雖然最近可能還會用幾天的時間把寫書的資料整理收拾一下就是。但是由於我論文要寫的也是一個讓人使用的系統,而且這次是重頭開始做起,而在我對於系統相當要求的標準之下,也是需要花很長一段時間來讓論文趨於完善。

      與其他趕著畢業而草草完成論文的學生不同,我將會繼續耍任性,任性地寫好論文再畢業。

      就如這個Blog的副標題一樣:是的,我正在繞遠路。反正人生繞的路已經夠遠了,似乎也沒差這段距離。就讓我繼續耍任性吧。


      很久沒有寫這種日記文了,本篇寫完耗時三個多小時,寫到手有點痠。

      在待辦事項裡面還有好多篇Blog要寫,我可能在整理寫書資料的同時,一併把他們寫一寫。

      這篇就這樣告一段落啦。呼~~有點累XD

      (more...)

      DSpace建置數位典藏資料 投影片

      布丁布丁吃布丁

      DSpace建置數位典藏資料 投影片

      image

      這一份是給陳志銘老師在政大圖檔所數位典藏學程上課時使用的投影片。改進了以前DSpace資料結構的講法,加上一些簡單的例子,應該會比較容易理解。

      2010-01-02_230149

      特別的是,編輯遞交表單是我另外設計的功能。它改良了原始DSpace在編輯input-forms.xml的門檻,用圖形化介面來編輯input-forms.xml的內容。至於程式的部份,我想等到寫書告一段落,到程式穩定之後,再行公開。

      (more...)

      DSpace遇到「Failed to resolve artifact.」的問題

      布丁布丁吃布丁

      1 Comments

      DSpace遇到「Failed to resolve artifact.」的問題

      image

      在DSpace編譯的過程中,如果遇到以下錯誤訊息,大部分時候是網路連線已經中斷的問題:

      [ERROR] BUILD ERROR
      [INFO] ------------------------------------------------------------------------
      [INFO] Failed to resolve artifact.
      
      No versions are present in the repository for the artifact with a range [1.5.0.0,1.6.0.0)
        org.dspace:dspace-api-lang:jar:null
      
      from the specified remote repositories:
        central (http://repo1.maven.org/maven2),
        maven.dspace.org/snapshot (http://maven.dspace.org/snapshot)
      
      
      [INFO] ------------------------------------------------------------------------
      [INFO] For more information, run Maven with the -e switch
      [INFO] ------------------------------------------------------------------------

      這是由於DSpace在做MVN的時候需要去網路上檢查jar檔案,而如果你的伺服器網路如果不通,那就無法順利進行編譯。

      解決方法則就是一般網管的問題囉。VirtualBox的NAT虛擬網卡偶爾會當掉,就會發生上述情況,我在此留下一個記錄。

      (more...)

      JAVA寄信問題「HELO requires domain address」的解決方法

      布丁布丁吃布丁

      JAVA寄信問題「HELO requires domain address」的解決方法

      image

      當我利用VirtualBox架設虛擬機器時,會發現沒辦法正常地使用註冊信的功能。這是因為虛擬機器內部的domain name並不是其他domain name server認可的名稱,只是我測試用的名字。此時可以自行在伺服器當中新增此domain name,對應到127.0.0.1,也就是本機端,就可以解決此問題。

      以下詳述這個問題的發生與解決過程。

      虛擬機器中DSpace的郵件設定
      ##### Email settings ######
      
      # SMTP mail server
      mail.server = 127.0.0.1
      
      # SMTP mail server authentication username and password (if required)
      # mail.server.username = myusername
      # mail.server.password = mypassword
      
      # SMTP mail server alternate port (defaults to 25)
      mail.server.port = 25
      
      # From address for mail
      mail.from.address = dspace-noreply@dspace-dlll.nccu.edu.tw
      
      # Currently limited to one recipient!
      feedback.recipient = dspace-help@dspace-dlll.nccu.edu.tw
      
      # General site administration (Webmaster) e-mail
      mail.admin = dspace-help@dspace-dlll.nccu.edu.tw
      
      

      必須說明到,上述設定當中的「dspace-dlll.nccu.edu.tw」完全沒有註冊在任何domain name server當中。因此執行時就會發生錯誤。

      認不出domain name的錯誤訊息

      image

      在此設定當中進入DSpace的使用者註冊時,就會發生錯誤。我們來到DSpace的記錄檔當中看看,預設位置在「[dspace]/log/dspace.log」,可以用文字編輯器來開啟。

      錯誤訊息如下:

      2009-10-02 23:58:27,828 INFO  org.dspace.app.webui.servlet.RegisterServlet @ anonymous:session_id=29633B32BF10EEEF95FCF4DC71B5C7FD:ip_addr=10.0.2.2:sendtoken_register:email=puddingchen.35@gmail.com
      2009-10-02 23:58:30,669 INFO  org.dspace.app.webui.servlet.RegisterServlet @ anonymous:session_id=29633B32BF10EEEF95FCF4DC71B5C7FD:ip_addr=10.0.2.2:error_emailing:email=puddingchen.35@gmail.com
      javax.mail.MessagingException: 501 5.0.0 HELO requires domain address
      
              at com.sun.mail.smtp.SMTPTransport.issueCommand(SMTPTransport.java:1363)
              at com.sun.mail.smtp.SMTPTransport.helo(SMTPTransport.java:838)
              at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:375)
              at javax.mail.Service.connect(Service.java:275)
              at javax.mail.Service.connect(Service.java:156)
              at javax.mail.Service.connect(Service.java:105)
              at javax.mail.Transport.send0(Transport.java:168)
              at javax.mail.Transport.send(Transport.java:98)
              at org.dspace.core.Email.send(Email.java:362)
              at org.dspace.eperson.AccountManager.sendEmail(AccountManager.java:296)
              at org.dspace.eperson.AccountManager.sendInfo(AccountManager.java:256)
              at org.dspace.eperson.AccountManager.sendRegistrationInfo(AccountManager.java:101)
              at org.dspace.app.webui.servlet.RegisterServlet.processEnterEmail(RegisterServlet.java:287)
              at org.dspace.app.webui.servlet.RegisterServlet.doDSPost(RegisterServlet.java:202)
              at org.dspace.app.webui.servlet.DSpaceServlet.processRequest(DSpaceServlet.java:147)
              at org.dspace.app.webui.servlet.DSpaceServlet.doPost(DSpaceServlet.java:105)
              at javax.servlet.http.HttpServlet.service(HttpServlet.java:710)
              at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
              at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
              at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
              at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
              at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
              at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
              at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
              at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
              at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
              at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
              at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
              at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
              at java.lang.Thread.run(Thread.java:619)

      你可能會發現到IP很奇怪,因為這是VirtualBox配給的內部IP。

      這段記錄的重點在於錯誤訊息「HELO requires domain address」,代表的意思是HELO認不出來「dspace-dlll.nccu.edu.tw」對應到哪台主機。

      設定伺服器當中的domain name對照表

      用指令列來修改「/etc/hosts」,增加下列設定:

      127.0.0.1       dspace-dlll.nccu.edu.tw dspace-dlll

      然後得重新啟動網路,指令是「/etc/init.d/network restart」

      或著你也可以用圖形介面來設定。

      image

      先進入「網路」當中。

      image 

      切換到「主機」那一頁,然後按「新增」。

      image

      設定位址、要對應的主機名稱跟其別名。

      image

      最後記得要儲存才會生效。


      以上,大功告成。用虛擬機器果然是比較麻煩了一些,不過也可以藉此在精進網路知識就是了。

      (more...)

      VirtualBox擴大CentOS的LVM硬碟筆記

      布丁布丁吃布丁

      VirtualBox擴大CentOS的LVM硬碟筆記

      image

      前言

      VirtualBox使用虛擬動態映像檔(vdi),VDI的好處在於你能夠保留最大到2TB的擴增空間,但卻又只會佔用實際儲存的資料。具體來說,vdi可以讓GuestOS(在此指虛擬機器)當中讀取起來有到2TB(大概2024GB)的硬碟,但在HostOS(在此指實際安裝虛擬機器的本機端)中只會佔用vdi中實際儲存的檔案,可能只需要23GB。當你發現VDI的大小超過HostOS所能允許的空間的話,就直接更換VDI儲存位置,放在更大的硬碟空間裡面就行了,非常方便。

      問題敘述

      之前在建立VDI時的錯誤決定,讓他的實體空間只有8GB,這對於我系統的要求是不夠的。所以得想辦法讓他擴大才行。

      HostOS是Windows XP,GuestOS則是Linux CentOS 5 final。

      GuestOS的硬碟在一開始安裝CentOS時都被切割成LVM(Logical Volume Manager)格式——而我後來才知道,這真是個麻煩的格式。因此調整大小的步驟就會多了很多繁雜的步驟。

      那麼,接下來我就一步一步地去記錄我是怎麼調整VDI大小的吧。

      擴大VDI虛擬大小空間

      一、取得Clonezilla

      VirtualBox並沒有直接擴大VDI的功能,網路上大部分的教學都是使用GPart Live CD來複製硬碟分割。但很遺憾的,GPart沒辦法讀取LVM (是的,真的很煩人),所以我採用國人自製的自由軟體Clonezilla Live

      • image下載Clonezilla Live,請選擇iso檔案下載,或是下載zip之後解壓縮成為iso。

      image

      在VirtualBox當中利用掛載光碟映像檔的方式將Clonezilla掛載上去之後,就可以利用Clonezilla開機來複製硬碟資料。

      二、建立新的VDI硬碟

      我建立一顆新的VDI硬碟,這次把大小提昇到極限值2TB。然後把舊的8GB VDI硬碟跟2TB VDI硬碟都掛到同一台虛擬機器上。

      三、使用Clonezilla複製硬碟

      我利用Clonezilla將舊硬碟複製到新硬碟去,細節我沒有特別記錄。但是必須讓它保持原本的分割區,不要放大分割區。因為對LVM來說,放大分割區並沒有意義。整個複製作業大概花了我30分鐘。

      複製完成之後關掉虛擬機器,卸載就VDI硬碟跟Clonezilla,再以新硬碟開啟,可以成功啟動。而且利用「fdisk -l」的指令查詢,會發現到除了原本的分割區之外,還有很多空間可以利用。

      四、擴大LVM的空間

      鳥哥的fdiskLVM教學中還蠻詳細的,在此我僅節錄指令步驟:(我的LVM主要空間是「/dev/VolGroup00/LogVol00」,VDI硬碟代號是「/dev/hdb」)

      1. 進入fdisk,用「n」新增分割,選擇「p」主分割,編號為「3」(因為我原本系統中1為boot,2為其他空間),然後指令「w」建立分割並離開。
      2. 使用「partprobe」讓核心重新抓取一次硬碟分割表,成功建立第三個分割,代號是「/dev/hdb3」。
      3. 用「pvcreate /dev/hdb3」建立新的PV,然後用「pvscan」檢查。
      4. 用「vgextend /dev/VolGroup00/LogVol00」來加大VG。
      5. 用「vgdisplay」檢查,注意訊息中會有類似「Free  PE / Size       16486 / 2 TB」(正確數字我有點忘了),那個「16486」就是待會可以新增的空間。
      6. 用「lvresize –l + 16486 /dev/VolGroup00/LogVol00」加大空間。
      7. 用「resize2fs /dev/VolGroup00/LogVol00」把LV的容量擴大到整個檔案系統可以允許的上限。需要耗費一段時間,此時VDI實際大小也會逐漸加大。
      8. 完成後可以用「df -h」來檢查是否有真的擴大了。

      到目前為止,儘管VDI的虛擬大小總算擴大到2TB了,但實體大小卻也從7GB增大到23GB。進去虛擬機器中查詢使用量,卻也只有5GB多的用量而已。我猜可能是2TB所需要得區塊量(blocks)比較多,所以也佔去了不少空間。這就跟「買了80G硬碟,實際上可用只有75G」的道理一樣。詳細的原理請回去查查「作業系統」的課本吧。

      即使如此,現在VDI的實際大小還是太大了,我們下一節就來談談如何減少VDI的實體大小。

      縮小VDI實際檔案大小

      image

      VirtualBox的VDI的實際大小似乎是取決於虛擬機器當中動到的區塊量。也就是說,即使你在虛擬機器當中刪除了檔案,但VDI的實際大小並不會因此減少。因此VDI只會越用越多,並不會縮小。

      在此有兩種方法可以使用:VirtualBox的VBoxManage提供了「modifyhd」來清除被設為0的區塊以壓縮VDI的實際大小;或用檔案壓縮工具7-zip來減少檔案大小。以下一一介紹作法。

      VBoxManage的modifyhd

      自由流浪的心靈世界中介紹縮小VirtualBox VDI檔案的作法十分詳細,我參考其他資料之後整理的大致上步驟如下

      1. 先刪除虛擬機器裡面不需要的檔案。
      2. 安裝「zerofree」這個工具,RPM Search裡面可以找到給Red Hat/CentOS的版本。RPM安裝方法可以參考鳥哥,指令是「rpm –ivh [*.rpm]」。
        安裝完畢之後,可以用「/usr/sbin/zerofree」來使用他
      3. 重新啟動虛擬機器,進入CentOS的單機模式(single user mode)。具體作法是開機時按esc進入選單,按e編輯選單內容,再選擇有「kernal」那一項按e編輯開機參數。進入指令列之後再原有指令最後加上「singel」,然後按b開機即可。
      4. 執行init 1 (還沒去查這到底是什麼功能)
      5. 將硬碟以ro模式掛載:mount -n -o remount,ro -t ext3 /dev/VolGroup00/LogVol00 /
      6. 執行zerofree:/usr/sbin/zerofree /dev/VolGroup00/LogVol00。他需要花上好長一段時間來作這個動作,請慢慢等待。
      7. 完成zerofree之後關閉虛擬機器。
      8. 在HostOS底下執行壓縮指令:VBoxManage modifyhd 你的VDI位置.vdi compact。當然,VBoxManage的執行位置你也要修改成你安裝VirtualBox的位置才行。
        整個壓縮過程大概耗費2小時完成。

      完成之後,原本在虛擬機器中刪除檔案所減少的空間,也讓VDI實際大小減少了。

      7-zip壓縮

      image 使用modifyhd之後讓VDI的實體大小從23GB減到22GB,但這大小對我來說仍然是過大的負荷。當我架設完虛擬機器而不需要執行時,可以考慮採用7-zip之類的壓縮軟體來壓縮檔案。我選擇使用7-zip Portable,一來這是開放原始碼的自由軟體;二來7-zip可以壓縮超過2GB大小的檔案,而且壓縮比例又很高,儘管比較需要花時間;最後Portable則是不需要安裝即可執行的版本,下載下來馬上就可以使用。

      利用7-zip壓縮了22GB的VDI檔案之後,我取得了2GB的壓縮檔,成果讓我非常滿意。


      一邊找尋資料、一邊實際操作,然後又來不斷修改這篇Blog。這一篇是我大概一天多的成果,又是一篇用時間跟精力換來的筆記記錄,還好最後有達到我想要的成效,真是可喜可賀。

      (more...)

      CentOS安裝odf-converter,轉換Office 2007文件為OpenOffice格式

      布丁布丁吃布丁

      CentOS安裝odf-converter,轉換Office 2007文件為OpenOffice格式

      為了讓DSpacemedia filter功能能夠接受Microsoft Office 2007的DOCX、XLSX與PPTX,我們需要借助odf-converter把Office 2007的格式轉換成OpenOffice相對應的ODT、ODS、ODP格式,才能作接下來的處理。

      image

      上圖右邊是原始的Microsoft Office 2007的PPTX格式投影片,左邊則是利用odf-converter轉換成OpenOffce的ODP格式投影片,儘管在字型、版面上有點差異,但還是可以接受的程度。


      安裝

      安裝的步驟很簡單,只要下載以下檔案並以rpm安裝即可

      你可以用以下指令下載並安裝:

      [root@dspace ~] wget http://katana.oooninja.com/f/software/odf-converter-integrator-0.2.3-1.i386.rpm
      [root@dspace ~] rpm -ivh odf-converter-integrator-0.2.3-1.i386.rpm

      使用

      使用範例如下:(/f表示強制覆蓋,/i後面接輸入檔名,詳細用法請直接執行OdfConverter)

      [root@dspace ~] OdfConverter /f /i input.docx

      這樣預設會輸出一個檔名為「input.odt」的OpenOffice檔案,這樣就轉換完成囉。


      這次不偷懶,用Zotero好好地作參考資料的書目。使用此篇時也別忘了感謝以下參考資料來源喔!

      參考資料:

      Convert OpenXML (.docx, etc.) in Linux using command line - OpenOffice.org Ninja. (n.d.). . Retrieved August 9, 2009, from http://www.oooninja.com/2008/01/convert-openxml-docx-etc-in-linux-using.html.

      odf-converter-integrator:download [OpenOffice.org Ninja]. (n.d.). . Retrieved August 9, 2009, from http://katana.oooninja.com/w/odf-converter-integrator/download.

      小傑的部落格 - Jay's Blog: OpenDocument Format 與 Office Open XML 互轉. (n.d.). . Retrieved August 9, 2009, from http://jay-notebook.blogspot.com/2009/01/opendocument-format-office-open-xml.html.

      (more...)

      用Xvfb讓OpenOffice開機時自動啟動

      布丁布丁吃布丁

      用Xvfb讓OpenOffice開機時自動啟動

      使用DSpacemedia filter功能時,需要把各種文件檔轉換成PDF文件,這個功能可以藉由OpenOffice來完成。但是OpenOffice必須在圖形介面(也就是Xwindow)中才能開啟,在無法自動啟動的情況下,實在是不太方便。在網路上搜尋各種方法之後,終於找到方法了。

      大致上作法如下:利用Xvfb來製作出虛擬的圖形顯示畫面,然後讓OpenOffice在這虛擬的介面開啟,就可以正常啟動OpenOffice並提供轉檔功能了。


      我的作業系統是CentOS 5 Final,以下開始介紹安裝方法。

      一、安裝Xvfb

      可以利用yum來安裝Xvfb:(注意大小寫要正確喔)

      [root@ ~] yum install Xvfb 

      二、安裝OpenOffice

      在安裝CentOS的時候我已經把OpenOffice安裝。如果你沒有安裝,那麼也可以利用yum來安裝OpenOffice:

      [root@ ~] yum install openoffice.org-*

      注意找尋一下你OpenOffice的安裝路徑,我們需要呼叫他的執行程式「soffice.bin」。你可以利用locate指令來搜尋soffice.bin看是放在哪裡路徑底下:

      [root@ ~] locate /soffice.bin

      CentOS預設安裝是擺在「/usr/lib/openoffice.org/program/soffice.bin」當中,記住這個路徑,在底下設定時會使用到喔!

      三、設定啟動時開啟OpenOffice文件轉換服務

      請建立「/etc/init.d/openoffice」,並設定執行權限為755。/etc/init.d/openoffice的檔案內容如下:

      #!/bin/bash
      
      case "$1" in
      start)
           DISPLAY=:5.0
           export DISPLAY
           Xvfb :5 -screen scrn 1024x768x24 &
           /opt/openoffice.org3/program/soffice.bin "-accept=socket,host=127.0.0.1,port=8100;urp;StarOffice.ServiceManager -nofirststartwizard -nologo -headless -display:5" &
             ;;
      stop)
             pkill soffice &
             pkill Xvfb &
             exit 1 &
             ;;
      *)
             echo "Usage: $0 { start | stop }"
             exit 1
             ;;
      esac
      exit 0

      注意到上面的「/usr/lib/openoffice.org/program/soffice.bin」的路徑,請改成你系統安裝OpenOffice的路徑喔!


      結果還是花了一整個下午在弄這個。不管怎麼說能用好就好啦……

       

      參考資料:

      (more...)

      DSpace加強Browse功能的BrowseUtil

      布丁布丁吃布丁

      DSpace加強Browse功能的BrowseUtil

      image

      DSpace具備強大的Browse功能,可是唯獨換頁的功能卻只有薄弱的「next」(下一頁)跟「prev」(上一頁)。因此我寫了一支BrowseUtil來提供這方面的功能,也把[dspace-jspui-webapp]/browse/中full.jsp、single.jsp能作到的功能也加了進去,提供程式設計師在修改Browse功能時能夠有靈活的彈性。


      安裝BrowseUtil

      請下載以下檔案,並放置指定的位置:

      • BrowseUtil.java (SkyDriveMiroko)
        [dspace-source]/dspace-jspui/src/main/java/org/dspace/app/webui/util/BrowseUtil.java
      • BrowseInfo.java (SkyDriveMiroko)
        [dspace-source]/dspace-jspui/src/main/java/org/dspace/browse/BrowseInfo.java
      • full.jsp (SkyDriveMiroko)
        single.jsp (SkyDriveMiroko)
        [dspace-source]/dspace/modules/jspui/src/main/webapp/browse/full.jsp
        [dspace-source]/dspace/modules/jspui/src/main/webapp/browse/single.jsp

      然後請重新編譯DSpace,作mvn package跟ant update的動作。

      使用BrowseUtil

      引用與建立BrowseUtil物件

      在JSP檔案裡面,請輸入以下語法以引用BrowseUtil:

      <%@ page import="org.dspace.app.webui.util.BrowseUtil" %>

      BrowseUtil物件建立需要輸入兩個參數,個別是HttpServletRequest跟BrowseInfo(這是DSpace的Browse物件),建立範例如下;

      <%
      BrowseInfo bi = (BrowseInfo) request.getAttribute("browse.info"); //先取得BrowseInfo物件
      BrowseUtil bu = new BrowseUtil(request, bi); //建立BrowseUtil
      %>

      然後我們就可以以這個bu物件來取得連結了。

      取得換頁連結
      <%
      String next = bu.getNextLink(); //下一頁
      String last = bu.getLastLink(); //最後一頁
      String prev = bu.getPrevLink(); //前一頁
      String first = bu.getFirstLink(); //第一頁
      %>

      取得頁碼

      以下語法會取得每一頁頁碼與連結,但是會排除自己的頁碼:

      <%= bu.getPagesList() %>

      結果如下:

      <<first < previous 1 2 3 4 5 6 next > last >>

      以下語法會取得該頁前後2頁之內的頁碼:

      <%= bu.getPagesLink(2) %>

      結果如下:

      <<first < previous ... 2 3 4 5 6 ... next > last >>


      其他BrowseInfo其實還有小功能,如果有需要的話就請自行看看程式碼囉。寫小功能還是非常讓人愉快的,大家加油!

      (more...)

      DSpace擴增Collection Browse功能

      布丁布丁吃布丁

      DSpace擴增Collection Browse功能

      image

      DSpace內建了非常強大的Browse功能,只是一般好像比較少看到有人善加利用。這次主要是要擴增Browse功能,讓他具備可以找出特定Metadata欄位中的值。


      安裝方法

      請下載以下檔案,依照同樣的目錄結構放到[dspace-source]當中,再重新編譯DSpace即可。


      使用方法

      舉例來說,下面網址與圖片顯示是在預設情況下全部的item:(因為這是區域網路,所以下面的網址應該連不到這個網頁)

      http://192.168.1.30:8080/jspui/handle/123456789/56/browse?type=title&submit_browse=Title

      image

      但是只要在網址的GET參數當中加入「fdc[0]=欄位=值」(fdc是FilterDCValue的縮寫),就會出現特定item的效果,如下,注意紅字的位置:

      http://192.168.1.30:8080/jspui/handle/123456789/56/browse?type=title&submit_browse=Title&fdc[0]=dc.title=121212

      image

      如果你要找出具備兩個條件的item,那就輸入「fdc[0]=欄位=值&fdc[1]=欄位=值」,例如下面的網址與圖:

      http://192.168.1.30:8080/jspui/handle/123456789/56/browse?type=title&submit_browse=Title&fdc[0]=dc.title=121212&fdc[1]=dc.date.issued=2009

      image

      裡面的所有連結我都已經調整過了,會自動帶入fdc的參數進去。至於細微的版面調整,那就是大家各自努力囉。


      DSpace的Browse功能意外地複雜,解析物件的結構、資料的流向花了我不少的時間。雖然瀏覽感覺上只是個小功能,但是既然DSpace都有提供了,還是希望大家能夠好好利用吧!

      (more...)

      使用SWFTools把PDF轉成可以瀏覽的SWF檔案

      布丁布丁吃布丁

      使用SWFTools把PDF轉成可以瀏覽的SWF檔案

      image

      SWFTools,是個功能強大的SWF工具,可以把AVI影片、PNG JPEG圖片、PDF轉換成SWF格式的檔案。SWF格式是Adobe Flash匯出後的檔案,現在大部分都支援Flash的瀏覽器中都可以直接播放,Wikipedia寫說有99%的網路使用者都可以讀取swf檔案,包括任天堂Wii或是Sony的PSP。

      image

      其中pdf2swf + rfxview viewer 的功能最讓我感到驚豔。如名稱所示,他可以把PDF轉換成SWF之後,再結合rfxview viewer輸出成一個可供瀏覽的SWF檔案。瀏覽的項目包括放大、縮小、拖曳、換頁等功能,而且可以直接在網頁上播放,非常令人讚賞!有興趣的話可以先開啟範例網頁來玩玩看!

      詳細的SWFTools指令,可以參考「光头的专栏 - SWFTools 命令」,裡面也介紹了中文字的解決方案。

      我也把SWFTools加入了DSpace的Media-filter功能當中,這一篇則是先單純地介紹怎麼安裝SWFTools,並且把PDF轉換成SWF、並結合到SWFTools。


      安裝SWFTools

      SWFTools下載網頁:http://www.swftools.org/download.html,內有Windows版本跟Linux版本。

      如果你跟我一樣是用CentOS的話,我們可以直接使用yum指令來直接安裝SWFTOOLS喔!

      請以root身份登入,然後輸入以下指令:

      [root@dspace ~]# yum -y install swftools

      安裝完成之後,就可以用「pdf2swf [來源的pdf檔] [輸出的swf檔]」來作轉換喔,例如下面的指令:

      [root@dspace ~]# pdf2swf input.pdf output.swf

      取得rfxview.swf瀏覽器

      直接用pdf2swf轉換出來的swf檔案並不具備瀏覽器的功能,必須搭配rfxview.swf才有這個效果。

      rfxview.swf可以從SWFTools下載頁面中的swftools-0.9.0.tar.gz找到,我也另外備份了一份到SkyDriveMiroko空間當中。

      實作範例

      請先把PDF檔案、rfxview.swf瀏覽器放到同一個資料夾當中。
      PDF範例檔案可以使用我的Blog(SkyDrive下載Miroko下載)

      轉換的指令如下:

      pdf2swf -z -B [rfxview.swf瀏覽器的路徑] -s flashversion=7 -t [來源PDF] -o [輸出SWF]

      於是實際上輸入的指令如下:

      [dspace@dspace-course ~]$ pdf2swf -z -B rfxview.swf -s flashversion=7 -t 1.pdf -o 2.swf

      你可以用以下HTML程式碼寫在網頁中以開啟轉換後的2.swf:

      <OBJECT CLASSID="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
       WIDTH="595"
       HEIGHT="842"
       CODEBASE="http://active.macromedia.com/flash5/cabs/swflash.cab#version=8,0,0,0">
        <PARAM NAME="MOVIE" VALUE="2.swf">
        <PARAM NAME="PLAY" VALUE="true">
        <PARAM NAME="LOOP" VALUE="true">
        <PARAM NAME="QUALITY" VALUE="high">
        <EMBED SRC="2.swf" WIDTH="595" HEIGHT="842"
         PLAY="true" ALIGN="" LOOP="true" QUALITY="high"
         TYPE="application/x-shockwave-flash"
         PLUGINSPAGE="http://www.macromedia.com/go/getflashplayer">
        </EMBED>
      </OBJECT>

      輸出結果應該要如下所示(SkyDrive下載Miroko下載):


      SWFTools轉出來的PDF2SWF+rfxview仍有個缺點,就是他的大圖瀏覽在一開始的顯示比例跟位置不是說很好,開啟之後無法預設用「全畫面」來瀏覽。不過暫時也找不到其他的開放原始碼的替代方案,所以就期待SWFTools繼續改版吧。

      (more...)

      HTML中object標籤在Firefox會出現底下margin-bottom: 2px現象的解決方法

      布丁布丁吃布丁

      HTML中object標籤在Firefox會出現底下margin-bottom: 2px現象的解決方法

      image

      上圖的圖片是一個<object>標籤,外面包著一層<div>用以表示圖片與其他元素的位置,但是會發現到底下多出了大約2px的間隔,除了原本在<object>裡面設定的height之外,還被強迫下向擠了一些間隔。

      這是Firefox才會出現的錯誤,修正方法是在<object>的style屬性當中加入font-size: 0 (字體大小為0)、line-height: 0 (行高為0) 即可,程式碼如下:

      <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
      	width="640"
      	height="380"
      	style="font-size: 0;line-height: 0;"
      	codebase="http://active.macromedia.com/flash5/cabs/swflash.cab#version=4,0,0,0">
      		<param name="movie" value="http://140.119.61.174:8080/jspui/retrieve/1366">
      		<param name="play" value="true">
      		<param name="loop" value="true">
      		<param name="quality" value="high">
      		<param name="wmode" value="transparent">
      
      		<embed src="http://140.119.61.174:8080/jspui/retrieve/1366" width="640" height="380" style="font-size: 0;line-height: 0;" 
      			play="true" align="" loop="true" quality="high"
      			type="application/x-shockwave-flash"
      			wmode="transparent"
      			pluginspage="http://www.macromedia.com/go/getflashplayer">
      		</embed>
      	</object>

      修正結果之後的畫面如下,下面的間隔不見了。

      image

      (more...)

      CentOS安裝Xpdf教學

      布丁布丁吃布丁

      CentOS安裝Xpdf教學

      image

      Xpdf是Linux中可以讀取PDF檔案的開放原始碼程式,我引用一下Wikipedia的詳細介紹:

      Xpdf 是一個開放原始碼PDF檔案瀏覽器,此軟體運行於X Window以及Motif上。 Xpdf 也實際運行於所有類Unix作業系統上。Xpdf 可解碼LZW壓縮格式並閱讀加密的PDF文件。官方版本的Xpdf遵循PDF檔案的智慧財產權政策,因此可能禁止拷貝、列印或轉換的功能。當然有某些破解補丁可以忽略這些智慧財產管理限制。

      Xpdf包含數項不需要X windows系統的程式,包含了解析PDF的圖檔以及將PDF轉檔成文字檔或PostScript的程式。

      Xpdf也被其他PDF瀏覽程式用於前端,例如KPDF(一個運行在KDE桌面的程式)。而它的文字引擎則被許多PDF瀏覽程式運用,例如BeOS上的BePDF、RISCOS上的!PDF以及Palm OS上的PalmPDF。

      Poppler以xpdf 3.0的繪圖函式庫為基礎創造出來,以便增加其再用性。許多程式(包括Xpdf自己)可使用poppler為它們的後端繪圖器。

      來源:Xpdf - 維基百科,自由的百科全書,http://zh.wikipedia.org/wiki/Xpdf

      Xpdf很重要的功能在於「從PDF轉成文字檔」,這可以取代DSpace原本使用PDFbox的缺點:PDFbox不支援Acrobat 9的PDF檔案。

      在一篇網路上到處轉載的「JAVA抽取WORD和PDF格式文件的四种武器」當中也有介紹到Xpdf,但並沒有很詳盡的安裝方法。所以這一篇主要是來教大家怎麼在Linux,特別是在CentOS當中安裝Xpdf。


      Xpdf可以利用rpm來安裝,而相依套件的部份我們則是用yum來安裝。

      1. 安裝Xpdf的相依套件

      請以root的身份輸入以下指令:

      [root@dspace ~]# yum install -y openmotif libpaper poppler-utils xdg-utils

      2. 下載Xpdf的rpm檔案並安裝

      Xpdf沒有提供rpm,但我們可以在RPM pbone.net找到Xpdf的rpm安裝檔。網頁位置在這裡,其中一個載點請點此下載,另外我準備了SkyDrive備份。

      確定你存放的位置之後,請以root的身份輸入以下指令:.

      [root@dspace ~]# rpm -ivh xpdf-3.02-5.el5.1.i386.rpm

      如果沒有錯誤訊息,表示安裝成功。

      3. 安裝語系檔

      請先下載以下語系檔,或是下載我在SkyDrive的語系檔備份

      如果你下載我備份的壓縮檔,請依照以下指令來解壓縮並安裝。

      [root@dspace ~]# unzip xpdf-language-i386.zip -d lang
      [root@dspace ~]# rpm –ivh lang/xpdf-*.rpm --force

      4. 使用Xpdf的pdftotext來抽取PDF的文字檔

      讓我們試著將一個PDF檔案中的文字抽取成txt文字檔吧。

      1. 請下載PDF檔案:「Chen, A Study on Knowledge Extraction from User Reading Annotation of Digital Library.pdf」(其實這是我的論文計畫書初稿XD)。
      2. 放到伺服器中的位置,你知道的地方即可。
      3. 執行pdftotext指令與檔名,如下:
      4. [root@dspace ~]# pdftotext Chen\,\ A\ Study\ on\ Knowledge\ Extraction\ from\ User\ Reading\ Annotation\ of\ Digital\ Library.pdf
      5. 此時應該會有同樣檔名,但是副檔名為.txt的檔案產生。結果應該跟這個檔案一樣,下圖中,左邊是PDF原稿,右邊則是抽取出來的文字檔!image

      這樣就安裝完成囉。此外,上面安裝過語系檔的檔案也全都可以如法炮製地抽取出文字檔,Xpdf非常地強大!


      本篇教學是為了擴增DSpace的Media-filter而鋪路,我現在正要把Xpdf跟DSpace整合,讓DSpace全文搜尋功能更為完整。

      (more...)