Index: /VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/README.txt
===================================================================
--- /VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/README.txt	(revision 233)
+++ /VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/README.txt	(revision 234)
@@ -2,10 +2,11 @@
 ----------------------------------
 
-The connection to the database is configured using JNDI using
-the name "jdbc/VirtualCollectionStore".
-When using Apache Tomcat add the following to the Context of the Web-App
-(either modifying "server.xml" or by providing the appropriate context.xml,
- e.g. "$CATALINA_HOME/conf/Catalina/localhost/VirtualCollectionRegistry.xml";
- if in doubt, check the Apache Tomcat documentation):
+The connection to the database is configured using JNDI using the
+name "jdbc/VirtualCollectionStore".
+When using Apache Tomcat add the following to the context configuration
+of the web application (by either modifying "server.xml" or providing an
+appropiate context configuration, e.g. like
+  "$CATALINA_HOME/conf/Catalina/localhost/VirtualCollectionRegistry.xml";
+if in doubt, please check the Apache Tomcat documentation):
 
   <Resource name="jdbc/VirtualCollectionStore" auth="Container"
@@ -21,4 +22,10 @@
 
   This will configure a DBCP data source for the virtual collection registry.
-  Customize $dbuser, $dbpass and $dbname to match your local setiings.
+  Customize $dbuser, $dbpass and $dbname to match your local settings.
   NOTE: currently only MySQL is supported.
+
+  Furthermore, you will need to set the base URI for virtual collection
+  registry (customize value as needed):
+  <Parameter name="pid_provider.base_uri"
+             value="http://127.0.0.1:8080/VirtualCollectionRegistry"
+             override="false"/>
Index: /VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/VirtualCollectionRegistry.java
===================================================================
--- /VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/VirtualCollectionRegistry.java	(revision 233)
+++ /VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/VirtualCollectionRegistry.java	(revision 234)
@@ -13,5 +13,7 @@
 import javax.persistence.TypedQuery;
 
-import eu.clarin.cmdi.virtualcollectionregistry.model.Handle;
+import eu.clarin.cmdi.virtualcollectionregistry.model.InternalPersistentIdentifierProvider;
+import eu.clarin.cmdi.virtualcollectionregistry.model.PersistentIdentifier;
+import eu.clarin.cmdi.virtualcollectionregistry.model.PersistentIdentifierProvider;
 import eu.clarin.cmdi.virtualcollectionregistry.model.User;
 import eu.clarin.cmdi.virtualcollectionregistry.model.VirtualCollection;
@@ -28,6 +30,7 @@
 	private AtomicBoolean intialized = new AtomicBoolean(false);
 	private DataStore datastore = null;
+	private PersistentIdentifierProvider pid_provider = null;
 	private VirtualCollectionRegistryMarshaller marshaller = null;
-	
+
 	private VirtualCollectionRegistry() {
 		super();
@@ -45,13 +48,13 @@
 		}
 		logger.fine("initialize ...");
-		if (config == null) {
+		if (config != null) {
+			config = Collections.unmodifiableMap(config);
+		} else {
 			config = Collections.emptyMap();
 		}
-		for (String key : config.keySet()) {
-			logger.fine("XXX: " + key + " = \"" + config.get(key) + "\"");
-		}
-		datastore  = new DataStore(config);
-		marshaller = new VirtualCollectionRegistryMarshaller();
-		intialized.set(true);
+		this.datastore    = new DataStore(config);
+		this.pid_provider = new InternalPersistentIdentifierProvider(config);
+		this.marshaller   = new VirtualCollectionRegistryMarshaller();
+		this.intialized.set(true);
 	}
 
@@ -104,12 +107,14 @@
 			// store virtual collection
 			vc.setOwner(user);
-			String uuid = vc.createUUID();
+			vc.createUUID();
 			em.persist(vc);			
 			em.getTransaction().commit();
 
-			// XXX: for test PID service
-			em.getTransaction().begin();
-			em.persist(new Handle(uuid, Handle.Type.COLLECTION, vc.getId()));
-			em.getTransaction().commit();
+			PersistentIdentifier pid =
+				pid_provider.createPersistentIdentifier(vc);
+			em.getTransaction().begin();
+			em.persist(pid);
+			em.getTransaction().commit();
+
 			return vc.getId();
 		} catch (Exception e) {
Index: /VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/model/ClarinVirtualCollection.java
===================================================================
--- /VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/model/ClarinVirtualCollection.java	(revision 233)
+++ /VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/model/ClarinVirtualCollection.java	(revision 234)
@@ -49,6 +49,7 @@
 		@XmlElement(name = "MdSelfLink")
 		public URI getSelfLink() {
-			// FIXME: wrong link
-			return cvc.createHandleURI(cvc.getVirtualCollection().getUUID());
+			return cvc.getVirtualCollection()
+                      .getPersistentIdentifier()
+                      .createURI();
 		}
 
@@ -169,5 +170,4 @@
 	}
 
-	private URI handleBaseUri;
 	private VirtualCollection vc;
 	private Header header;
@@ -180,10 +180,9 @@
 	}
 
-	public ClarinVirtualCollection(VirtualCollection vc, URI handleBaseUri) {
+	public ClarinVirtualCollection(VirtualCollection vc) {
 		if (vc == null) {
 			throw new NullPointerException("vc == null");
 		}
 		this.vc = vc;
-		this.handleBaseUri = handleBaseUri;
 		this.header = new Header(this);
 		this.resources = new Resources(this);
@@ -191,8 +190,4 @@
 	}
 
-	URI createHandleURI(String pid) {
-		return URI.create(handleBaseUri.toString() + "/" + pid);
-	}
-
 	VirtualCollection getVirtualCollection() {
 		return vc;
Index: rtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/model/Handle.java
===================================================================
--- /VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/model/Handle.java	(revision 233)
+++ 	(revision )
@@ -1,68 +1,0 @@
-package eu.clarin.cmdi.virtualcollectionregistry.model;
-
-import java.util.UUID;
-
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.EnumType;
-import javax.persistence.Enumerated;
-import javax.persistence.GeneratedValue;
-import javax.persistence.GenerationType;
-import javax.persistence.Id;
-import javax.persistence.NamedQueries;
-import javax.persistence.NamedQuery;
-import javax.persistence.Table;
-
-@Entity
-@Table(name = "handle")
-@NamedQueries({
-	@NamedQuery(name = "Handle.findByPid",
-				query = "SELECT h FROM Handle h WHERE h.pid = :pid")
-})
-public class Handle {
-	public static enum Type {
-		COLLECTION, METADATA;
-	}
-	@Id
-	@GeneratedValue(strategy = GenerationType.AUTO)
-	@Column(name = "id", nullable = false, updatable = false)
-	private long id = -1;
-	@Column(name = "pid", nullable = false, updatable = false, unique = true)
-	private String pid;
-	@Enumerated(EnumType.ORDINAL)
-	@Column(name = "type", nullable = false, updatable = false)
-	private Type type;
-	@Column(name = "target", nullable = false, updatable = false)
-	private long target;
-	
-	@SuppressWarnings("unused")
-	private Handle() {
-	}
-
-	public Handle(String pid, Type type, long target) {
-		this.pid = pid;
-		this.type = type;
-		this.target = target;
-	}
-
-	public long getId() {
-		return id;
-	}
-
-	public String getPid() {
-		return pid;
-	}
-
-	public Type getType() {
-		return type;
-	}
-	
-	public long getTarget() {
-		return target;
-	}
-
-	public static String createPid() {
-		return UUID.randomUUID().toString();
-	}
-
-} // class Handle
Index: /VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/model/InternalPersistentIdentifier.java
===================================================================
--- /VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/model/InternalPersistentIdentifier.java	(revision 234)
+++ /VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/model/InternalPersistentIdentifier.java	(revision 234)
@@ -0,0 +1,47 @@
+package eu.clarin.cmdi.virtualcollectionregistry.model;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import javax.persistence.DiscriminatorValue;
+import javax.persistence.Entity;
+
+@Entity
+@DiscriminatorValue("I")
+public class InternalPersistentIdentifier extends PersistentIdentifier {
+	private static String uri_prefix = null;
+	
+	@SuppressWarnings("unused")
+	private InternalPersistentIdentifier() {
+		super();
+	}
+
+	InternalPersistentIdentifier(VirtualCollection vc) {
+		super(vc, "VC-" + Long.toHexString(vc.getId()));
+	}
+
+	public URI createURI() {
+		return URI.create(uri_prefix + collection.getId());
+	}
+
+	static void initBaseURI(String baseURI) {
+		if (baseURI == null) {
+			throw new NullPointerException("baseURI == null");
+		}
+		baseURI = baseURI.trim();
+		if (baseURI.isEmpty()) {
+			throw new IllegalArgumentException("empty baseURI is not allowed");
+		}
+		if (!baseURI.endsWith("/")) {
+			baseURI = baseURI + "/";
+		}
+		baseURI = baseURI + "service/clarin-virtualcollection/";
+		try {
+			URI pfx =  new URI(baseURI);
+			uri_prefix = pfx.toString();
+		} catch (URISyntaxException e) {
+			throw new IllegalArgumentException("baseURI is invalid", e);
+		}
+	}
+
+} // class InternalPersistentIdentifier
Index: /VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/model/InternalPersistentIdentifierProvider.java
===================================================================
--- /VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/model/InternalPersistentIdentifierProvider.java	(revision 234)
+++ /VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/model/InternalPersistentIdentifierProvider.java	(revision 234)
@@ -0,0 +1,31 @@
+package eu.clarin.cmdi.virtualcollectionregistry.model;
+
+import java.util.Map;
+
+import eu.clarin.cmdi.virtualcollectionregistry.VirtualCollectionRegistryException;
+
+public class InternalPersistentIdentifierProvider extends
+		PersistentIdentifierProvider {
+
+	public InternalPersistentIdentifierProvider(Map<String, String> config)
+			throws VirtualCollectionRegistryException {
+		super(config);
+		String prefix = config.get(BASE_URI);
+		if (prefix == null) {
+			throw new VirtualCollectionRegistryException("configuration " +
+					      "parameter \"" + BASE_URI + "\" is not set");
+		}
+		try {
+			InternalPersistentIdentifier.initBaseURI(prefix);
+		} catch (Exception e) {
+			throw new VirtualCollectionRegistryException("configuration " +
+					      "paremeter \"" + BASE_URI + "\" is invalid", e);
+		}
+	}
+
+	public PersistentIdentifier createPersistentIdentifier(VirtualCollection vc)
+			throws VirtualCollectionRegistryException {
+		return new InternalPersistentIdentifier(vc);
+	}
+
+} // class InternalPersistentIdentifierProvider
Index: /VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/model/PersistentIdentifier.java
===================================================================
--- /VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/model/PersistentIdentifier.java	(revision 234)
+++ /VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/model/PersistentIdentifier.java	(revision 234)
@@ -0,0 +1,79 @@
+package eu.clarin.cmdi.virtualcollectionregistry.model;
+
+import java.net.URI;
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.DiscriminatorColumn;
+import javax.persistence.DiscriminatorType;
+import javax.persistence.DiscriminatorValue;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Inheritance;
+import javax.persistence.InheritanceType;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import javax.persistence.Version;
+
+@Entity
+@Table(name = "pid")
+@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
+@DiscriminatorColumn(discriminatorType = DiscriminatorType.CHAR, name = "type")
+@DiscriminatorValue("_")
+public abstract class PersistentIdentifier {
+	@Id
+	@GeneratedValue(strategy = GenerationType.AUTO)
+	@Column(name = "id")
+	private long id = -1;
+	@OneToOne(fetch = FetchType.EAGER, optional = false)
+	protected VirtualCollection collection;
+	@Column(name = "identifier", nullable = false, updatable = false)
+	protected String identifier;
+	@Column(name = "last_modified", nullable = false)
+	@Temporal(TemporalType.TIMESTAMP)
+	@Version
+	private Date lastModifed;
+
+	protected PersistentIdentifier() {
+	}
+
+	protected PersistentIdentifier(VirtualCollection collection,
+			                       String identifier) {
+		if (collection == null) {
+			throw new NullPointerException("collection == null");
+		}
+		if (identifier == null) {
+			throw new NullPointerException("identifier == null");
+		}
+		identifier = identifier.trim();
+		if (identifier.isEmpty()) {
+			throw new IllegalArgumentException("identifier is empty");
+		}
+		this.collection = collection;
+		this.identifier = identifier;
+	}
+
+	public long getId() {
+		return id;
+	}
+
+	public VirtualCollection getVirtualCollection() {
+		return collection;
+	}
+
+	public String getIdentifier() {
+		return identifier;
+	}
+
+	public Date getLastModified() {
+		return lastModifed;
+	}
+
+	public abstract URI createURI();
+
+} // class PersistentIdentifier
Index: /VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/model/PersistentIdentifierProvider.java
===================================================================
--- /VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/model/PersistentIdentifierProvider.java	(revision 234)
+++ /VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/model/PersistentIdentifierProvider.java	(revision 234)
@@ -0,0 +1,19 @@
+package eu.clarin.cmdi.virtualcollectionregistry.model;
+
+import java.util.Map;
+
+import eu.clarin.cmdi.virtualcollectionregistry.VirtualCollectionRegistryException;
+
+public abstract class PersistentIdentifierProvider {
+	public static final String BASE_URI = "pid_provider.base_uri";
+
+	protected PersistentIdentifierProvider(Map<String, String> config)
+			throws VirtualCollectionRegistryException {
+		super();
+	}
+
+	public abstract PersistentIdentifier
+		createPersistentIdentifier(VirtualCollection vc)
+		throws VirtualCollectionRegistryException;
+
+} // interface PersistentIdentifierProvider
Index: /VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/model/VirtualCollection.java
===================================================================
--- /VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/model/VirtualCollection.java	(revision 233)
+++ /VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/model/VirtualCollection.java	(revision 234)
@@ -22,4 +22,5 @@
 import javax.persistence.NamedQuery;
 import javax.persistence.OneToMany;
+import javax.persistence.OneToOne;
 import javax.persistence.OrderBy;
 import javax.persistence.Table;
@@ -93,4 +94,7 @@
                            updatable = false, length = 36)
 	private String uuid;
+	@OneToOne(fetch = FetchType.EAGER, orphanRemoval = true, optional = true,
+			  mappedBy = "collection")
+	private PersistentIdentifier pid;
 	@Column(name = "name", nullable = false)
 	private String name;
@@ -149,5 +153,16 @@
 	@XmlAttribute(name = "uuid")
 	public String getUUID() {
-		return this.uuid;
+		return uuid;
+	}
+
+	public void setPersistentIdentifier(PersistentIdentifier pid) {
+		if (pid == null) {
+			throw new NullPointerException("pid == null");
+		}
+		this.pid = pid;
+	}
+
+	public PersistentIdentifier getPersistentIdentifier() {
+		return pid;
 	}
 
Index: /VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/rest/VirtualCollectionRegistryRestService.java
===================================================================
--- /VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/rest/VirtualCollectionRegistryRestService.java	(revision 233)
+++ /VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/rest/VirtualCollectionRegistryRestService.java	(revision 234)
@@ -7,6 +7,4 @@
 import java.security.Principal;
 
-import javax.persistence.EntityManager;
-import javax.persistence.Query;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
@@ -32,5 +30,4 @@
 import eu.clarin.cmdi.virtualcollectionregistry.VirtualCollectionRegistryMarshaller.Format;
 import eu.clarin.cmdi.virtualcollectionregistry.model.ClarinVirtualCollection;
-import eu.clarin.cmdi.virtualcollectionregistry.model.Handle;
 import eu.clarin.cmdi.virtualcollectionregistry.model.VirtualCollection;
 import eu.clarin.cmdi.virtualcollectionregistry.model.VirtualCollectionList;
@@ -216,7 +213,5 @@
 			@PathParam("id") long id) throws VirtualCollectionRegistryException {
 		VirtualCollection vc = registry.retrieveVirtualCollection(id);
-		URI handleBaseUri = uriInfo.getBaseUriBuilder().path("handle").build();  
-		final ClarinVirtualCollection cvc =
-			new ClarinVirtualCollection(vc, handleBaseUri);
+		final ClarinVirtualCollection cvc = new ClarinVirtualCollection(vc);
 		StreamingOutput writer = new StreamingOutput() {
 			public void write(OutputStream output) throws IOException,
@@ -226,36 +221,4 @@
 		};
 		return Response.ok(writer).build();
-	}
-
-	@GET
-	@Path("/handle/{pid}")
-	public Response getHandle(@PathParam("pid") String pid) {
-		System.err.println("Pid: " + pid);
-		EntityManager em = registry.getDataStore().getEntityManager();
-		try {
-			em.getTransaction().begin();
-			Query q = em.createNamedQuery("Handle.findByPid");
-			q.setParameter("pid", pid);
-			Handle handle = (Handle) q.getSingleResult();
-			System.err.println("handle: " + handle.getType());
-			URI target;
-			switch (handle.getType()) {
-			case COLLECTION:
-				target = uriInfo.getBaseUriBuilder().path(
-						"clarin-virtualcollection/" + handle.getTarget()).build();
-				break;
-			case METADATA:
-				target = uriInfo.getBaseUriBuilder().path(
-						"clarin-metadata/" + handle.getTarget()).build();
-				break;
-			default:
-				throw new VirtualCollectionRegistryException("internel error");
-			} // switch
-			return Response.seeOther(target).build();
-		} catch (Exception e) {
-			throw new WebApplicationException(e);
-		} finally {
-			em.getTransaction().commit();
-		}
 	}
 
Index: /VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/resources/META-INF/persistence.xml
===================================================================
--- /VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/resources/META-INF/persistence.xml	(revision 233)
+++ /VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/resources/META-INF/persistence.xml	(revision 234)
@@ -12,5 +12,6 @@
 		<class>eu.clarin.cmdi.virtualcollectionregistry.model.Creator</class>
 		<class>eu.clarin.cmdi.virtualcollectionregistry.model.Resource</class>
-		<class>eu.clarin.cmdi.virtualcollectionregistry.model.Handle</class>
+		<class>eu.clarin.cmdi.virtualcollectionregistry.model.PersistentIdentifier</class>
+		<class>eu.clarin.cmdi.virtualcollectionregistry.model.InternalPersistentIdentifier</class>
 		<properties>
 			<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
