Index: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/OAIPMH.java
===================================================================
--- main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/OAIPMH.java	(revision 26095)
+++ main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/OAIPMH.java	(revision 26096)
@@ -483,4 +483,11 @@
         String[] metadata_names = getMetadataNameMapping(metadata_format);
         HashMap meta_map = getInfoByNames(info, metadata_names);
+		
+		// if there's no dc:identifier already after the mapping, we'll add it in
+		if(!meta_map.containsKey(OAIXML.DC+":identifier")) { // dc:identifier OAIXML.IDENTIFIER
+			outputCustomMetadata(meta_map, info, OAIXML.DC+":identifier");
+		}
+	
+		
 	if (meta_map == null) {
 	  return metadata;
@@ -701,4 +708,35 @@
     return (empty_map == true) ? null : map;
   }
+  
+  // GS3 version of GS2's runtime-src/src/oaiservr/dublincore.cpp function output_custom_metadata
+  protected void outputCustomMetadata(HashMap meta_map, DBInfo info, String dc_identifier) {
+		
+	// try gs.OAIResourceURL, else srclinkFile, else the GS version of the document
+	String identifier_value = info.getInfo(OAIXML.GS_OAI_RESOURCE_URL);
+	
+	if(identifier_value.equals("")) {
+		String url = OAIXML.getBaseURL(); // e.g. e.g. http://host:port/greenstone3/library/oaiserver
+	
+		identifier_value = info.getInfo("srclinkFile");
+		if(identifier_value.equals("")) 
+		{
+			// no source file to link to, so link to the GS version of the document (need to use URL-style slashes)
+			// e.g. http://host:port/greenstone3/library/collection/lucene-jdbm-demo/document/HASH014602ec89e16b7d431c7627
+			
+			identifier_value = url.replace("oaiserver", "library") + "collection/" + this.coll_name + "/document/" + info.getInfo("identifier"); // OID
+		} 
+		else // use srclinkFile
+		{		
+			// e.g. http://host:port/greenstone3/sites/localsite/collect/backdrop/index/assoc/D0.dir/Cat.jpg
+			identifier_value = url.replace("oaiserver", "") + "sites/" + this.site_name 
+				+ "/collect/" + this.coll_name + "/index/assoc/" 
+				+ info.getInfo("assocfilepath") + "/" + identifier_value; // srclinkFile
+		}
+	} // else use gs.OAIResourceURL as-is
+	
+	//logger.info("**** dc:identifier: " + identifier_value);
+	
+	meta_map.put(dc_identifier, identifier_value);
+  }
 }
 
Index: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/util/OAIXML.java
===================================================================
--- main/trunk/greenstone3/src/java/org/greenstone/gsdl3/util/OAIXML.java	(revision 26095)
+++ main/trunk/greenstone3/src/java/org/greenstone/gsdl3/util/OAIXML.java	(revision 26096)
@@ -99,4 +99,5 @@
     public static final String GRANULARITY = "granularity";
     public static final String GS3OAI = "GS3OAI";
+	public static final String GS_OAI_RESOURCE_URL = "gs.OAIResourceURL";
     public static final String HAS_OAI = "hasOAI";
     public static final String HEADER = "header";
@@ -177,4 +178,5 @@
      */
     public static String oai_version = "2.0";
+	public static String baseURL = "";
     
     /**response owner document */
@@ -194,4 +196,9 @@
       return oai_version;
     }
+	
+	public static String getBaseURL() {
+		return baseURL;
+	}
+	
     public static Element createElement(String tag_name) {
       return response_doc.createElement(tag_name);
@@ -286,5 +293,5 @@
     }
     /** Read in OAIConfig.xml (residing web/WEB-INF/classes/) and use it to configure the receptionist etc.
-     *  the oai_version variable is also set in here. 
+     *  the oai_version and baseURL variables are also set in here. 
      *  The init() method is also called in here. */ 
     public static Element getOAIConfigXML() {
@@ -310,4 +317,8 @@
       oai_version = GSXML.getNodeText(protocol_version).trim();
 
+	  // initialize baseURL
+	  Element base_url_elem = (Element)GSXML.getChildByTagName(oai_config_elem, BASE_URL);
+      baseURL = GSXML.getNodeText(base_url_elem);
+	  
       //initialize token_expiration
       Element expiration = (Element)GSXML.getChildByTagName(oai_config_elem, RESUMPTION_TOKEN_EXPIRATION);
@@ -387,7 +398,6 @@
         }
       }//end of for()
-      Element base_url_elem = (Element)GSXML.getChildByTagName(oai_config_elem, BASE_URL);
-      String base_url = GSXML.getNodeText(base_url_elem);
-      GSXML.setNodeText(request_elem, base_url);
+      
+	  GSXML.setNodeText(request_elem, baseURL);
       
       Node resp_date = GSXML.getChildByTagName(response, RESPONSE_DATE);
