B カスタム空間データ・プロバイダの作成および登録

この付録では、空間データ・プロバイダのサンプル実装を示し、このプロバイダをマップ視覚化コンポーネントで使用するための登録方法について説明します。

完全な実装は、マップ視覚化コンポーネントのweb/demo/spatialproviderディレクトリにあります。実装では次のファイルが使用されます。

  • us_bigcities.xml: プロバイダが解析するサンプルXMLファイル

  • customSpatialProviderSample.java: 空間データ・プロバイダのJava実装

  • spatialprovider.jar: ソース・ファイルcustomSpatialProviderSample.javaのコンパイル済バージョンを含むjarファイル

us_bigcities.xmlファイルには、データ属性、データ・エクステントおよび地物情報を定義するセクションがあり、ジオメトリ(GML形式)および属性値が含まれます。このファイルの内容は次のとおりです。

<?xml version="1.0" standalone="yes"?>
<spatial_data>
 
<data_attributes>
  <attribute name="city" type="string" />
  <attribute name="state_abrv" type="string" />
  <attribute name="pop90" type="double" />
</data_attributes>
 
<data_extents>
   <xmin> -122.49586 </xmin>
   <ymin> 29.45765 </ymin>
   <xmax> -73.943849 </xmax>
   <ymax> 42.3831 </ymax>
</data_extents>
 
<geoFeature>
  <attributes> New York,NY,7322564 </attributes>
  <geometricProperty>
    <Point>
      <coordinates>-73.943849, 40.6698</coordinates>
    </Point>
   </geometricProperty>
 </geoFeature>
 
. . .
</spatial_data>

B.1 空間プロバイダ・クラスの実装

空間プロバイダ・クラス・インタフェースを実装する必要があります。

このプロバイダには、「カスタム・ジオメトリ・テーマ」に示されているクラス・インタフェースを実装する必要があります。例B-1に、提供されているデモ内にある空間プロバイダのコードの抜粋を示します。このサンプル・コードは意図的に簡略化されており、最適化されたものではありません。このプロバイダではどのような空間索引メカニズムも作成されません。

プロバイダのコードを実装したら、コードをコンパイルしてコンパイル済クラスを含むjarファイルを生成します。demoディレクトリのspatialprovider.jarファイルに、このサンプル・コードのコンパイル済バージョンが含まれているので、それを直接使用できます。このjarファイルをマップ視覚化コンポーネントのCLASSPATH定義に指定されているディレクトリ(web/WB-INF/libなど)にコピーします。

例B-1 空間プロバイダ・クラスの実装

package spatialprovider.samples;
 
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.File;
import java.util.ArrayList;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.Vector;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import oracle.mapviewer.share.Field;
import oracle.mapviewer.share.ext.SDataProvider;
import oracle.mapviewer.share.ext.SDataSet;
import oracle.mapviewer.share.ext.SObject;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import oracle.spatial.geometry.JGeometry;
import oracle.spatial.util.GML;
 
public class CustomSpatialProviderSample implements SDataProvider
{
 ...
 
 /**
  * Constructor.
  */
 public CustomSpatialProviderSample()
 {
   ...
 }
 
 /**
  * Returns the initialization parameters for the provider.
  * The "datadir" parameter should be registered in the map visualization component
  * configuration file and can be used to access the data.
  * @return
  */
 public String[] getInitParameterNames()
 {
   return new String[]{ "datadir" };
 }
 
 /**
  * Returns runtime parameter names. Runtime parameters are additional parameters
  * that the provider may use when retrieving the data objects.
  * @return
  */
 public String[] getRuntimeParameterNames()
 {
   return new String[]{ "filename" };
 }
 
 /**
  * Initializes the provider
  * @param params  init properties
  * @return
  */
 public boolean init(Properties params)
 {
   dataDirectory = null;
     if(params == null)
     return true;
     dataDirectory = params.getProperty("datadir");
   if(dataDirectory == null || dataDirectory.trim().length() == 0)
   {
     // try upper case
     dataDirectory = params.getProperty("DATADIR");
     if(dataDirectory == null || dataDirectory.trim().length() == 0)
       System.out.println("FINE: Init properties does not define \"datadir\" parameter.");
   }
       return true;
 }
 
 /**
  * Returns the data set (geometries plus attributes) that intersects the
  * query window. In this sample the data is parsed just once and
  * there is no spatial index for searching. The search is sequential.
  * @param queryWin  search area
  * @param nonSpatialColumns   attribute columns
  * @param params      runtime properties
  * @return
  */
 public SDataSet buildDataSet(Rectangle2D queryWin,
                              String []nonSpatialColumns,
                              Properties params)
 {
   if(!dataParsed)
   {
     dataParsed = parseData(params);
     if(!dataParsed)
       return null;
   }
     if(geometries.size() == 0)
     return null;
 
   SDataSet dataset = new SDataSet();
     boolean fullExtent = isFullExtent(queryWin);
     if(fullExtent)
   {
     for(int i=0;i<geometries.size();i++)
     {
       JGeometry geom = (JGeometry)geometries.get(i);
       SObject obj = new SObject(geom,getGeometryAttributes(nonSpatialColumns,i));
       dataset.addObject(obj);      }
   }
   else
   {
     for(int i=0;i<geometries.size();i++)
     {
       JGeometry geom = (JGeometry)geometries.get(i);
       double []mbr = geom.getMBR();
       if(mbr == null)
         continue;
       Rectangle2D.Double rect = new Rectangle2D.Double(mbr[0],mbr[1],
                                   mbr[2]-mbr[0],
                                   mbr[3]-mbr[1]);
             if(rect.getWidth() == 0. && rect.getHeight() == 0.)
       {
         Point2D.Double pt = new Point2D.Double(mbr[0],mbr[1]);
         if(queryWin.contains(pt))
         {
           SObject obj = new SObject(geom,getGeometryAttributes(nonSpatialColumns,i));
           dataset.addObject(obj);                    }
       }
       else if(queryWin.contains(rect) || queryWin.intersects(rect))
       {
         SObject obj = new SObject(geom,getGeometryAttributes(nonSpatialColumns,i));
         dataset.addObject(obj);
       }
     }        }
     if(dataset.getSize() == 0)
     return null;
       return dataset;
 }
 
 /**
  * Returns the data provider attribute list.
  * @return
  */
 public Field[] getAttributeList(Properties params)
 {
   if(!dataParsed)
   {
     dataParsed = parseData(params);
     if(!dataParsed)
       return null;
   }
     if(attributes.size() == 0)
     return null;
 
   return (Field[])attributes.toArray(new Field[attributes.size()]);
 }
 
 /**
  * Returns the data extents.
  * @return
  */
 public Rectangle2D getDataExtents(Properties params)
 {
   if(!dataParsed)
   {
     dataParsed = parseData(params);
     if(!dataParsed)
       return null;
   }
     if(extents == null || extents.length < 4)
     return null;
   else
     return new Rectangle2D.Double(extents[0],extents[1],
                                   extents[2]-extents[0],
                                   extents[3]-extents[1]);
 }
 
 /**
  * Builds a spatial index for the data. In this sample there is no
  * spatial index. The data is loaded into memory when data is parsed.
  * @return
  */
 public boolean buildSpatialIndex(Properties params)
 {
   return true;
 }
 
}

B.2 マップ視覚化コンポーネントへの空間プロバイダの登録

空間プロバイダをマップ視覚化コンポーネントに登録するには、次の内容をマップ視覚化コンポーネント構成ファイルの空間プロバイダ・セクションに追加し、マップ視覚化コンポーネントを再起動します。

<s_data_provider
  id="xmlProvider"
  class="spatialprovider.samples.CustomSpatialProviderSample"
  >
  <parameters>
    <parameter name="datadir" value="/temp/data" />
  </parameters>
</s_data_provider>

マップ視覚化コンポーネントを再起動すると、空間プロバイダが登録されたことを示すコンソール・メッセージが表示されます。次に例を示します。

2007-10-01 14:30:31.109 NOTIFICATION Spatial Provider xmlProvider has been registered.

B.3 外部空間データのレンダリング

マップ視覚化ンポーネントに付属しているサンプル外部空間データをレンダリングできるようにするには、このデータを指すデータ・ソースを作成します。

例B-2は、動的カスタム・ジオメトリ・テーマを含むXMLリクエストです。

例B-2 外部空間データをレンダリングするマップ・リクエスト

<?xml version="1.0" standalone="yes"?>
<map_request
 title="Custom Geometry Theme"
 datasource="mvdemo"
 width="500"
 height="400"
 bgcolor="#a6caf0"
 antialiase="true"
 format="PNG_STREAM"
>
 <center size="40">
   <geoFeature>
     <geometricProperty typeName="center">
       <Point>
         <coordinates>-90,32</coordinates>
       </Point>
     </geometricProperty>
   </geoFeature>
 </center>
 
 <themes>
   <theme name="custom_theme" >
      <custom_geom_theme
        provider_id="xmlProvider"
        srid="8307"
        render_style="M.CIRCLE"
        label_column="city"
        label_style="T.CITY NAME"
        datasource="mvdemo">
      <parameters>
       <parameter name="filename" value="/lbs/demo/spatialprovider/us_bigcities.xml"/>
      </parameters>
     </custom_geom_theme>
   </theme>
 </themes>
</map_request>

例B-2で、<parameter>要素内のファイル名は/lbs/demo/spatialprovider/us_bigcities.xmlを指しています。このファイル・パスにマップ視覚化コンポーネントからアクセスできない場合、このマップ・リクエストはログ・ファイルに次のようなエラー・メッセージを生成します。

07/09/28 10:26:47 ParseData: Can not access file: /lbs/demo/spatialprovider/us_bigcities.xml
07/09/28 10:26:47 ParseData: File to be parsed: /temp/data\us_bigcities.xml
07/09/28 10:26:47 ParseData: File can not be accessed on provider data directory. Copy files there.

マップ視覚化コンポーネントがファイルを検索する際、まず、元のテーマ定義パラメータを使用してファイルへのアクセスを試行し、これに失敗した場合、次に、マップ視覚化コンポーネント構成ファイルに定義されているデータ・ディクショナリを試します(前述の例のエラー・メッセージ内の/temp/data)。そのため、元のテーマ定義データのパスがマップ視覚化コンポーネントからアクセス不可能である場合、データファイルを構成ファイルに定義されているディレクトリにコピーしてから、マップ・リクエストを発行してください。

マップ視覚化コンポーネントによってデータ・ファイルが検出された場合、例B-2のマップ・リクエストにより、図B-1内のものと類似した画像が生成されます。

図B-1 カスタム・ジオメトリ・テーマおよび外部空間データを使用したマップ画像

図B-1の説明が続きます
図B-1「カスタム・ジオメトリ・テーマおよび外部空間データを使用したマップ画像」の説明