/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/citations/trunk/citations-servlet/servlet/src/java/org/sakaiproject/citation/servlet/BatchCitationServlet.java $
* $Id: BatchCitationServlet.java 118204 2013-01-09 18:22:51Z jimeng@umich.edu $
***********************************************************************************
*
* Copyright (c) 2011 The Sakai Foundation
*
* Licensed under the Educational Community License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.opensource.org/licenses/ECL-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**********************************************************************************/
package org.sakaiproject.citation.servlet;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sakaiproject.citation.api.Citation;
import org.sakaiproject.citation.api.Schema;
import org.sakaiproject.content.api.ContentResource;
import org.sakaiproject.exception.IdUnusedException;
import org.sakaiproject.exception.PermissionException;
import org.sakaiproject.exception.ServerOverloadException;
import org.sakaiproject.util.ParameterParser;
import org.sakaiproject.util.Validator;
/**
*
*
*/
public class BatchCitationServlet extends CitationServlet
{
private static Log log = LogFactory.getLog(BatchCitationServlet.class);
/**
* respond to an HTTP GET request
*
* @param req
* HttpServletRequest object with the client request
* @param res
* HttpServletResponse object back to the client
* @exception ServletException
* in case of difficulties
* @exception IOException
* in case of difficulties
*/
public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
{
super.doGet(req, res);
}
/**
*
* @param req
* HttpServletRequest object with the client request
* @param res
* HttpServletResponse object back to the client
* @exception ServletException
* in case of difficulties
* @exception IOException
* in case of difficulties
*/
public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
{
//log.info("doPost() " + req.getMethod());
// process any login that might be present
basicAuth.doLogin(req);
// catch the login helper posts
String option = req.getPathInfo();
String[] parts = option.split("/");
if ((parts.length == 2) && ((parts[1].equals("login"))))
{
doLogin(req, res, null);
}
else if (req.getParameter("batch_urls") == null)
{
// There is no POST handling at the base, so just throw here
// If there was some single-URL handling, we could call super.doPost
sendError(res, HttpServletResponse.SC_NOT_FOUND);
}
else
{
setupResponse(req, res);
ContentResource resource = null;
try {
ParameterParser paramParser = (ParameterParser) req
.getAttribute(ATTR_PARAMS);
resource = findResource(paramParser, option);
ArrayList<Citation> citations = new ArrayList<Citation>();
ArrayList<String> failures = new ArrayList<String>();
String[] urls = req.getParameterValues("url[]");
if (urls != null && urls.length > 0) {
for (String url : urls) {
//decode POSTed URL
String decodedUrl = URLDecoder.decode(url);
Map<String, String[]> params = getUrlParameters(decodedUrl);
OpenUrlRequest wrappedReq = new OpenUrlRequest(req, params);
Citation citation = findOpenUrlCitation(wrappedReq);
if (citation != null) {
citations.add(citation);
addCitation(resource, citation);
}
else {
failures.add(url);
}
}
}
// set the success flag
setVmReference("success", citations.size() > 0, req);
if (citations.size() > 0) {
setVmReference( "citations", citations, req );
setVmReference("topRefresh", Boolean.TRUE, req ); // TODO
String resourceUuid = this.contentService.getUuid(resource.getId());
setVmReference( "resourceId", resourceUuid , req );
} else {
// return failure
setVmReference("error", rb.getString("error.notfound"), req);
}
} catch (IdUnusedException iue) {
setVmReference("error", rb.getString("error.noid"), req);
} catch (ServerOverloadException e) {
setVmReference("error", rb.getString("error.unavailable"), req);
} catch (PermissionException e) {
setVmReference("error", rb.getString("error.permission"), req);
}
// Set near end so we always have something
setVmReference("titleArgs", new String[]{ getCollectionTitle(resource) }, req);
setVmReference("openUrlLabel", configurationService.getSiteConfigOpenUrlLabel(), req);
setVmReference("titleProperty", Schema.TITLE, req);
// validator
setVmReference("xilator", new Validator(), req);
// return the servlet template
includeVm( COMPACT_TEMPLATE, req, res );
}
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpServlet#doDelete(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
public void doDelete(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
super.doDelete(req, res);
}
// This is a little adapter to return parsed values rather than the raw
// ones supplied in the real request. This is to avoid needing to modify
// the existing parsing code in citations-impl (OpenURLServiceImpl,
// InlineHttpTransport, etc.). We parse the real POST body and supply these
// faked requests to CitationService.addCitation. Each one looks like a GET
// request with the decoded parameters on the query string as a standard
// Open URL 1.0 request would appear.
public class OpenUrlRequest extends HttpServletRequestWrapper {
private Map<String, String[]> openUrlParams;
private StringBuilder queryString;
public OpenUrlRequest(HttpServletRequest request, Map<String, String[]> openUrlParams) {
super(request);
this.openUrlParams = openUrlParams;
queryString = new StringBuilder();
for (String key : openUrlParams.keySet()) {
if (queryString.length() > 0) {
queryString.append("&");
}
boolean first = true;
for (String val : openUrlParams.get(key)) {
if (!first) {
queryString.append("&");
first = false;
}
try {
queryString.append(URLEncoder.encode(key, "UTF-8"));
queryString.append("=");
queryString.append(URLEncoder.encode(val, "UTF-8"));
} catch (UnsupportedEncodingException uee) {
// These should really never happen since UTF-8 is the W3C advised encoding
log.warn("Error encoding key/value pairs for OpenURL 1.0. [" + key + " => " + val + "] -- " + uee.getLocalizedMessage());
}
}
}
}
public String getMethod() {
return "GET";
}
public String getQueryString() {
return queryString.toString();
}
public Map<String, String[]> getParameterMap() {
return Collections.unmodifiableMap(openUrlParams);
}
public String getParameter(String name) {
String[] vals = openUrlParams.get(name);
if (vals != null && vals.length > 0) {
return vals[0];
}
return null;
}
public Enumeration<String> getParameterNames() {
return Collections.enumeration(Collections.unmodifiableSet(openUrlParams.keySet()));
}
public String[] getParameterValues(String name) {
String[] val = openUrlParams.get(name);
if (val != null) {
ArrayList list = new ArrayList(Arrays.asList(val));
ArrayList copy = new ArrayList(list);
return (String[]) copy.toArray(new String[] {});
}
return null;
}
}
public static Map<String, String[]> getUrlParameters(String url) throws UnsupportedEncodingException {
Map<String, List<String>> params = new HashMap<String, List<String>>();
if (url != null) {
for (String param : url.split("&")) {
String pair[] = param.split("=");
String key = URLDecoder.decode(pair[0], "UTF-8");
String value = "";
if (pair.length > 1) {
value = URLDecoder.decode(pair[1], "UTF-8");
}
List<String> values = params.get(key);
if (values == null) {
values = new ArrayList<String>();
params.put(key, values);
}
values.add(value);
}
}
Map<String, String[]> ret = new HashMap<String, String[]>();
for (String k : params.keySet()) {
ret.put(k, (String[]) params.get(k).toArray(new String[] {}));
}
return ret;
}
}