Index: /FCSSimpleEndpoint/trunk/pom.xml
===================================================================
--- /FCSSimpleEndpoint/trunk/pom.xml	(revision 5545)
+++ /FCSSimpleEndpoint/trunk/pom.xml	(revision 5546)
@@ -4,5 +4,5 @@
     <groupId>eu.clarin.sru.fcs</groupId>
     <artifactId>fcs-simple-endpoint</artifactId>
-    <version>2.0-SNAPSHOT</version>
+    <version>1.3.0-SNAPSHOT</version>
     <packaging>jar</packaging>
     <name>A simple CLARIN FCS endpoint</name>
@@ -18,5 +18,5 @@
         <maven.compiler.target>1.6</maven.compiler.target>
         <!-- versions of common dependencies -->
-        <slf4j.version>1.7.2</slf4j.version>
+        <slf4j.version>1.7.7</slf4j.version>
     </properties>
 
@@ -45,4 +45,15 @@
             <artifactId>woodstox-core-lgpl</artifactId>
             <version>4.1.3</version>
+			<exclusions>
+				<!-- StAX comes with Java 1.6 -->
+				<exclusion>
+					<artifactId>stax-api</artifactId>
+					<groupId>javax.xml.stream</groupId>
+				</exclusion>
+				<exclusion>
+					<artifactId>stax-api</artifactId>
+					<groupId>stax</groupId>
+				</exclusion>
+			</exclusions>
         </dependency> 
     </dependencies>
Index: /FCSSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/DataView.java
===================================================================
--- /FCSSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/DataView.java	(revision 5545)
+++ /FCSSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/DataView.java	(revision 5546)
@@ -1,72 +1,86 @@
 package eu.clarin.sru.server.fcs;
 
+/**
+ * This class is used to hold information about a data view that is implemented
+ * by the endpoint.
+ */
 public class DataView {
+    /**
+     * Enumeration to indicate the delivery policy of a data view.
+     */
+    public enum DeliveryPolicy {
+        /**
+         * The data view is sent automatically  by the endpoint.
+         */
+        SEND_BY_DEFAULT,
+        /**
+         * A client must explicitly request the endpoint.
+         */
+        NEED_TO_REQUEST;
+    } // enum PayloadDelivery
+    private final String identifier;
+    private final String mimeType;
+    private final DeliveryPolicy deliveryPolicy;
 
-	public enum PayloadDelivery {
-		SEND_BY_DEFAULT, NEED_TO_REQUEST;
-		
-		@Override
-		public String toString(){
-			String str = super.toString().toLowerCase();
-			return str.replace("_", "-");
-		}
-	}
 
-	public enum PayloadDisposition {
-		INLINE, REFERENCE;
-		
-		@Override
-		public String toString(){
-			return super.toString().toLowerCase();
-		}
-	}
-	
-	private String description;
-	private String mimeType;
-	private String payloadDisposition;
-	private String payloadDelivery;
-	private String shortIdentifier;
-	
-	public DataView() {	}
-	public DataView(String description, String mimeType, 
-			PayloadDisposition payloadDisposition, PayloadDelivery payloadDelivery, 
-			String shortId){
-		this.description = description;
-		this.mimeType = mimeType;
-		this.payloadDisposition = payloadDisposition.toString();
-		this.payloadDelivery = payloadDelivery.toString();
-		this.shortIdentifier = shortId;		
-	}
-	
-	
-	public String getDescription() {
-		return description;
-	}
-	public void setDescription(String description) {
-		this.description = description;
-	}
-	public String getMimeType() {
-		return mimeType;
-	}
-	public void setMimeType(String mimeType) {
-		this.mimeType = mimeType;
-	}
-	public String getPayloadDisposition() {
-		return payloadDisposition;
-	}
-	public void setPayloadDisposition(String payloadDisposition) {
-		this.payloadDisposition = payloadDisposition;
-	}
-	public String getPayloadDelivery() {
-		return payloadDelivery;
-	}
-	public void setPayloadDelivery(String payloadDelivery) {
-		this.payloadDelivery = payloadDelivery;
-	}
-	public String getShortIdentifier() {
-		return shortIdentifier;
-	}
-	public void setShortIdentifier(String shortIdentifier) {
-		this.shortIdentifier = shortIdentifier;
-	}
-}
+    /**
+     * Constructor.
+     *
+     * @param identifier
+     *            a unique short identifier for the data view
+     * @param mimeType
+     *            the MIME type of the data view
+     * @param deliveryPolicy
+     *            the delivery policy for this data view
+     */
+    public DataView(String identifier, String mimeType,
+            DeliveryPolicy deliveryPolicy) {
+        if (identifier == null) {
+            throw new NullPointerException("identifier == null");
+        }
+        if (identifier.isEmpty()) {
+            throw new IllegalArgumentException("identifier is empty");
+        }
+        this.identifier = identifier;
+
+        if (mimeType == null) {
+            throw new NullPointerException("mimeType == null");
+        }
+        if (mimeType.isEmpty()) {
+            throw new IllegalArgumentException("mimeType is empty");
+        }
+        this.mimeType = mimeType;
+
+        if (deliveryPolicy == null) {
+            throw new NullPointerException("deliveryPolicy == null");
+        }
+        this.deliveryPolicy = deliveryPolicy;
+    }
+
+
+    public String getIdentifier() {
+        return identifier;
+    }
+
+
+    public String getMimeType() {
+        return mimeType;
+    }
+
+
+    public DeliveryPolicy getDeliveryPolicy() {
+        return deliveryPolicy;
+    }
+
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(getClass().getSimpleName());
+        sb.append("[");
+        sb.append("identifier=").append(identifier);
+        sb.append(", mimeType=").append(mimeType);
+        sb.append("]");
+        return sb.toString();
+    }
+} // class DataView
Index: /FCSSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/EndpointDescription.java
===================================================================
--- /FCSSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/EndpointDescription.java	(revision 5546)
+++ /FCSSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/EndpointDescription.java	(revision 5546)
@@ -0,0 +1,78 @@
+package eu.clarin.sru.server.fcs;
+
+import java.net.URI;
+import java.util.List;
+
+import eu.clarin.sru.server.SRUException;
+
+
+/**
+ * An interface for abstracting resource endpoint descriptions. This interface
+ * allows you to provide a version of a endpoint description tailored to your
+ * environment.
+ * <p>
+ * The implementation of this interface <em>must</em> be thread-safe.
+ * </p>
+ */
+public interface EndpointDescription {
+    /**
+     * Constant for a (synthetic) persistent identifier identifying the top-most
+     * (= root) resources in the resource inventory.
+     */
+    public static final String PID_ROOT = "root";
+
+    /**
+     * Destroy the resource info inventory. Use this method for any cleanup the
+     * resource info inventory needs to perform upon termination, i.e. closing
+     * of persistent database connections, etc.
+     */
+    public void destroy();
+
+
+    /**
+     * Get the list of capabilities supported by this endpoint. The list
+     * contains the appropriate URIs defined by the CLARIN-FCS specification to
+     * indicate support for certain capabilities. This list <em>must</em> always
+     * contain at least
+     * <code>http://clarin.eu/fcs/capability/basic-search</code> for the
+     * <em>Basic Search</em> capability.
+     * <p>
+     * The implementation of this method <em>must</em> be thread-safe.
+     * </p>
+     *
+     * @return the list of capabilities supported by this endpoint
+     */
+    public List<URI> getCapabilities();
+
+
+    /**
+     * Get the list of data views supported by this endpoint. This list
+     * <em>must</em> always contain an entry for the
+     * <em>Generic Hits (HITS)</em> data view.
+     * <p>
+     * The implementation of this method <em>must</em> be thread-safe.
+     * </p>
+     *
+     * @return the list of data views supported by this endpoint
+     */
+    public List<DataView> getSupportedDataViews();
+
+
+    /**
+     * Get a list of all resources sub-ordinate to a resource identified by a
+     * given persistent identifier.
+     * <p>
+     * The implementation of this method <em>must</em> be thread-safe.
+     * </p>
+     *
+     * @param pid
+     *            the persistent identifier of the superior resource
+     * @return a list of all sub-ordinate ResourceInfo or <code>null</code> if
+     *         not applicable
+     * @throws SRUException
+     *             if an error occurred
+     */
+    public List<ResourceInfo> getResourceList(String pid)
+            throws SRUException;
+
+} // interface EndpointDescription
Index: SSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/EndpointDescriptionWriter.java
===================================================================
--- /FCSSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/EndpointDescriptionWriter.java	(revision 5545)
+++ 	(revision )
@@ -1,67 +1,0 @@
-package eu.clarin.sru.server.fcs;
-
-import java.util.List;
-
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamWriter;
-
-public class EndpointDescriptionWriter {
-		
-	public static final String NAMESPACE = "http://clarin.eu/fcs/endpoint-description";
-	public static final String PREFIX = "ed";
-	public static final int VERSION = 1;
-		
-	public static void writeEndpointDescription(XMLStreamWriter writer, 
-			List<String> capabilities, List<DataView> supportedDataViews, 
-			List<ResourceInfo> resourceInfoList) 
-			throws XMLStreamException{
-		
-		if (writer == null) {
-            throw new NullPointerException("writer == null");
-        }
-		
-        writer.writeStartElement(PREFIX, "EndpointDescription", NAMESPACE);
-        writer.writeNamespace(PREFIX, NAMESPACE);
-        writer.writeAttribute("version", String.valueOf(VERSION));
-        writeCapabilities(writer,capabilities);
-        writeSupportedDataViews(writer,supportedDataViews);
-        ResourceInfoWriter.writeFullResourceInfo(writer,PREFIX, resourceInfoList);
-        writer.writeEndElement();
-	}
-	
-	private static void writeCapabilities(XMLStreamWriter writer, 
-			List<String> capabilities) throws XMLStreamException{
-		
-		if (writer == null) {
-            throw new NullPointerException("writer == null");
-        }
-		
-        writer.writeStartElement(PREFIX, "Capabilities", NAMESPACE);
-		
-		for (String c : capabilities){
-	        writer.writeStartElement(PREFIX, "Capability", NAMESPACE);
-	        writer.writeCharacters(c);
-		    writer.writeEndElement();
-		}
-		writer.writeEndElement();		
-	}
-	
-	private static void writeSupportedDataViews(XMLStreamWriter writer,
-			List<DataView> supportedDataViews) throws XMLStreamException {
-		
-		if (writer == null) {
-            throw new NullPointerException("writer == null");
-        }
-		
-        writer.writeStartElement(PREFIX, "SupportedDataViews", NAMESPACE);
-		
-		for (DataView dv : supportedDataViews) {
-	        writer.writeStartElement(PREFIX, "SupportedDataView", NAMESPACE);
-	        writer.writeAttribute("id", dv.getShortIdentifier());
-	        writer.writeAttribute("delivery-policy", dv.getPayloadDelivery());
-	        writer.writeCharacters(dv.getMimeType());
-	        writer.writeEndElement();
-		}
-		writer.writeEndElement();
-	}	
-}
Index: /FCSSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/ResourceInfo.java
===================================================================
--- /FCSSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/ResourceInfo.java	(revision 5545)
+++ /FCSSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/ResourceInfo.java	(revision 5546)
@@ -9,18 +9,16 @@
  * This class implements a resource info record, which provides supplementary
  * information about a resource that is available at the endpoint.
- * 
- * @see ResourceInfoInventory
+ *
+ * @see EndpointDescription
  */
 public class ResourceInfo {
     private final String pid;
-    @Deprecated
-    private final int resourceCount;
     private final Map<String, String> title;
     private final Map<String, String> description;
     private final String landingPageURI;
     private final List<String> languages;
-    private List<String> availableDataViews;
-    private List<ResourceInfo> subResources;
-    
+    private final List<DataView> availableDataViews;
+    private final List<ResourceInfo> subResources;
+
 
     /**
@@ -29,7 +27,4 @@
      * @param pid
      *            the persistent identifier of the resource
-     * @param resourceCount
-     *            the number of items within the resource or <code>-1</code> if
-     *            not applicable
      * @param title
      *            the title of the resource represented as a map with pairs of
@@ -45,17 +40,19 @@
      *            the languages represented within this resource represented as
      *            a list of ISO-632-3 three letter language codes
+     * @param availableDataViews
+     *            the list of available data views for this resource
      * @param subResources
      *            a list of resource sub-ordinate to this resource or
      *            <code>null</code> if not applicable
      */
-    public ResourceInfo(String pid, int resourceCount,
-            Map<String, String> title, Map<String, String> description,
-            String landingPageURI, List<String> languages,
+    public ResourceInfo(String pid, Map<String, String> title,
+            Map<String, String> description, String landingPageURI,
+            List<String> languages, List<DataView> availableDataViews,
             List<ResourceInfo> subResources) {
         if (pid == null) {
-            throw new NullPointerException("id == null");
+            throw new NullPointerException("pid == null");
         }
         this.pid = pid;
-        this.resourceCount = (resourceCount > 0) ? resourceCount : -1;
+
         if (title == null) {
             throw new NullPointerException("title == null");
@@ -70,4 +67,5 @@
             this.description = null;
         }
+
         this.landingPageURI = landingPageURI;
         if (languages == null) {
@@ -78,28 +76,18 @@
         }
         this.languages = languages;
-        
+
+        if (availableDataViews == null) {
+            throw new IllegalArgumentException("availableDataViews == null");
+        }
+        this.availableDataViews =
+                Collections.unmodifiableList(availableDataViews);
+
         if ((subResources != null) && !subResources.isEmpty()) {
             this.subResources = Collections.unmodifiableList(subResources);
         } else {
             this.subResources = null;
-        }        
+        }
     }
 
-    public ResourceInfo(String pid, int resourceCount,
-            Map<String, String> title, Map<String, String> description,
-            String landingPageURI, List<String> languages,
-            List<String> availableDataViews,
-            List<ResourceInfo> subResources) {
-    	this(pid,resourceCount, title, description, landingPageURI, languages, subResources);
-    	
-    	if (availableDataViews == null){
-        	throw new IllegalArgumentException("available data views == null");
-        }
-        if (availableDataViews.isEmpty()){
-        	throw new IllegalArgumentException("available data views are empty");
-        }
-        this.availableDataViews = availableDataViews;        
-    }
-    
 
     /**
@@ -110,17 +98,4 @@
     public String getPid() {
         return pid;
-    }
-
-
-    /**
-     * Get the number of resources within this resource. If this resource has
-     * sub-ordinate resources, this number should be the sum of all items within
-     * the sub-ordinate resources plus the number of items within this resource.
-     *
-     * @return a number of items or <code>-1</code> if not applicable
-     */
-    @Deprecated
-    public int getResourceCount() {
-        return resourceCount;
     }
 
@@ -217,8 +192,7 @@
 
 
-	public List<String> getAvailableDataViews() {
+	public List<DataView> getAvailableDataViews() {
 		return availableDataViews;
 	}
 
-
 } // class ResourceInfo
Index: SSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/ResourceInfoInventory.java
===================================================================
--- /FCSSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/ResourceInfoInventory.java	(revision 5545)
+++ 	(revision )
@@ -1,49 +1,0 @@
-package eu.clarin.sru.server.fcs;
-
-import java.util.List;
-
-import eu.clarin.sru.server.SRUException;
-
-
-/**
- * An interface for abstracting resource info inventories. This class allows you
- * to provide a version of a resource info inventory tailored to your
- * environment, e.g. retrieving the information from a database, etc.
- * <p>
- * The implementation of this interface <em>must</em> be thread-safe.
- * </p>
- */
-public interface ResourceInfoInventory {
-    /**
-     * Constant for a (synthetic) persistent identifier identifying the top-most
-     * (= root) resource in the resource info inventory.
-     */
-    public static final String PID_ROOT = "root";
-
-
-    /**
-     * Destroy the resource info inventory. Use this method for any cleanup the
-     * resource info inventory needs to perform upon termination, i.e. closing
-     * of persistent database connections, etc.
-     */
-    public void destroy();
-
-
-    /**
-     * Get a list of all resources sub-ordinate to a resource identified by a
-     * given persistent identifier.
-     * <p>
-     * The implementation of this method <em>must</em> be thread-safe.
-     * </p>
-     *
-     * @param pid
-     *            the persistent identifier of the superior resource
-     * @return a list of all sub-ordinate ResourceInfo or <code>null</code> if
-     *         not applicable
-     * @throws SRUException
-     *             if an error occurred
-     */
-    public List<ResourceInfo> getResourceInfoList(String pid)
-            throws SRUException;
-
-} // interface ResourceInfoInventory
Index: SSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/ResourceInfoWriter.java
===================================================================
--- /FCSSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/ResourceInfoWriter.java	(revision 5545)
+++ 	(revision )
@@ -1,150 +1,0 @@
-package eu.clarin.sru.server.fcs;
-
-import java.util.List;
-import java.util.Map;
-
-import javax.xml.XMLConstants;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamWriter;
-
-public class ResourceInfoWriter {
-
-	public static final String FCS_RESOURCE_INFO_NS =
-            "http://clarin.eu/fcs/endpoint-description";
-    
-	public static void writeFullResourceInfo(XMLStreamWriter writer,
-            String prefix, List<ResourceInfo> resourceInfoList)
-            throws XMLStreamException {
-		
-        if (resourceInfoList == null) {
-            throw new NullPointerException("resourceInfoList == null");
-        }
-        if (!resourceInfoList.isEmpty()) {
-            final boolean defaultNS = ((prefix == null) || prefix.isEmpty());
-            if (defaultNS) {
-                writer.setDefaultNamespace(FCS_RESOURCE_INFO_NS);
-            } else {
-                writer.setPrefix(prefix, FCS_RESOURCE_INFO_NS);
-            }
-            writer.writeStartElement(FCS_RESOURCE_INFO_NS, "Resources");
-            if (defaultNS) {
-                writer.writeDefaultNamespace(FCS_RESOURCE_INFO_NS);
-            } else {
-                writer.writeNamespace(prefix, FCS_RESOURCE_INFO_NS);
-            }
-            for (ResourceInfo resourceInfo : resourceInfoList) {
-                doWriteResourceInfo(writer, prefix, resourceInfo, false, true);
-            }
-            writer.writeEndElement(); // "ResourceCollection" element
-        }
-    }
-
-
-	public static void writeResourceInfo(XMLStreamWriter writer, String prefix,
-            ResourceInfo resourceInfo) throws XMLStreamException {        
-        doWriteResourceInfo(writer, prefix, resourceInfo, true, false);
-    }
-
-
-	private static void doWriteResourceInfo(XMLStreamWriter writer,
-            String prefix, ResourceInfo resourceInfo, boolean writeNS,
-            boolean recursive) throws XMLStreamException {
-		
-		if (writer == null) {
-            throw new NullPointerException("writer == null");
-        }		
-		if (resourceInfo == null) {
-            throw new NullPointerException("resourceInfo == null");
-        }
-		
-        final boolean defaultNS = ((prefix == null) || prefix.isEmpty());
-        if (writeNS) {
-            if (defaultNS) {
-                writer.setDefaultNamespace(FCS_RESOURCE_INFO_NS);
-            } else {
-                writer.setPrefix(prefix, FCS_RESOURCE_INFO_NS);
-            }
-        }
-        writer.writeStartElement(FCS_RESOURCE_INFO_NS, "Resource");
-        if (writeNS) {
-            if (defaultNS) {
-                writer.writeDefaultNamespace(FCS_RESOURCE_INFO_NS);
-            } else {
-                writer.writeNamespace(prefix, FCS_RESOURCE_INFO_NS);
-            }
-        }
-        if (recursive) {
-            /*
-             * HACK: only output @pid for recursive (= explain) requests.
-             * This should be revisited, if we decide to go for the explain
-             * style enumeration of resources.
-             */
-            writer.writeAttribute("pid", resourceInfo.getPid());
-        }
-        if (resourceInfo.hasSubResources()) {
-            writer.writeAttribute("hasSubResources", "true");
-        }
-
-        final Map<String, String> title = resourceInfo.getTitle();
-        for (Map.Entry<String, String> i : title.entrySet()) {
-            writer.setPrefix(XMLConstants.XML_NS_PREFIX,
-                    XMLConstants.XML_NS_URI);
-            writer.writeStartElement(FCS_RESOURCE_INFO_NS, "Title");
-            writer.writeAttribute(XMLConstants.XML_NS_URI, "lang", i.getKey());
-            writer.writeCharacters(i.getValue());
-            writer.writeEndElement(); // "title" element
-        }
-
-        final Map<String, String> description = resourceInfo.getDescription();
-        if (description != null) {
-            for (Map.Entry<String, String> i : description.entrySet()) {
-                writer.writeStartElement(FCS_RESOURCE_INFO_NS, "Description");
-                writer.writeAttribute(XMLConstants.XML_NS_URI, "lang",
-                        i.getKey());
-                writer.writeCharacters(i.getValue());
-                writer.writeEndElement(); // "Description" element
-            }
-        }
-
-        final String landingPageURI = resourceInfo.getLandingPageURI();
-        if (landingPageURI != null) {
-            writer.writeStartElement(FCS_RESOURCE_INFO_NS, "LandingPageURI");
-            writer.writeCharacters(landingPageURI);
-            writer.writeEndElement(); // "LandingPageURI" element
-        }
-
-        final List<String> languages = resourceInfo.getLanguages();
-        writer.writeStartElement(FCS_RESOURCE_INFO_NS, "Languages");
-        for (String i : languages) {
-            writer.writeStartElement(FCS_RESOURCE_INFO_NS, "Language");
-            writer.writeCharacters(i);
-            writer.writeEndElement(); // "Language" element
-
-        }
-        writer.writeEndElement(); // "Languages" element
-        
-        if (!defaultNS && prefix.equals(EndpointDescriptionWriter.PREFIX)){
-	        final List<String> availableDataViews = resourceInfo.getAvailableDataViews();
-	        writer.writeStartElement(FCS_RESOURCE_INFO_NS, "AvailableDataViews");
-	        
-	        StringBuilder sb = new StringBuilder();
-	        for (int i = 0; i < availableDataViews.size(); i++) {
-	            sb.append(availableDataViews.get(i));
-	            sb.append(" ");
-	        }        
-	        writer.writeAttribute("ref", sb.toString().trim());
-	        
-	        writer.writeEndElement(); // "AvailableDataViews" element
-        }
-        
-        if (recursive && resourceInfo.hasSubResources()) {
-            writer.writeStartElement(FCS_RESOURCE_INFO_NS,
-                    "ResourceInfoCollection");
-            for (ResourceInfo r : resourceInfo.getSubResources()) {
-                doWriteResourceInfo(writer, prefix, r, writeNS, recursive);
-            }
-            writer.writeEndElement(); // "ResourceCollection" element
-        }
-        writer.writeEndElement(); // "ResourceInfo" element
-    }	
-}
Index: /FCSSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/SimpleEndpointSearchEngineBase.java
===================================================================
--- /FCSSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/SimpleEndpointSearchEngineBase.java	(revision 5545)
+++ /FCSSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/SimpleEndpointSearchEngineBase.java	(revision 5546)
@@ -1,5 +1,5 @@
 package eu.clarin.sru.server.fcs;
 
-import java.util.ArrayList;
+import java.net.URI;
 import java.util.Collections;
 import java.util.List;
@@ -7,4 +7,5 @@
 
 import javax.servlet.ServletContext;
+import javax.xml.XMLConstants;
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamWriter;
@@ -30,14 +31,16 @@
 
 /**
- * A base class for implementing a simple search engine to be used as a CLARIN
- * FCS endpoint.
+ * A base class for implementing a simple search engine to be used as a
+ * CLARIN-FCS endpoint.
  *
  */
 public abstract class SimpleEndpointSearchEngineBase extends
         SRUSearchEngineBase {
-    
+    private static final String X_FCS_ENDPOINT_DESCRIPTION = "x-fcs-endpoint-description";
     private static final String X_CMD_RESOURCE_INFO = "x-cmd-resource-info";
-    private static final String X_FCS_ENDPOINT_DESCRIPTION = "x-fcs-endpoint-description";
-    
+    private static final String ED_NS = "http://clarin.eu/fcs/endpoint-description";
+    private static final String ED_PREFIX = "ed";
+    private static final int ED_VERSION = 1;
+    private static final String FCS_RESOURCE_INFO_NS = "http://clarin.eu/fcs/1.0/resource-info";
     private static final String FCS_SCAN_INDEX_FCS_RESOURCE = "fcs.resource";
     private static final String FCS_SCAN_INDEX_CQL_SERVERCHOICE = "cql.serverChoice";
@@ -47,36 +50,8 @@
     private static final Logger logger =
             LoggerFactory.getLogger(SimpleEndpointSearchEngineBase.class);
-    protected ResourceInfoInventory resourceInfoInventory;
-    
-    public List<String> capabilities;
-    public List<DataView> supportedDataViews;
-    
-    public void addEndpointCapability(String c){
-    	capabilities.add(c);
-    }
-    
-    public void addDataView(DataView d){
-    	supportedDataViews.add(d);
-    }	
-       
-    public void setCapabilities(){
-    	 logger.debug("Setting basic capability");
-         capabilities = new ArrayList<String>();
-         capabilities.add("http://clarin.eu/fcs/capability/basic-search");
-    }      
-    
-    public void setSupportedDataViews(){
-         logger.debug("Setting Generic Hits dataview");
-         supportedDataViews = new ArrayList<DataView>();
-         supportedDataViews.add(
-         		new DataView("The representation of the hit", 
-         			"application/x-clarin-fcs-hits+xml", 
-         			DataView.PayloadDisposition.INLINE, 
-         			DataView.PayloadDelivery.SEND_BY_DEFAULT, 
-         			"hits")
-         );
-    }
-    
-	/**
+    protected EndpointDescription endpointDescription;
+
+
+    /**
      * This method should not be overridden. Perform your custom initialization
      * in the {@link #doInit(ServletContext, SRUServerConfig, Map)} method
@@ -89,16 +64,17 @@
             Map<String, String> params) throws SRUConfigException {
         logger.debug("initializing");
-        super.init(context, config, params);              
-        
+        super.init(context, config, params);
+
         logger.debug("initializing search engine implementation");
         doInit(context, config, params);
-        	
-        logger.debug("initizalizing resource info inventory");
-        this.resourceInfoInventory = createResourceInfoInventory(context, config, params);
-        if (this.resourceInfoInventory == null) {
-            logger.error("ClarinFCSSearchEngineBase implementation error: " +
-                    "initResourceCatalog() returned null");
-            throw new SRUConfigException("initResourceCatalog() returned no " +
-                    "valid implementation of a ResourceCatalog");
+
+        logger.debug("initizalizing endpoint description");
+        this.endpointDescription =
+                createEndpointDescription(context, config, params);
+        if (this.endpointDescription == null) {
+            logger.error("SimpleEndpointSearchEngineBase implementation " +
+                    "error: createEndpointDescription() returned null");
+            throw new SRUConfigException("createEndpointDescription() " +
+                    "returned no valid implementation of an EndpointDescription");
         }
     }
@@ -113,6 +89,6 @@
     @Override
     public final void destroy() {
-        logger.debug("performing cleanup of resource info inventory");
-        resourceInfoInventory.destroy();
+        logger.debug("performing cleanup of endpoint description");
+        endpointDescription.destroy();
         logger.debug("performing cleanup of search engine");
         doDestroy();
@@ -125,56 +101,24 @@
             SRURequest request, SRUDiagnosticList diagnostics)
             throws SRUException {
-    	
-        final boolean provideCmdResourceInfo =
-                parseBoolean(request.getExtraRequestData(X_CMD_RESOURCE_INFO));
-        final boolean provideFcsResourceInfo =
-                parseBoolean(request.getExtraRequestData(X_FCS_ENDPOINT_DESCRIPTION));
-                
-        if (provideCmdResourceInfo) {
-            final List<ResourceInfo> resourceInfoList =
-                    resourceInfoInventory.getResourceInfoList(
-                            ResourceInfoInventory.PID_ROOT);
-            
+
+        final boolean provideEndpointDescription =
+                parseBoolean(request.getExtraRequestData(
+                        X_FCS_ENDPOINT_DESCRIPTION));
+
+        if (provideEndpointDescription) {
             return new SRUExplainResult(diagnostics) {
                 @Override
                 public boolean hasExtraResponseData() {
-                    return provideCmdResourceInfo;
-                }
+                    return provideEndpointDescription;
+                }
+
+
                 @Override
                 public void writeExtraResponseData(XMLStreamWriter writer)
                         throws XMLStreamException {
-                    ResourceInfoWriter.writeFullResourceInfo(writer, null, resourceInfoList);
+                    writeEndpointDescription(writer);
                 }
             };
-        }
-        else if (provideFcsResourceInfo && capabilities != null 
-        		&& supportedDataViews != null){
-        	
-        	final List<ResourceInfo> resourceInfoList =
-                    resourceInfoInventory.getResourceInfoList(
-                            ResourceInfoInventory.PID_ROOT);
-        	
-//        	if (capabilities == null){
-//        		throw new SRUException(SRUConstants.SRU_GENERAL_SYSTEM_ERROR, 
-//        				"Capabilities are not set.");
-//        	}
-//        	if (supportedDataViews == null){
-//        		throw new SRUException(SRUConstants.SRU_GENERAL_SYSTEM_ERROR, 
-//        				"Supported data views are not set.");
-//        	}
-        	return new SRUExplainResult(diagnostics) {
-                @Override
-                public boolean hasExtraResponseData() {
-                    return provideFcsResourceInfo;
-                }
-                @Override
-                public void writeExtraResponseData(XMLStreamWriter writer)
-                        throws XMLStreamException {
-            		EndpointDescriptionWriter.writeEndpointDescription(writer, 
-            			capabilities, supportedDataViews, resourceInfoList);
-                }
-            };
-        }
-        else {
+        } else {
             return null;
         }
@@ -191,5 +135,4 @@
      */
     @Override
-    @Deprecated
     public final SRUScanResultSet scan(SRUServerConfig config,
             SRURequest request, SRUDiagnosticList diagnostics)
@@ -215,5 +158,5 @@
              */
             final boolean provideResourceInfo = parseBoolean(
-                    request.getExtraRequestData(X_FCS_ENDPOINT_DESCRIPTION));
+                    request.getExtraRequestData(X_CMD_RESOURCE_INFO));
 
             return new SRUScanResultSet(diagnostics) {
@@ -234,5 +177,5 @@
                 @Override
                 public int getNumberOfRecords() {
-                    return result.get(idx).getResourceCount();
+                    return -1;
                 }
 
@@ -260,5 +203,5 @@
                         throws XMLStreamException {
                     if (provideResourceInfo) {
-                        ResourceInfoWriter.writeResourceInfo(writer, null, result.get(idx));
+                        writeLegacyResourceInfo(writer, result.get(idx));
                     }
                 }
@@ -270,24 +213,5 @@
 
 
-
-    /**
-     * Create the resource info inventory to be used with this endpoint.
-     * Implement this method to provide an implementation of a
-     * {@link ResourceInfoInventory} that is tailored towards your environment
-     * and needs.
-     *
-     * @param context
-     *            the {@link ServletContext} for the Servlet
-     * @param config
-     *            the {@link SRUServerConfig} object for this search engine
-     * @param params
-     *            additional parameters gathered from the Servlet configuration
-     *            and Servlet context.
-     * @return an instance of a {@link ResourceInfoInventory} used by this
-     *         search engine
-     * @throws SRUConfigException
-     *             if an error occurred
-     */
-    protected abstract ResourceInfoInventory createResourceInfoInventory(
+    protected abstract EndpointDescription createEndpointDescription(
             ServletContext context, SRUServerConfig config,
             Map<String, String> params) throws SRUConfigException;
@@ -328,5 +252,4 @@
      *      SRUDiagnosticList)
      */
-    @Deprecated
     protected SRUScanResultSet doScan(SRUServerConfig config,
             SRURequest request, SRUDiagnosticList diagnostics)
@@ -364,5 +287,5 @@
     }
 
-    @Deprecated
+
     private List<ResourceInfo> translateFcsScanResource(CQLNode scanClause)
             throws SRUException {
@@ -386,4 +309,6 @@
             }
 
+            logger.warn("scan on 'fcs.resource' for endpoint resource " +
+                    "enumeration is deprecated.");
 
             // only allow "=" relation without any modifiers
@@ -422,5 +347,5 @@
                     FCS_SCAN_INDEX_FCS_RESOURCE.equals(term)) ||
                     (FCS_SCAN_INDEX_FCS_RESOURCE.equals(index))) {
-                results = resourceInfoInventory.getResourceInfoList(term);
+                results = endpointDescription.getResourceList(term);
             }
             if ((results == null) || results.isEmpty()) {
@@ -436,5 +361,261 @@
 
 
-    
+    private void writeEndpointDescription(XMLStreamWriter writer)
+            throws XMLStreamException {
+        writer.setPrefix(ED_PREFIX, ED_NS);
+        writer.writeStartElement(ED_NS, "EndpointDescription");
+        writer.writeNamespace(ED_PREFIX, ED_NS);
+        writer.writeAttribute("version", Integer.toString(ED_VERSION));
+
+        // capabilities
+        writer.writeStartElement(ED_NS, "Capabilities");
+        for (URI capability : endpointDescription.getCapabilities()) {
+            writer.writeStartElement(ED_NS, "Capability");
+            writer.writeCharacters(capability.toString());
+            writer.writeEndElement(); // "Capability" element
+        }
+        writer.writeEndElement(); // "Capabilities" element
+
+        // supported data views
+        writer.writeStartElement(ED_NS, "SupportedDataViews");
+        for (DataView dataView : endpointDescription.getSupportedDataViews()) {
+            writer.writeStartElement(ED_NS, "SupportedDataView");
+            writer.writeAttribute("id", dataView.getIdentifier());
+            String s;
+            switch (dataView.getDeliveryPolicy()) {
+            case SEND_BY_DEFAULT:
+                s = "send-by-default";
+                break;
+            case NEED_TO_REQUEST:
+                s = "need-to-request";
+                break;
+            default:
+                throw new XMLStreamException(
+                        "invalid value for payload delivery policy: " +
+                                dataView.getDeliveryPolicy());
+            } // switch
+            writer.writeAttribute("delivery-policy", s);
+            writer.writeCharacters(dataView.getMimeType());
+            writer.writeEndElement(); // "SupportedDataView" element
+        }
+        writer.writeEndElement(); // "SupportedDataViews" element
+
+        try {
+            // resources
+            List<ResourceInfo> resources =
+                    endpointDescription.getResourceList(
+                            EndpointDescription.PID_ROOT);
+            writeResourceInfos(writer, resources);
+        } catch (SRUException e) {
+            throw new XMLStreamException("error retriving top-level resources",
+                    e);
+        }
+        writer.writeEndElement(); // "EndpointDescription" element
+    }
+
+
+    private void writeResourceInfos(XMLStreamWriter writer,
+            List<ResourceInfo> resources) throws XMLStreamException {
+        if (resources == null) {
+            throw new NullPointerException("resources == null");
+        }
+        if (!resources.isEmpty()) {
+            writer.writeStartElement(ED_NS, "Resources");
+
+            for (ResourceInfo resource : resources) {
+                writer.writeStartElement(ED_NS, "Resource");
+                writer.writeAttribute("pid", resource.getPid());
+
+                // title
+                final Map<String, String> title = resource.getTitle();
+                for (Map.Entry<String, String> i : title.entrySet()) {
+                    writer.setPrefix(XMLConstants.XML_NS_PREFIX,
+                            XMLConstants.XML_NS_URI);
+                    writer.writeStartElement(ED_NS, "Title");
+                    writer.writeAttribute(XMLConstants.XML_NS_URI, "lang", i.getKey());
+                    writer.writeCharacters(i.getValue());
+                    writer.writeEndElement(); // "title" element
+                }
+
+                // description
+                final Map<String, String> description = resource.getDescription();
+                if (description != null) {
+                    for (Map.Entry<String, String> i : description.entrySet()) {
+                        writer.writeStartElement(ED_NS, "Description");
+                        writer.writeAttribute(XMLConstants.XML_NS_URI, "lang",
+                                i.getKey());
+                        writer.writeCharacters(i.getValue());
+                        writer.writeEndElement(); // "Description" element
+                    }
+                }
+
+                // landing page
+                final String landingPageURI = resource.getLandingPageURI();
+                if (landingPageURI != null) {
+                    writer.writeStartElement(ED_NS, "LandingPageURI");
+                    writer.writeCharacters(landingPageURI);
+                    writer.writeEndElement(); // "LandingPageURI" element
+                }
+
+                // languages
+                final List<String> languages = resource.getLanguages();
+                writer.writeStartElement(ED_NS, "Languages");
+                for (String i : languages) {
+                    writer.writeStartElement(ED_NS, "Language");
+                    writer.writeCharacters(i);
+                    writer.writeEndElement(); // "Language" element
+
+                }
+                writer.writeEndElement(); // "Languages" element
+
+                // available data views
+                StringBuilder sb = new StringBuilder();
+                for (DataView dataview : resource.getAvailableDataViews()) {
+                    if (sb.length() > 0) {
+                        sb.append(" ");
+                    }
+                    sb.append(dataview.getIdentifier());
+                }
+                writer.writeEmptyElement(ED_NS, "AvailableDataViews");
+                writer.writeAttribute("ref", sb.toString());
+
+                // child resources
+                List<ResourceInfo> subs = resource.getSubResources();
+                if ((subs != null) && !subs.isEmpty()) {
+                    writeResourceInfos(writer, subs);
+                }
+
+                writer.writeEndElement(); // "Resource" element
+            }
+            writer.writeEndElement(); // "Resources" element
+        }
+    }
+
+
+    private void writeLegacyResourceInfo(XMLStreamWriter writer,
+            ResourceInfo resourceInfo) throws XMLStreamException {
+        writer.setDefaultNamespace(FCS_RESOURCE_INFO_NS);
+        writer.writeStartElement(FCS_RESOURCE_INFO_NS, "ResourceInfo");
+        writer.writeDefaultNamespace(FCS_RESOURCE_INFO_NS);
+
+        // title
+        final Map<String, String> title = resourceInfo.getTitle();
+        for (Map.Entry<String, String> i : title.entrySet()) {
+            writer.setPrefix(XMLConstants.XML_NS_PREFIX,
+                    XMLConstants.XML_NS_URI);
+            writer.writeStartElement(FCS_RESOURCE_INFO_NS, "Title");
+            writer.writeAttribute(XMLConstants.XML_NS_URI, "lang", i.getKey());
+            writer.writeCharacters(i.getValue());
+            writer.writeEndElement(); // "title" element
+        }
+
+        // description
+        final Map<String, String> description = resourceInfo.getDescription();
+        if (description != null) {
+            for (Map.Entry<String, String> i : description.entrySet()) {
+                writer.writeStartElement(FCS_RESOURCE_INFO_NS, "Description");
+                writer.writeAttribute(XMLConstants.XML_NS_URI, "lang",
+                        i.getKey());
+                writer.writeCharacters(i.getValue());
+                writer.writeEndElement(); // "Description" element
+            }
+        }
+
+        // landing page
+        final String landingPageURI = resourceInfo.getLandingPageURI();
+        if (landingPageURI != null) {
+            writer.writeStartElement(FCS_RESOURCE_INFO_NS, "LandingPageURI");
+            writer.writeCharacters(landingPageURI);
+            writer.writeEndElement(); // "LandingPageURI" element
+        }
+
+        // languages
+        final List<String> languages = resourceInfo.getLanguages();
+        writer.writeStartElement(FCS_RESOURCE_INFO_NS, "Languages");
+        for (String i : languages) {
+            writer.writeStartElement(FCS_RESOURCE_INFO_NS, "Language");
+            writer.writeCharacters(i);
+            writer.writeEndElement(); // "Language" element
+
+        }
+        writer.writeEndElement(); // "Languages" element
+        writer.writeEndElement(); // "ResourceInfo" element
+    }
+
+
+//             final boolean defaultNS = ((prefix == null) || prefix.isEmpty());
+//            if (writeNS) {
+//                 if (defaultNS) {
+//                     writer.setDefaultNamespace(FCS_RESOURCE_INFO_NS);
+//                } else {
+//                    writer.setPrefix(prefix, FCS_RESOURCE_INFO_NS);
+//                }
+//            }
+//            writer.writeStartElement(FCS_RESOURCE_INFO_NS, "ResourceInfo");
+//            if (writeNS) {
+//                if (defaultNS) {
+//                    writer.writeDefaultNamespace(FCS_RESOURCE_INFO_NS);
+//                 } else {
+//                    writer.writeNamespace(prefix, FCS_RESOURCE_INFO_NS);
+//                 }
+//          } )
+//}
+
+//    public static void XwriteResourceInfo(XMLStreamWriter writer, String prefix,
+//            ResourceInfo resourceInfo) throws XMLStreamException {
+//        doWriteResourceInfo(writer, prefix, resourceInfo, true, false);
+//    }
+//
+//
+//    private static void XdoWriteResourceInfo(XMLStreamWriter writer,
+//            String prefix, ResourceInfo resourceInfo, boolean writeNS,
+//            boolean recursive) throws XMLStreamException {
+//
+//        if (writer == null) {
+//            throw new NullPointerException("writer == null");
+//        }
+//        if (resourceInfo == null) {
+//            throw new NullPointerException("resourceInfo == null");
+//        }
+//
+//        final boolean defaultNS = ((prefix == null) || prefix.isEmpty());
+//        if (writeNS) {
+//            if (defaultNS) {
+//                writer.setDefaultNamespace(FCS_RESOURCE_INFO_NS);
+//            } else {
+//                writer.setPrefix(prefix, FCS_RESOURCE_INFO_NS);
+//            }
+//        }
+//        writer.writeStartElement(FCS_RESOURCE_INFO_NS, "Resource");
+//        if (writeNS) {
+//            if (defaultNS) {
+//                writer.writeDefaultNamespace(FCS_RESOURCE_INFO_NS);
+//            } else {
+//                writer.writeNamespace(prefix, FCS_RESOURCE_INFO_NS);
+//            }
+//        }
+//        if (recursive) {
+//            /*
+//             * HACK: only output @pid for recursive (= explain) requests.
+//             * This should be revisited, if we decide to go for the explain
+//             * style enumeration of resources.
+//             */
+//            writer.writeAttribute("pid", resourceInfo.getPid());
+//        }
+//        if (resourceInfo.hasSubResources()) {
+//            writer.writeAttribute("hasSubResources", "true");
+//        }
+//
+//
+//        if (recursive && resourceInfo.hasSubResources()) {
+//            writer.writeStartElement(FCS_RESOURCE_INFO_NS,
+//                    "ResourceInfoCollection");
+//            for (ResourceInfo r : resourceInfo.getSubResources()) {
+//                doWriteResourceInfo(writer, prefix, r, writeNS, recursive);
+//            }
+//            writer.writeEndElement(); // "ResourceCollection" element
+//        }
+//        writer.writeEndElement(); // "ResourceInfo" element
+//    }
 
 } // class SimpleEndpointSearchEngineBase
Index: SSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/SimpleFcsResourceWriter.java
===================================================================
--- /FCSSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/SimpleFcsResourceWriter.java	(revision 5545)
+++ 	(revision )
@@ -1,73 +1,0 @@
-package eu.clarin.sru.server.fcs;
-
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamWriter;
-
-public class SimpleFcsResourceWriter {
-	private static final String FCS_NS = "http://clarin.eu/fcs/resource";
-    private static final String FCS_PREFIX = "fcs";
-    private static final String FCS_DATAVIEW_MIMETYPE =
-            "application/x-clarin-fcs-hits+xml";
-    
-    private static final String HITS_NS = "http://clarin.eu/fcs/dataview/hits";
-    private static final String HITS_PREFIX = "hits";
-    
-    public static void writeResource(XMLStreamWriter writer, String pid, String ref, 
-			String leftContext, String keyword, String rightContext)
-            throws XMLStreamException {
-		
-		if (writer == null) {
-            throw new NullPointerException("writer == null");
-        }
-		
-		writer.setPrefix(FCS_PREFIX, FCS_NS);
-        writer.writeStartElement(FCS_NS, "Resource");
-        writer.writeNamespace(FCS_PREFIX, FCS_NS);
-        if ((pid != null) && !pid.isEmpty()) {
-            writer.writeAttribute("pid", pid);
-        }
-        if ((ref != null) && !ref.isEmpty()) {
-            writer.writeAttribute("ref", ref);
-        }        
-        writeDataView(writer, leftContext, keyword, rightContext);        
-        writer.writeEndElement();
-	}
-    
-    public static void writeDataView(XMLStreamWriter writer, String leftContext, 
-    		String keyword, String rightContext) throws XMLStreamException { 
-    	
-    	if (writer == null) {
-            throw new NullPointerException("writer == null");
-        }
-    	
-    	writer.writeStartElement(FCS_NS, "DataView");
-        writer.writeAttribute("type", FCS_DATAVIEW_MIMETYPE);        
-        writeHits(writer, leftContext, keyword, rightContext);        
-        writer.writeEndElement();
-    }
-    
-    public static void writeHits(XMLStreamWriter writer, String leftContext, 
-    		String keyword, String rightContext) throws XMLStreamException {                                    
-            
-    	if (writer == null) {
-            throw new NullPointerException("writer == null");
-        }
-        writer.setPrefix(HITS_PREFIX, HITS_NS);
-        writer.writeStartElement(HITS_NS, "Result");
-        writer.writeNamespace(HITS_PREFIX, HITS_NS);
-        
-        if (leftContext != null && !leftContext.isEmpty()) {
-            writer.writeCharacters(leftContext);
-        }
-        
-        writer.writeStartElement(HITS_NS, "Hit");
-        writer.writeCharacters(keyword);
-        writer.writeEndElement(); // Hit
-
-        if (rightContext != null && !rightContext.isEmpty()) {
-            writer.writeCharacters(rightContext);
-        }
-        
-        writer.writeEndElement(); // Result
-    }
-}
Index: /FCSSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/XMLStreamWriterHelper.java
===================================================================
--- /FCSSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/XMLStreamWriterHelper.java	(revision 5545)
+++ /FCSSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/XMLStreamWriterHelper.java	(revision 5546)
@@ -8,10 +8,10 @@
  * This class provides several helper methods for writing records in the
  * CLARIN-FCS record schema. These methods <em>do not</em> cover the full
- * spectrum of all variations of records that are permitted by the CLARIN FCS
+ * spectrum of all variations of records that are permitted by the CLARIN-FCS
  * specification.
  *
  * @see <a
- *      href="https://trac.clarin.eu/wiki/FCS-specification#SearchRetrieveOperation">
- *      CLARIN FCS specification, section "SearchRetrieve Operation"</a>
+ *      href="https://trac.clarin.eu/wiki/FCS/Specification">
+ *      CLARIN FCS specification, section "Operation searchRetrieve"</a>
  */
 public final class XMLStreamWriterHelper {
@@ -23,4 +23,9 @@
     private static final String FCS_KWIC_MIMETYPE =
             "application/x-clarin-fcs-kwic+xml";
+    private static final String FCS_HITS_NS =
+            "http://clarin.eu/fcs/dataview/hits";
+    private static final String FCS_HITS_PREFIX = "hits";
+    private static final String FCS_HITS_MIMETYPE =
+            "application/x-clarin-fcs-hits+xml";
 
 
@@ -205,9 +210,14 @@
      * @throws XMLStreamException
      *             if an error occurred
-     */
+     * @deprecated The the HITS data view instead.
+     */
+    @Deprecated
     public static void writeKWICDataView(XMLStreamWriter writer, String left,
             String keyword, String right) throws XMLStreamException {
         if (writer == null) {
             throw new NullPointerException("writer == null");
+        }
+        if (keyword == null) {
+            throw new NullPointerException("keyword == null");
         }
 
@@ -246,4 +256,5 @@
      * Convince method for writing a record with a KWIC data view. The following
      * code (arguments omitted) would accomplish the same result:
+     *
      * <pre>
      * ...
@@ -272,5 +283,7 @@
      * @throws XMLStreamException
      *             if an error occurred
-     */
+     * @deprecated The the HITS data view instead.
+     */
+    @Deprecated
     public static void writeResourceWithKWICDataView(XMLStreamWriter writer,
             String pid, String ref, String left, String keyword, String right)
@@ -285,3 +298,233 @@
     }
 
+
+
+    /**
+     * Convince method to write a simple HITS data view. It automatically
+     * performs the calls to
+     * {@link #writeStartDataView(XMLStreamWriter, String)} and
+     * {@link #writeEndDataView(XMLStreamWriter)}.
+     *
+     * @param writer
+     *            the {@link XMLStreamWriter} to be used
+     * @param left
+     *            the left context of the hit or <code>null</code> if not
+     *            applicable
+     * @param hit
+     *            the actual hit, that will be highlighted
+     * @param right
+     *            the right context of the hit or <code>null</code> if not
+     *            applicable
+     * @throws XMLStreamException
+     *             if an error occurred
+     */
+    public static void writeHitsDataView(XMLStreamWriter writer, String left,
+            String hit, String right) throws XMLStreamException {
+        if (writer == null) {
+            throw new NullPointerException("writer == null");
+        }
+        if (hit == null) {
+            throw new NullPointerException("hit == null");
+        }
+
+        writeStartDataView(writer, FCS_HITS_MIMETYPE);
+
+        // actual "hits" data view
+        writer.setPrefix(FCS_HITS_PREFIX, FCS_HITS_NS);
+        writer.writeStartElement(FCS_HITS_NS, "Result");
+        writer.writeNamespace(FCS_HITS_PREFIX, FCS_HITS_NS);
+
+        if ((left != null) && !left.isEmpty()) {
+            writer.writeCharacters(left);
+        }
+
+        writer.writeStartElement(FCS_HITS_NS, "Hit");
+        writer.writeCharacters(hit);
+        writer.writeEndElement(); // "Hit" element
+
+        if ((right != null) && !right.isEmpty()) {
+            writer.writeCharacters(right);
+        }
+
+        writer.writeEndElement(); // "Result" element
+
+        writeEndDataView(writer);
+    }
+
+
+    /**
+     * Convince method for writing a record with a KWIC data view. The following
+     * code (arguments omitted) would accomplish the same result:
+     *
+     * <pre>
+     * ...
+     * writeStartResource(...);
+     * writeHitsDataView(...);
+     * writeEndResource(...);
+     * ...
+     * </pre>
+     *
+     * @param writer
+     *            the {@link XMLStreamWriter} to be used
+     * @param pid
+     *            the persistent identifier of this resource or
+     *            <code>null</code>, if not applicable
+     * @param ref
+     *            the reference of this resource or <code>null</code>, if not
+     *            applicable
+     * @param left
+     *            the left context of the hit or <code>null</code> if not
+     *            applicable
+     * @param hit
+     *            the actual hit, that will be highlighted
+     * @param right
+     *            the right context of the hit or <code>null</code> if not
+     *            applicable
+     * @throws XMLStreamException
+     *             if an error occurred
+     */
+    public static void writeResourceWithHitsDataView(XMLStreamWriter writer,
+            String pid, String ref, String left, String hit, String right)
+            throws XMLStreamException {
+        if (writer == null) {
+            throw new NullPointerException("writer == null");
+        }
+
+        writeStartResource(writer, pid, ref);
+        writeHitsDataView(writer, left, hit, right);
+        writeEndResource(writer);
+    }
+
+
+    /**
+     * Convince method to write a simple HITS data view. It automatically
+     * performs the calls to
+     * {@link #writeStartDataView(XMLStreamWriter, String)} and
+     * {@link #writeEndDataView(XMLStreamWriter)}.
+     *
+     * @param writer
+     *            the {@link XMLStreamWriter} to be used
+     * @param text
+     *            the text content of the hit
+     * @param hits
+     *            an even-element array containing tuples for the hit markers in
+     *            the text content
+     * @param secondIsLength
+     *            if <code>true</code> the second element of each tuple in this
+     *            <code>hits</code> array is interpreted as an length; if
+     *            <code>false</code> it is interpreted as an end-offset
+     * @throws XMLStreamException
+     *             if an error occurred
+     */
+    public static void writeHitsDataView(XMLStreamWriter writer, String text,
+            int[] hits, boolean secondIsLength) throws XMLStreamException {
+        if (writer == null) {
+            throw new NullPointerException("writer == null");
+        }
+        if (text == null) {
+            throw new NullPointerException("text == null");
+        }
+        if (hits == null) {
+            throw new NullPointerException("text == null");
+        }
+        if ((hits.length == 0) || ((hits.length % 2) != 0)) {
+            throw new NullPointerException("length of hits array must " +
+                    "contain an even number of elements");
+        }
+
+        writeStartDataView(writer, FCS_HITS_MIMETYPE);
+
+        // actual "hits" data view
+        writer.setPrefix(FCS_HITS_PREFIX, FCS_HITS_NS);
+        writer.writeStartElement(FCS_HITS_NS, "Result");
+        writer.writeNamespace(FCS_HITS_PREFIX, FCS_HITS_NS);
+
+        int pos = 0;
+        for (int i = 0; i < hits.length; i += 2) {
+            int start  = hits[i];
+            int end    = hits[i + 1];
+
+            if ((start < 0) && (start > text.length())) {
+                throw new IllegalArgumentException("start index out of " +
+                        "bounds: start=" + start);
+            }
+            if (secondIsLength) {
+                if (end < 1) {
+                    throw new IllegalArgumentException(
+                            "length must be larger than 0: length = " + end);
+                }
+                end += start;
+            }
+            if (start >= end) {
+                throw new IllegalArgumentException("end offset must be " +
+                        "larger then start offset: start=" + start +
+                        ", end="+ end);
+            }
+
+            if (start > pos) {
+                String s = text.substring(pos, start);
+                writer.writeCharacters(s);
+            }
+            writer.writeStartElement(FCS_HITS_NS, "Hit");
+            writer.writeCharacters(text.substring(start, end));
+            writer.writeEndElement(); // "Hits" element
+            pos = end;
+        }
+        if (pos < text.length() - 1) {
+            writer.writeCharacters(text.substring(pos));
+        }
+
+        writer.writeEndElement(); // "Result" element
+
+        writeEndDataView(writer);
+    }
+
+
+    /**
+     * Convince method to write a simple HITS data view. It automatically
+     * performs the calls to
+     * {@link #writeStartDataView(XMLStreamWriter, String)} and
+     * {@link #writeEndDataView(XMLStreamWriter)}.
+     *
+     * <pre>
+     * ...
+     * writeStartResource(...);
+     * writeHitsDataView(...);
+     * writeEndResource(...);
+     * ...
+     * </pre>
+     *
+     * @param writer
+     *            the {@link XMLStreamWriter} to be used
+     * @param pid
+     *            the persistent identifier of this resource or
+     *            <code>null</code>, if not applicable
+     * @param ref
+     *            the reference of this resource or <code>null</code>, if not
+     *            applicable
+     * @param text
+     *            the text content of the hit
+     * @param hits
+     *            an even-element array containing tuples for the hit markers in
+     *            the text content
+     * @param secondIsLength
+     *            if <code>true</code> the second element of each tuple in this
+     *            <code>hits</code> array is interpreted as an length; if
+     *            <code>false</code> it is interpreted as an end-offset
+     * @throws XMLStreamException
+     *             if an error occurred
+     */
+    public static void writeResourceWithHitsDataView(XMLStreamWriter writer,
+            String pid, String ref, String text,
+            int[] hits, boolean secondIsLength)
+            throws XMLStreamException {
+        if (writer == null) {
+            throw new NullPointerException("writer == null");
+        }
+
+        writeStartResource(writer, pid, ref);
+        writeHitsDataView(writer, text, hits, secondIsLength);
+        writeEndResource(writer);
+    }
+
 } // class XMLStreamWriterHelper
Index: /FCSSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/utils/AbstractEndpointDescriptionBase.java
===================================================================
--- /FCSSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/utils/AbstractEndpointDescriptionBase.java	(revision 5546)
+++ /FCSSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/utils/AbstractEndpointDescriptionBase.java	(revision 5546)
@@ -0,0 +1,62 @@
+package eu.clarin.sru.server.fcs.utils;
+
+import java.net.URI;
+import java.util.Collections;
+import java.util.List;
+
+import eu.clarin.sru.server.fcs.DataView;
+import eu.clarin.sru.server.fcs.EndpointDescription;
+
+
+/**
+ * An abstract base class for implementing endpoint descriptions. It already
+ * implements the methods required for capabilities and supported dataviews.
+ *
+ * @see EndpointDescription
+ *
+ */
+public abstract class AbstractEndpointDescriptionBase implements EndpointDescription {
+    protected final List<URI> capabilities;
+    protected final List<DataView> supportedDataViews;
+
+    /**
+     * Constructor.
+     *
+     * @param capabilities
+     *            a list of capabilities supported by this endpoint
+     * @param supportedDataViews
+     *            a list of data views that are supported by this endpoint
+     */
+    protected AbstractEndpointDescriptionBase(List<URI> capabilities,
+            List<DataView> supportedDataViews) {
+        if (capabilities == null) {
+            throw new NullPointerException("capabilities == null");
+        }
+        if (capabilities.isEmpty()) {
+            throw new IllegalArgumentException("capabilities are empty");
+        }
+        this.capabilities = Collections.unmodifiableList(capabilities);
+
+        if (supportedDataViews == null) {
+            throw new NullPointerException("supportedDataViews == null");
+        }
+        if (supportedDataViews.isEmpty()) {
+            throw new IllegalArgumentException("supportedDataViews are empty");
+        }
+        this.supportedDataViews =
+                Collections.unmodifiableList(supportedDataViews);
+    }
+
+
+    @Override
+    public List<URI> getCapabilities() {
+        return capabilities;
+    }
+
+
+    @Override
+    public List<DataView> getSupportedDataViews() {
+        return supportedDataViews;
+    }
+
+} // abstract class EndpointDescriptionBase
Index: /FCSSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/utils/SimpleEndpointDescription.java
===================================================================
--- /FCSSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/utils/SimpleEndpointDescription.java	(revision 5546)
+++ /FCSSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/utils/SimpleEndpointDescription.java	(revision 5546)
@@ -0,0 +1,106 @@
+package eu.clarin.sru.server.fcs.utils;
+
+import java.net.URI;
+import java.util.Collections;
+import java.util.List;
+
+import eu.clarin.sru.server.SRUException;
+import eu.clarin.sru.server.fcs.DataView;
+import eu.clarin.sru.server.fcs.EndpointDescription;
+import eu.clarin.sru.server.fcs.ResourceInfo;
+
+
+/**
+ * A very simple implementation of an endpoint description that is initialized
+ * from static information supplied at construction time. Mostly used together
+ * with {@link SimpleEndpointDescriptionParser}, but it is agnostic how the
+ * static list of resource info records is generated.
+ *
+ * @see EndpointDescription
+ * @see SimpleEndpointDescriptionParser
+ */
+public class SimpleEndpointDescription extends AbstractEndpointDescriptionBase {
+    private final boolean pidCaseSensitive;
+    private final List<ResourceInfo> entries;
+
+
+    /**
+     * Constructor.
+     *
+     * @param capabilities
+     *            a list of capabilities supported by this endpoint
+     * @param supportedDataViews
+     *            a list of data views that are supported by this endpoint
+     * @param resources
+     *            a static list of resource info records
+     * @param pidCaseSensitive
+     *            <code>true</code> if comparison of persistent identifiers
+     *            should be performed case-sensitive, <code>false</code>
+     *            otherwise
+     */
+    public SimpleEndpointDescription(List<URI> capabilities,
+            List<DataView> supportedDataViews, List<ResourceInfo> resources,
+            boolean pidCaseSensitive) {
+        super(capabilities, supportedDataViews);
+
+        if (resources == null) {
+            throw new NullPointerException("entries == null");
+        }
+        this.entries = Collections.unmodifiableList(resources);
+        this.pidCaseSensitive = pidCaseSensitive;
+    }
+
+
+    @Override
+    public void destroy() {
+    }
+
+
+    @Override
+    public List<ResourceInfo> getResourceList(String pid) throws SRUException {
+        if (pid == null) {
+            throw new NullPointerException("pid == null");
+        }
+        if (pid.isEmpty()) {
+            throw new IllegalArgumentException("pid is empty");
+        }
+        if (!pidCaseSensitive) {
+            pid = pid.toLowerCase();
+        }
+        if (pid.equals(PID_ROOT)) {
+            return entries;
+        } else {
+            ResourceInfo ri = findRecursive(entries, pid);
+            if (ri != null) {
+                return ri.getSubResources();
+            }
+        }
+        return null;
+    }
+
+
+    private ResourceInfo findRecursive(List<ResourceInfo> items, String pid) {
+        if ((items != null) && !items.isEmpty()) {
+            for (ResourceInfo item : items) {
+                if (pidCaseSensitive) {
+                    if (pid.equals(item.getPid())) {
+                        return item;
+                    }
+                } else {
+                    if (pid.equalsIgnoreCase(item.getPid())) {
+                        return item;
+                    }
+                }
+                if (item.hasSubResources()) {
+                    ResourceInfo ri =
+                            findRecursive(item.getSubResources(), pid);
+                    if (ri != null) {
+                        return ri;
+                    }
+                }
+            } // for
+        }
+        return null;
+    }
+
+} // class SimpleEndpointDescription
Index: /FCSSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/utils/SimpleEndpointDescriptionParser.java
===================================================================
--- /FCSSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/utils/SimpleEndpointDescriptionParser.java	(revision 5546)
+++ /FCSSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/utils/SimpleEndpointDescriptionParser.java	(revision 5546)
@@ -0,0 +1,532 @@
+package eu.clarin.sru.server.fcs.utils;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import eu.clarin.sru.server.SRUConfigException;
+import eu.clarin.sru.server.fcs.DataView;
+import eu.clarin.sru.server.fcs.DataView.DeliveryPolicy;
+import eu.clarin.sru.server.fcs.EndpointDescription;
+import eu.clarin.sru.server.fcs.ResourceInfo;
+
+
+/**
+ * A parser, that parses an XML file and produces a endpoint description with
+ * static list of resource info records. The XML file has the same format as the
+ * result format defined for endpoint description of the CLARIN-FCS
+ * specification. The {@link #parse(URL)} returns a
+ * {@link SimpleEndpointDescription} instance.
+ *
+ * @see EndpointDescription
+ * @see SimpleEndpointDescription
+ */
+public class SimpleEndpointDescriptionParser {
+    private static final String NS =
+            "http://clarin.eu/fcs/endpoint-description";
+    private static final String NS_LEGACY =
+            "http://clarin.eu/fcs/1.0/resource-info";
+    private static final String CAP_BASIC_SEARCH =
+            "http://clarin.eu/fcs/capability/basic-search";
+    private static final String LANG_EN = "en";
+    private static final String POLICY_SEND_DEFAULT = "send-by-default";
+    private static final String POLICY_NEED_REQUEST = "need-to-request";
+    private static final Logger logger =
+            LoggerFactory.getLogger(SimpleEndpointDescriptionParser.class);
+
+
+    /**
+     * Parse an XML file and return a static list of resource info records.
+     *
+     * @param url
+     *            the URI pointing to the file to be parsed
+     * @return an {@link EndpointDescription} instance
+     * @throws SRUConfigException
+     *             if an error occurred
+     */
+    public static EndpointDescription parse(URL url) throws SRUConfigException {
+        if (url == null) {
+            throw new NullPointerException("url == null");
+        }
+
+        logger.debug("parsing endpoint description from: {}", url);
+
+        try {
+            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+            dbf.setNamespaceAware(true);
+            dbf.setCoalescing(true);
+            DocumentBuilder db = dbf.newDocumentBuilder();
+            Document doc = db.parse(url.openStream());
+
+            /*
+             * Detect for deprecated resource-info catalog files and bail, if necessary
+             */
+            checkLegacyMode(doc, url);
+
+            /*
+             * Parse on and create endpoint description ...
+             */
+            return parseEndpointDescription(doc);
+        } catch (ParserConfigurationException e) {
+            throw new SRUConfigException("internal error", e);
+        } catch (SAXException e) {
+            throw new SRUConfigException("parsing error", e);
+        } catch (IOException e) {
+            throw new SRUConfigException("error reading file", e);
+        } catch (XPathExpressionException e) {
+            throw new SRUConfigException("internal error", e);
+        }
+    }
+
+
+    private static EndpointDescription parseEndpointDescription(Document doc)
+            throws SRUConfigException, XPathExpressionException {
+        XPathFactory factory = XPathFactory.newInstance();
+        XPath xpath = factory.newXPath();
+
+        xpath.setNamespaceContext(new NamespaceContext() {
+            @Override
+            public Iterator<?> getPrefixes(String namespaceURI) {
+                throw new UnsupportedOperationException();
+            }
+
+            @Override
+            public String getPrefix(String namespaceURI) {
+                throw new UnsupportedOperationException();
+            }
+
+            @Override
+            public String getNamespaceURI(String prefix) {
+                if (prefix == null) {
+                    throw new NullPointerException("prefix == null");
+                }
+                if (prefix.equals("ed")) {
+                    return NS;
+                } else if (prefix.equals(XMLConstants.XML_NS_PREFIX)) {
+                    return XMLConstants.XML_NS_URI;
+                } else {
+                    return XMLConstants.NULL_NS_URI;
+                }
+            }
+        });
+
+        // capabilities
+        List<URI> capabilities = new ArrayList<URI>();
+        XPathExpression exp1 =
+                xpath.compile("//ed:Capabilities/ed:Capability");
+        NodeList list1 = (NodeList) exp1.evaluate(doc, XPathConstants.NODESET);
+        if ((list1 != null) && (list1.getLength() > 0)) {
+            logger.debug("parsing capabilities");
+            for (int i = 0; i < list1.getLength(); i++) {
+                String s = list1.item(i).getTextContent().trim();
+                try {
+                    URI uri = new URI(s);
+                    if (capabilities.contains(uri)) {
+                        logger.warn("ignoring duplicate capability " +
+                                "entry for '{}'", uri);
+                    }
+                    capabilities.add(uri);
+                } catch (URISyntaxException e) {
+                    throw new SRUConfigException("capability is not encoded " +
+                            "as proper URI: " + s);
+                }
+            }
+        } else {
+            logger.warn("No capabilities where defined in " +
+                    "endpoint configuration");
+        }
+        URI cap = URI.create(CAP_BASIC_SEARCH);
+        if (!capabilities.contains(cap)) {
+            logger.warn("capability '{}' was not defined in endpoint " +
+                    "description; added it to meet specification. Please " +
+                    "update your endpoint description!", CAP_BASIC_SEARCH);
+            capabilities.add(cap);
+        }
+        logger.debug("CAPS:'{}'", capabilities);
+
+        // supported data views
+        List<DataView> supportedDataViews = new ArrayList<DataView>();
+        XPathExpression exp2 =
+                xpath.compile("//ed:SupportedDataViews/ed:SupportedDataView");
+        NodeList list2 = (NodeList) exp2.evaluate(doc, XPathConstants.NODESET);
+        if ((list2 != null) && (list2.getLength() > 0)) {
+            logger.debug("parsing supported data views");
+            for (int i = 0; i < list2.getLength(); i++) {
+                Element item = (Element) list2.item(i);
+                String id = getAttribute(item, "id");
+                if (id == null) {
+                    throw new SRUConfigException("Element <SupportedDataView> "
+                            + "must carry a proper 'id' attribute");
+                }
+                String p = getAttribute(item, "delivery-policy");
+                if (p == null) {
+                    throw new SRUConfigException("Element <SupportedDataView> "
+                            + "must carry a 'delivery-policy' attribute");
+                }
+                DeliveryPolicy policy = null;
+                if (POLICY_SEND_DEFAULT.equals(p)) {
+                    policy = DeliveryPolicy.SEND_BY_DEFAULT;
+                } else if (POLICY_NEED_REQUEST.equals(p)) {
+                    policy = DeliveryPolicy.NEED_TO_REQUEST;
+                } else {
+                    throw new SRUConfigException("Invalid value '" + p +
+                            "' for attribute 'delivery-policy' on element " +
+                            "<SupportedDataView>");
+                }
+                String mimeType = item.getTextContent();
+                if (mimeType != null) {
+                    mimeType = mimeType.trim();
+                    if (mimeType.isEmpty()) {
+                        mimeType = null;
+                    }
+                }
+                if (mimeType == null) {
+                    throw new SRUConfigException("Element <SupportedDataView> "
+                            + "must contain a MIME-type as content");
+                }
+                // check for duplicate entries ...
+                for (DataView dataView : supportedDataViews) {
+                    if (id.equals(dataView.getIdentifier())) {
+                        throw new SRUConfigException(
+                                "A <SupportedDataView> with " + "the id '" +
+                                        id + "' is already defined!");
+                    }
+                    if (mimeType.equals(dataView.getMimeType())) {
+                        throw new SRUConfigException(
+                                "A <SupportedDataView> with " +
+                                        "the MIME-type '" + mimeType +
+                                        "' is already defined!");
+                    }
+                }
+                supportedDataViews.add(new DataView(id, mimeType, policy));
+            }
+        } else {
+            logger.error("Endpoint configuration contains no valid " +
+                    "information about supported data views");
+            throw new SRUConfigException("Endpoint configuration contains " +
+                    "no valid information about supported data views");
+        }
+
+        logger.debug("DV: {}", supportedDataViews);
+
+
+        // resources
+        XPathExpression x3 =
+                xpath.compile("/ed:EndpointDescription/ed:Resources/ed:Resource");
+        NodeList l3 = (NodeList) x3.evaluate(doc, XPathConstants.NODESET);
+        final Set<String> ids = new HashSet<String>();
+        List<ResourceInfo> resources =
+                parseRessources(xpath, l3, ids, supportedDataViews);
+        if ((resources == null) || resources.isEmpty()) {
+            throw new SRUConfigException("No resources where " +
+                    "defined in endpoint description");
+        }
+
+        return new SimpleEndpointDescription(capabilities,
+                supportedDataViews,
+                resources,
+                false);
+    }
+
+
+    private static List<ResourceInfo> parseRessources(XPath xpath,
+            NodeList nodes, Set<String> ids, List<DataView> supportedDataViews)
+            throws SRUConfigException, XPathExpressionException {
+      List<ResourceInfo> ris = null;
+      for (int k = 0; k < nodes.getLength(); k++) {
+          final Element node                = (Element) nodes.item(k);
+          String pid                        = null;
+          Map<String, String> titles        = null;
+          Map<String, String> descrs        = null;
+          String link                       = null;
+          List<String> langs                = null;
+          List<DataView> availableDataViews = null;
+          List<ResourceInfo> sub            = null;
+
+          pid = getAttribute(node, "pid");
+          if (pid == null) {
+              throw new SRUConfigException("Element <ResourceInfo> " +
+                      "must carry a proper 'pid' attribute");
+          }
+          if (ids.contains(pid)) {
+              throw new SRUConfigException("Another element <Resource> " +
+                      "with pid '" + pid + "' already exists");
+          }
+          ids.add(pid);
+
+          XPathExpression x1 = xpath.compile("ed:Title");
+          NodeList l1 = (NodeList) x1.evaluate(node, XPathConstants.NODESET);
+          if ((l1 != null) && (l1.getLength() > 0)) {
+              for (int i = 0; i < l1.getLength(); i++) {
+                  final Element n = (Element) l1.item(i);
+
+                  final String lang = getLangAttribute(n);
+                  if (lang == null) {
+                      throw new SRUConfigException("Element <Title> must " +
+                              "carry a proper 'xml:lang' attribute");
+                  }
+
+                  final String title = cleanString(n.getTextContent());
+                  if (title == null) {
+                      throw new SRUConfigException("Element <Title> must " +
+                              "carry a non-empty 'xml:lang' attribute");
+                  }
+
+                  if (titles == null) {
+                      titles = new HashMap<String, String>();
+                  }
+                  if (titles.containsKey(lang)) {
+                      logger.warn("title with language '{}' already exists",
+                              lang);
+                  } else {
+                      logger.debug("title: '{}' '{}'", lang, title);
+                      titles.put(lang, title);
+                  }
+              }
+              if ((titles != null) && !titles.containsKey(LANG_EN)) {
+                  throw new SRUConfigException(
+                          "A <Title> with language 'en' is mandatory");
+              }
+          }
+
+          XPathExpression x2 = xpath.compile("ed:Description");
+          NodeList l2 = (NodeList) x2.evaluate(node, XPathConstants.NODESET);
+          if ((l2 != null) && (l2.getLength() > 0)) {
+              for (int i = 0; i < l2.getLength(); i++) {
+                  Element n = (Element) l2.item(i);
+
+                  String lang = getLangAttribute(n);
+                  if (lang == null) {
+                      throw new SRUConfigException("Element <Description> " +
+                              "must carry a proper 'xml:lang' attribute");
+
+                  }
+                  String desc = cleanString(n.getTextContent());
+
+                  if (descrs == null) {
+                      descrs = new HashMap<String, String>();
+                  }
+
+                  if (descrs.containsKey(lang)) {
+                      logger.warn("description with language '{}' "
+                              + "already exists", lang);
+                  } else {
+                      logger.debug("description: '{}' '{}'", lang, desc);
+                      descrs.put(lang, desc);
+                  }
+              }
+              if ((descrs != null) && !descrs.containsKey(LANG_EN)) {
+                  throw new SRUConfigException(
+                          "A <Description> with language 'en' is mandatory");
+              }
+          }
+
+          XPathExpression x3 = xpath.compile("ed:LandingPageURI");
+          NodeList l3 = (NodeList) x3.evaluate(node, XPathConstants.NODESET);
+          if ((l3 != null) && (l3.getLength() > 0)) {
+              for (int i = 0; i < l3.getLength(); i++) {
+                  Element n = (Element) l3.item(i);
+                  link = cleanString(n.getTextContent());
+              }
+          }
+
+          XPathExpression x4 = xpath.compile("ed:Languages/ed:Language");
+          NodeList l4 = (NodeList) x4.evaluate(node, XPathConstants.NODESET);
+          if ((l4 != null) && (l4.getLength() > 0)) {
+              for (int i = 0; i < l4.getLength(); i++) {
+                  Element n = (Element) l4.item(i);
+
+                  String s = n.getTextContent();
+                  if (s != null) {
+                      s = s.trim();
+                      if (s.isEmpty()) {
+                          s = null;
+                      }
+                  }
+
+                  /*
+                   * enforce three letter codes
+                   */
+                  if ((s == null) || (s.length() != 3)) {
+                      throw new SRUConfigException("Element <Language> " +
+                              "must use ISO-632-3 three letter " +
+                              "language codes");
+                  }
+
+                  if (langs == null) {
+                      langs = new ArrayList<String>();
+                  }
+                  langs.add(s);
+              }
+          }
+
+          XPathExpression x5 = xpath.compile("ed:AvailableDataViews");
+          Node n = (Node) x5.evaluate(node, XPathConstants.NODE);
+          if ((n != null) && (n instanceof Element)) {
+              String ref = getAttribute((Element) n, "ref");
+              if (ref == null) {
+                  throw new SRUConfigException("Element <AvailableDataViews> " +
+                          "must carry a 'ref' attribute");
+              }
+              String[] refs = ref.split("\\s+");
+              if ((refs == null) || (refs.length < 1)) {
+                  throw new SRUConfigException("Attribute 'ref' on element " +
+                          "<AvailableDataViews> must contain a whitespace " +
+                          "seperated list of data view references");
+              }
+
+
+              for (int i = 0; i < refs.length; i++) {
+                  DataView dataview = null;
+                  for (DataView dv : supportedDataViews) {
+                      if (refs[i].equals(dv.getIdentifier())) {
+                          dataview = dv;
+                          break;
+                      }
+                  }
+                  if (dataview != null) {
+                      if (availableDataViews == null) {
+                          availableDataViews = new ArrayList<DataView>();
+                      }
+                      availableDataViews.add(dataview);
+                  } else {
+                      throw new SRUConfigException("A data view with " +
+                              "identifier '" + refs[i] + "' was not defined " +
+                              "in <SupportedDataViews>");
+                  }
+              }
+          } else {
+              throw new SRUConfigException(
+                      "missing element <ed:AvailableDataViews>");
+          }
+          if (availableDataViews == null) {
+              throw new SRUConfigException("No available data views where " +
+                      "defined for resource with PID '" + pid + "'");
+          }
+
+          XPathExpression x6 = xpath.compile("ed:Resources/ed:Resource");
+          NodeList l6 = (NodeList) x6.evaluate(node, XPathConstants.NODESET);
+          if ((l6 != null) && (l6.getLength() > 0)) {
+              sub = parseRessources(xpath, l6, ids, supportedDataViews);
+          }
+
+          if (ris == null) {
+              ris = new ArrayList<ResourceInfo>();
+          }
+          ris.add(new ResourceInfo(pid,
+                  titles,
+                  descrs,
+                  link,
+                  langs,
+                  availableDataViews,
+                  sub));
+      }
+      return ris;
+    }
+
+
+    private static String getAttribute(Element el, String localName) {
+        String lang = el.getAttribute(localName);
+        if (lang != null) {
+            lang = lang.trim();
+            if (!lang.isEmpty()) {
+                return lang;
+            }
+        }
+        return null;
+    }
+
+
+    private static String getLangAttribute(Element el) {
+        String lang = el.getAttributeNS(XMLConstants.XML_NS_URI, "lang");
+        if (lang != null) {
+            lang = lang.trim();
+            if (!lang.isEmpty()) {
+                return lang;
+            }
+        }
+        return null;
+    }
+
+
+    private static String cleanString(String s) {
+        if (s != null) {
+            s = s.trim();
+            if (!s.isEmpty()) {
+                StringBuilder sb = new StringBuilder();
+                for (String z : s.split("\\s*\\n+\\s*")) {
+                    z = z.trim();
+                    if (!z.isEmpty()) {
+                        if (sb.length() > 0) {
+                            sb.append(' ');
+                        }
+                        sb.append(z);
+                    }
+                }
+                if (sb.length() > 0) {
+                    return sb.toString();
+                }
+            }
+        }
+        return null;
+    }
+
+
+    private static void checkLegacyMode(Document doc, URL url)
+            throws SRUConfigException {
+        Element root = doc.getDocumentElement();
+        if (root != null) {
+            String ns = root.getNamespaceURI();
+            if (ns != null) {
+                if (ns.equals(NS_LEGACY)) {
+                    logger.error("Detected out-dated " +
+                            "resource info catalog file '" + url +
+                            "'. Please update to the " +
+                            "current version");
+                    throw new SRUConfigException("unsupport file format: " + ns);
+                } else if (!ns.equals(NS)) {
+                    logger.error("Detected unsupported resource info " +
+                            "catalog file '" + url + "' with namespace '" + ns + '"');
+                    throw new SRUConfigException("unsupport file format: " + ns);
+                }
+            } else {
+                throw new SRUConfigException("No namespace URI was detected " +
+                        "for resource info catalog file '" + url +"'!");
+            }
+        } else {
+            throw new SRUConfigException("Error retrieving root element");
+        }
+    }
+
+
+//    private static List<ResourceInfo> parseLegacy(Document doc)
+//            throws SRUConfigException, XPathExpressionException {
+
+} // class SimpleResourceInfoInventoryParser
Index: SSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/utils/SimpleResourceInfoInventory.java
===================================================================
--- /FCSSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/utils/SimpleResourceInfoInventory.java	(revision 5545)
+++ 	(revision )
@@ -1,95 +1,0 @@
-package eu.clarin.sru.server.fcs.utils;
-
-import java.util.Collections;
-import java.util.List;
-
-import eu.clarin.sru.server.fcs.ResourceInfoInventory;
-import eu.clarin.sru.server.fcs.ResourceInfo;
-
-
-/**
- * A very simple resource info inventory that is initialized with a static list
- * of resource info records. Mostly used together with
- * {@link SimpleResourceInfoInventoryParser}, but it is agnostic how the static
- * list of resource info records is generated.
- * 
- * @see ResourceInfoInventory
- * @see SimpleResourceInfoInventoryParser
- */
-public class SimpleResourceInfoInventory implements ResourceInfoInventory {
-    private final boolean pidCaseSensitive;
-    private final List<ResourceInfo> entries;
-
-
-    /**
-     * Constructor.
-     *
-     * @param entries
-     *            a static list of resource info records
-     * @param pidCaseSensitive
-     *            <code>true</code> if comparison of persistent identifiers
-     *            should be performed case-sensitive, <code>false</code> otherwise
-     */
-    public SimpleResourceInfoInventory(List<ResourceInfo> entries,
-            boolean pidCaseSensitive) {
-        if (entries == null) {
-            throw new NullPointerException("entries == null");
-        }
-        this.entries = Collections.unmodifiableList(entries);
-        this.pidCaseSensitive = pidCaseSensitive;
-    }
-
-
-    @Override
-    public void destroy() {
-    }
-
-
-    @Override
-    public List<ResourceInfo> getResourceInfoList(String id) {
-        if (id == null) {
-            throw new NullPointerException("id == null");
-        }
-        if (id.isEmpty()) {
-            throw new IllegalArgumentException("id is empty");
-        }
-        if (!pidCaseSensitive) {
-            id = id.toLowerCase();
-        }
-        if (id.equals(PID_ROOT)) {
-            return entries;
-        } else {
-            ResourceInfo ri = findRecursive(entries, id);
-            if (ri != null) {
-                return ri.getSubResources();
-            }
-        }
-        return null;
-    }
-
-
-    private ResourceInfo findRecursive(List<ResourceInfo> items, String pid) {
-        if ((items != null) && !items.isEmpty()) {
-            for (ResourceInfo item : items) {
-                if (pidCaseSensitive) {
-                    if (pid.equals(item.getPid())) {
-                        return item;
-                    }
-                } else {
-                    if (pid.equalsIgnoreCase(item.getPid())) {
-                        return item;
-                    }
-                }
-                if (item.hasSubResources()) {
-                    ResourceInfo ri =
-                            findRecursive(item.getSubResources(), pid);
-                    if (ri != null) {
-                        return ri;
-                    }
-                }
-            } // for
-        }
-        return null;
-    }
-
-} // class SimpleResourceInfoInventory
Index: SSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/utils/SimpleResourceInfoInventoryParser.java
===================================================================
--- /FCSSimpleEndpoint/trunk/src/main/java/eu/clarin/sru/server/fcs/utils/SimpleResourceInfoInventoryParser.java	(revision 5545)
+++ 	(revision )
@@ -1,330 +1,0 @@
-package eu.clarin.sru.server.fcs.utils;
-
-import java.io.IOException;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.xml.XMLConstants;
-import javax.xml.namespace.NamespaceContext;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.xpath.XPath;
-import javax.xml.xpath.XPathConstants;
-import javax.xml.xpath.XPathExpression;
-import javax.xml.xpath.XPathExpressionException;
-import javax.xml.xpath.XPathFactory;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-import org.xml.sax.SAXException;
-
-import eu.clarin.sru.server.SRUConfigException;
-import eu.clarin.sru.server.fcs.ResourceInfoInventory;
-import eu.clarin.sru.server.fcs.ResourceInfo;
-
-
-/**
- * A parser, that parses an XML file and produces a static list of resource info
- * records. The resulting list can be used to construct a
- * {@link SimpleResourceInfoInventory} instance.
- * 
- * @see ResourceInfo
- * @see SimpleResourceInfoInventory
- */
-public class SimpleResourceInfoInventoryParser {
-    private static final String NS = "http://clarin.eu/fcs/endpoint-description";
-    private static final String LANG_EN = "en";
-    private static final Logger logger =
-            LoggerFactory.getLogger(SimpleResourceInfoInventoryParser.class);
-
-
-    /**
-     * Parse an XML file and return a static list of resource info records.
-     * 
-     * @param url
-     *            the URI pointing to the file to be parsed
-     * @return a list of resource info records represented as
-     *         {@link ResourceInfo} instances
-     * @throws SRUConfigException
-     *             if an error occurred
-     */
-    public static ResourceInfoInventory parse(URL url) throws SRUConfigException {
-        if (url == null) {
-            throw new NullPointerException("url == null");
-        }
-
-        logger.debug("parsing resource-info from: {}", url);
-
-        final Set<String> ids = new HashSet<String>();
-        try {
-            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
-            dbf.setNamespaceAware(true);
-            dbf.setCoalescing(true);
-            DocumentBuilder db = dbf.newDocumentBuilder();
-            Document doc = db.parse(url.openStream());
-
-            XPathFactory factory = XPathFactory.newInstance();
-            XPath xpath = factory.newXPath();
-            xpath.setNamespaceContext(new NamespaceContext() {
-                @Override
-                public Iterator<?> getPrefixes(String namespaceURI) {
-                    throw new UnsupportedOperationException();
-                }
-
-                @Override
-                public String getPrefix(String namespaceURI) {
-                    throw new UnsupportedOperationException();
-                }
-
-                @Override
-                public String getNamespaceURI(String prefix) {
-                    if (prefix == null) {
-                        throw new NullPointerException("prefix == null");
-                    }
-                    if (prefix.equals("ri")) {
-                        return NS;
-                    } else if (prefix.equals(XMLConstants.XML_NS_PREFIX)) {
-                        return XMLConstants.XML_NS_URI;
-                    } else {
-                        return XMLConstants.NULL_NS_URI;
-                    }
-                }
-            });
-            XPathExpression expression =
-                    xpath.compile("/ri:Resources/ri:Resource");
-            NodeList list =
-                    (NodeList) expression.evaluate(doc, XPathConstants.NODESET);
-
-            List<ResourceInfo> entries = parseResourceInfo(xpath, list, ids);
-            return new SimpleResourceInfoInventory(entries, false);
-        } catch (ParserConfigurationException e) {
-            e.printStackTrace();
-        } catch (SAXException e) {
-            e.printStackTrace();
-        } catch (IOException e) {
-            e.printStackTrace();
-        } catch (XPathExpressionException e) {
-            e.printStackTrace();
-        }
-        return null;
-    }
-
-
-    private static List<ResourceInfo> parseResourceInfo(XPath xpath,
-            NodeList nodes, Set<String> ids) throws SRUConfigException,
-            XPathExpressionException {
-        logger.debug("parsing 'ResourceInfo' ({} nodes) ...",
-                nodes.getLength());
-
-        List<ResourceInfo> ris = null;
-        for (int k = 0; k < nodes.getLength(); k++) {
-            final Element node = (Element) nodes.item(k);
-            String pid = null;
-            int resourceCount = -1;
-            Map<String, String> titles = null;
-            Map<String, String> descrs = null;
-            String link = null;
-            List<String> langs = null;
-            String[] availableDataViews = null;
-            List<ResourceInfo> sub = null;
-
-            pid = node.getAttribute("pid");
-            if (pid != null) {
-                pid = pid.trim();
-                if (pid.isEmpty()) {
-                    pid = null;
-                }
-            }
-            if (pid == null) {
-                throw new SRUConfigException("Element <ResourceInfo> " +
-                        "must carry a proper 'pid' attribute");
-            }
-            if (ids.contains(pid)) {
-                throw new SRUConfigException("Another element <ResourceInfo> " +
-                        "with pid '" + pid + "' already exists");
-            }
-            ids.add(pid);
-
-            XPathExpression x1 = xpath.compile("ri:Title");
-            NodeList l1 = (NodeList) x1.evaluate(node, XPathConstants.NODESET);
-            if (l1 != null) {
-                for (int i = 0; i < l1.getLength(); i++) {
-                    final Element n = (Element) l1.item(i);
-
-                    final String lang = getLangAttribute(n);
-                    if (lang == null) {
-                        throw new SRUConfigException("Element <Title> must " +
-                                "carry a proper 'xml:lang' attribute");
-                    }
-
-                    final String title = cleanString(n.getTextContent());
-                    if (title == null) {
-                        throw new SRUConfigException("Element <Title> must " +
-                                "carry a non-empty 'xml:lang' attribute");
-                    }
-
-                    if (titles == null) {
-                        titles = new HashMap<String, String>();
-                    }
-                    if (titles.containsKey(lang)) {
-                        logger.warn("title with language '{}' already exists",
-                                lang);
-                    } else {
-                        logger.debug("title: '{}' '{}'", lang, title);
-                        titles.put(lang, title);
-                    }
-                }
-                if ((titles != null) && !titles.containsKey(LANG_EN)) {
-                    throw new SRUConfigException(
-                            "A <Title> with language 'en' is mandatory");
-                }
-            }
-            XPathExpression x2 = xpath.compile("ri:Description");
-            NodeList l2 = (NodeList) x2.evaluate(node, XPathConstants.NODESET);
-            if (l2 != null) {
-                for (int i = 0; i < l2.getLength(); i++) {
-                    Element n = (Element) l2.item(i);
-
-                    String lang = getLangAttribute(n);
-                    if (lang == null) {
-                        throw new SRUConfigException("Element <Description> " +
-                                "must carry a proper 'xml:lang' attribute");
-
-                    }
-                    String desc = cleanString(n.getTextContent());
-
-                    if (descrs == null) {
-                        descrs = new HashMap<String, String>();
-                    }
-
-                    if (descrs.containsKey(lang)) {
-                        logger.warn("description with language '{}' "
-                                + "already exists", lang);
-                    } else {
-                        logger.debug("description: '{}' '{}'", lang, desc);
-                        descrs.put(lang, desc);
-                    }
-                }
-                if ((descrs != null) && !descrs.containsKey(LANG_EN)) {
-                    throw new SRUConfigException(
-                            "A <Description> with language 'en' is mandatory");
-                }
-            }
-
-            XPathExpression x3 = xpath.compile("ri:LandingPageURI");
-            NodeList l3 = (NodeList) x3.evaluate(node, XPathConstants.NODESET);
-            if (l3 != null) {
-                for (int i = 0; i < l3.getLength(); i++) {
-                    Element n = (Element) l3.item(i);
-                    link = cleanString(n.getTextContent());
-                    logger.debug("link: \"{}\"", n.getTextContent());
-                }
-            }
-
-            XPathExpression x4 = xpath.compile("ri:Languages/ri:Language");
-            NodeList l4 = (NodeList) x4.evaluate(node, XPathConstants.NODESET);
-            if (l4 != null) {
-                for (int i = 0; i < l4.getLength(); i++) {
-                    Element n = (Element) l4.item(i);
-
-                    String s = n.getTextContent();
-                    if (s != null) {
-                        s = s.trim();
-                        if (s.isEmpty()) {
-                            s = null;
-                        }
-                    }
-
-                    /*
-                     * enforce three letter codes
-                     */
-                    if ((s == null) || (s.length() != 3)) {
-                        throw new SRUConfigException("Element <Language> " +
-                                "must use ISO-632-3 three letter " +
-                                "language codes");
-                    }
-
-                    if (langs == null) {
-                        langs = new ArrayList<String>();
-                    }
-                    logger.debug("language: '{}'", n.getTextContent());
-                    langs.add(s);
-                }
-            }
-            
-            XPathExpression x6 = xpath.compile("ri:AvailableDataViews/@ref");
-            String ref = (String) x6.evaluate(node, XPathConstants.STRING);
-            
-            if (ref == null || ref.isEmpty()){
-            	throw new SRUConfigException("Element <AvailableDataViews> " +
-                        "must have a non-empty attribute ref.");
-            }
-            
-            availableDataViews = ref.split("\\s+");
-            
-            
-            XPathExpression x5 =
-                    xpath.compile("ri:Resources/ri:Resource");
-            NodeList l5 = (NodeList) x5.evaluate(node, XPathConstants.NODESET);
-            if ((l5 != null) && (l5.getLength() > 0)) {
-                sub = parseResourceInfo(xpath, l5, ids);
-            }
-
-            if (ris == null) {
-                ris = new LinkedList<ResourceInfo>();
-            }
-            ris.add(new ResourceInfo(pid, resourceCount, titles, descrs, link,
-                    langs, Arrays.asList(availableDataViews),sub));
-        }
-        return ris;
-    }
-
-
-    private static String getLangAttribute(Element el) {
-        String lang = el.getAttributeNS(XMLConstants.XML_NS_URI, "lang");
-        if (lang != null) {
-            lang = lang.trim();
-            if (!lang.isEmpty()) {
-                return lang;
-            }
-        }
-        return null;
-    }
-
-
-    private static String cleanString(String s) {
-        if (s != null) {
-            s = s.trim();
-            if (!s.isEmpty()) {
-                StringBuilder sb = new StringBuilder();
-                for (String z : s.split("\\s*\\n+\\s*")) {
-                    z = z.trim();
-                    if (!z.isEmpty()) {
-                        if (sb.length() > 0) {
-                            sb.append(' ');
-                        }
-                        sb.append(z);
-                    }
-                }
-                if (sb.length() > 0) {
-                    return sb.toString();
-                }
-            }
-        }
-        return null;
-    }
-
-} // class SimpleResourceInfoInventoryParser
