//$Header: /home/deegree/jail/deegreerepository/deegree/src/org/deegree/portal/standard/csw/control/ISO19115RequestFactory.java,v 1.18 2006/11/27 09:07:53 poth Exp $
/*---------------- FILE HEADER ------------------------------------------
This file is part of deegree.
Copyright (C) 2001-2006 by:
Department of Geography, University of Bonn
http://www.giub.uni-bonn.de/deegree/
lat/lon GmbH
http://www.lat-lon.de
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact:
Andreas Poth
lat/lon GmbH
Aennchenstr. 19
53177 Bonn
Germany
E-Mail: poth@lat-lon.de
Prof. Dr. Klaus Greve
Department of Geography
University of Bonn
Meckenheimer Allee 166
53115 Bonn
Germany
E-Mail: greve@giub.uni-bonn.de
---------------------------------------------------------------------------*/
package org.deegree.portal.standard.csw.control;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Properties;
import org.deegree.datatypes.QualifiedName;
import org.deegree.enterprise.control.RPCStruct;
import org.deegree.framework.log.ILogger;
import org.deegree.framework.log.LoggerFactory;
import org.deegree.framework.util.StringTools;
import org.deegree.model.crs.CRSFactory;
import org.deegree.model.crs.CoordinateSystem;
import org.deegree.model.crs.GeoTransformer;
import org.deegree.model.crs.IGeoTransformer;
import org.deegree.model.crs.UnknownCRSException;
import org.deegree.model.filterencoding.Literal;
import org.deegree.model.filterencoding.Operation;
import org.deegree.model.filterencoding.OperationDefines;
import org.deegree.model.filterencoding.PropertyIsCOMPOperation;
import org.deegree.model.filterencoding.PropertyIsLikeOperation;
import org.deegree.model.filterencoding.PropertyIsNullOperation;
import org.deegree.model.filterencoding.PropertyName;
import org.deegree.model.filterencoding.SpatialOperation;
import org.deegree.model.spatialschema.Envelope;
import org.deegree.model.spatialschema.Geometry;
import org.deegree.model.spatialschema.GeometryException;
import org.deegree.model.spatialschema.GeometryFactory;
import org.deegree.portal.standard.csw.CatalogClientException;
/**
* A <code>${type_name}</code> class.<br/>
*
* class for creating a get GetRecord Request against a catalog based on OGC
* Stateless Web Service Catalog Profil and GDI NRW catalog specifications to
* access data metadata (ISO 19115).<p>
* The only public method of the class receives a 'model' represented by a
* <tt>HashMap</tt> that contains the request parameters as name-value-pairs.
* The names corresponds to the form-field-names. For common this will be
* the fields of a HTML-form but it can be any other form (e.g. swing-application)
* </p>
*
* @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
* @author last edited by: $Author: poth $
*
* @version $Revision: 1.18 $, $Date: 2006/11/27 09:07:53 $
*/
public class ISO19115RequestFactory extends CSWRequestFactory {
private static final ILogger LOG = LoggerFactory.getLogger( ISO19115RequestFactory.class );
static final String RPC_SIMPLESEARCH = "RPC_SIMPLESEARCH";
private static final char WILDCARD = '*';
private static final String OUTPUTSCHEMA = "csw:profile";
private RPCStruct struct = null;
private Properties requestElementsProps = new Properties();
public ISO19115RequestFactory() {
try {
InputStream is = ISO19115RequestFactory.class.getResourceAsStream( "ISO19115requestElements.properties" );
this.requestElementsProps.load( is );
} catch ( Exception e ) {
e.printStackTrace();
}
}
/**
* creates a GetRecord request that is conform to the OGC Stateless Web
* Service Catalog Profil and GDI NRW catalog specifications from a RPC struct.
*
* @param struct RPC structure containing the request parameter
* @return GetFeature request as a string
* @throws CatalogClientException
*/
public String createRequest( RPCStruct struct, String resultType )
throws CatalogClientException {
LOG.entering();
this.struct = struct;
boolean isSearchRequest = false;
boolean isOverviewRequest = false;
if ( "HITS".equals( resultType ) || "RESULTS".equals( resultType ) ) {
isSearchRequest = true;
} else if ( resultType == null ) {
isOverviewRequest = true;
}
InputStream is = null;
InputStreamReader ireader = null;
BufferedReader br = null;
StringBuffer sb = null;
String request = null;
if ( isSearchRequest ) {
is = ISO19115RequestFactory.class.getResourceAsStream( "CSWGetRecordsTemplate.xml" );
} else if ( isOverviewRequest ) {
is = ISO19115RequestFactory.class.getResourceAsStream( "CSWGetRecordByIdTemplate.xml" );
}
try {
ireader = new InputStreamReader( is );
br = new BufferedReader( ireader );
sb = new StringBuffer( 50000 );
while ( ( request = br.readLine() ) != null ) {
sb.append( request );
}
request = sb.toString();
br.close();
} catch ( Exception e ) {
e.printStackTrace();
}
if ( isSearchRequest ) {
try {
request = replaceVarsInSearchRequest( request, resultType );
} catch ( UnknownCRSException e ) {
throw new CatalogClientException( e.getMessage(), e );
}
} else if ( isOverviewRequest ) {
request = replaceVarsInOverviewRequest( request );
}
LOG.exiting();
return request;
}
/**
* @param request
* @param resultType
* @return Returns the request, where all variables are replaced by values.
* @throws CatalogClientException
* @throws UnknownCRSException
*/
private String replaceVarsInSearchRequest( String request, String resultType )
throws CatalogClientException, UnknownCRSException {
LOG.entering();
// replace variables from template
String filter = createFilterEncoding();
request = request.replaceFirst( "\\$FILTER", filter );
request = request.replaceFirst( "\\$OUTPUTSCHEMA", OUTPUTSCHEMA );
request = request.replaceFirst( "\\$RESULTTYPE", resultType );
// According to OGC CSW-spec default is 1
String startPos = "1";
if ( struct.getMember( RPC_STARTPOSITION ) != null ) {
startPos = (String) struct.getMember( RPC_STARTPOSITION ).getValue();
}
request = request.replaceFirst( "\\$STARTPOSITION", startPos );
// According to OGC CSW-spec default is 10
String maxRecords = Integer.toString( config.getMaxRecords() );
request = request.replaceFirst( "\\$MAXRECORDS", maxRecords );
String queryType = "csw:dataset"; // dataset, dataseries, service, application
if ( struct.getMember( RPC_TYPENAME ) != null ) {
queryType = (String) struct.getMember( RPC_TYPENAME ).getValue();
}
request = request.replaceFirst( "\\$TYPENAME", queryType );
String elementSet = "brief"; // brief, summary, full
if ( struct.getMember( RPC_ELEMENTSETNAME ) != null ) {
elementSet = (String) struct.getMember( RPC_ELEMENTSETNAME ).getValue();
}
request = request.replaceFirst( "\\$ELEMENTSETNAME", elementSet );
LOG.exiting();
return request;
}
/**
* @param request
* @return Returns the request, where all variables are replaced by values.
* @throws CatalogClientException
*/
private String replaceVarsInOverviewRequest( String request )
throws CatalogClientException {
LOG.entering();
String id;
if ( struct.getMember( Constants.RPC_IDENTIFIER ) != null ) {
id = (String) struct.getMember( Constants.RPC_IDENTIFIER ).getValue();
} else {
throw new CatalogClientException( "Identifier is not set in RPC request." );
}
request = request.replaceFirst( "\\$IDENTIFIER", id );
request = request.replaceFirst( "\\$OUTPUTSCHEMA", OUTPUTSCHEMA );
String elementSet = "full"; // brief, summary, full
if ( struct.getMember( RPC_ELEMENTSETNAME ) != null ) {
elementSet = (String) struct.getMember( RPC_ELEMENTSETNAME ).getValue();
}
request = request.replaceFirst( "\\$ELEMENTSETNAME", elementSet );
LOG.exiting();
return request;
}
/**
* takes RequestModel and builds a String result out of it.
* The result should be OGC FilterEncoding conformant.
*
* @return Returns the fragment for filter encoding.
* @throws CatalogClientException
* @throws UnknownCRSException
*/
private String createFilterEncoding()
throws CatalogClientException, UnknownCRSException {
//Debug.level = Debug.ALL;
LOG.entering();
StringBuffer sb = new StringBuffer( 2000 );
int expCounter = 0;
sb.append( "<csw:Constraint><ogc:Filter>" );
// build filter encoding structure, handle all known fields sequentially
String s = handleFileIdentifier();
if ( ( s != null ) && ( s.length() > 0 ) ) {
expCounter++;
sb.append( s );
}
s = handleParentIdentifier();
if ( ( s != null ) && ( s.length() > 0 ) ) {
expCounter++;
sb.append( s );
}
s = handleSimpleSearch();
if ( ( s != null ) && ( s.length() > 0 ) ) {
expCounter++;
sb.append( s );
}
s = handleTopiccategory();
if ( ( s != null ) && ( s.length() > 0 ) ) {
expCounter++;
sb.append( s );
}
s = handleKeywords();
if ( ( s != null ) && ( s.length() > 0 ) ) {
expCounter++;
sb.append( s );
}
s = handleDate();
if ( ( s != null ) && ( s.length() > 0 ) ) {
expCounter++;
sb.append( s );
}
s = handleBbox();
if ( ( s != null ) && ( s.length() > 0 ) ) {
expCounter++;
sb.append( s );
}
if ( expCounter > 1 ) {
sb.insert( "<ogc:Constraint><ogc:Filter>".length(), "<ogc:And>" );
sb.append( "</ogc:And>" );
}
sb.append( "</ogc:Filter></csw:Constraint>" );
LOG.exiting();
return sb.toString();
}
/**
* Build OGC Filterencoding fragment:
* use <code>CSWRequestmodel</code> field <b>fileIdentifier</b> to create Comparison Operation.
*
* @return Returns the fragment for fileIdentifier.
* May be empty.
*/
private String handleFileIdentifier() {
LOG.entering();
StringBuffer sb = new StringBuffer( 1000 );
String id = null;
if ( struct.getMember( Constants.RPC_IDENTIFIER ) != null ) {
id = (String) struct.getMember( Constants.RPC_IDENTIFIER ).getValue();
}
if ( ( id != null ) && ( id.trim().length() > 0 ) ) {
String cf_props = requestElementsProps.getProperty( Constants.CONF_IDENTIFIER );
String[] cf = cf_props.split( ";" );
sb = new StringBuffer( 1000 );
Operation op1 = createOperation( OperationDefines.PROPERTYISEQUALTO, cf[0], id );
sb.append( op1.toXML() );
}
LOG.exiting();
return sb.toString();
}
/**
* Build OGC Filterencoding fragment:
* use <code>CSWRequestmodel</code> field <b>parentIdentifier</b> to create Comparison Operation.
*
* @return Returns the fragment for parentIdentifier.
* May be empty.
*/
private String handleParentIdentifier() {
LOG.entering();
StringBuffer sb = new StringBuffer( 1000 );
String id = null;
if ( struct.getMember( RPC_DATASERIES ) != null ) {
id = (String) struct.getMember( RPC_DATASERIES ).getValue();
}
if ( ( id != null ) && ( id.trim().length() > 0 ) ) {
String cf_props = requestElementsProps.getProperty( CONF_DATASERIES );
String[] cf = cf_props.split( ";" );
sb = new StringBuffer( 1000 );
Operation op1 = createOperation( OperationDefines.PROPERTYISEQUALTO, cf[0], id );
sb.append( op1.toXML() );
}
LOG.exiting();
return sb.toString();
}
/**
* Spread <code>CSWRequestmodel</code> field <b>terms</b> to several Comparison Operations
* with pre-defined Property names.
*
* @return Returns the fragment for the search string.
* May be empty.
*/
private String handleSimpleSearch() {
LOG.entering();
StringBuffer sb = new StringBuffer( 2000 );
String[] t = null;
if ( struct.getMember( RPC_SIMPLESEARCH ) != null ) {
String s = (String) struct.getMember( RPC_SIMPLESEARCH ).getValue();
t = StringTools.toArray( s, ",;|", true );
}
if ( ( t != null ) && ( t.length > 0 ) ) {
sb.append( "<ogc:Or>" );
for ( int i = 0; i < t.length; i++ ) {
// replace invalid chars
if ( ( t[i] != null ) && ( t[i].length() > 0 ) ) {
t[i] = StringTools.replace( t[i], "'", " ", true );
t[i] = StringTools.replace( t[i], "\"", " ", true );
// determine the way to build FilterEncoding part
String cf_props = requestElementsProps.getProperty( Constants.CONF_SIMPLESEARCH );
String[] cf = cf_props.split( ";" );
for ( int k = 0; k < cf.length; k++ ) {
String strOp = t[i];
if ( ( strOp != null ) && ( strOp.length() > 0 ) ) {
// LOWERCASE SECTION
strOp = strOp.substring( 0, 1 ).toLowerCase() + strOp.substring( 1 );
Operation op = createOperation( OperationDefines.PROPERTYISLIKE, cf[k],
strOp );
sb.append( op.toXML() );
// FIRST LETTER UPPERCASE SECTION
strOp = strOp.substring( 0, 1 ).toUpperCase() + strOp.substring( 1 );
op = createOperation( OperationDefines.PROPERTYISLIKE, cf[k], strOp );
sb.append( op.toXML() );
}
}
}
}
sb.append( "</ogc:Or>" );
}
LOG.exiting();
return sb.toString();
}
/**
* Builds OGC Filterencoding fragment:
* for <code>CSWRequestmodel</code> field <b>topiccategory</b>.
*
* @return Returns the fragment for topiccategory.
* May be null, if no topiccategory is specified.
*/
private String handleTopiccategory() {
LOG.entering();
String tc = null;
if ( struct.getMember( RPC_TOPICCATEGORY ) != null ) {
tc = (String) struct.getMember( RPC_TOPICCATEGORY ).getValue();
}
if ( tc != null && !tc.startsWith( "..." ) && tc.length() > 0 ) {
String cf_props = requestElementsProps.getProperty( Constants.CONF_TOPICCATEGORY );
String[] cf = cf_props.split( ";" );
Operation op1 = createOperation( OperationDefines.PROPERTYISEQUALTO, cf[0], tc );
tc = op1.toXML().toString();
} else {
tc = null;
}
LOG.exiting();
return tc;
}
/**
* Build OGC Filterencoding fragment:
* Split <code>CSWRequestmodel</code> field <b>keywords</b> to one Comparison Operation for
* each keyword.
*
* @return Returns the fragment for keywords.
* May be empty, if no keywords are specified.
*/
private String handleKeywords() {
LOG.entering();
StringBuffer sb = new StringBuffer( 1000 );
String[] tc = null;
if ( struct.getMember( RPC_KEYWORDS ) != null ) {
String s = (String) struct.getMember( RPC_KEYWORDS ).getValue();
tc = StringTools.toArray( s, ",;", true );
}
if ( ( tc != null ) && ( tc.length > 0 ) ) {
String cf_props = requestElementsProps.getProperty( Constants.CONF_KEYWORDS );
String[] cf = cf_props.split( ";" );
sb = new StringBuffer( 1000 );
int i = 0;
for ( i = 0; i < tc.length; i++ ) {
if ( tc[i].trim().length() > 0 ) {
Operation op1 = createOperation( OperationDefines.PROPERTYISEQUALTO, cf[0],
tc[i] );
sb.append( op1.toXML() );
}
}
if ( i > 1 ) {
sb.insert( 0, "<ogc:Or>" );
sb.append( "</ogc:Or>" );
}
}
LOG.exiting();
return sb.toString();
}
/**
* Build OGC Filterencoding fragment:
* use <code>dateFrom</code> and <code>dateTo</code> to create Comparison Operations.
*
* @return Returns the fragment for dates specified in the <code>RPCStruct</code>.
* May be null, if no dates are specified.
*/
private String handleDate() {
LOG.entering();
String s = null;
if ( struct.getMember( Constants.RPC_DATEFROM ) == null
&& struct.getMember( Constants.RPC_DATETO ) == null ) {
LOG.exiting();
return s;
}
// RPC_DATEFROM
String fy = null;
String fm = null;
String fd = null;
if ( struct.getMember( Constants.RPC_DATEFROM ) != null ) {
RPCStruct st = (RPCStruct) struct.getMember( Constants.RPC_DATEFROM ).getValue();
if ( st.getMember( Constants.RPC_YEAR ) != null ) {
fy = st.getMember( Constants.RPC_YEAR ).getValue().toString();
}
if ( st.getMember( Constants.RPC_MONTH ) != null ) {
fm = st.getMember( Constants.RPC_MONTH ).getValue().toString();
}
if ( st.getMember( Constants.RPC_DAY ) != null ) {
fd = st.getMember( Constants.RPC_DAY ).getValue().toString();
}
}
if ( fy == null ) {
fy = "0000";
}
if ( fm == null ) {
fm = "1";
}
if ( Integer.parseInt( fm ) < 10 ) {
fm = "0" + Integer.parseInt( fm );
}
if ( fd == null ) {
fd = "1";
}
if ( Integer.parseInt( fd ) < 10 ) {
fd = "0" + Integer.parseInt( fd );
}
String df = fy + "-" + fm + "-" + fd;
//RPC_DATETO
String ty = null;
String tm = null;
String td = null;
if ( struct.getMember( Constants.RPC_DATETO ) != null ) {
RPCStruct st = (RPCStruct) struct.getMember( Constants.RPC_DATETO ).getValue();
if ( st.getMember( Constants.RPC_YEAR ) != null ) {
ty = st.getMember( Constants.RPC_YEAR ).getValue().toString();
}
if ( st.getMember( Constants.RPC_MONTH ) != null ) {
tm = st.getMember( Constants.RPC_MONTH ).getValue().toString();
}
if ( st.getMember( Constants.RPC_DAY ) != null ) {
td = st.getMember( Constants.RPC_DAY ).getValue().toString();
}
}
if ( ty == null ) {
ty = "9999";
}
if ( tm == null ) {
tm = "12";
}
if ( Integer.parseInt( tm ) < 10 ) {
tm = "0" + Integer.parseInt( tm );
}
if ( td == null ) {
td = "31";
}
if ( Integer.parseInt( td ) < 10 ) {
td = "0" + Integer.parseInt( td );
}
String dt = ty + "-" + tm + "-" + td;
String date_props = requestElementsProps.getProperty( Constants.CONF_DATE );
String[] conf_date = date_props.split( ";" );
if ( ( ty != null ) && ( ty.length() > 0 ) ) {
StringBuffer sb = new StringBuffer( "<ogc:And>" );
Operation op1 = null;
op1 = createOperation( OperationDefines.PROPERTYISGREATERTHANOREQUALTO, conf_date[0],
df );
sb.append( op1.toXML() );
op1 = createOperation( OperationDefines.PROPERTYISLESSTHANOREQUALTO, conf_date[0], dt );
sb.append( op1.toXML() );
sb.append( "</ogc:And>" );
s = sb.toString();
}
LOG.exiting();
return s;
}
/**
* Build OGC Filterencoding fragment:
* use <code>CSWRequestmodel</code> field <b>geographicBox</b> to create Comparison Operation.
*
* @return Returns the fragment for the geographic bounding box.
* May be empty, if no bounding box is specified.
* @throws CatalogClientException
* @throws UnknownCRSException
*/
private String handleBbox()
throws CatalogClientException, UnknownCRSException {
LOG.entering();
StringBuffer sb = new StringBuffer( 1000 );
if ( struct.getMember( Constants.RPC_BBOX ) != null ) {
RPCStruct bboxStruct = (RPCStruct) struct.getMember( Constants.RPC_BBOX ).getValue();
Double minx = (Double) bboxStruct.getMember( Constants.RPC_BBOXMINX ).getValue();
Double miny = (Double) bboxStruct.getMember( Constants.RPC_BBOXMINY ).getValue();
Double maxx = (Double) bboxStruct.getMember( Constants.RPC_BBOXMAXX ).getValue();
Double maxy = (Double) bboxStruct.getMember( Constants.RPC_BBOXMAXY ).getValue();
// FIXME check if srs is correct
CoordinateSystem srs = CRSFactory.create( config.getSrs() );
Envelope bbox = GeometryFactory.createEnvelope( minx.doubleValue(), miny.doubleValue(),
maxx.doubleValue(), maxy.doubleValue(),
srs );
try {
// transform request boundingbox to EPSG:4326 because a ISO 19115
// compliant catalog must store the bbox of an entry like this
IGeoTransformer gt = new GeoTransformer( "EPSG:4326" );
bbox = gt.transform( bbox, config.getSrs() );
} catch ( Exception e ) {
throw new CatalogClientException( e.toString() );
}
Geometry boxGeom = null;
try {
boxGeom = GeometryFactory.createSurface( bbox, srs );
} catch ( GeometryException e ) {
e.printStackTrace();
throw new CatalogClientException( "Cannot create surface from bbox."
+ e.getMessage() );
}
String reProps = requestElementsProps.getProperty( Constants.CONF_GEOGRAPHICBOX );
String[] re = reProps.split( ";" );
if ( boxGeom != null ) {
Operation op1 = createOperation( OperationDefines.BBOX, re[0], boxGeom );
sb.append( op1.toXML() );
}
}
LOG.exiting();
return sb.toString();
}
// /**
// * @param bbox The bounding box to be used as filter condition.
// * @return Returns the GML bounding box snippet.
// */
// private String createGMLBox( Envelope bbox ) {
// StringBuffer sb = new StringBuffer( 1000 );
//
// sb.append( "<gml:Box xmlns:gml=\"http://www.opengis.net/gml\" >" );
// sb.append( "<gml:coord><gml:X>" );
// sb.append( "" + bbox.getMin().getX() );
// sb.append( "</gml:X><gml:Y>" );
// sb.append( "" + bbox.getMin().getY() );
// sb.append( "</gml:Y></gml:coord><gml:coord><gml:X>" );
// sb.append( "" + bbox.getMax().getX() );
// sb.append( "</gml:X><gml:Y>" );
// sb.append( "" + bbox.getMax().getY() );
// sb.append( "</gml:Y></gml:coord></gml:Box>" );
//
// return sb.toString();
// }
/**
* @param opId
* @param property
* @param value
* @return Returns the operation to create.
*/
private Operation createOperation( int opId, String property, Object value ) {
LOG.entering();
Operation op = null;
switch ( opId ) {
case OperationDefines.PROPERTYISEQUALTO:
op = new PropertyIsCOMPOperation( OperationDefines.PROPERTYISEQUALTO,
new PropertyName( new QualifiedName( property ) ),
new Literal( (String) value ) );
break;
case OperationDefines.PROPERTYISLIKE:
char wildCard = WILDCARD;
char singleChar = '?';
char escapeChar = '/';
String lit = wildCard + (String) value + wildCard;
op = new PropertyIsLikeOperation( new PropertyName( new QualifiedName( property ) ),
new Literal( lit ), wildCard, singleChar, escapeChar );
break;
case OperationDefines.PROPERTYISLESSTHANOREQUALTO:
op = new PropertyIsCOMPOperation( OperationDefines.PROPERTYISLESSTHANOREQUALTO,
new PropertyName( new QualifiedName( property ) ),
new Literal( (String) value ) );
break;
case OperationDefines.PROPERTYISGREATERTHANOREQUALTO:
op = new PropertyIsCOMPOperation( OperationDefines.PROPERTYISGREATERTHANOREQUALTO,
new PropertyName( new QualifiedName( property ) ),
new Literal( (String) value ) );
break;
case OperationDefines.BBOX:
op = new SpatialOperation( OperationDefines.BBOX,
new PropertyName( new QualifiedName( property ) ),
(Geometry) value );
break;
case OperationDefines.PROPERTYISNULL:
op = new PropertyIsNullOperation( new PropertyName( new QualifiedName( property ) ) );
break;
default:
op = new PropertyIsCOMPOperation( OperationDefines.PROPERTYISEQUALTO,
new PropertyName( new QualifiedName( property ) ),
new Literal( (String) value ) );
}
LOG.exiting();
return op;
}
}
/* ********************************************************************
Changes to this class. What the people have been up to:
$Log: ISO19115RequestFactory.java,v $
Revision 1.18 2006/11/27 09:07:53 poth
JNI integration of proj4 has been removed. The CRS functionality now will be done by native deegree code.
Revision 1.17 2006/10/12 13:08:58 mays
bugfix: according to OGC CSW-spec default value for startPosition is 1.
Revision 1.16 2006/09/27 16:46:41 poth
transformation method signature changed
Revision 1.15 2006/07/31 11:02:44 mays
move constants from class Constants to the classes where they are needed
Revision 1.14 2006/07/31 09:33:58 mays
move Constants to package control, update imports
Revision 1.13 2006/07/05 10:20:57 mays
remove sysout
Revision 1.12 2006/06/30 08:43:19 mays
clean up code and java doc
Revision 1.11 2006/06/23 13:38:25 mays
add/update csw control files
********************************************************************** */