Jay Paz (SF#1898241) Add item Export from jspui and xmlui.

git-svn-id: http://scm.dspace.org/svn/repo/branches/dspace-1_5_x@2968 9c30dcfa-912a-0410-8fc2-9e0234be79fd
This commit is contained in:
Scott Phillips
2008-06-24 21:08:28 +00:00
parent 0292f77157
commit eb717aa6e1
19 changed files with 2179 additions and 465 deletions

View File

@@ -0,0 +1,158 @@
/*
* ItemExportArchiveServlet.java
*
* Version: $Revision: 2073 $
*
* Date: $Date: 2007-07-19 11:45:10 -0500 (Thu, 19 Jul 2007) $
*
* Copyright (c) 2002-2005, Hewlett-Packard Company and Massachusetts
* Institute of Technology. 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.webui.servlet;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.dspace.app.itemexport.ItemExport;
import org.dspace.app.webui.util.JSPManager;
import org.dspace.authorize.AuthorizeException;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.core.LogManager;
import org.dspace.core.Utils;
/**
* Servlet for retrieving item export archives. The bits are simply piped to the
* user. If there is an <code>If-Modified-Since</code> header, only a 304
* status code is returned if the containing item has not been modified since
* that date.
* <P>
* <code>/exportdownload/filename</code>
*
* @author Jay Paz
*/
public class ItemExportArchiveServlet extends DSpaceServlet {
/** log4j category */
private static Logger log = Logger
.getLogger(ItemExportArchiveServlet.class);
/**
* Threshold on export size size before content-disposition will be set.
*/
private int threshold;
@Override
public void init(ServletConfig arg0) throws ServletException {
super.init(arg0);
threshold = ConfigurationManager
.getIntProperty("webui.content_disposition_threshold");
}
@Override
protected void doDSGet(Context context, HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException,
SQLException, AuthorizeException {
String filename = null;
filename = request.getPathInfo().substring(
request.getPathInfo().lastIndexOf('/')+1);
System.out.println(filename);
if (ItemExport.canDownload(context, filename)) {
try {
InputStream exportStream = ItemExport
.getExportDownloadInputStream(filename, context
.getCurrentUser());
if (exportStream == null || filename == null) {
// No bitstream found or filename was wrong -- ID invalid
log.info(LogManager.getHeader(context, "invalid_id",
"path=" + filename));
JSPManager.showInvalidIDError(request, response, filename,
Constants.BITSTREAM);
return;
}
log.info(LogManager.getHeader(context,
"download_export_archive", "filename=" + filename));
// Modification date
// TODO: Currently the date of the item, since we don't have
// dates
// for files
long lastModified = ItemExport
.getExportFileLastModified(filename);
response.setDateHeader("Last-Modified", lastModified);
// Check for if-modified-since header
long modSince = request.getDateHeader("If-Modified-Since");
if (modSince != -1 && lastModified < modSince) {
// Item has not been modified since requested date,
// hence bitstream has not; return 304
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
return;
}
// Set the response MIME type
response.setContentType(ItemExport.COMPRESSED_EXPORT_MIME_TYPE);
// Response length
long size = ItemExport.getExportFileSize(filename);
response.setHeader("Content-Length", String.valueOf(size));
response.setHeader("Content-Disposition",
"attachment;filename=" + filename);
Utils.bufferedCopy(exportStream, response.getOutputStream());
exportStream.close();
response.getOutputStream().flush();
} catch (Exception e) {
throw new ServletException(e);
}
} else {
throw new AuthorizeException(
"You are not authorized to download this Export Archive.");
}
}
}

View File

@@ -50,11 +50,13 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.dspace.app.webui.util.JSPManager;
import org.dspace.app.itemexport.ItemExport;
import org.dspace.app.util.SubmissionConfigReader;
import org.dspace.app.util.SubmissionConfig;
import org.dspace.app.webui.util.UIUtil;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.Item;
import org.dspace.content.ItemIterator;
import org.dspace.content.SupervisedItem;
@@ -73,6 +75,7 @@ import org.dspace.workflow.WorkflowManager;
* Servlet for constructing the components of the "My DSpace" page
*
* @author Robert Tansley
* @author Jay Paz
* @version $Id$
*/
public class MyDSpaceServlet extends DSpaceServlet
@@ -95,6 +98,9 @@ public class MyDSpaceServlet extends DSpaceServlet
/** The "reason for rejection" page */
public static final int REJECT_REASON_PAGE = 4;
/** The "request export archive for download" page */
public static final int REQUEST_EXPORT_ARCHIVE = 5;
protected void doDSGet(Context context, HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException,
SQLException, AuthorizeException
@@ -135,6 +141,10 @@ public class MyDSpaceServlet extends DSpaceServlet
case REJECT_REASON_PAGE:
processRejectReason(context, request, response);
break;
case REQUEST_EXPORT_ARCHIVE:
processExportArchive(context, request, response);
break;
default:
@@ -576,6 +586,99 @@ public class MyDSpaceServlet extends DSpaceServlet
}
}
private void processExportArchive(Context context,
HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
if (request.getParameter("item_id") != null) {
Item item = null;
try {
item = Item.find(context, Integer.parseInt(request
.getParameter("item_id")));
} catch (Exception e) {
log.warn(LogManager.getHeader(context, "integrity_error", UIUtil
.getRequestLogInfo(request)));
JSPManager.showIntegrityError(request, response);
return;
}
if (item == null) {
log.warn(LogManager.getHeader(context, "integrity_error", UIUtil
.getRequestLogInfo(request)));
JSPManager.showIntegrityError(request, response);
return;
} else {
try {
ItemExport.createDownloadableExport(item, context);
} catch (Exception e) {
log.warn(LogManager.getHeader(context, "integrity_error", UIUtil
.getRequestLogInfo(request)));
JSPManager.showIntegrityError(request, response);
return;
}
}
// success
JSPManager.showJSP(request, response, "/mydspace/task-complete.jsp");
} else if (request.getParameter("collection_id") != null) {
Collection col = null;
try {
col = Collection.find(context, Integer.parseInt(request
.getParameter("collection_id")));
} catch (Exception e) {
log.warn(LogManager.getHeader(context, "integrity_error", UIUtil
.getRequestLogInfo(request)));
JSPManager.showIntegrityError(request, response);
return;
}
if (col == null) {
log.warn(LogManager.getHeader(context, "integrity_error", UIUtil
.getRequestLogInfo(request)));
JSPManager.showIntegrityError(request, response);
return;
} else {
try {
ItemExport.createDownloadableExport(col, context);
} catch (Exception e) {
log.warn(LogManager.getHeader(context, "integrity_error", UIUtil
.getRequestLogInfo(request)));
JSPManager.showIntegrityError(request, response);
return;
}
}
JSPManager.showJSP(request, response, "/mydspace/task-complete.jsp");
} else if (request.getParameter("community_id") != null) {
Community com = null;
try {
com = Community.find(context, Integer.parseInt(request
.getParameter("community_id")));
} catch (Exception e) {
log.warn(LogManager.getHeader(context, "integrity_error", UIUtil
.getRequestLogInfo(request)));
JSPManager.showIntegrityError(request, response);
return;
}
if (com == null) {
log.warn(LogManager.getHeader(context, "integrity_error", UIUtil
.getRequestLogInfo(request)));
JSPManager.showIntegrityError(request, response);
return;
} else {
try {
org.dspace.app.itemexport.ItemExport.createDownloadableExport(com, context);
} catch (Exception e) {
log.warn(LogManager.getHeader(context, "integrity_error", UIUtil
.getRequestLogInfo(request)));
JSPManager.showIntegrityError(request, response);
return;
}
}
JSPManager.showJSP(request, response, "/mydspace/task-complete.jsp");
}
}
// ****************************************************************
// ****************************************************************
// METHODS FOR SHOWING FORMS
@@ -623,6 +726,15 @@ public class MyDSpaceServlet extends DSpaceServlet
SupervisedItem[] supervisedItems = SupervisedItem.findbyEPerson(
context, currentUser);
// export archives available for download
List<String> exportArchives = null;
try{
exportArchives = ItemExport.getExportsAvailable(currentUser);
}
catch (Exception e) {
// nothing to do they just have no export archives available for download
}
// Set attributes
request.setAttribute("mydspace.user", currentUser);
@@ -633,6 +745,7 @@ public class MyDSpaceServlet extends DSpaceServlet
request.setAttribute("group.memberships", memberships);
request.setAttribute("display.groupmemberships", new Boolean(displayMemberships));
request.setAttribute("supervised.items", supervisedItems);
request.setAttribute("export.archives", exportArchives);
// Forward to main mydspace page
JSPManager.showJSP(request, response, "/mydspace/main.jsp");

View File

@@ -164,6 +164,11 @@
<servlet-class>org.dspace.app.webui.servlet.BitstreamServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>exportdownload</servlet-name>
<servlet-class>org.dspace.app.webui.servlet.ItemExportArchiveServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>browse</servlet-name>
<servlet-class>org.dspace.app.webui.servlet.BrowserServlet</servlet-class>
@@ -413,6 +418,11 @@
<url-pattern>/bitstream/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>exportdownload</servlet-name>
<url-pattern>/exportdownload/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>browse</servlet-name>
<url-pattern>/browse</url-pattern>

View File

@@ -126,6 +126,7 @@
ItemCounter ic = new ItemCounter(UIUtil.obtainContext(request));
%>
<%@page import="org.dspace.app.webui.servlet.MyDSpaceServlet"%>
<dspace:layout locbar="commLink" title="<%= name %>" feedData="<%= feedData %>">
<table border="0" cellpadding="5" width="100%">
@@ -288,6 +289,17 @@
</form>
</td>
</tr>
<% } %>
<% if( editor_button || admin_button) { %>
<tr>
<td headers="t1" class="standard" align="center">
<form method="post" action="<%=request.getContextPath()%>/mydspace">
<input type="hidden" name="collection_id" value="<%= collection.getID() %>" />
<input type="hidden" name="step" value="<%= MyDSpaceServlet.REQUEST_EXPORT_ARCHIVE %>" />
<input type="submit" value="<fmt:message key="jsp.mydspace.request.export.collection"/>" />
</form>
</td>
</tr>
<% } %>
<tr>
<td headers="t1" class="standard" align="center">

View File

@@ -103,6 +103,7 @@
ItemCounter ic = new ItemCounter(UIUtil.obtainContext(request));
%>
<%@page import="org.dspace.app.webui.servlet.MyDSpaceServlet"%>
<dspace:layout locbar="commLink" title="<%= name %>" feedData="<%= feedData %>">
<table border="0" cellpadding="5" width="100%">
@@ -333,6 +334,17 @@
<% } %>
</td>
</tr>
<% if( editor_button ) { %>
<tr>
<td headers="t1" class="standard" align="center">
<form method="post" action="<%=request.getContextPath()%>/mydspace">
<input type="hidden" name="community_id" value="<%= community.getID() %>" />
<input type="hidden" name="step" value="<%= MyDSpaceServlet.REQUEST_EXPORT_ARCHIVE %>" />
<input type="submit" value="<fmt:message key="jsp.mydspace.request.export.community"/>" />
</form>
</td>
</tr>
<% } %>
<tr>
<td headers="t1" class="standard" align="center">
<dspace:popup page="<%= LocaleSupport.getLocalizedMessage(pageContext, \"help.site-admin\")%>"><fmt:message key="jsp.adminhelp"/></dspace:popup>

View File

@@ -111,6 +111,7 @@
}
%>
<%@page import="org.dspace.app.webui.servlet.MyDSpaceServlet"%>
<dspace:layout title="<%= title %>">
<%
@@ -136,6 +137,14 @@
<input type="submit" name="submit" value="<fmt:message key="jsp.general.edit.button"/>" />
</form>
</td>
<td class="evenRowEvenCol" align="center">
<form method="post" action="<%= request.getContextPath() %>/mydspace">
<input type="hidden" name="item_id" value="<%= item.getID() %>" />
<input type="hidden" name="step" value="<%= MyDSpaceServlet.REQUEST_EXPORT_ARCHIVE %>" />
<%--<input type="submit" name="submit" value="Edit...">--%>
<input type="submit" name="submit" value="<fmt:message key="jsp.mydspace.request.export.item"/>" />
</form>
</td>
<% } %>
</tr>
</table>

View File

@@ -73,6 +73,7 @@
<%@ page import="org.dspace.eperson.Group" %>
<%@ page import="org.dspace.workflow.WorkflowItem" %>
<%@ page import="org.dspace.workflow.WorkflowManager" %>
<%@ page import="java.util.List" %>
<%
EPerson user = (EPerson) request.getAttribute("mydspace.user");
@@ -95,6 +96,8 @@
SupervisedItem[] supervisedItems =
(SupervisedItem[]) request.getAttribute("supervised.items");
List<String> exportsAvailable = (List<String>)request.getAttribute("export.archives");
// Is the logged in user an admin
Boolean displayMembership = (Boolean)request.getAttribute("display.groupmemberships");
boolean displayGroupMembership = (displayMembership == null ? false : displayMembership.booleanValue());
@@ -438,4 +441,13 @@
<%
}
%>
<%if(exportsAvailable!=null && exportsAvailable.size()>0){ %>
<h2><fmt:message key="jsp.mydspace.main.heading7"/></h2>
<ol class="exportArchives">
<%for(String fileName:exportsAvailable){%>
<li><a href="<%=request.getContextPath()+"/exportdownload/"+fileName%>" title="<fmt:message key="jsp.mydspace.main.export.archive.title"><fmt:param><%= fileName %></fmt:param></fmt:message>"><%=fileName%></a></li>
<% } %>
</ol>
<%} %>
</dspace:layout>

View File

@@ -0,0 +1,323 @@
/*
* ItemExport.java
*
* Version: $Revision: 1.3 $
*
* Date: $Date: 2006/07/13 23:20:54 $
*
* Copyright (c) 2002, Hewlett-Packard Company and Massachusetts
* Institute of Technology. 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.aspect.administrative;
import java.io.IOException;
import java.io.Serializable;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Map;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.caching.CacheableProcessingComponent;
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.util.HashUtil;
import org.apache.excalibur.source.SourceValidity;
import org.apache.excalibur.source.impl.validity.NOPValidity;
import org.dspace.app.xmlui.cocoon.AbstractDSpaceTransformer;
import org.dspace.app.xmlui.utils.DSpaceValidity;
import org.dspace.app.xmlui.utils.UIException;
import org.dspace.app.xmlui.wing.Message;
import org.dspace.app.xmlui.wing.WingException;
import org.dspace.app.xmlui.wing.element.Body;
import org.dspace.app.xmlui.wing.element.Division;
import org.dspace.app.xmlui.wing.element.List;
import org.dspace.app.xmlui.wing.element.PageMeta;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.Item;
import org.dspace.eperson.Group;
import org.xml.sax.SAXException;
/**
*
* Create the ability to view currently available export archives for download.
*
* @author Jay Paz
*/
public class ItemExport extends AbstractDSpaceTransformer implements
CacheableProcessingComponent {
private final static Message T_dspace_home = message("xmlui.general.dspace_home");
private static final Message T_main_head = message("xmlui.administrative.ItemExport.head");
private static final Message T_export_bad_item_id = message("xmlui.administrative.ItemExport.item.id.error");
private static final Message T_export_bad_col_id = message("xmlui.administrative.ItemExport.collection.id.error");
private static final Message T_export_bad_community_id = message("xmlui.administrative.ItemExport.community.id.error");
private static final Message T_export_item_not_found = message("xmlui.administrative.ItemExport.item.not.found");
private static final Message T_export_col_not_found = message("xmlui.administrative.ItemExport.collection.not.found");
private static final Message T_export_community_not_found = message("xmlui.administrative.ItemExport.community.not.found");
private static final Message T_item_export_success = message("xmlui.administrative.ItemExport.item.success");
private static final Message T_col_export_success = message("xmlui.administrative.ItemExport.collection.success");
private static final Message T_community_export_success = message("xmlui.administrative.ItemExport.community.success");
private static final Message T_avail_head = message("xmlui.administrative.ItemExport.available.head");
/** The Cocoon request */
Request request;
/** The Cocoon response */
Response response;
java.util.List<Message> errors;
java.util.List<String> availableExports;
Message message;
/** Cached validity object */
private SourceValidity validity;
@Override
public void setup(SourceResolver resolver, Map objectModel, String src,
Parameters parameters) throws ProcessingException, SAXException,
IOException {
super.setup(resolver, objectModel, src, parameters);
this.objectModel = objectModel;
this.request = ObjectModelHelper.getRequest(objectModel);
this.response = ObjectModelHelper.getResponse(objectModel);
try {
availableExports = org.dspace.app.itemexport.ItemExport
.getExportsAvailable(context.getCurrentUser());
} catch (Exception e) {
// nothing to do
}
errors = new ArrayList<Message>();
if (request.getParameter("itemID") != null) {
Item item = null;
try {
item = Item.find(context, Integer.parseInt(request
.getParameter("itemID")));
} catch (Exception e) {
errors.add(T_export_bad_item_id);
}
if (item == null) {
errors.add(T_export_item_not_found);
} else {
try {
org.dspace.app.itemexport.ItemExport
.createDownloadableExport(item, context);
} catch (Exception e) {
errors.add(message(e.getMessage()));
}
}
if (errors.size() <= 0)
message = T_item_export_success;
} else if (request.getParameter("collectionID") != null) {
Collection col = null;
try {
col = Collection.find(context, Integer.parseInt(request
.getParameter("collectionID")));
} catch (Exception e) {
errors.add(T_export_bad_col_id);
}
if (col == null) {
errors.add(T_export_col_not_found);
} else {
try {
org.dspace.app.itemexport.ItemExport
.createDownloadableExport(col, context);
} catch (Exception e) {
errors.add(message(e.getMessage()));
}
}
if (errors.size() <= 0)
message = T_col_export_success;
} else if (request.getParameter("communityID") != null) {
Community com = null;
try {
com = Community.find(context, Integer.parseInt(request
.getParameter("communityID")));
} catch (Exception e) {
errors.add(T_export_bad_community_id);
}
if (com == null) {
errors.add(T_export_community_not_found);
} else {
try {
org.dspace.app.itemexport.ItemExport
.createDownloadableExport(com, context);
} catch (Exception e) {
errors.add(message(e.getMessage()));
}
}
if (errors.size() <= 0)
message = T_community_export_success;
}
}
/**
* Generate the unique cache key.
*
* @return The generated key hashes the src
*/
public Serializable getKey() {
Request request = ObjectModelHelper.getRequest(objectModel);
// Special case, don't cache anything if the user is logging
// in. The problem occures because of timming, this cache key
// is generated before we know whether the operation has
// succeded or failed. So we don't know whether to cache this
// under the user's specific cache or under the anonymous user.
if (request.getParameter("login_email") != null
|| request.getParameter("login_password") != null
|| request.getParameter("login_realm") != null) {
return "0";
}
String key;
if (context.getCurrentUser() != null) {
key = context.getCurrentUser().getEmail();
if (availableExports != null && availableExports.size() > 0) {
for (String fileName : availableExports) {
key += ":" + fileName;
}
}
if (request.getQueryString() != null) {
key += request.getQueryString();
}
} else
key = "anonymous";
return HashUtil.hash(key);
}
/**
* Generate the validity object.
*
* @return The generated validity object or <code>null</code> if the
* component is currently not cacheable.
*/
public SourceValidity getValidity() {
if (this.validity == null) {
// Only use the DSpaceValidity object is someone is logged in.
if (context.getCurrentUser() != null) {
try {
DSpaceValidity validity = new DSpaceValidity();
validity.add(eperson);
Group[] groups = Group.allMemberGroups(context, eperson);
for (Group group : groups) {
validity.add(group);
}
this.validity = validity.complete();
} catch (SQLException sqle) {
// Just ignore it and return invalid.
}
} else {
this.validity = NOPValidity.SHARED_INSTANCE;
}
}
return this.validity;
}
/**
* Add Page metadata.
*/
public void addPageMeta(PageMeta pageMeta) throws SAXException,
WingException, UIException, SQLException, IOException,
AuthorizeException {
pageMeta.addMetadata("title").addContent(T_main_head);
pageMeta.addTrailLink(contextPath + "/", T_dspace_home);
pageMeta.addTrail().addContent(T_main_head);
}
public void addBody(Body body) throws SAXException, WingException,
UIException, SQLException, IOException, AuthorizeException {
Division main = body.addDivision("export_main");
main.setHead(T_main_head);
if (message != null) {
main.addDivision("success", "success").addPara(message);
}
if (errors.size() > 0) {
Division errors = main.addDivision("export-errors", "error");
for (Message error : this.errors) {
errors.addPara(error);
}
}
if (availableExports != null && availableExports.size() > 0) {
Division avail = main.addDivision("available-exports",
"available-exports");
avail.setHead(T_avail_head);
List fileList = avail.addList("available-files", List.TYPE_ORDERED);
for (String fileName : availableExports) {
fileList.addItem().addXref(
this.contextPath + "/exportdownload/" + fileName,
fileName);
}
}
}
/**
* recycle
*/
public void recycle() {
this.validity = null;
this.errors = null;
this.message = null;
this.availableExports = null;
super.recycle();
}
}

View File

@@ -42,13 +42,18 @@ package org.dspace.app.xmlui.aspect.administrative;
import java.io.IOException;
import java.io.Serializable;
import java.sql.SQLException;
import java.util.Map;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.caching.CacheableProcessingComponent;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.cocoon.util.HashUtil;
import org.apache.excalibur.source.SourceValidity;
import org.apache.excalibur.source.impl.validity.NOPValidity;
import org.dspace.app.itemexport.ItemExport;
import org.dspace.app.xmlui.cocoon.AbstractDSpaceTransformer;
import org.dspace.app.xmlui.utils.DSpaceValidity;
import org.dspace.app.xmlui.utils.HandleUtil;
@@ -75,6 +80,7 @@ import org.xml.sax.SAXException;
* @author Scott Phillips
* @author Afonso Araujo Neto (internationalization)
* @author Alexey Maslov
* @author Jay Paz
*/
public class Navigation extends AbstractDSpaceTransformer implements CacheableProcessingComponent
{
@@ -101,12 +107,18 @@ public class Navigation extends AbstractDSpaceTransformer implements CacheablePr
private static final Message T_statistics = message("xmlui.administrative.Navigation.statistics");
private static final Message T_context_export_item = message("xmlui.administrative.Navigation.context_export_item");
private static final Message T_context_export_collection = message("xmlui.administrative.Navigation.context_export_collection");
private static final Message T_context_export_community = message("xmlui.administrative.Navigation.context_export_community");
private static final Message T_account_export = message("xmlui.administrative.Navigation.account_export");
/** Cached validity object */
private SourceValidity validity;
/** exports available for download */
java.util.List<String> availableExports = null;
/**
* Generate the unique cache key.
*
@@ -128,9 +140,16 @@ public class Navigation extends AbstractDSpaceTransformer implements CacheablePr
return "0";
}
String key;
String key;
if (context.getCurrentUser() != null)
key = context.getCurrentUser().getEmail();
{
key = context.getCurrentUser().getEmail();
if(availableExports!=null && availableExports.size()>0){
for(String fileName:availableExports){
key+= ":"+fileName;
}
}
}
else
key = "anonymous";
@@ -176,6 +195,20 @@ public class Navigation extends AbstractDSpaceTransformer implements CacheablePr
return this.validity;
}
public void setup(SourceResolver resolver, Map objectModel, String src, Parameters parameters) throws ProcessingException, SAXException, IOException {
super.setup(resolver, objectModel, src, parameters);
try{
availableExports = ItemExport.getExportsAvailable(context.getCurrentUser());
}
catch (Exception e) {
// nothing to do
}
}
public void addOptions(Options options) throws SAXException, WingException,
UIException, SQLException, IOException, AuthorizeException
{
@@ -183,10 +216,16 @@ public class Navigation extends AbstractDSpaceTransformer implements CacheablePr
* even if they are never used
*/
options.addList("browse");
options.addList("account");
List account = options.addList("account");
List context = options.addList("context");
List admin = options.addList("administrative");
// My Account options
if(availableExports!=null && availableExports.size()>0){
account.addItem().addXref(contextPath+"/admin/export", T_account_export);
}
// Context Administrative options
DSpaceObject dso = HandleUtil.obtainHandle(objectModel);
if (dso instanceof Item)
@@ -197,6 +236,7 @@ public class Navigation extends AbstractDSpaceTransformer implements CacheablePr
{
context.setHead(T_context_head);
context.addItem().addXref(contextPath+"/admin/item?itemID="+item.getID(), T_context_edit_item);
context.addItem().addXref(contextPath+"/admin/export?itemID="+item.getID(), T_context_export_item );
}
}
else if (dso instanceof Collection)
@@ -210,6 +250,7 @@ public class Navigation extends AbstractDSpaceTransformer implements CacheablePr
context.setHead(T_context_head);
context.addItemXref(contextPath+"/admin/collection?collectionID=" + collection.getID(), T_context_edit_collection);
context.addItemXref(contextPath+"/admin/mapper?collectionID="+collection.getID(), T_context_item_mapper);
context.addItem().addXref(contextPath+"/admin/export?collectionID="+collection.getID(), T_context_export_collection );
}
}
else if (dso instanceof Community)
@@ -221,6 +262,7 @@ public class Navigation extends AbstractDSpaceTransformer implements CacheablePr
{
context.setHead(T_context_head);
context.addItemXref(contextPath+"/admin/community?communityID=" + community.getID(), T_context_edit_community);
context.addItem().addXref(contextPath+"/admin/export?communityID="+community.getID(), T_context_export_community );
}
// can they add to this community?

View File

@@ -223,7 +223,13 @@ public class DSpaceCocoonServlet extends CocoonServlet
finally
{
// Ensure that the current context is removed from ThreadLocal
ContextMap.removeCurrentContext();
try {
ContextMap.removeCurrentContext();
}
catch (NoSuchMethodError nsme)
{
// just ignore this, it means we're using an out of date logging library.
}
}
}

View File

@@ -0,0 +1,299 @@
/*
* ItemExportDownlaodReader.java
*
* Version: $Revision: 1.5 $
*
* Date: $Date: 2006/08/08 20:59:54 $
*
* Copyright (c) 2002, Hewlett-Packard Company and Massachusetts
* Institute of Technology. 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.io.InputStream;
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.environment.http.HttpResponse;
import org.apache.cocoon.reading.AbstractReader;
import org.apache.cocoon.util.ByteRange;
import org.dspace.app.itemexport.ItemExport;
import org.dspace.app.xmlui.utils.AuthenticationUtil;
import org.dspace.app.xmlui.utils.ContextUtil;
import org.dspace.core.Context;
import org.xml.sax.SAXException;
/**
* @author Jay Paz
*/
public class ItemExportDownloadReader extends AbstractReader implements Recyclable
{
/**
* Messages to be sent when the user is not authorized to view
* a particular bitstream. They will be redirected to the login
* where this message will be displayed.
*/
private final static String AUTH_REQUIRED_HEADER = "xmlui.ItemExportDownloadReader.auth_header";
private final static String AUTH_REQUIRED_MESSAGE = "xmlui.ItemExportDownloadReader.auth_message";
/**
* How big of a buffer should we use when reading from the bitstream before
* writting to the HTTP response?
*/
protected static final int BUFFER_SIZE = 8192;
/**
* When should a download expire in milliseconds. This should be set to
* some low value just to prevent someone hiting DSpace repeatily from
* killing the server. Note: 60000 milliseconds are in a second.
*
* Format: minutes * seconds * milliseconds
*/
protected static final int expires = 60 * 60 * 60000;
/** The Cocoon response */
protected Response response;
/** The Cocoon request */
protected Request request;
/** The bitstream file */
protected InputStream compressedExportInputStream;
/** The compressed export's reported size */
protected long compressedExportSize;
protected String compressedExportName;
/**
* Set up the export reader.
*
* See the class description for information on configuration options.
*/
public void setup(SourceResolver resolver, Map objectModel, String src,
Parameters par) throws ProcessingException, SAXException,
IOException
{
super.setup(resolver, objectModel, src, par);
try
{
this.request = ObjectModelHelper.getRequest(objectModel);
this.response = ObjectModelHelper.getResponse(objectModel);
Context context = ContextUtil.obtainContext(objectModel);
// Get our parameters that identify the bitstream
String fileName = par.getParameter("fileName", null);
// Is there a User logged in and does the user have access to read it?
if (!ItemExport.canDownload(context, fileName))
{
if(this.request.getSession().getAttribute("dspace.current.user.id")!=null){
// A user is logged in, but they are not authorized to read this bitstream,
// instead of asking them to login again we'll point them to a friendly error
// message that tells them the bitstream is restricted.
String redictURL = request.getContextPath() + "/restricted-resource?name=" + fileName;
HttpServletResponse httpResponse = (HttpServletResponse)
objectModel.get(HttpEnvironment.HTTP_RESPONSE_OBJECT);
httpResponse.sendRedirect(redictURL);
return;
}
else{
// The user does not have read access to this bitstream. Inturrupt this current request
// and then forward them to the login page so that they can be authenticated. Once that is
// successfull they will request will be resumed.
AuthenticationUtil.interruptRequest(objectModel, AUTH_REQUIRED_HEADER, AUTH_REQUIRED_MESSAGE, null);
// Redirect
String redictURL = request.getContextPath() + "/login";
HttpServletResponse httpResponse = (HttpServletResponse)
objectModel.get(HttpEnvironment.HTTP_RESPONSE_OBJECT);
httpResponse.sendRedirect(redictURL);
return;
}
}
// Success, bitstream found and the user has access to read it.
// Store these for later retreval:
this.compressedExportInputStream = ItemExport.getExportDownloadInputStream(fileName, context.getCurrentUser());
this.compressedExportSize = ItemExport.getExportFileSize(fileName);
this.compressedExportName = fileName;
}
catch (Exception e)
{
throw new ProcessingException("Unable to read bitstream.",e);
}
}
/**
* Write the actual data out to the response.
*
* Some implementation notes,
*
* 1) We set a short expires time just in the hopes of preventing someone
* from overloading the server by clicking reload a bunch of times. I
* realize that this is nowhere near 100% effective but it may help in some
* cases and shouldn't hurt anything.
*
*/
public void generate() throws IOException, SAXException,
ProcessingException
{
if (this.compressedExportInputStream == null)
return;
byte[] buffer = new byte[BUFFER_SIZE];
int length = -1;
response.setDateHeader("Expires", System.currentTimeMillis()
+ expires);
response.setHeader("Content-disposition","attachement; filename=" + this.compressedExportName );
// Turn off partial downloads, they cause problems
// and are only rarely used. Specifically some windows pdf
// viewers are incapable of handling this request. By
// uncommenting the following two lines you will turn this feature back on.
// response.setHeader("Accept-Ranges", "bytes");
// String ranges = request.getHeader("Range");
String ranges = null;
ByteRange byteRange = null;
if (ranges != null)
{
try
{
ranges = ranges.substring(ranges.indexOf('=') + 1);
byteRange = new ByteRange(ranges);
}
catch (NumberFormatException e)
{
byteRange = null;
if (response instanceof HttpResponse)
{
// Respond with status 416 (Request range not
// satisfiable)
((HttpResponse) response).setStatus(416);
}
}
}
if (byteRange != null)
{
String entityLength;
String entityRange;
if (this.compressedExportSize != -1)
{
entityLength = "" + this.compressedExportSize;
entityRange = byteRange.intersection(
new ByteRange(0, this.compressedExportSize)).toString();
}
else
{
entityLength = "*";
entityRange = byteRange.toString();
}
response.setHeader("Content-Range", entityRange + "/"
+ entityLength);
if (response instanceof HttpResponse)
{
// Response with status 206 (Partial content)
((HttpResponse) response).setStatus(206);
}
int pos = 0;
int posEnd;
while ((length = this.compressedExportInputStream.read(buffer)) > -1)
{
posEnd = pos + length - 1;
ByteRange intersection = byteRange
.intersection(new ByteRange(pos, posEnd));
if (intersection != null)
{
out.write(buffer, (int) intersection.getStart()
- pos, (int) intersection.length());
}
pos += length;
}
}
else
{
response.setHeader("Content-Length", String
.valueOf(this.compressedExportSize));
while ((length = this.compressedExportInputStream.read(buffer)) > -1)
{
out.write(buffer, 0, length);
}
out.flush();
}
}
/**
* Returns the mime-type of the bitstream.
*/
public String getMimeType()
{
return ItemExport.COMPRESSED_EXPORT_MIME_TYPE;
}
/**
* Recycle
*/
public void recycle() {
this.response = null;
this.request = null;
this.compressedExportInputStream = null;
this.compressedExportSize = 0;
}
}

View File

@@ -105,6 +105,7 @@ to administer DSpace.
<map:transformer name="SystemwideAlerts" src="org.dspace.app.xmlui.aspect.administrative.SystemwideAlerts"/>
<map:transformer name="ControlPanel" src="org.dspace.app.xmlui.aspect.administrative.ControlPanel" />
<map:transformer name="WithdrawnItems" src="org.dspace.app.xmlui.aspect.administrative.WithdrawnItems" />
<map:transformer name="ItemExport" src="org.dspace.app.xmlui.aspect.administrative.ItemExport"/>
</map:transformers>
<map:matchers default="wildcard">
@@ -777,6 +778,10 @@ to administer DSpace.
<map:match pattern="admin/authorize">
<map:act type="StartAuthentication"/>
</map:match>
<map:match pattern="admin/export">
<map:act type="StartAuthentication"/>
</map:match>
</map:otherwise>
</map:select>
@@ -796,6 +801,10 @@ to administer DSpace.
</map:select>
</map:match>
<map:match pattern="admin/export">
<map:transform type="ItemExport"/>
</map:match>
<map:match pattern="admin/withdrawn">
<map:select type="AuthenticatedSelector">
<map:when test="administrator">

View File

@@ -162,6 +162,14 @@ and searching the repository.
<map:serialize type="xml"/>
</map:match>
<!-- restricted resource -->
<map:match pattern="restricted-resource">
<map:transform type="RestrictedItem"/>
<map:serialize type="xml"/>
</map:match>
<!-- Handle specific features -->
<map:match pattern="handle/*/**">

View File

@@ -320,7 +320,9 @@
<message key="xmlui.BitstreamReader.auth_header">The file is restricted</message>
<message key="xmlui.BitstreamReader.auth_message">The file you are attempting to access is a restricted file and requires credentials to view. Please login below to access the file.</message>
<!-- Export Archive download messages -->
<message key="xmlui.ItemExportDownloadReader.auth_header">This export archive is restricted.</message>
<message key="xmlui.ItemExportDownloadReader.auth_message">The export archive you are attempting to access is a restricted resource and requires credentials to view. Please login below to access the export archive.</message>
<!--!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
@@ -796,6 +798,9 @@
<message key="xmlui.administrative.Navigation.context_create_collection">Create Collection</message>
<message key="xmlui.administrative.Navigation.context_create_subcommunity">Create Sub-community</message>
<message key="xmlui.administrative.Navigation.context_create_community">Create Community</message>
<message key="xmlui.administrative.Navigation.context_export_item">Export Item</message>
<message key="xmlui.administrative.Navigation.context_export_collection">Export Collection</message>
<message key="xmlui.administrative.Navigation.context_export_community">Export Community</message>
<!-- Site administrator options -->
<message key="xmlui.administrative.Navigation.administrative_head">Administrative</message>
@@ -811,6 +816,24 @@
<message key="xmlui.administrative.Navigation.administrative_control_panel">Control Panel</message>
<message key="xmlui.administrative.Navigation.statistics">Statistics</message>
<!-- my account items -->
<message key="xmlui.administrative.Navigation.account_export">My Exports</message>
<!-- export item -->
<message key="xmlui.administrative.ItemExport.head">Export Archive</message>
<message key="xmlui.administrative.ItemExport.item.id.error">The item id provided is invalid.</message>
<message key="xmlui.administrative.ItemExport.collection.id.error">The collection id provided is invalid.</message>
<message key="xmlui.administrative.ItemExport.community.id.error">The community id provided is invalid</message>
<message key="xmlui.administrative.ItemExport.item.not.found">The item requested was not found.</message>
<message key="xmlui.administrative.ItemExport.collection.not.found">The collection requested was not found.</message>
<message key="xmlui.administrative.ItemExport.community.not.found">The community requested was not found.</message>
<message key="xmlui.administrative.ItemExport.export.success">The item was exported successfully. You should receive an e-mail when the archive is ready for download. You can also use the 'My Exports' link to view a list of your available archives.</message>
<message key="xmlui.administrative.ItemExport.collection.success">The collection was exported successfully. You should receive an e-mail when the archive is ready for download. You can also use the 'My Exports' link to view a list of your available archives.</message>
<message key="xmlui.administrative.ItemExport.community.success">The community was exported successfully. You should receive an e-mail when the archive is ready for download. You can also use the 'My Exports' link to view a list of your available archives.</message>
<message key="xmlui.administrative.ItemExport.available.head">Available export archives for download:</message>
<!-- org.dspace.app.xmlui.administrative.eperson.ManageEPeopleMain -->
<message key="xmlui.administrative.eperson.ManageEPeopleMain.title">Manage E-people</message>

View File

@@ -158,6 +158,7 @@
<expires>3600000</expires> <!-- 1000 * 60 * 60 = 3600000 = One hour -->
</map:reader>
<map:reader name="BitstreamReader" src="org.dspace.app.xmlui.cocoon.BitstreamReader"/>
<map:reader name="ExportReader" src="org.dspace.app.xmlui.cocoon.ItemExportDownloadReader"/>
</map:readers>
<map:actions>
<map:action name="locale" src="org.dspace.app.xmlui.cocoon.DSpaceLocaleAction"/>
@@ -261,6 +262,16 @@
<map:match pattern="html/*/*/**">
<map:redirect-to uri="{request:contextPath}/bitstream/handle/{1}/{2}/{3}" permanent="yes"/>
</map:match>
<!--
Downloads for the package download export
-->
<map:match pattern="exportdownload/*">
<map:read type="ExportReader">
<map:parameter name="fileName" value="{1}"/>
</map:read>
</map:match>
</map:pipeline>

View File

@@ -578,6 +578,27 @@ checker.retention.default=10y
checker.retention.CHECKSUM_MATCH=8w
### Item export and download settings ###
# The directory where the exports will be done and compressed
org.dspace.app.itemexport.work.dir = ${dspace.dir}/exports
# The directory where the compressed files will reside and be read by the downloader
org.dspace.app.itemexport.download.dir = ${dspace.dir}/exports/download
# The length og time in hours each archive should live for. When new archives are
# created this entry is used to delete old ones
org.dspace.app.itemexport.life.span.hours = 48
# The maximum size in Megabytes the export should be. This is enforced before the
# compression. Each bitstream's size in each item being exported is added up, if their
# cummulative sizes are more than this entry the export is not kicked off
org.dspace.app.itemexport.max.size = 200
#---------------------------------------------------------------#
#--------------JSPUI & XMLUI CONFIGURATIONS---------------------#
#---------------------------------------------------------------#

View File

@@ -100,3 +100,4 @@ show_feedback_form=Feedback Form Displayed
create_dc_type=New Dublin Core Type Created
remove_template_item=Item Template Removed
withdraw_item=Item Withdrawn
download_export_archive = Download Export Archive

View File

@@ -598,6 +598,7 @@ jsp.mydspace.main.heading3 = Tasks in the P
jsp.mydspace.main.heading4 = Unfinished Submissions
jsp.mydspace.main.heading5 = Submissions In Workflow Process
jsp.mydspace.main.heading6 = Authorization Groups I'm a Member Of
jsp.mydspace.main.heading7 = Export Archives Available for Download
jsp.mydspace.main.item = Item
jsp.mydspace.main.link = See Your Subscriptions
jsp.mydspace.main.perform.button = Perform This Task
@@ -656,6 +657,7 @@ jsp.mydspace.subscriptions.title = Your Subscript
jsp.mydspace.subscriptions.unsub.button = Unsubscribe
jsp.mydspace.task-complete.text1 = The task is complete, and notification has been sent to the appropriate people.
jsp.mydspace.task-complete.title = Thank You
jsp.mydspace.main.export.archive.title = Download Export Archive {0}
jsp.register.already-registered.info1 = Our records show that you've already registered with DSpace and have an active account with us.
jsp.register.already-registered.info2 = You can <a href="{0}">set a new password if you've forgotten it</a>.
jsp.register.already-registered.info4 = If you're having trouble logging in, please contact us.