Wednesday, February 22, 2012

Oracle Database 呼叫外部地址定位網路服務(Web Service)

先至Oracle Database Web Service 下載 Web Services Callout Utility
按照說明(10.htm 或11.htm)至少完成 步驟1. Preparing the Oracle Client and Oracle Database Server

在完成上述步驟之後, 可以在$ORACLE_HOME/bin下找到"jpub"的script,複製一份(我的環境是 Oracle 11g, $ORACLE_HOME/jdk的版本是"1.5.0_30")
$ cp jpub jpub1.5
修改 jpub1.5, 以下為jpub1.5的內容

#! /bin/sh
#
# jpub - shell for invoking the JPublisher tool
# Usage: jpub <-J-javavm-options> <-jpub-options>
#
# %W% %E%



unset JAVA_HOME
JAVA_HOME=$ORACLE_HOME/jdk
export JAVA_HOME


TMPCLASSPATH=$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$ORACLE_HOME/jdbc/lib/ojdbc5_g.jar:$ORACLE_HOME/jlib/orai18n.jar:$ORACLE_HOME/sqlj/lib/runtime12.jar:$ORACLE_HOME/jlib/orai18n.jar:$ORACLE_HOME/jlib/orai18n-mapping.jar:$ORACLE_HOME/sqlj/lib/translator.jar:$ORACLE_HOME/javavm/lib/aurora.zip:$ORACLE_HOME/sqlj/lib/dbwsa.jar:$ORACLE_HOME/rdbms/jlib/xdb.jar:$ORACLE_HOME/lib/xsu12.jar:$ORACLE_HOME/jlib/jndi.jar:$ORACLE_HOME/rdbms/jlib/aqapi.jar:$ORACLE_HOME/rdbms/jlib/jmscommon.jar:$ORACLE_HOME/lib/xmlparserv2.jar:$CLASSPATH
export TMPCLASSPATH
TMP_C_CLASSPATH=$TMPCLASSPATH
export TMP_C_CLASSPATH LD_LIBRARY_PATH=$ORACLE_HOME/lib32:$ORACLE_HOME/lib:$JAVA_HOME/lib
export LD_LIBRARY_PATH


switches=-Xmx1024M 


JRE64FLAG=
export JRE64FLAG
files=
switcharg=


javavm=$JAVA_HOME/bin/java


while [ $# -gt 0 ]
do
 case "$1" in
 -J-classpath) TMPCLASSPATH="$2"
 shift;;
 -classpath) TMP_C_CLASSPATH="$2"
 shift;;
 -J-*) switcharg=`echo $1 | cut -c3-`
 switches="$switches $switcharg";;
 -vm=*) javavm=`echo $1 | cut -c5-` ;;
 *) files="$files $1";;
 esac
 shift
done 
exec $javavm $JRE64FLAG -classpath $TMPCLASSPATH $switches oracle.jpub.java.Main -C-classpath=$TMP_C_CLASSPATH $files


然後執行(為一行的指令,若看到分行為版本格式的緣故)
$ jpub1.5 -httpproxy=proxy.my_company.com:80 -proxywsdl=http://address.tgos.nat.gov.tw/ADDR_WS/Multiple_MatchLocate/Multiple_MatchLocate.asmx?WSDL -endpoint=http://address.tgos.nat.gov.tw/ADDR_WS/Multiple_MatchLocate/Multiple_MatchLocate.asmx


Multiple ports available. To publish a particular port, use -proxyopts=port:Multiple_MatchLocateSoap12, or -proxyopts=port:Multiple_MatchLocateSoap.
Use the default port Multiple_MatchLocateSoap12.
tmp/src/genproxy/Multiple_MatchLocateSoap12ClientJPub.java
plsql_wrapper.sql
plsql_dropper.sql
plsql_grant.sql
plsql_revoke.sql
plsql_proxy.jar
Please run plsql_wrapper.sql in the user schema, load the generated jar file and run plsql_grant.sql in the SYS schema.


使用jpub(jpub操作手冊)的測試對象為台灣地址定位服務(內政部資訊中心提供的網路服務-Web Service-元件),其WSDL的位址:
http://address.tgos.nat.gov.tw/ADDR_WS/Multiple_MatchLocate/Multiple_MatchLocate.asmx?WSDL
Endpoint 網址:
http://address.tgos.nat.gov.tw/ADDR_WS/Multiple_MatchLocate/Multiple_MatchLocate.asmx?
依jpub 所需要輸入的參數對應,則會產生幾個PL/SQL wrapper package(應用程式套件)及 SOAP proxy jar檔。
依照指示,在使用呼叫的使用者下("MVDEMO")執行"plsql_wrapper.sql",並使用"loadjava"將"plsql_proxy.jar"載入資料庫:修改"plsql_grant.sql",將"<USER>"置換成要呼叫的使用者名稱("MVDEMO"),再以SYS執行"plsql_grant.sql"。
以上就完成了從Oracle DB 呼叫外部Web Service的PL/SQL程式界面。

Thursday, February 16, 2012

在Oracle 資料庫使用 Google Geocoding (地址定位)

Google Geocoding API 的說明網頁請參考:http://code.google.com/intl/zh-TW/apis/maps/documentation/geocoding/
我所關心的是輸入中文(台灣)的地址,Google Geocoding回傳座標,取得經緯度之後,轉換成Oracle SDO_GEOMETRY資料型態,更新該欄位。
首先,測試以下URL,以確定必要的資訊都已輸入
http://maps.googleapis.com/maps/api/geocode/xml?address=台北市忠孝西路一段66號&language=zh-tw&region=tw&sensor=true
其回應如下:
紅色框的地方就是我要的座標(預設為WGS84)。
確定了使用Google Geocoding的傳遞參數之後,接下來就要在資料庫中撰寫一函式,使用HTTP呼叫Google Geocoding API來取得座標並轉化成SDO_GEOMETRY資料型態。
在資料庫內要能執行HTTP的呼叫,必需進行以下的設定:

以SYS登入資料庫賦予使用者(這裏使用'MVDEMO'))能夠執行UTL_HTTP程式套件的權限
 grant execute on utl_http to mvdemo;

以SYSTEM登入建立對外存取網站ACL(Access Control List)清單
connect system/password
-- Step 1: Create the Access Control List and Its Privilege Definitions
 BEGIN
 DBMS_NETWORK_ACL_ADMIN.CREATE_ACL (
  acl          => 'maps_googleapis_com.xml',  -- ACL XML檔案,自己定義一個名稱
  description  => 'Google Maps API ACL', -- 說明該ACL XML檔案的用途
  principal    => 'MVDEMO',  -- 指定管理的使用者或角色(role),在這裏是以mvdemo使用者
  is_grant     => TRUE,
  privilege    => 'connect', -- 對外網站的權限
  start_date   => null,
  end_date     => null);
END;
/

將要可以對外連結的網站加入ACL
Step 2: Assign the Access Control List to One or More Network Hosts
BEGIN
 DBMS_NETWORK_ACL_ADMIN.ASSIGN_ACL (
  acl         => 'maps_googleapis_com.xml',   -- 要對應上一步剛剛建立的ACL XML檔案名稱
  host        => 'maps.googleapis.com',   -- Google Geo-coding的網站位址
  lower_port  => null, -- 允許對外連結的網路埠(port)的範圍;NULL表示不設限
  upper_port  => null);
END;
如果會透過 PROXY SERVER對外連接,不要忘了要加入允許存取網站的清單
BEGIN
 DBMS_NETWORK_ACL_ADMIN.ASSIGN_ACL (
  acl         => 'maps_googleapis_com.xml',
  host        => 'proxy.mycompany.com',  -- HTTP Proxy Server (http://host[:port]/)
  lower_port  => null,
  upper_port  => null);
END;

建立取得地址定位的函式
create or replace
function google_geocoding
( p_address in varchar2 default '台北市忠孝西路一段66號')
return sdo_geometry -- 回傳 Oracle 空間資料型態
deterministic
as
  http_req_url varchar2(32767);
  http_req utl_http.req;
  http_resp utl_http.resp;
  http_resp_html varchar2(32767);
  resp_xml XMLType;
  latitude number;
  longitude number;
begin
  UTL_HTTP.SET_PROXY (' proxy.mycompany.com ');  -- 設定 HTTP Proxy Server
  http_req_url:='http://maps.googleapis.com/maps/api/geocode/xml?language=zh-tw&region=tw&sensor=true&address=' || p_address; -- 準備送的URL參數
  http_req:= utl_http.begin_request(http_req_url); -- 開始進行HTTP 的傳送要求,預設方式為GET
-- 設定 HTTP Header
  UTL_HTTP.SET_HEADER(http_req, 'User-Agent', 'Mozilla/4.0');
  UTL_HTTP.SET_HEADER(http_req,'Content-Type','text/xml;charset=UTF-8');
  http_resp:= utl_http.get_response(http_req); -- 取得 HTTP 回傳
  utl_http.read_text(http_resp, http_resp_html); -- 讀取 HTTP 回傳內容
  utl_http.end_response(http_resp); -- 結束HTTP的請求
  -- 將讀取的HTTP 內容轉換成XML 文件
  resp_xml:= XMLType.createXML(http_resp_html);
  -- 讀取 Latitude, Longitude 的內容並將其轉換成數字
  latitude:= resp_xml.extract('/GeocodeResponse/result/geometry/location/lat/text()').GETNUMBERVAL();
  longitude:= resp_xml.extract('/GeocodeResponse/result/geometry/location/lng/text()').GETNUMBERVAL();
  return point(longitude,latitude); -- 傳回"點"空間位置
  EXCEPTION
    WHEN others THEN
      return point(NULL,NULL);
end;

測試:
select google_geocoding() from dual;
GOOGLE_GEOCODING()
---------------------------------------------------------------------------------------
MDSYS.SDO_GEOMETRY(2001,8307,MDSYS.SDO_POINT_TYPE(121.515241,25.046139,NULL),NULL,NULL)


select google_geocoding('台北市政府') from dual;
GOOGLE_GEOCODING('台北市政府')
-----------------------------------------------------------------------------------------MDSYS.SDO_GEOMETRY(2001,8307,MDSYS.SDO_POINT_TYPE(121.5644722,25.0372787,NULL),NULL,NULL)


select google_geocoding('不知道的地方') from dual;
GOOGLE_GEOCODING('不知道的地方')
----------------------------------------------------------------------------MDSYS.SDO_GEOMETRY(2001,8307,MDSYS.SDO_POINT_TYPE(NULL,NULL,NULL),NULL,NULL)

Monday, February 13, 2012

建立 Oracle Spatial WFS Part II

Oracle Web Feature Service 架構
如上圖,要特別指出的是,在Application Server上提供WFS Server API,資料是儲存在資料庫上的"Spatial Tables",所以要透過"Feature Mapping"或稱為Publish (發佈)提供原"Spatial Tables"額外的資訊以滿足WFS的要求,但是原"Spatial Tables"並不需要再多一份複製(所以是用"Feature Mapping"這個字眼)。
設定Oracle WFS 的步驟,如下圖
在這些設定步驟,我們會使用SDO_WFS_PROCESS與SDO_WFS_LOCK packages
1. Set capabilities info
設定 Server Capabilities 的方法有(任選一種方法就可以)
I. 將外部"WFScapabilitiesTemplate.xml" 載入資料庫
以SYSTEM登入資料庫,執行下列SQL (WFScapabilitiesTemplate.xml 放在'/u01/oracle/db/product/11.2.0.3/dbhome_1' 目錄下
create or replace directory WFS_XML
  as '/u01/oracle/db/product/11.2.0.3/dbhome_1';
begin
  SDO_WFS_PROCESS.insertCapabilitiesInfo(
    xmltype(
      bfilename('WFS_XML', 'WFScapabilitiesTemplate.xml'),
      nls_charset_id('AL32UTF8')
    )
  );
end;
/
commit;
II. 直接使用PL/SQL載入WFScapabilitiesTemplate.xml 的內容
範例
WFS GetCapabilities 測試URL:
http://localhost:7001/SpatialWS-SpatialWS-context-root/xmlwfsservlet?request=GetCapabilities&service=WFS&version=1.0.0
正確的設定應該會出下面的結果
2. Enable the schema
這個步驟相對簡單,只要透過MDSYS, SYSTEM或SYS執行"SDO_WFS_PROCESS.GrantMDAccessToUser"
SQL> execute SDO_WFS_PROCESS.GrantMDAccessToUser('MVDEMO')

3. Publish Table
必須要用SYSTEM或SYS來執行(但不包括MDSYS)Publish Tables的預儲程序(stored procedure)
範例:
declare
  featureDescriptorXML CLOB :=
    '<?xml version="1.0" ?>
       <FeatureType xmlns:mvdemons="http://www.myserver.com/mvdemo" 
         xmlns="http://www.opengis.net/wfs">
         <Name> mvdemons:Cities</Name>
         <Title>Cities</Title>
         <SRS>SDO:8307</SRS>
     </FeatureType>';
begin
  SDO_WFS_PROCESS.publishFeatureType(
    dataSrc           => 'MVDEMO.CITIES',
    ftNsUrl           => 'http://www.myserver.com/mvdemo',
    ftName            => 'Cities',
    ftNsAlias         => 'mvdemons' ,
    featureDesc       => xmltype(featureDescriptorXML),
    schemaLocation    => null,
    pkeyCol           => 'CITY',
    columnInfo        => MDSYS.StringList('PointMemberType'),
    pSpatialCol       => 'LOCATION',
    featureMemberNs   => null,
    featureMemberName => null,
    srsNs             => null,
    srsNsAlias        => null
  );
end;
/
其中 MVDEMO.CITIES
SQL> desc cities
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 LOCATION                                           MDSYS.SDO_GEOMETRY
 CITY                                               VARCHAR2(42)
 STATE_ABRV                                         VARCHAR2(2)
 POP90                                              NUMBER
 RANK90                                             NUMBER

說明
featureDescriptorXML為當收到 GetCapabilities要求時,所回傳XML的內容
dataSrc => 'MVDEMO.CITIES' 表示所對應旳Schema與Table名稱
ftName => 'Cities' 表示WFS的Feature Name
pkeyCol => 'CITY' 表示該表的的 Primary Key
columnInfo => MDSYS.StringList('PointMemberType') 表示所對應GML 圖徵)feature)的型態
pSpatialCol => 'LOCATION' 表示表格為SDO_GEOMETRY欄位型態的欄位名稱

4. Register table for updates
Oracle Spatial WFS 支援 WFS-T。要能支援WFS-T需要將能提供此項功能的資料表格進行註冊。透過該表格的擁有者(Owner)執行SDO_WFS_LOCK.registerFeatureTable
範例:
SQL> execute SDO_WFS_LOCK.registerFeatureTable('MVDEMO','CITIES')

5. Notify WFS server
新增的異動並不動自動送到WFS server,透過MDSYS, SYSTEM或SYS執行SDO_WFS_PROCESS. insertFtMDUpdated來通知WFS有新的更新異動;WFS 則會每10秒(預設)(定義在<wfs_cache_sync_interval>10000</wfs_cache_sync_interval>)來檢查更新的時間,如果有變動,則會載入新的WFS定義
範例:
SQL> execute SDO_WFS_PROCESS.InsertFtMDUpdated('http://www.myserver.com/mvdemo','Cities', sysdate)

6. Grant access rights
給予"匿名使用者"對資料表格適當的存取權限。以本範來說,MVDEMO.CITIES需要給予SELECT、INSERT、UPDATE、DELETE(為滿足WFS-T的功能)。
SQL> grant SELECT, INSERT, UPDATE, DELETE on cities to SpatialWsXmlUser;

7. Set Configuration params
主要是修改 WEB-INF/conf/wsconfig.xml 的設定內容(基本上使用預設就可以了)

<wfs_cache_sync_interval>10000</wfs_cache_sync_interval>
設定WFS檢查異動同步的時間間隔
<wfs_query_timeout>10</wfs_query_timeout>
預設查詢鎖定時間(單位是分鐘)
<wfs_lock_expiry>4</wfs_lock_expiry>
預設異動鎖定時間(單位是秒)
<cached_feature_types>
  <feature_type ns="http://www.myserver.com/mvdemo" name="Cities" />
  <feature_type ns="http://www.myserver.com/mvdemo" name="Counties" />
</cached_feature_types>
設定需要放置於WFS memory cache 的Features

Friday, February 10, 2012

Using PL/SQL To Load WFScapabilitiesTemplate.xml Directly


-- Run as MDSYS, SYSTEM or SYS


-- Load the capabilities from a PL/SQL variable
declare
  capabilitiesXML CLOB :=
'<WFS_Capabilities version="1.0.0" xmlns="http://www.opengis.net/wfs" xmlns:ogc="http://www.opengis.net/ogc" >
   <Service>
     <Name> Oracle WFS </Name>
     <Title> Oracle Web Feature Service </Title>
     <Abstract> Web Feature Service maintained by Oracle </Abstract>
     <OnlineResource> http://www.someserver.com/wfs/cwwfs.cgi? </OnlineResource>
   </Service>
   <Capability>
      <Request>
         <GetCapabilities>
            <DCPType>
               <HTTP>
                  <Get onlineResource="http://www.myserver.com/get?"/>
               </HTTP>
            </DCPType>
            <DCPType>
               <HTTP>
                  <Post onlineResource="http://www.myserver.com/post?"/>
               </HTTP>
            </DCPType>
         </GetCapabilities>
         <DescribeFeatureType>
            <SchemaDescriptionLanguage>
               <XMLSCHEMA/>
            </SchemaDescriptionLanguage>
            <DCPType>
               <HTTP>
                  <Post onlineResource="http://www.myserver.com/post?"/>
               </HTTP>
            </DCPType>
         </DescribeFeatureType>
         <GetFeature>
            <ResultFormat>
               <GML2/>
            </ResultFormat>
            <DCPType>
               <HTTP>
                  <Post onlineResource="http://www.myserver.com/post?"/>
               </HTTP>
            </DCPType>
         </GetFeature>
         <GetFeatureWithLock>
            <ResultFormat>
               <GML2/>
            </ResultFormat>
            <DCPType>
               <HTTP>
                  <Post onlineResource="http://www.myserver.com/post?"/>
               </HTTP>
            </DCPType>
         </GetFeatureWithLock>
         <Transaction>
            <DCPType>
               <HTTP>
                  <Post onlineResource="http://www.myserver.com/post?"/>
               </HTTP>
            </DCPType>
         </Transaction>
         <LockFeature>
            <DCPType>
               <HTTP>
                  <Post onlineResource="http://www.myserver.com/post?"/>
               </HTTP>
            </DCPType>
         </LockFeature>
      </Request>
   </Capability>
   <FeatureTypeList>
      <Operations>
         <Insert/>
         <Update/>
         <Delete/>
         <Query/>
         <Lock/>
      </Operations>
   </FeatureTypeList>
   <ogc:Filter_Capabilities>
      <ogc:Spatial_Capabilities>
         <ogc:Spatial_Operators>
            <ogc:BBOX/>
            <ogc:Equals/>
            <ogc:Disjoint/>
            <ogc:Intersect/>
            <ogc:Touches/>
            <ogc:Crosses/>
            <ogc:Within/>
            <ogc:Contains/>
            <ogc:Overlaps/>
            <ogc:Beyond/>
            <ogc:DWithin/>
         </ogc:Spatial_Operators>
      </ogc:Spatial_Capabilities>
      <ogc:Scalar_Capabilities>
         <ogc:Logical_Operators/>
         <ogc:Comparison_Operators>
            <ogc:Simple_Comparisons/>
            <ogc:Like/>
            <ogc:Between/>
            <ogc:NullCheck/>
         </ogc:Comparison_Operators>
         <ogc:Arithmetic_Operators>
            <ogc:Simple_Arithmetic/>
         </ogc:Arithmetic_Operators>
      </ogc:Scalar_Capabilities>
   </ogc:Filter_Capabilities>
</WFS_Capabilities>
';
begin
  SDO_WFS_PROCESS.insertCapabilitiesInfo (xmltype(capabilitiesXML));
end;
/

-- Commit the change
commit;

WFScapabilitiesTemplate.xml


<WFS_Capabilities version="1.0.0" xmlns="http://www.opengis.net/wfs" xmlns:ogc="http://www.opengis.net/ogc" >
   <Service>
  <Name> Oracle WFS </Name>
  <Title> Oracle Web Feature Service </Title>
  <Abstract> Web Feature Service maintained by Oracle </Abstract>
  <OnlineResource> http://www.someserver.com/wfs/cwwfs.cgi? </OnlineResource>
</Service>
   <Capability>
      <Request>
         <GetCapabilities>
            <DCPType>
               <HTTP>
                  <Get onlineResource="http://www.myserver.com/get?"/>
               </HTTP>
            </DCPType>
            <DCPType>
               <HTTP>
                  <Post onlineResource="http://www.myserver.com/post?"/>
               </HTTP>
            </DCPType>
         </GetCapabilities>
         <DescribeFeatureType>
            <SchemaDescriptionLanguage>
               <XMLSCHEMA/>
            </SchemaDescriptionLanguage>
            <DCPType>
               <HTTP>
                  <Post onlineResource="http://www.myserver.com/post?"/>
               </HTTP>
            </DCPType>
         </DescribeFeatureType>
         <GetFeature>
            <ResultFormat>
               <GML2/>
            </ResultFormat>
            <DCPType>
               <HTTP>
                  <Post onlineResource="http://www.myserver.com/post?"/>
               </HTTP>
            </DCPType>
         </GetFeature>
         <GetFeatureWithLock>
            <ResultFormat>
               <GML2/>
            </ResultFormat>
            <DCPType>
               <HTTP>
                  <Post onlineResource="http://www.myserver.com/post?"/>
               </HTTP>
            </DCPType>
         </GetFeatureWithLock>
         <Transaction>
            <DCPType>
               <HTTP>
                  <Post onlineResource="http://www.myserver.com/post?"/>
               </HTTP>
            </DCPType>
         </Transaction>
         <LockFeature>
            <DCPType>
               <HTTP>
                  <Post onlineResource="http://www.myserver.com/post?"/>
               </HTTP>
            </DCPType>
         </LockFeature>
      </Request>
   </Capability>
   <FeatureTypeList>
      <Operations>
         <Insert/>
         <Update/>
         <Delete/>
         <Query/>
         <Lock/>
      </Operations>
   </FeatureTypeList>
   <ogc:Filter_Capabilities>
      <ogc:Spatial_Capabilities>
         <ogc:Spatial_Operators>
            <ogc:BBOX/>
            <ogc:Equals/>
            <ogc:Disjoint/>
            <ogc:Intersect/>
            <ogc:Touches/>
            <ogc:Crosses/>
            <ogc:Within/>
            <ogc:Contains/>
            <ogc:Overlaps/>
            <ogc:Beyond/>
            <ogc:DWithin/>
         </ogc:Spatial_Operators>
      </ogc:Spatial_Capabilities>
      <ogc:Scalar_Capabilities>
         <ogc:Logical_Operators/>
         <ogc:Comparison_Operators>
            <ogc:Simple_Comparisons/>
            <ogc:Like/>
            <ogc:Between/>
            <ogc:NullCheck/>
         </ogc:Comparison_Operators>
         <ogc:Arithmetic_Operators>
            <ogc:Simple_Arithmetic/>
         </ogc:Arithmetic_Operators>
      </ogc:Scalar_Capabilities>
   </ogc:Filter_Capabilities>
</WFS_Capabilities>

建立 Oracle Spatial WFS Part I

環境
Oracle Database 11g Release 2 (11.2.0.2 以上)
Oraacle Weblogic 11g Release 1 (10.3.5)+
Oracle Spatial Web Service 架構圖如下:
不同於 Oracle WMS的架構是Spatial Web Service在Middleware上提供WS Server API,實際WS的處理則是在Oracle Database內;管理與設定工具也是建置於資料庫內(PL/SQL API)。
建立Oracle Spatial Web Service的主要步驟:
1. Deploy SDOWS Web 應用程式
2. 設定相關資料庫使用者帳號
3. 設定Middleware連接資料庫的data sources
4. 設定一般Web Service的參數
5. 重新啓動 SDO web Service

Deploy Spatial Web Service
實際上將"sdows.ear"佈署到middleware中間件應用伺服器。我們使用的middleware是WebLogic 10.3.5;建議使用最新的sdows.ear,sdows.ear會跟著資料庫軟體的安裝,放置於$ORACLE_HOME/md/jlib的目錄下。
我是將$ORACLE_HOME/md/jlib/sdows.ear複製至安裝的目錄"/home/oracle"
[以Linux為範例,先解開sdows.ear]
$ cp $ORACLE_HOME/md/jlib/sdows.ear /home/oracle/.
$ cd /home/oracle
[oracle@localhost ~]$ mv sdows.ear sdows.ear1
[oracle@localhost ~]$ mkdir sdows.ear
[oracle@localhost ~]$ cd sdows.ear
[oracle@localhost sdows.ear]$ /usr/java/default/bin/jar xvf ../sdows.ear1
[oracle@localhost sdows.ear]$ mv sdows.war sdows.war1
[oracle@localhost sdows.ear]$ mkdir sdows.war
[oracle@localhost sdows.ear]$ cd  sdows.war
[oracle@localhost sdows.war]$  /usr/java/default/bin/jar xvf ../sdows.war1

設定相關資料庫者帳號
Oracle資料庫預設管理者的帳號都是被鎖定的,需要被解開且重新設定其密碼
以資料庫系統管理者 (system)登入,執行下列SQL

-- 解除鎖定帳號
alter user mdsys account unlock;
alter user spatial_csw_admin_usr account unlock;
alter user spatial_wfs_admin_usr account unlock;

-- 設定管理者帳號的密碼(需要記住密碼,待會在設定WebLogic data sources時需要用到)
alter user mdsys identified by <password>;
alter user spatial_csw_admin_usr identified by <password>;
alter user spatial_wfs_admin_usr identified by <password>;

接下來要設定"匿名使用者",預設資料庫使用者名稱"SpatialWsXmlUser"。該使用者會處理所有傳入XML/HTTP的要求,透過MDSYS進行"proxy authentication",因此SpatialWsXmlUser的密碼跟本不重要(因為完全用不到),但不要設成很好猜到。若要修改"匿名者"的預設使用者名稱,則要一起修改"WSConfig.xml"所對應的使用者。
 -- 建立 "匿名使用者"使用者proxy authentication
create user spatialwsxmluser identified by whatever;
-- 給予"匿名使用者"連接資料庫的系統權限
grant create session to spatialwsxmluser;
-- 透過MDSYS資料庫使用者進行 proxy authentication
alter user spatialwsxmluser grant connect through mdsys;
-- 給予"匿名使用者"接受處理WFS與CSW外部要求的角色能力
grant wfs_usr_role to spatialwsxmluser;
grant csw_usr_role to spatialwsxmluser;

移除不必要角色密碼的設定(選項)

alter role WFS_USR_ROLE not identified;
alter role CSW_USR_ROLE not identified;
alter role SPATIAL_WFS_ADMIN not identified;
alter role SPATIAL_CSW_ADMIN not identified;

設定Middleware連接資料庫的data sources
這裏我們使用WebLogic 10.3.5 做為應用伺服器(middleware application server)。以下們要建立的data sources與相關資訊:
Data Source Name JNDI  Name Database User
Usage
WfsProxyConnection jdbc/WfsProxyConnectionCoreDS mdsys WFS User connections
WFS_ADMIN_CONN_NAME jdbc/WFS_ADMIN_CONN_NAME spatial_wfs_admin_usr WFS Administration
CatalogProxyConnection jdbc/CatalogProxyConnectionCoreDS mdsys CSW User connections
CSW_ADMIN_CONN_NAME jdbc/CSW_ADMIN_CONN_NAME spatial_csw_admin_usr CSW Administration
OpenLsProxyConnection jdbc/OpenLsProxyConnectionCoreDS mdsys OpenLS User connections
 在WebLogic Console (http://localhost:7001/console, for example),點選左邊選單Services->data Sources
在中間"Summary of JDBC Data Sources","Data Sources" 點選 'New","Generic Data Source";分別設定 "Name","JNDI Name","Database Type";Database Type 選 Oracle,按下一步
選擇Oracle JDBC Driver -- "Oracle's Driver (Thin) for Service connections: Versions: 9.0.1 and later";按下一步
點掉(unchecked) "Supports Global Transactions",按下一步
 設定Oracle JDBC連線資訊,按下一步
 按下"測試連線設定"(選項)
 結果顯示連線成功,則表示資料庫連線設定正確,按下一步
 設定Data Source至指定的 application servers,按下"完成"。
依次將要設定的Data Source 設定完成。

設定一般Web Service 的參數
如果都使用預設值,基本上沒有什麼要特別設定的。如果需要可以更改log的設定值,以方便追踪與除錯。WSConfig.xml位於 WEB-INF/conf/WSConfig.xml

<logging log_level="finest" log_thread_name="true"
         log_time="true">
   <log_output name="System.err" />
   <log_output name="log/ws.log" />
</logging>
如果有變動"匿名使用者"的預設使用者,也在此一併修改。

重新啓動 SDO Web Service
停止SDO Web Service:按下Deployments -> 點選 sdows -> 點 "Stop" -> "Force Stop Now"
啓動SDO Web Service:按下Deployments -> 點選 sdows -> 點 "Start" -> "Servicing all requests"


Thursday, February 09, 2012

建立 Oracle Spatial/Location WMS

簡單地介紹如何將儲存在Oracle Spatial/Location 的空間資料發佈成WMS (Web Map Service)
需要具備的環境
1. Oracle Database (已經將空間資料載入於SDO_GEOMETRY欄位的表格)
2. Oracle Mapviewer (透過 Oracle Mabuilder 將空間資料表格已定義成BASE_MAP,THEME)
Oracle WMS 是由Oracle Mapviewer提供,架構圖簡化如下:
1. 啓動WMS的設定
進入Oracle Mapviewer的設定,並移除<wms_cnfig>的註解
修改成適當的主機名稱,Port,通訊協定 (protocol),default_datasource (這個設定很重要)以及 public_datasource

<wms_config
  host="www.oracle.com"
  port="80"
  protocol="http“
  default_datasource="mvdemo"
  public_datasources="mvdemo"

>
...
</wms_config>

在這裏用的data_source是"mvdemo",應該在之前Mapviewer的設定上已經談過了,這裏就略過。附加說明:如果沒有設定default_datasource,則預設值為"wms"。

2. 設定其它在<wms_config>的內容
3. 設定SDO與EPSG座標參數對應表(選項,如果要使用EPSG座標代號就一定要設定)
修改<wms_config>的內容設定

<wms_config> ...
  <sdo_epsg_mapfile>
    ../conf/epsg_srids.properties
  </sdo_epsg_mapfile>
</wms_config>
epsg_srids.properties 的內容格式為 sdo_srid=epsg_srid
範例
82208=32601
82271=32602
81989=27700
27700-27700

這樣就大致設定完成
接下來就可以進行測試
GetCapabilities
http://127.0.0.1:7001/mapviewer/wms?VERSION=1.1.1&REQUEST=GetCapabilities&SERVICE=WMS
http://127.0.0.1:7001/mapviewer/wms?VERSION=1.3.0&REQUEST=GetCapabilities&SERVICE=WMS
(請注意URL並沒有換行)
GetMap
http://127.0.0.1:7001/mapviewer/wms?VERSION=1.1.0&REQUEST=GetMap&FORMAT=image/png&SRS=EPSG:4326&BBOX=-127,25,-78,40&WIDTH=800&HEIGHT=600&LAYERS=THEME_DEMO_STATES,THEME_DEMO_STATES_LINE,CUSTOMERS
http://127.0.0.1:7001/mapviewer/wms?VERSION=1.3.0&REQUEST=GetMap&FORMAT=image/png&CRS=EPSG:4326&BBOX=-127,25,-78,40&WIDTH=800&HEIGHT=600&LAYERS=THEME_DEMO_STATES,THEME_DEMO_STATES_LINE,CUSTOMERS
(BBOX 不要超出WMS可以提供的範圍)
以下為使用"BASE_MAP"再加套上"LAYERS"
http://127.0.0.1:7001/mapviewer/wms?VERSION=1.1.0&REQUEST=GetMap&FORMAT=image/jpeg&SRS=SDO:8307&BBOX=-127,25,-78,40&WIDTH=800&HEIGHT=600&BASEMAP=DEMO_MAP&DATASOURCE=mvdemo&LAYERS=CUSTOMERS
http://127.0.0.1:7001/mapviewer/wms?VERSION=1.3.0&REQUEST=GetMap&FORMAT=image/jpeg&CRS=SDO:8307&BBOX=-127,25,-78,40&WIDTH=800&HEIGHT=600&BASEMAP=DEMO_MAP&DATASOURCE=mvdemo&LAYERS=CUSTOMERS

GetFeatureInfo

http://127.0.0.1:7001/mapviewer/wms?VERSION=1.1.0&REQUEST=GetFeatureInfo&query_Layers=THEME_DEMO_STATES&SRS=SDO:8307&BBOX=-124,32,-116,41&WIDTH=800&HEIGHT=600&X=10&Y=10
http://127.0.0.1:7001/mapviewer/wms?VERSION=1.3.0&REQUEST=GetFeatureInfo&query_Layers=THEME_DEMO_STATES&CRS=SDO:8307&BBOX=-124,32,-116,41&WIDTH=800&HEIGHT=600&I=10&J=10
其結果
<GetFeatureInfo_Result>
<ROWSET name="THEME_DEMO_STATES">
<ROW num="1">
<ROWID>
AAASeoAABAAAVghAAE
</ROWID>
</ROW>
</ROWSET>
</GetFeatureInfo_Result>




Thursday, February 02, 2012

SELECT COUNT(*)

最近在客戶那邊遇到了一個效能上的問題。客戶有一個程式會對資料表不斷地新增資料,有另外一支程式會來處理新增進入資料表格的資料,並對處理的結果異動其狀態;但最後不會將該資料刪除。也就是說該資料表格會愈長愈大。
客戶也會要知道,目前待處理的資料筆數還有多少,最簡單的方式就是 SELECT COUNT(*)....一開始當然速度是在可以接受的情況下,但隨著時間,資料筆數愈來愈大,每次 SELECT COUNT(*)的時間就愈來愈長...。然後加入自動更新(Refresh),從5秒自動更新變成10秒, 30秒,....;再加上同時之間有許多使用者會同時上線,然後你會看到資料庫主機CPU都花在USER I/O,速度愈變愈慢....
很熟悉嗎? 如何改善執行效率呢?
我的想法是:沒辦法,除非改變程式 SELECT COUNT(*)的架構,不然 USER I/O是無法避免的。怎麼做--利用一資料表格來儲存計數 -- SELECT COUNT(*) -- 的結果,新增資料的程式則異動該值+1;處理異動的程式則異動該值-1;查詢筆數的程式則直接取得該值。

建立計數儲存表格
create table table_row_counts (table_name varchar2(40), row_counts number);

設定初始值、讀取數值、新增數值與異動...等
當然直接UPDATE是一種方法,在這我使用 stored procedure

create or replace
PACKAGE ROW_COUNTS AS
  procedure init_rows;
  procedure add_row;
  procedure reduce_row;
  function get_rows return number;
END ROW_COUNTS;
/

create or replace
package body row_counts as

function get_rows return number as
rowsn number;
begin
select row_counts into rowsn from table_row_counts where table_name = 'EMP';
return rowsn;
end;

procedure add_row as
begin
update table_row_counts set row_counts = row_counts + 1 where table_name = 'EMP';
commit;
end;

procedure init_rows as
begin
update table_row_counts set row_counts = (select count(*) from emp ) where  table_name = 'EMP';
commit;
end;

procedure reduce_row as
begin
update table_row_counts set row_counts = row_counts - 1 where table_name = 'EMP';
commit;
end;

end;


/