/* * OpenURLReader.java * * Version: $Revision: 3705 $ * * Date: $Date: 2009-04-11 17:02:24 +0000 (Sat, 11 Apr 2009) $ * * Copyright (c) 2002-2009, The DSpace Foundation. 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 the Hewlett-Packard Company nor the name of the * Massachusetts Institute of Technology nor the names of their * 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.xmlui.cocoon; import java.io.IOException; import java.sql.SQLException; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletResponse; import org.apache.avalon.excalibur.pool.Recyclable; import org.apache.avalon.framework.parameters.Parameters; import org.apache.cocoon.ProcessingException; import org.apache.cocoon.environment.ObjectModelHelper; import org.apache.cocoon.environment.Request; import org.apache.cocoon.environment.Response; import org.apache.cocoon.environment.SourceResolver; import org.apache.cocoon.environment.http.HttpEnvironment; import org.apache.cocoon.reading.AbstractReader; import org.apache.log4j.Logger; import org.dspace.app.xmlui.utils.ContextUtil; import org.dspace.content.DSpaceObject; import org.dspace.core.Constants; import org.dspace.core.Context; import org.dspace.core.LogManager; import org.dspace.handle.HandleManager; import org.dspace.search.DSQuery; import org.dspace.search.QueryArgs; import org.dspace.search.QueryResults; import org.xml.sax.SAXException; /** * Simple servlet for open URL support. Presently, simply extracts terms from * open URL and redirects to search. * * @author Robert Tansley * @author Mark Diggory (mdiggory at mire.be) * @version $Revision: 3705 $ */ public class OpenURLReader extends AbstractReader implements Recyclable { private static final String Z39882004 = "Z39.88-2004"; private static final String Z39882004DC = "info:ofi/fmt:kev:mtx:dc"; private static final String Z39882004CTX = "info:ofi/fmt:kev:mtx:ctx"; /** The Cocoon response */ protected Response response; /** The Cocoon request */ protected Request request; /** The Servlet Response */ protected HttpServletResponse httpResponse; protected Context context; /** Logger */ private static Logger log = Logger.getLogger(OpenURLReader.class); public void generate() throws IOException, SAXException, ProcessingException { } @Override public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par) throws ProcessingException, SAXException, IOException { super.setup(resolver, objectModel, src, par); try { this.httpResponse = (HttpServletResponse) objectModel .get(HttpEnvironment.HTTP_RESPONSE_OBJECT); this.request = ObjectModelHelper.getRequest(objectModel); this.response = ObjectModelHelper.getResponse(objectModel); this.context = ContextUtil.obtainContext(objectModel); if (Z39882004.equals(request.getParameter("url_ver"))) { handleZ39882004(); } else { handleLegacy(); } } catch (SQLException sqle) { throw new ProcessingException("Unable to resolve OpenURL.", sqle); } } @Override public void recycle() { super.recycle(); this.response = null; this.request = null; this.httpResponse = null; this.context = null; } public void handleLegacy() throws IOException { String query = ""; String title = request.getParameter("title"); String authorFirst = request.getParameter("aufirst"); String authorLast = request.getParameter("aulast"); String logInfo = ""; if (title != null) { query = query + " " + title; logInfo = logInfo + "title=\"" + title + "\","; } if (authorFirst != null) { query = query + " " + authorFirst; logInfo = logInfo + "aufirst=\"" + authorFirst + "\","; } if (authorLast != null) { query = query + " " + authorLast; logInfo = logInfo + "aulast=\"" + authorLast + "\","; } log.info(LogManager.getHeader(context, "openURL", logInfo + "dspacequery=" + query)); httpResponse.sendRedirect(httpResponse.encodeRedirectURL(request .getContextPath() + "/simple-search?query=" + query)); } private String getFirstHandle(String query) throws IOException { List<String> handles = getHandles(query); for (String handle : handles) { return handle; } return null; } private List<String> getHandles(String query) throws IOException { QueryArgs args = new QueryArgs(); args.setQuery(query); QueryResults results = DSQuery.doQuery(context, args); return results.getHitHandles(); } /** * Validate supported formats * * We can deal with various formats if they exist such as journals and * books, but we currently do not have specific needs represent * different formats, thus it may be more appropriate to use dublin core * here directly. * * rft_val_fmt=info:ofi/fmt:kev:mtx:dc * * See Dublin Core OpenURL Profile Citation Guidelines: * http://dublincore.org/documents/dc-citation-guidelines/ * http://alcme.oclc * .org/openurl/servlet/OAIHandler/extension?verb=GetMetadata * &metadataPrefix=mtx&identifier=info:ofi/fmt:kev:mtx:dc * * What happens when we use Context Objects of different versions? Do * they exist? ctx_ver=Z39.88-2004 * * COinS will be implemented as: * * <span class="Z3988" title="ctx_ver=Z39.88-2004&rft_val_fmt=info:ofi/fmt:kev:mtx:journal&rft.issn=1045-4438" * > <A HREF="http://library.example.edu/?url_ver=Z39.88-2004&ctx_ver=Z39.88-2004&rft_val_fmt=info:ofi/fmt:kev:mtx:journal&rft.issn=1045-4438" * >Find at Example Library</A> </span> * * If an ctx_id is present use it to resolve the item directly. * Otherwise, use the search mechanism. Our ctx_id are going to be local * handle identifiers like the following * * ctx_id=10255/dryad.111 * * Global identifiers will be any other valid dc.identifier present * within that field. Thus: * * dc.identifier.uri http://dx.doi.org/10.1080/106351598260806 * dc.identifier.uri http://hdl.handle.net/10255/dryad.111 * * will lead to * * rft.identifier=http%3A%2F%2Fdx.doi.org%2F10.1080%2F106351598260806 * rft.identifier=http%3A%2F%2Fhdl.handle.net%2F10255%2Fdryad.111 * * And Thus be resolvable as well * @throws SQLException */ public void handleZ39882004() throws IOException, ProcessingException, SQLException { String rft_val_fmt = request.getParameter("rft_val_fmt"); if (rft_val_fmt != null && !rft_val_fmt.equals(Z39882004DC)) { throw new ProcessingException( "DSpace 1.0 OpenURL Service only supports rft_val_fmt=" + Z39882004DC); } String url_ctx_fmt = request.getParameter("url_ctx_fmt"); if (url_ctx_fmt != null && !url_ctx_fmt.equals(Z39882004CTX)) { throw new ProcessingException( "DSpace 1.0 OpenURL Service only supports url_ctx_fmt=" + Z39882004CTX); } /** * First attempt to resolve an rft_id identifier as a handle */ String[] rft_ids = request.getParameterValues("rft_id"); if(rft_ids != null) { for (String rft_id : rft_ids) { DSpaceObject obj = HandleManager.resolveToObject(context, rft_id); if (obj != null) { httpResponse.sendRedirect(httpResponse .encodeRedirectURL(request.getContextPath() + "/handle/" + obj.getHandle())); return; } } } String[] identifiers = request.getParameterValues("rtf.identifier"); /** * Next attempt to resolve an identifier in search */ if(identifiers != null) { for (String identifier : identifiers) { String handle = getFirstHandle("identifier: " + identifier); if (handle != null) { httpResponse.sendRedirect(httpResponse .encodeRedirectURL(request.getContextPath() + "/handle/" + handle)); return; } } } /** * Otherwise, attempt to full text search for the item */ String query = ""; Enumeration<String> e = request.getParameterNames(); boolean error = true; while (e.hasMoreElements()) { String name = e.nextElement(); if (name.startsWith("rft.")) { for (String value : request.getParameterValues(name)) { query += value + " "; error = false; } } } if(query.trim().length() == 0) { httpResponse.sendError(httpResponse.SC_BAD_REQUEST, "OpenURL Request requires a valid rtf_id, rtf.identifier or other rtf.<dublincore> search fields" ); } httpResponse.sendRedirect(httpResponse.encodeRedirectURL(request .getContextPath() + "/simple-search?query=" + java.net.URLEncoder.encode(query, request.getCharacterEncoding()))); } }