/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.dav;
import java.io.IOException;
import java.sql.SQLException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.AuthorizeManager;
import org.dspace.content.Bitstream;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.handle.HandleManager;
import org.jdom.Element;
/**
* Superclass for resources representing DSpace Objects like Item, Collection
* etc. Defines the behavior of DSpace "resources" in the WebDAV interface; maps
* DAV operations onto DSpace object.
*/
abstract class DAVDSpaceObject extends DAVResource
{
/** Object of this resource, set by subclass' initializer. */
protected DSpaceObject dso = null;
/** Prototype of DAV Property "handle". */
protected static final Element handleProperty = new Element("handle",
DAV.NS_DSPACE);
/** Special character used to separate handle prefix from suffix in DAV resource URIs - substitute this for the '/' normally used in Handle syntax since the '/' causes all sorts of problems for broken DAV clients. */
private static final char handleSeparator = '$';
/**
* Instantiates a new DAVD space object.
*
* @param context the context
* @param request the request
* @param response the response
* @param pathElt the path elt
* @param dso the dso
*/
protected DAVDSpaceObject(Context context, HttpServletRequest request,
HttpServletResponse response, String pathElt[], DSpaceObject dso)
{
super(context, request, response, pathElt);
this.dso = dso;
}
/**
* Make URI path element for a DSpaceObject.
*
* @param dso the DSpaceObject, which needs to have a valid Handle.
*
* @return path element string or null if no handle.
*/
protected static String getPathElt(DSpaceObject dso)
{
String handle = dso.getHandle();
if (handle == null)
{
return null;
}
return getPathElt(handle);
}
/**
* Make URI path element for a DSpaceObject.
*
* @param handle handle of a DSpaceObject.
*
* @return path element string or null if no handle.
*/
protected static String getPathElt(String handle)
{
int hs;
if (handleSeparator != '/')
{
if(handleSeparator != '$') {
handle = handle.replaceFirst("/", String.valueOf(handleSeparator));
} else {
// handle $ specially
handle = handle.replaceFirst("/", "\\$");
}
}
return "dso_" + encodeHandle(handle);
}
/**
* Match the URIs this subclass understands and return the corresponding
* resource. Since the "dso_" format can lead to several different resource
* types, handle it here.
*
* @param context the context
* @param request the request
* @param response the response
* @param pathElt the path elt
*
* @return the DAV resource
*
* @throws DAVStatusException the DAV status exception
* @throws SQLException the SQL exception
* @throws AuthorizeException the authorize exception
*/
protected static DAVResource matchResourceURI(Context context,
HttpServletRequest request, HttpServletResponse response,
String pathElt[]) throws DAVStatusException, SQLException,
AuthorizeException
{
// Match /dso_<handle>{...} .. look for last "dso_" element
if (pathElt[0].startsWith("dso_"))
{
int i = 1;
for (; i < pathElt.length && pathElt[i].startsWith("dso_"); ++i)
{
// empty
}
--i;
String handle = decodeHandle(pathElt[i].substring(4));
// Replace substituted handle separator char with '/' to
// get back a normal handle: (inverse of getPathElt() above)
int sepIndex = handle.indexOf(handleSeparator);
if (sepIndex >= 0)
{
char hc[] = handle.toCharArray();
hc[sepIndex] = '/';
handle = String.copyValueOf(hc);
}
DSpaceObject dso = HandleManager.resolveToObject(context, handle);
if (dso == null)
{
throw new DAVStatusException(HttpServletResponse.SC_NOT_FOUND,
"Cannot resolve handle \"" + handle + "\"");
}
else if (dso.getType() == Constants.ITEM)
{
if (i + 1 < pathElt.length)
{
if (pathElt[i + 1].startsWith("bitstream_"))
{
Bitstream bs = DAVBitstream.findBitstream(context,
(Item) dso, pathElt[i + 1]);
if (bs == null)
{
throw new DAVStatusException(
HttpServletResponse.SC_NOT_FOUND,
"Bitstream \"" + pathElt[i + 1]
+ "\" not found in item: "
+ pathElt[i]);
}
return new DAVBitstream(context, request, response,
pathElt, (Item) dso, bs);
}
else
{
throw new DAVStatusException(
HttpServletResponse.SC_NOT_FOUND,
"Illegal resource path, \""
+ pathElt[i + 1]
+ "\" is not a Bitstream identifier for item: "
+ pathElt[i]);
}
}
else
{
return new DAVItem(context, request, response, pathElt,
(Item) dso);
}
}
else if (dso.getType() == Constants.COLLECTION)
{
return new DAVCollection(context, request, response, pathElt,
(Collection) dso);
}
else if (dso.getType() == Constants.COMMUNITY)
{
return new DAVCommunity(context, request, response, pathElt,
(Community) dso);
}
else
{
throw new DAVStatusException(
HttpServletResponse.SC_BAD_REQUEST,
"Unrecognized DSpace object type for handle=" + handle);
}
}
return null;
}
/**
* Interposed between subclass and common props, take care of shared props
* like privileges, handle, dspace:type.
*
* @param property the property
*
* @return the element
*
* @throws SQLException the SQL exception
* @throws AuthorizeException the authorize exception
* @throws IOException Signals that an I/O exception has occurred.
* @throws DAVStatusException the DAV status exception
*/
@Override
protected Element propfindInternal(Element property) throws SQLException,
AuthorizeException, IOException, DAVStatusException
{
String value = null;
if (elementsEqualIsh(property, handleProperty))
{
value = canonicalizeHandle(this.dso.getHandle());
}
else if (elementsEqualIsh(property, current_user_privilege_setProperty))
{
Element c = (Element) current_user_privilege_setProperty.clone();
// if we're an admin we have all privs everywhere.
if (AuthorizeManager.isAdmin(this.context))
{
addPrivilege(c, new Element("all", DAV.NS_DAV));
}
else
{
for (int i = 0; i < Constants.actionText.length; ++i)
{
if (AuthorizeManager
.authorizeActionBoolean(this.context, this.dso, i))
{
Element priv = actionToPrivilege(i);
if (priv != null)
{
addPrivilege(c, priv);
}
}
}
}
return c;
}
else
{
return commonPropfindInternal(property,
this.dso.getType() != Constants.BITSTREAM);
}
// value was set up by "if" clause:
if (value == null)
{
throw new DAVStatusException(HttpServletResponse.SC_NOT_FOUND,
"Not found.");
}
Element p = new Element(property.getName(), property.getNamespace());
p.setText(filterForXML(value));
return p;
}
/**
* Return value of DSpace type property. It is conveniently the same as our
* internal type name.
*
* @return the element
*/
@Override
protected Element typeValue()
{
return new Element(Constants.typeText[this.dso.getType()].toLowerCase(),
DAV.NS_DSPACE);
}
}