この付録では、空間データ・プロバイダのサンプル実装を示し、このプロバイダをMapViewerで使用するための登録方法について説明します。完全な実装は、MapViewerの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>
この付録の主な項目は、次のとおりです。
このプロバイダには、2.3.9項に示されているクラス・インタフェースを実装する必要があります。例D-1に、提供されているデモ内にある空間プロバイダのコードの抜粋を示します。このサンプル・コードは意図的に簡略化されており、最適化されたものではありません。このプロバイダではどのような空間索引メカニズムも作成されません。
例D-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 on MapViewer
* 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;
}
}
プロバイダのコードを実装したら、コードをコンパイルしてコンパイル済クラスを含むjarファイルを生成します。demoディレクトリのspatialprovider.jarファイルに、このサンプル・コードのコンパイル済バージョンが含まれているので、それを直接使用できます。このjarファイルをMapViewerのCLASSPATH定義に指定されているディレクトリ(web/WB-INF/libなど)にコピーします。
空間プロバイダをMapViewerに登録するには、MapViewer構成ファイルの空間プロバイダ・セクションに次の内容を追加してから、MapViewerを再起動します。
<s_data_provider
id="xmlProvider"
class="spatialprovider.samples.CustomSpatialProviderSample"
>
<parameters>
<parameter name="datadir" value="/temp/data" />
</parameters>
</s_data_provider>
MapViewerを再起動すると、空間プロバイダが登録されたことを示すコンソール・メッセージが表示されます。例:
2007-10-01 14:30:31.109 NOTIFICATION Spatial Provider xmlProvider has been registered.
MapViewerキット付属のサンプル外部空間データをレンダリングできるようにするには、このデータを指すデータソースを作成します。例D-2は、動的なカスタム・ジオメトリ・テーマを含むXMLリクエストです。
例D-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>
例D-2で、<parameter>要素内のファイル名は/lbs/demo/spatialprovider/us_bigcities.xmlを指しています。このファイル・パスにMapViewerからアクセスできない場合、このマップ・リクエストはログ・ファイルに次のようなエラー・メッセージを生成します。
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.
MapViewerではファイルを検索する際、まず元のテーマ定義のパラメータを使用してファイルにアクセスしようとします。それに失敗すると、MapViewer構成ファイルに定義されているdataディレクトリ(前述の例のエラー・メッセージでは/temp/data)を試行します。そのため、元のテーマ定義データのパスがMapViewerからアクセス不可能である場合、データファイルを構成ファイルに定義されているディレクトリにコピーしてから、マップ・リクエストを発行してください。
MapViewerでデータファイルを見つけられた場合、例D-2のマップ・リクエストでは図D-1に示すような画像が生成されます。