/**
* Copyright (c) 2008, Aberystwyth University
*
* 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 Centre for Advanced Software and
* Intelligent Systems (CASIS) 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
* OWNER 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.purl.sword.server;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.StringTokenizer;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.codec.binary.Base64;
import org.apache.log4j.Logger;
import org.purl.sword.base.HttpHeaders;
import org.purl.sword.base.SWORDAuthenticationException;
import org.purl.sword.base.SWORDErrorException;
import org.purl.sword.base.SWORDException;
import org.purl.sword.base.ServiceDocument;
import org.purl.sword.base.ServiceDocumentRequest;
/**
* ServiceDocumentServlet
*
* @author Stuart Lewis
*/
public class ServiceDocumentServlet extends HttpServlet {
/** The repository */
private SWORDServer myRepository;
/** Authentication type. */
private String authN;
/** Maximum file upload size in kB **/
private int maxUploadSize;
/** Logger */
private static Logger log = Logger.getLogger(ServiceDocumentServlet.class);
/**
* Initialise the servlet.
*
* @throws ServletException
*/
public void init() throws ServletException {
// Instantiate the correct SWORD Server class
String className = getServletContext().getInitParameter("sword-server-class");
if (className == null) {
log.fatal("Unable to read value of 'sword-server-class' from Servlet context");
} else {
try {
myRepository = (SWORDServer) Class.forName(className)
.newInstance();
log.info("Using " + className + " as the SWORDServer");
} catch (Exception e) {
log.fatal("Unable to instantiate class from 'server-class': "
+ className);
throw new ServletException(
"Unable to instantiate class from 'server-class': "
+ className);
}
}
// Set the authentication method
authN = getServletContext().getInitParameter("authentication-method");
if ((authN == null) || ("".equals(authN))) {
authN = "None";
}
log.info("Authentication type set to: " + authN);
String maxUploadSizeStr = getServletContext().getInitParameter("maxUploadSize");
if ((maxUploadSizeStr == null) ||
(maxUploadSizeStr.equals("")) ||
(maxUploadSizeStr.equals("-1"))) {
maxUploadSize = -1;
log.warn("No maxUploadSize set, so setting max file upload size to unlimited.");
} else {
try {
maxUploadSize = Integer.parseInt(maxUploadSizeStr);
log.info("Setting max file upload size to " + maxUploadSize);
} catch (NumberFormatException nfe) {
maxUploadSize = -1;
log.warn("maxUploadSize not a number, so setting max file upload size to unlimited.");
}
}
}
/**
* Process the get request.
*/
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// Create the ServiceDocumentRequest
ServiceDocumentRequest sdr = new ServiceDocumentRequest();
// Are there any authentication details?
String usernamePassword = getUsernamePassword(request);
if ((usernamePassword != null) && (!usernamePassword.equals(""))) {
int p = usernamePassword.indexOf(":");
if (p != -1) {
sdr.setUsername(usernamePassword.substring(0, p));
sdr.setPassword(usernamePassword.substring(p + 1));
}
} else if (authenticateWithBasic()) {
String s = "Basic realm=\"SWORD\"";
response.setHeader("WWW-Authenticate", s);
response.setStatus(401);
return;
}
// Set the x-on-behalf-of header
sdr.setOnBehalfOf(request.getHeader(HttpHeaders.X_ON_BEHALF_OF
.toString()));
// Set the IP address
sdr.setIPAddress(request.getRemoteAddr());
// Set the deposit location
sdr.setLocation(getUrl(request));
// Get the ServiceDocument
try {
ServiceDocument sd = myRepository.doServiceDocument(sdr);
if ((sd.getService().getMaxUploadSize() == -1) && (maxUploadSize != -1)) {
sd.getService().setMaxUploadSize(maxUploadSize);
}
// Print out the Service Document
response.setContentType("application/atomsvc+xml; charset=UTF-8");
PrintWriter out = response.getWriter();
out.write(sd.marshall());
out.flush();
} catch (SWORDAuthenticationException sae) {
if (authN.equals("Basic")) {
String s = "Basic realm=\"SWORD\"";
response.setHeader("WWW-Authenticate", s);
response.setStatus(401);
}
} catch (SWORDErrorException see) {
// Return the relevant HTTP status code
response.sendError(see.getStatus(), see.getDescription());
} catch (SWORDException se) {
se.printStackTrace();
// Throw a HTTP 500
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, se.getMessage());
}
}
/**
* Process the post request. This will return an unimplemented response.
*/
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// Send a '501 Not Implemented'
response.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
}
/**
* Utiliy method to return the username and password (separated by a colon
* ':')
*
* @param request
* @return The username and password combination
*/
private String getUsernamePassword(HttpServletRequest request) {
try {
String authHeader = request.getHeader("Authorization");
if (authHeader != null) {
StringTokenizer st = new StringTokenizer(authHeader);
if (st.hasMoreTokens()) {
String basic = st.nextToken();
if (basic.equalsIgnoreCase("Basic")) {
String credentials = st.nextToken();
String userPass = new String(Base64
.decodeBase64(credentials.getBytes()));
return userPass;
}
}
}
} catch (Exception e) {
log.debug(e.toString());
}
return null;
}
/**
* Utility method to decide if we are using HTTP Basic authentication
*
* @return if HTTP Basic authentication is in use or not
*/
private boolean authenticateWithBasic() {
if (authN.equalsIgnoreCase("Basic")) {
return true;
} else {
return false;
}
}
/**
* Utility method to construct the URL called for this Servlet
*
* @param req The request object
* @return The URL
*/
private static String getUrl(HttpServletRequest req) {
String reqUrl = req.getRequestURL().toString();
String queryString = req.getQueryString();
log.debug("Requested url is: " + reqUrl);
if (queryString != null) {
reqUrl += "?" + queryString;
}
log.debug("Requested url with Query String is: " + reqUrl);
return reqUrl;
}
}