//$Header: /home/deegree/jail/deegreerepository/deegree/src/org/deegree/ogcwebservices/csw/discovery/GetRecords.java,v 1.29 2006/10/10 15:53:59 mschneider Exp $
/*---------------- FILE HEADER ------------------------------------------
This file is part of deegree.
Copyright (C) 2001-2006 by:
EXSE, 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
53115 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.ogcwebservices.csw.discovery;
import java.io.StringReader;
import java.util.Map;
import org.deegree.framework.log.ILogger;
import org.deegree.framework.log.LoggerFactory;
import org.deegree.framework.util.StringTools;
import org.deegree.framework.xml.XMLTools;
import org.deegree.i18n.Messages;
import org.deegree.model.filterencoding.AbstractFilter;
import org.deegree.model.filterencoding.Filter;
import org.deegree.ogcbase.SortProperty;
import org.deegree.ogcwebservices.InvalidParameterValueException;
import org.deegree.ogcwebservices.MissingParameterValueException;
import org.deegree.ogcwebservices.OGCWebServiceException;
import org.deegree.ogcwebservices.csw.AbstractCSWRequest;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* Class representation of a <code>GetRecords</code> request.
* <p>
* The primary means of resource discovery in the general model are the two operations search and
* present. In the HTTP protocol binding these are combined in the form of the mandatory
* <code>GetRecords</code> operation, which does a search.
* <p>
* Parameters specific to the <code>GetRecords</code> -request (omitting REQUEST, SERVICE and
* VERSION): <table border="1">
* <tr>
* <th>Name</th>
* <th>Occurences</th>
* <th>Function</th>
* </tr>
* <tr>
* <td align="center">NAMESPACE</td>
* <td align="center">0|1</td>
* <td>The NAMESPACE parameter is included in the KVP encoding to allow clients to bind any
* namespace prefixes that might be used for qualified names specified in other parameters. For
* example, the typeName parameter may include qualified names of the form namespace prefix:name.
* The value of the NAMESPACE parameter is a comma separated list of character strings of the form
* [namespace prefix:] namespace url. Not including the name namespace prefix binds the specified
* URL to the default namespace. As in XML, only one default namespace may be bound. This parameter
* is not required for the XML encoding since XML includes a mechanism for binding namespace
* prefixes.</td>
* </tr>
* <tr>
* <td align="center">resultType</td>
* <td align="center">0|1 (default: RESULTS)</td>
* <td>The resultType parameter may have the values HITS, RESULTS or VALIDATE and is used to
* indicate whether the catalogue service returns the full result set, the number of hits the query
* found or validates the request. If the resultType parameter is set to HITS, the catalogue service
* shall return an empty <GetRecordsResponse> element with the numberOfRecordsMatched
* attribute set to indicate the number of hits. The other attributes may be set to zero or not
* specified at all if they are optional. If the resultType parameter is set to HITS, then the
* values for the parameters outputFormat and outputSchema (if specified) shall be ignored since no
* actual records will be returned. If the resultType parameter is set to RESULTS, the catalogue
* service should generate a complete response with the <GetRecordsResponse> element
* containing the result set for the request. If the resultType parameter is set to VALIDATE, the
* catalogue service shall validate the request and return an empty <GetRecordsResponse>. All
* mandatory attributes may be given a value of zero and all optional attributes may be omitted. If
* the request does not validate then a service exception shall be raised as describe in Subclause
* 10.3.2.3.</td>
* </tr>
* <tr>
* <td align="center">outputFormat</td>
* <td align="center">0|1 (default: text/xml)</td>
* <td>The outputFormat parameter is used to control the format of the output that is generated in
* response to a GetRecords request. Its value must be a MIME type. The default value, "text/xml",
* means that the output shall be an XML document. All registries shall at least support XML as an
* output format. Other output formats may be supported and may include output formats such as TEXT
* (MIME type text/plain), or HTML (MIME type text/html). The list of output formats that a CSW
* instance provides must be advertised in the Capabilities document. In the case where the output
* format is text/xml, the CSW must generate an XML document that validates against a schema
* document that is specified in the output document via the xsi:schemaLocation attribute defined in
* XML.</td>
* </tr>
* <tr>
* <td align="center">outputSchema</td>
* <td align="center">0|1 (default: OGCCORE)</td>
* <td>The outputSchema parameter is used to indicate the schema of the output that is generated in
* response to a GetRecords request. The default value for this parameter shall be OGCCORE
* indicating that the schema for the core returnable properties (as defined in subclause 6.3.3)
* shall be used. Application profiles may define additional values for outputSchema and may
* redefine the default value but all profiles must support the value OGCCORE. Examples values for
* the outputSchema parameter might be FGDC, or ISO19119, ISO19139 or ANZLIC. The list of supported
* output schemas must be advertised in the capabilities document.</tr>
* <tr>
* <td align="center">startPosition</td>
* <td align="center">0|1 (default: 1)</td>
* <td>The startPosition paramater is used to indicate at which record position the catalogue
* should start generating output. The default value is 1 meaning it starts at the first record in
* the result set.</td>
* </tr>
* <tr>
* <td align="center">maxRecords</td>
* <td align="center">0|1 (default: 10)</td>
* <td>The maxRecords parameter is used to define the maximum number of records that should be
* returned from the result set of a query. If it is not specified, then 10 records shall be
* returned. If its value is set to zero, then the behavior is indentical to setting
* "resultType=HITS" as described above.</td>
* </tr>
* <tr>
* <td align="center">typeName</td>
* <td align="center">1</td>
* <td>The typeName parameter is a list of record type names that define a set of metadata record
* element names which will be constrained in the predicate of the query. In addition, all or some
* of the these names may be specified in the query to define which metadata record elements the
* query should present in the response to the GetRecords operation.</td>
* </tr>
* <tr>
* <td align="center">ElementSetName / ElementName</td>
* <td align="center">* (default: 10)</td>
* <td>The ElementName parameter is used to specify one or more metadata record elements that the
* query should present in the response to the a GetRecords operation. Well known sets of element
* may be named, in which case the ElementSetName parameter may be used (e.g.brief, summary or
* full). If neither parameter is specified, then a CSW shall present all metadata record elements.
* As mentioned above, if the outputFormat parameter is set to text/xml, then the response to the
* GetRecords operation shall validate against a schema document that is referenced in the response
* using the xmlns attributes. If the set of metadata record elements that the client specifies in
* the query in insufficient to generate a valid XML response document, a CSW may augment the list
* of elements presented to the client in order to be able to generate a valid document. Thus a
* client application should expect to receive more than the requested elements if the output format
* is set to XML. </td>
* </tr>
* <tr>
* <td align="center">CONSTRAINTLANGUAGE / Constraint</td>
* <td align="center">0|1</td>
* <td>Each request encoding (XML and KVP) has a specific mechanism for specifying the predicate
* language that will be used to constrain a query. In the XML encoding, the element
* <Constraint> is used to define the query predicate. The root element of the content of the
* <Constraint> element defines the predicate language that is being used. Two possible root
* elements are <ogc:Filter> for the OGC XML filter encoding, and <csw:CqlText> for a
* common query language string. An example predicate specification in the XML encoding is:
*
* <Constraint> <CqlText>prop1!=10</CqlText> </Constraint>
*
* In the KVP encoding, the parameter CONSTRAINTLANGUAGE is used to specify the predicate language
* being used. The Constraint parameter is used to specify the actual predicate. For example, to
* specify a CQL predicate, the following parameters would be set in the KVP encoding: <br>
*
* ...CONSTRAINTLANGUAGE=CQL_TEXT&CONSTRAINT="prop1!=10"...
*
* </td>
* </tr>
* <tr>
* <td align="center">SortBy</td>
* <td align="center">0|1</td>
* <td>The result set may be sorted by specifying one or more metadata record elements upon which
* to sort. In KVP encoding, the SORTBY parameter is used to specify the list of sort elements. The
* value for the SORTBY parameter is a comma-separated list of metadata record element names upon
* which to sort the result set. The format for each element in the list shall be either element
* name:A indicating that the element values should be sorted in ascending order or element name:D
* indicating that the element values should be sorted in descending order. For XML encoded
* requests, the <ogc:SortBy> element is used to specify a list of sort metadata record
* elements. The attribute sortOrder is used to specify the sort order for each element. Valid
* values for the sortOrder attribute are ASC indicating an ascending sort and DESC indicating a
* descending sort.</td>
* </tr>
* <tr>
* <td align="center">DistributedSearch / hopCount</td>
* <td align="center">0|1 (default: FALSE)</td>
* <td>The DistributedSearch parameter may be used to indicate that the query should be
* distributed. The default query behaviour, if the DistributedSearch parameter is set to FALSE (or
* is not specified at all), is to execute the query on the local server. In the XML encoding, if
* the <DistributedSearch> element is not specified then the query is executed on the local
* server. <br>
* <br>
* The hopCount parameter controls the distributed query behaviour by limiting the maximum number of
* message hops before the search is terminated. Each catalogue decrements this value by one when
* the request is received and does not propagate the request if the hopCount=0.</td>
* </tr>
* <tr>
* <td align="center">ResponseHandler</td>
* <td align="center">0|1</td>
* <td>The ResponseHandler parameter is a flag that indicates how the GetRecords operation should
* be processed by a CSW. If the parameter is not present, then the GetRecords operation is
* processed synchronously meaning that the client sends the GetRecords request to a CSW and waits
* to receive a valid response or exception message. The CSW immediately processes the GetRecords
* request while the client waits for a response. The problem with this mode of operation is that
* the client may timeout waiting for the CSW to process the request. If the ResponseHandler
* parameter is present, the GetRecords operation is processed asynchronously. In this case, the CSW
* responds immediately to a client's request with an acknowledgment message that tells the client
* that the request has been received and validated, and notification of completion will be sent to
* the URI specified as the value of the ResponseHandler parameter.</td>
* </tr>
* </table>
*
* @since 2.0
* @author <a href="mailto:mschneider@lat-lon.de">Markus Schneider </a>
* @version $Revision: 1.29 $
*
*
* @author <a href="mailto:poth@lat-lon.de">Andreas Poth </a>
* @author <a href="mailto:tfr@users.sourceforge.net">Torsten Friebe </a>
* @author <a href="mailto:mschneider@lat-lon.de">Markus Schneider </a>
*
* @author last edited by: $Author: mschneider $
*
* @version 2.0, $Revision: 1.29 $, $Date: 2006/10/10 15:53:59 $
*/
public class GetRecords extends AbstractCSWRequest {
private static final long serialVersionUID = 2796229558893029054L;
private static final ILogger LOG = LoggerFactory.getLogger( GetRecords.class );
public static enum RESULT_TYPE {
HITS, VALIDATE, RESULTS
};
public static String RESULT_TYPE_STRING_HITS = "HITS";
public static String RESULT_TYPE_STRING_VALIDATE = "VALIDATE";
public static String RESULT_TYPE_STRING_RESULTS = "RESULTS";
private RESULT_TYPE resultType = RESULT_TYPE.RESULTS;
// keys are Strings (namespace prefix or "" for default namespace), values
// are URIs
private Map namespace;
private String outputFormat;
private String outputSchema;
private int startPosition;
private int maxRecords;
private int hopCount;
private String[] responseHandlers;
private Query[] queries;
/**
* creates a GetRecords request from the XML fragment passed. The passed element must be valid
* against the OGC CSW 2.0 GetRecords schema.
*
* TODO respect namespaces (use QualifiedNames) for type names
*
* @param id
* unique ID of the request
* @param root
* root element of the GetRecors request
* @return
*/
public static GetRecords create( String id, Element root )
throws MissingParameterValueException, InvalidParameterValueException,
OGCWebServiceException {
GetRecordsDocument document = new GetRecordsDocument();
document.setRootElement( root );
GetRecords ogcRequest = document.parse( id );
return ogcRequest;
}
/**
* Creates a new <code>GetRecords</code> instance from the values stored in the submitted Map.
* Keys (parameter names) in the Map must be uppercase.
*
* @TODO evaluate vendorSpecificParameter
*
* @param kvp
* Map containing the parameters
* @exception InvalidParameterValueException
* @exception MissingParameterValueException
*/
public static GetRecords create( Map kvp )
throws InvalidParameterValueException, MissingParameterValueException {
String id = null;
String version = "2.0.0";
Map vendorSpecificParameters = null;
Map namespaceMappings = null;
RESULT_TYPE resultType = RESULT_TYPE.HITS;
String outputFormat = "text/xml";
String outputSchema = "OGCCORE";
int startPosition = 1;
int maxRecords = 10;
int hopCount = 2;
String[] responseHandlers = null;
Query[] queries = null;
id = getParam( "ID", kvp, "" );
LOG.logDebug( "GetRecordRequest id=" + id );
version = getRequiredParam( "VERSION", kvp );
// extract namespace mappings
namespaceMappings = getNSMappings( getParam( "NAMESPACE", kvp, null ) );
String resultTypeString = getParam( "RESULTTYPE", kvp, RESULT_TYPE_STRING_RESULTS );
if ( RESULT_TYPE_STRING_HITS.equalsIgnoreCase( resultTypeString ) ) {
resultType = RESULT_TYPE.HITS;
} else if ( RESULT_TYPE_STRING_RESULTS.equalsIgnoreCase( resultTypeString ) ) {
resultType = RESULT_TYPE.RESULTS;
} else if ( RESULT_TYPE_STRING_VALIDATE.equalsIgnoreCase( resultTypeString ) ) {
resultType = RESULT_TYPE.VALIDATE;
} else {
String msg = "Value '" + resultTypeString
+ "' for parameter 'resultType' is invalid. Valid values are '"
+ RESULT_TYPE_STRING_HITS + "', '" + RESULT_TYPE_STRING_RESULTS
+ "' and '" + RESULT_TYPE_STRING_VALIDATE + "'.";
throw new InvalidParameterValueException( msg );
}
outputFormat = getParam( "OUTPUTFORMAT", kvp, "text/xml" );
outputSchema = getParam( "OUTPUTSCHEMA", kvp, "OGCCORE" );
startPosition = getParamAsInt( "STARTPOSITION", kvp, 1 );
if ( startPosition < 1 ) {
String msg = Messages.getMessage("CSW_INVALID_STARTPOSITION", startPosition);
throw new InvalidParameterValueException (msg);
}
maxRecords = getParamAsInt( "MAXRECORDS", kvp, 10 );
// build Filter object (from CONSTRAINT parameter)
Filter constraint = null;
String constraintLanguage = getParam( "CONSTRAINTLANGUAGE", kvp, "FILTER" );
if ( !constraintLanguage.equals( "FILTER" ) ) {
String msg = "Value '" + constraintLanguage
+ "'for Parameter CONSTRAINTLANGUAGE is invalid: "
+ "Only 'FILTER' is supported.";
throw new InvalidParameterValueException( msg );
}
String constraintString = (String) kvp.get( "CONSTRAINT" );
if ( constraintString != null ) {
try {
Document doc = XMLTools.parse( new StringReader( constraintString ) );
Element element = doc.getDocumentElement();
constraint = AbstractFilter.buildFromDOM( element );
} catch ( Exception e ) {
String msg = "An error occured when parsing the 'CONSTRAINT' parameter "
+ "Filter expression: " + e.getMessage();
throw new InvalidParameterValueException( msg );
}
}
SortProperty[] sortProperties = SortProperty.create( getParam( "SORTBY", kvp, null ) );
String elementSetName = (String) kvp.get( "ELEMENTSETNAME" );
String[] elementNames = null;
if ( elementSetName == null ) {
String elementNameString = (String) kvp.get( "ELEMENTNAME" );
if ( elementNameString != null ) {
elementNames = StringTools.toArray( elementNameString, ",", false );
if ( elementNames.length == 0 ) {
elementNames = null;
}
}
}
if ( elementSetName == null && elementNames == null ) {
elementSetName = "Full";
}
// build one Query object for each specified typeName
String tmp = getRequiredParam( "TYPENAMES", kvp );
String[] typeNames = StringTools.toArray( tmp, ",", false );
if ( typeNames.length == 0 ) {
throw new MissingParameterValueException( "Mandatory parameter 'TYPENAMES' is missing!" );
}
queries = new Query[typeNames.length];
for ( int i = 0; i < typeNames.length; i++ ) {
queries[i] = new Query( elementSetName, elementNames, constraint, sortProperties,
typeNames );
}
// find out if the query should be performed locally or in a distributed
// fashion
hopCount = -1;
String distributedSearch = getParam( "DISTRIBUTEDSEARCH", kvp, "false" );
if ( distributedSearch.equalsIgnoreCase( "true" ) ) {
hopCount = getParamAsInt( "HOPCOUNT", kvp, 2 );
}
return new GetRecords( id, version, vendorSpecificParameters, namespaceMappings,
resultType, outputFormat, outputSchema, startPosition, maxRecords,
hopCount, responseHandlers, queries );
}
/**
* Creates a new <code>GetRecords</code> instance.
*
* @param id
* @param version
* @param vendorSpecificParameters
* @param namespace
* @param resultType
* @param outputFormat
* @param outputSchema
* @param startPosition
* @param maxRecords
* @param hopCount
* @param responseHandlers
* @param queries
*/
GetRecords( String id, String version, Map vendorSpecificParameters, Map namespace,
RESULT_TYPE resultType, String outputFormat, String outputSchema,
int startPosition, int maxRecords, int hopCount, String[] responseHandlers,
Query[] queries ) {
super( version, id, vendorSpecificParameters );
this.namespace = namespace;
this.resultType = resultType;
this.outputFormat = outputFormat;
this.outputSchema = outputSchema;
this.startPosition = startPosition;
this.maxRecords = maxRecords;
this.hopCount = hopCount;
this.responseHandlers = responseHandlers;
this.queries = queries;
}
/**
* Used to specify a namespace and its prefix. Format must be [ <prefix>:] <url>. If the prefix
* is not specified then this is the default namespace
* <p>
* Zero or one (Optional) ; Include value for each distinct namespace used by all qualified
* names in the request. If not included, all qualified names are in default namespace
* <p>
* The NAMESPACE parameter is included in the KVP encoding to allow clients to bind any
* namespace prefixes that might be used for qualified names specified in other parameters. For
* example, the typeName parameter may include qualified names of the form namespace
* prefix:name.
* <p>
* The value of the NAMESPACE parameter is separated list of character strings of the form
* [namespace prefix:]namespace url. Not including the name namespace prefix binds the specified
* URL to the default namespace. As in XML, only one default namespace may be bound.
*
*/
public Map getNamespace() {
return this.namespace;
}
/**
* The resultType parameter may have the values HITS, RESULTS or VALIDATE and is used to
* indicate whether the catalogue service returns the full result set, the number of hits the
* query found or validates the request.
* <p>
* If the resultType parameter is set to HITS, the catalogue service shall return an empty
* <GetRecordsResponse>element with the numberOfRecordsMatched attribute set to indicate
* the number of hits. The other attributes may be set to zero or not specified at all if they
* are optional.
* <p>
* If the resultType parameter is set to HITS, then the values for the parameters outputFormat
* and outputSchema (if specified) shall be ignored since no actual records will be returned
* <p>
* If the resultType parameter is set to RESULTS, the catalogue service should generate a
* complete response with the <GetRecordsResponse>element containing the result set for
* the request
* <p>
* If the resultType parameter is set to VALIDATE, the catalogue service shall validate the
* request and return an empty <GetRecordsResponse>. All mandatory attributes may be given
* a value of zero and all optional attributes may be omitted. If the request does not validate
* then a service exception shall be raised
*
*/
public RESULT_TYPE getResultType() {
return this.resultType;
}
/**
* The resultType parameter may have the values HITS, RESULTS or VALIDATE and is used to
* indicate whether the catalogue service returns the full result set, the number of hits the
* query found or validates the request.
* <p>
* If the resultType parameter is set to HITS, the catalogue service shall return an empty
* <GetRecordsResponse>element with the numberOfRecordsMatched attribute set to indicate
* the number of hits. The other attributes may be set to zero or not specified at all if they
* are optional.
* <p>
* If the resultType parameter is set to HITS, then the values for the parameters outputFormat
* and outputSchema (if specified) shall be ignored since no actual records will be returned
* <p>
* If the resultType parameter is set to RESULTS, the catalogue service should generate a
* complete response with the <GetRecordsResponse>element containing the result set for
* the request
* <p>
* If the resultType parameter is set to VALIDATE, the catalogue service shall validate the
* request and return an empty <GetRecordsResponse>. All mandatory attributes may be given
* a value of zero and all optional attributes may be omitted. If the request does not validate
* then a service exception shall be raised
*
*/
public String getResultTypeAsString() {
String resultTypeString = null;
switch ( this.resultType ) {
case HITS: {
resultTypeString = RESULT_TYPE_STRING_HITS;
break;
}
case RESULTS: {
resultTypeString = RESULT_TYPE_STRING_RESULTS;
break;
}
case VALIDATE: {
resultTypeString = RESULT_TYPE_STRING_VALIDATE;
break;
}
}
return resultTypeString;
}
/**
* sets the resultType of a request. This may be useful to perform a request first
* with resultType = HITS to determine the total number of records matching a query
* and afterwards performing the same request with resultType = RESULTS (and maxRecords
* < number of matched records).
* @param resultType
*/
public void setResultType( RESULT_TYPE resultType ) {
this.resultType = resultType;
}
/**
* returns <= 0 if no distributed search shall be performed. otherwise the recursion depht is
* returned.
* <p>
* The hopCount parameter controls the distributed query behaviour by limiting the maximum
* number of message hops before the search is terminated. Each catalogue decrements this value
* by one when the request is received and does not propagate the request if the hopCount=0
*
*/
public int getHopCount() {
return this.hopCount;
}
/**
* Value is Mime type;The only value that must be supported is text/xml. Other suppored values
* may include text/html and text/plain
* <p>
* The outputFormat parameter is used to control the format of the output that is generated in
* response to a GetRecords request. Its value must be a MIME type. The default value,
* "text/xml", means that the output shall be an XML document. All registries shall at least
* support XML as an output format. Other output formats may be supported and may include output
* formats such as TEXT (MIME type text/plain), or HTML (MIME type text/html). The list of
* output formats that a CSW instance provides must be advertised in the Capabilities document
* <p>
* In the case where the output format is text/xml, the CSW must generate an XML document that
* validates against a schema document that is specified in the output document via the
* xsi:schemaLocation attribute defined in XML
*
*/
public String getOutputFormat() {
return this.outputFormat;
}
/**
* The outputSchema parameter is used to indicate the schema of the output that is generated in
* response to a GetRecords request. The default value for this parameter shall be OGCCORE
* indicating that the schema for the core returnable properties shall be used. Application
* profiles may define additional values for outputSchema and may redefine the default value but
* all profiles must support the value OGCCORE
* <p>
* Examples values for the outputSchema parameter might be FGDC, or ISO19119, ISO19139 or
* ANZLIC. The list of supported output schemas must be advertised in the capabilities document
*
*/
public String getOutputSchema() {
return this.outputSchema;
}
/**
* number of the first returned dataset. Zero or one (Optional)Default value is 1. If
* startPosition > the number of datasets satisfying the constraint, no dataset will be returned
*
*/
public int getStartPosition() {
return this.startPosition;
}
/**
* The maxRecords parameter is used to define the maximum number of records that should be
* returned from the result set of a query. If it is not specified, then 10 records shall be
* returned. If its value is set to zero, then the behavior is indentical to setting
* "resultType=HITS"
*
*/
public int getMaxRecords() {
return this.maxRecords;
}
/**
*
*/
public String[] getResponseHandlers() {
return responseHandlers;
}
/**
*
*/
public Query[] getQueries() {
return queries;
}
}
/* ********************************************************************
Changes to this class. What the people have been up to:
$Log: GetRecords.java,v $
Revision 1.29 2006/10/10 15:53:59 mschneider
Added handling of startPosition.
Revision 1.28 2006/08/18 12:30:09 poth
code cleaned
Revision 1.27 2006/07/10 20:57:05 mschneider
Fixed footer. Indentation.
********************************************************************** */