[DS-588] Patch for SFX (OpenURL resolver)

git-svn-id: http://scm.dspace.org/svn/repo/dspace/trunk@5478 9c30dcfa-912a-0410-8fc2-9e0234be79fd
This commit is contained in:
Stuart Lewis
2010-10-20 01:57:33 +00:00
parent d4a6ea6a1c
commit 314b3ed1ba
7 changed files with 495 additions and 107 deletions

View File

@@ -0,0 +1,352 @@
/*
* SFXFileReader.java
*
* Version: $Revision:$
*
* Date: $Date:$
*
* Copyright (c) 2002-2009, Duraspace. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Duraspace nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package org.dspace.app.sfx;
import java.io.File;
import java.io.IOException;
import java.lang.String;
import java.net.URLEncoder;
import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.dspace.content.DCPersonName;
import org.dspace.content.DCValue;
import org.dspace.content.Item;
import org.dspace.core.Constants;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class SFXFileReader {
/** The SFX configuration file */
private static Document doc;
/** log4j logger */
private static final Logger log = Logger.getLogger(SFXFileReader.class);
/**
* Loads the SFX configuraiton file
*
* @param fileName The name of the SFX configuration file
* @param item The item to process
*
* @return the SFX string
* @throws IOException
*/
public static String loadSFXFile(String fileName, Item item) throws IOException
{
// Parse XML file -> XML document will be build
if (doc == null) doc = parseFile(fileName);
// Return final sfx Query String
return doNodes(doc, item);
}
/** Parses XML file and returns XML document.
* @param fileName XML file to parse
* @return XML document or <B>null</B> if error occured
*/
public static Document parseFile(String fileName) {
log.info("Parsing XML file... " + fileName);
DocumentBuilder docBuilder;
Document doc = null;
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
docBuilderFactory.setIgnoringElementContentWhitespace(true);
try {
docBuilder = docBuilderFactory.newDocumentBuilder();
}
catch (ParserConfigurationException e) {
log.error("Wrong parser configuration: " + e.getMessage());
return null;
}
File sourceFile = new File(fileName);
try {
doc = docBuilder.parse(sourceFile);
}
catch (SAXException e) {
log.error("Wrong XML file structure: " + e.getMessage());
return null;
}
catch (IOException e) {
log.error("Could not read source file: " + e.getMessage());
}
log.info("XML file parsed");
return doc;
}
/**
* Process the item
*
* @param node
* @param item
* @return
* @throws IOException
*/
public static String doNodes(Node node, Item item) throws IOException
{
if (node == null)
{
log.error (" Empty Node ");
return null;
}
Node e = getElement(node);
NodeList nl = e.getChildNodes();
int len = nl.getLength();
String sfxfield = "";
int i = 0;
while ((i < len) && (sfxfield == ""))
{
Node nd = nl.item(i);
if ((nd == null) || isEmptyTextNode(nd))
{
i++;
continue;
}
String tagName = nd.getNodeName();
if (tagName.equals("query-pairs"))
{
sfxfield = processFields(nd, item);
}
i++;
}
log.info("Process fields : " + sfxfield);
return sfxfield;
}
/**
* Process the fields
*
* @param e
* @param item
* @return
* @throws IOException
*/
private static String processFields(Node e, Item item) throws IOException
{
NodeList cl = e.getChildNodes();
int lench = cl.getLength();
String myquery = "";
for (int j = 0; j < lench; j++)
{
Node nch = cl.item(j);
String querystring = "";
String schema = "";
String qualifier = "";
String element = "";
if (nch.getNodeName().equals("field"))
{
NodeList pl = nch.getChildNodes();
int plen = pl.getLength();
int finish = 0;
for (int k = 0; k < plen; k++)
{
Node vn= pl.item(k);
String vName = vn.getNodeName();
if (vName.equals("querystring"))
{
querystring = getValue(vn);
finish ++;
}
else if (vName.equals("dc-schema"))
{
schema = getValue(vn);;
finish ++;
}
else if (vName.equals("dc-element"))
{
element = getValue(vn);
finish ++;
}
else if (vName.equals("dc-qualifier"))
{
qualifier = getValue(vn);
finish ++;
if (qualifier == "")
{
qualifier = null;
}
}
if (finish == 4)
{
DCValue[] dcvalue = item.getMetadata(schema, element, qualifier, Item.ANY);
if (dcvalue.length > 0)
{
// Issued Date
if (element.equals("date") && qualifier.equals("issued"))
{
String fullDate = dcvalue[0].value;
// Remove the time if there is one - day is greatest granularity for SFX
if (fullDate.length() > 10)
{
fullDate = fullDate.substring(0, 10);
}
if (myquery.equals(""))
{ myquery = querystring + URLEncoder.encode(fullDate, Constants.DEFAULT_ENCODING); }
else
{ myquery = myquery + "&" + querystring + URLEncoder.encode(fullDate, Constants.DEFAULT_ENCODING); }
}
else
{
// Contributor Author
if (element.equals("contributor") && qualifier.equals("author"))
{
DCPersonName dpn = new DCPersonName(dcvalue[0].value);
String dpnName = dcvalue[0].value;
if (querystring.endsWith("aulast=")) { dpnName = dpn.getLastName(); }
else { if (querystring.endsWith("aufirst=")) { dpnName = dpn.getFirstNames(); }}
if (myquery.equals(""))
{ myquery = querystring + URLEncoder.encode(dpnName, Constants.DEFAULT_ENCODING); }
else
{ myquery = myquery + "&" + querystring + URLEncoder.encode(dpnName, Constants.DEFAULT_ENCODING); }
}
else
{
if (myquery.equals(""))
{ myquery = querystring + URLEncoder.encode(dcvalue[0].value, Constants.DEFAULT_ENCODING);}
else
{ myquery = myquery + "&" + querystring + URLEncoder.encode(dcvalue[0].value, Constants.DEFAULT_ENCODING);}
}
}
} // if dc.length > 0
finish = 0;
querystring = "";
schema = "";
element = "";
qualifier = "";
} // if finish == 4
} //for k
} // if field
} // for j
return myquery;
}
/** Returns element node
* @param node element (it is XML tag)
* @return Element node otherwise null
*/
public static Node getElement(Node node)
{
NodeList child = node.getChildNodes();
int length = child.getLength();
for (int i = 0; i < length; i++)
{
Node kid = child.item(i);
if (kid.getNodeType() == Node.ELEMENT_NODE)
{
return kid;
}
}
return null;
}
/** Is Empty text Node **/
public static boolean isEmptyTextNode(Node nd)
{
boolean isEmpty = false;
if (nd.getNodeType() == Node.TEXT_NODE)
{
String text = nd.getNodeValue().trim();
if (text.length() == 0)
{
isEmpty = true;
}
}
return isEmpty;
}
/**
* Returns the value of the node's attribute named <name>
**/
public static String getAttribute(Node e, String name)
{
NamedNodeMap attrs = e.getAttributes();
int len = attrs.getLength();
if (len > 0)
{
for (int i = 0; i < len; i++)
{
Node attr = attrs.item(i);
if (name.equals(attr.getNodeName()))
{
return attr.getNodeValue().trim();
}
}
}
//no such attribute
return null;
}
/**
* Returns the value found in the Text node (if any) in the
* node list that's passed in.
*/
public static String getValue(Node node)
{
NodeList child = node.getChildNodes();
for (int i = 0; i < child.getLength(); i++)
{
Node kid = child.item(i);
short type = kid.getNodeType();
if (type == Node.TEXT_NODE)
{
return kid.getNodeValue().trim();
}
}
// Didn't find a text node
return null;
}
}

View File

@@ -39,6 +39,7 @@
*/
package org.dspace.app.webui.jsptag;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
@@ -51,18 +52,27 @@ import org.dspace.content.Item;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Constants;
import org.w3c.dom.*;
import org.dspace.app.sfx.SFXFileReader;
/**
* Renders an SFX query link. Takes one attribute - "item" which must be an Item
* object.
*
*
* @author Robert Tansley
* @version $Revision$
*/
public class SFXLinkTag extends TagSupport
{
/** Item to display SFX link for */
private Item item;
/** The fully qualified pathname of the SFX XML file */
private String sfxFile = ConfigurationManager.getProperty("dspace.dir") + File.separator
+ "config" + File.separator + "sfx.xml";
public SFXLinkTag()
{
super();
@@ -81,78 +91,15 @@ public class SFXLinkTag extends TagSupport
return SKIP_BODY;
}
String sfxQuery = "";
String sfxQuery = "";
DCValue[] titles = item.getDC("title", null, Item.ANY);
if (titles.length > 0)
{
sfxQuery = sfxQuery
+ "&title="
+ URLEncoder.encode(titles[0].value,
Constants.DEFAULT_ENCODING);
}
DCValue[] authors = item.getDC("contributor", "author", Item.ANY);
if (authors.length > 0)
{
DCPersonName dpn = new DCPersonName(authors[0].value);
sfxQuery = sfxQuery
+ "&aulast="
+ URLEncoder.encode(dpn.getLastName(),
Constants.DEFAULT_ENCODING);
sfxQuery = sfxQuery
+ "&aufirst="
+ URLEncoder.encode(dpn.getFirstNames(),
Constants.DEFAULT_ENCODING);
}
DCValue[] isbn = item.getDC("identifier", "isbn", Item.ANY);
if (isbn.length > 0)
{
sfxQuery = sfxQuery
+ "&isbn="
+ URLEncoder.encode(isbn[0].value,
Constants.DEFAULT_ENCODING);
}
DCValue[] issn = item.getDC("identifier", "issn", Item.ANY);
if (issn.length > 0)
{
sfxQuery = sfxQuery
+ "&issn="
+ URLEncoder.encode(issn[0].value,
Constants.DEFAULT_ENCODING);
}
DCValue[] dates = item.getDC("date", "issued", Item.ANY);
if (dates.length > 0)
{
String fullDate = dates[0].value;
// Remove the time if there is one - day is greatest granularity
// for SFX
if (fullDate.length() > 10)
{
fullDate = fullDate.substring(0, 10);
}
sfxQuery = sfxQuery
+ "&date="
+ URLEncoder.encode(fullDate,
Constants.DEFAULT_ENCODING);
}
sfxQuery = SFXFileReader.loadSFXFile(sfxFile, item);
// Remove initial &, if any
if (sfxQuery.startsWith("&"))
{
sfxQuery = sfxQuery.substring(1);
}
pageContext.getOut().print(sfxServer + sfxQuery);
}
catch (IOException ie)
@@ -165,7 +112,7 @@ public class SFXLinkTag extends TagSupport
/**
* Get the item this tag should display SFX Link for
*
*
* @return the item
*/
public Item getItem()
@@ -175,7 +122,7 @@ public class SFXLinkTag extends TagSupport
/**
* Set the item this tag should display SFX Link for
*
*
* @param itemIn
* the item
*/
@@ -183,4 +130,5 @@ public class SFXLinkTag extends TagSupport
{
item = itemIn;
}
}

View File

@@ -39,12 +39,14 @@
*/
package org.dspace.app.xmlui.aspect.artifactbrowser;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.io.StringWriter;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.net.URLEncoder;
import javax.servlet.ServletException;
@@ -82,38 +84,45 @@ import org.jdom.Element;
import org.jdom.Text;
import org.jdom.output.XMLOutputter;
import org.xml.sax.SAXException;
import org.dspace.core.ConfigurationManager;
import org.dspace.app.sfx.SFXFileReader;
/**
* Display a single item.
*
*
* @author Scott Phillips
*/
public class ItemViewer extends AbstractDSpaceTransformer implements CacheableProcessingComponent
{
private static final Logger log = Logger.getLogger(ItemViewer.class);
/** Language strings */
private static final Message T_dspace_home =
message("xmlui.general.dspace_home");
private static final Message T_trail =
message("xmlui.ArtifactBrowser.ItemViewer.trail");
private static final Message T_show_simple =
message("xmlui.ArtifactBrowser.ItemViewer.show_simple");
private static final Message T_show_full =
message("xmlui.ArtifactBrowser.ItemViewer.show_full");
private static final Message T_head_parent_collections =
message("xmlui.ArtifactBrowser.ItemViewer.head_parent_collections");
/** Cached validity object */
private SourceValidity validity = null;
/** XHTML crosswalk instance */
private DisseminationCrosswalk xHTMLHeadCrosswalk = null;
private String sfxFile = ConfigurationManager.getProperty("dspace.dir") + File.separator
+ "config" + File.separator + "sfx.xml";
private String sfxQuery = null;
/**
* Generate the unique caching key.
* This key must be unique inside the space of this component.
@@ -121,12 +130,12 @@ public class ItemViewer extends AbstractDSpaceTransformer implements CacheablePr
public Serializable getKey() {
try {
DSpaceObject dso = HandleUtil.obtainHandle(objectModel);
if (dso == null)
return "0"; // no item, something is wrong.
return HashUtil.hash(dso.getHandle() + "full:" + showFullItem(objectModel));
}
}
catch (SQLException sqle)
{
// Ignore all errors and just return that the component is not cachable.
@@ -136,11 +145,11 @@ public class ItemViewer extends AbstractDSpaceTransformer implements CacheablePr
/**
* Generate the cache validity object.
*
* The validity object will include the item being viewed,
*
* The validity object will include the item being viewed,
* along with all bundles & bitstreams.
*/
public SourceValidity getValidity()
public SourceValidity getValidity()
{
DSpaceObject dso = null;
@@ -148,7 +157,7 @@ public class ItemViewer extends AbstractDSpaceTransformer implements CacheablePr
{
try {
dso = HandleUtil.obtainHandle(objectModel);
DSpaceValidity validity = new DSpaceValidity();
validity.add(dso);
this.validity = validity.complete();
@@ -161,8 +170,8 @@ public class ItemViewer extends AbstractDSpaceTransformer implements CacheablePr
}
return this.validity;
}
/**
* Add the item's title and trail links to the page's metadata.
*/
@@ -186,7 +195,25 @@ public class ItemViewer extends AbstractDSpaceTransformer implements CacheablePr
pageMeta.addTrailLink(contextPath + "/",T_dspace_home);
HandleUtil.buildHandleTrail(item,pageMeta,contextPath);
pageMeta.addTrail().addContent(T_trail);
// Add SFX link
String sfxserverUrl = ConfigurationManager.getProperty("sfx.server.url");
if (sfxserverUrl != null && sfxserverUrl.length() > 0)
{
sfxQuery = "";
// parse XML file -> XML document will be build
sfxQuery = SFXFileReader.loadSFXFile(sfxFile, item);
// Remove initial &, if any
if (sfxQuery.startsWith("&"))
{
sfxQuery = sfxQuery.substring(1);
}
sfxserverUrl = sfxserverUrl.trim() +"&" + sfxQuery.trim();
pageMeta.addMetadata("sfx","server").addContent(sfxserverUrl);
}
// Metadata for <head> element
if (xHTMLHeadCrosswalk == null)
{
@@ -232,7 +259,7 @@ public class ItemViewer extends AbstractDSpaceTransformer implements CacheablePr
if (!(dso instanceof Item))
return;
Item item = (Item) dso;
// Build the item viewer division.
Division division = body.addDivision("item-view","primary");
String title = getItemTitle(item);
@@ -254,7 +281,7 @@ public class ItemViewer extends AbstractDSpaceTransformer implements CacheablePr
+ "?show=full";
showfullPara.addXref(link).addContent(T_show_full);
}
ReferenceSet referenceSet;
if (showFullItem(objectModel))
{
@@ -270,13 +297,13 @@ public class ItemViewer extends AbstractDSpaceTransformer implements CacheablePr
// Refrence the actual Item
ReferenceSet appearsInclude = referenceSet.addReference(item).addReferenceSet(ReferenceSet.TYPE_DETAIL_LIST,null,"hierarchy");
appearsInclude.setHead(T_head_parent_collections);
// Reference all collections the item appears in.
for (Collection collection : item.getCollections())
{
appearsInclude.addReference(collection);
}
showfullPara = division.addPara(null,"item-view-toggle item-view-toggle-bottom");
if (showFullItem(objectModel))
@@ -291,7 +318,7 @@ public class ItemViewer extends AbstractDSpaceTransformer implements CacheablePr
showfullPara.addXref(link).addContent(T_show_full);
}
}
/**
* Determine if the full item should be referenced or just a summary.
*/
@@ -319,7 +346,7 @@ public class ItemViewer extends AbstractDSpaceTransformer implements CacheablePr
title = null;
return title;
}
/**
* Recycle
*/

View File

@@ -1012,21 +1012,14 @@
coins
-->
<xsl:template name="renderCOinS">
<xsl:text>ctx_ver=Z39.88-2004&amp;rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Adc&amp;</xsl:text>
<xsl:for-each select=".//dim:field[@element = 'identifier']">
<xsl:text>rft_id=</xsl:text>
<xsl:value-of select="encoder:encode(string(.))"/>
<xsl:text>&amp;</xsl:text>
</xsl:for-each>
<!--- SFX renderCOinS -->
<xsl:template name="renderCOinS">
<xsl:text>ctx_ver=Z39.88-2004&amp;rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Adc&amp;</xsl:text>
<xsl:value-of select="/dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='sfx'][@qualifier='server']"/>
<xsl:text>&amp;</xsl:text>
<xsl:text>rfr_id=info%3Asid%2Fdatadryad.org%3Arepo&amp;</xsl:text>
<xsl:for-each select=".//dim:field[@element != 'description' and @mdschema !='dc' and @qualifier != 'provenance']">
<xsl:value-of select="concat('rft.', @element,'=',encoder:encode(string(.))) "/>
<xsl:if test="position()!=last()">
<xsl:text>&amp;</xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:template>
</xsl:stylesheet>

View File

@@ -502,6 +502,14 @@
</div>
</xsl:if>
<xsl:apply-templates />
<xsl:if test="/dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='sfx'][@qualifier='server']">
<a>
<xsl:attribute name="href">
<xsl:value-of select="/dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='sfx'][@qualifier='server']"/>
</xsl:attribute>
<xsl:text>Find Full text</xsl:text>
</a>
</xsl:if>
</div>
</xsl:template>

View File

@@ -1,5 +1,8 @@
1.7.0
=====
(Yin Yin Latt)
- [DS-588] Patch for SFX (OpenURL resolver)
(Michael B. Klein)
- [DS-699] ChoiceAuthority plugin for old-style controlled vocabularies

57
dspace/config/sfx.xml Normal file
View File

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<openurl>
<query-pairs>
<field>
<querystring>rft_id=info:doi/</querystring>
<dc-schema>dc</dc-schema>
<dc-element>identifier</dc-element>
<dc-qualifier>doi</dc-qualifier>
</field>
</query-pairs>
<query-pairs>
<field>
<querystring>rft_id=info:pmid/</querystring>
<dc-schema>dc</dc-schema>
<dc-element>identifier</dc-element>
<dc-qualifier>pmid</dc-qualifier>
</field>
</query-pairs>
<query-pairs>
<field>
<querystring>rft.issn=</querystring>
<dc-schema>dc</dc-schema>
<dc-element>identifier</dc-element>
<dc-qualifier>issn</dc-qualifier>
</field>
<field>
<querystring>rft.isbn=</querystring>
<dc-schema>dc</dc-schema>
<dc-element>identifier</dc-element>
<dc-qualifier>isbn</dc-qualifier>
</field>
<field>
<querystring>rft.atitle=</querystring>
<dc-schema>dc</dc-schema>
<dc-element>title</dc-element>
<dc-qualifier></dc-qualifier>
</field>
<field>
<querystring>rft.aulast=</querystring>
<dc-schema>dc</dc-schema>
<dc-element>contributor</dc-element>
<dc-qualifier>author</dc-qualifier>
</field>
<field>
<querystring>rft.aufirst=</querystring>
<dc-schema>dc</dc-schema>
<dc-element>contributor</dc-element>
<dc-qualifier>author</dc-qualifier>
</field>
<field>
<querystring>rft.date=</querystring>
<dc-schema>dc</dc-schema>
<dc-element>date</dc-element>
<dc-qualifier>issued</dc-qualifier>
</field>
</query-pairs>
</openurl>