/**
* Copyright 2008 The University of North Carolina at Chapel Hill
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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 edu.unc.lib.dl.admin.controller;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import edu.unc.lib.dl.acl.util.AccessGroupSet;
import edu.unc.lib.dl.acl.util.GroupsThreadStore;
import edu.unc.lib.dl.fedora.PID;
import edu.unc.lib.dl.httpclient.HttpClientUtil;
import edu.unc.lib.dl.search.solr.model.BriefObjectMetadataBean;
import edu.unc.lib.dl.search.solr.model.SimpleIdRequest;
import edu.unc.lib.dl.search.solr.tags.TagProvider;
import edu.unc.lib.dl.ui.exception.InvalidRecordRequestException;
import edu.unc.lib.dl.util.ContentModelHelper;
import edu.unc.lib.dl.util.ContentModelHelper.Datastream;
import edu.unc.lib.dl.util.TripleStoreQueryService;
import edu.unc.lib.dl.util.VocabularyHelperManager;
import edu.unc.lib.dl.xml.JDOMNamespaceUtil;
import edu.unc.lib.dl.xml.VocabularyHelper;
@Controller
public class MODSController extends AbstractSwordController {
private static final Logger log = LoggerFactory.getLogger(MODSController.class);
@Autowired
private String swordUrl;
@Autowired
private String swordUsername;
@Autowired
private String swordPassword;
@Autowired
private TripleStoreQueryService tripleStoreQueryService;
private Map<String, String> namespaces;
@Autowired
private VocabularyHelperManager vocabularies;
protected @Resource(name = "tagProviders")
List<TagProvider> tagProviders;
@PostConstruct
public void init() {
namespaces = new HashMap<>();
namespaces.put(JDOMNamespaceUtil.MODS_V3_NS.getPrefix(), JDOMNamespaceUtil.MODS_V3_NS.getURI());
}
/**
* Forwards user to the MODS editor page with the
*
* @param idPrefix
* @param id
* @param model
* @param request
* @return
*/
@RequestMapping(value = "describe/{pid}", method = RequestMethod.GET)
public String editDescription(@PathVariable("pid") String pid, Model model,
HttpServletRequest request) {
AccessGroupSet accessGroups = GroupsThreadStore.getGroups();
// Retrieve the record for the object being edited
SimpleIdRequest objectRequest = new SimpleIdRequest(pid, accessGroups);
BriefObjectMetadataBean resultObject = queryLayer.getObjectById(objectRequest);
if (resultObject == null) {
throw new InvalidRecordRequestException();
}
model.addAttribute("resultObject", resultObject);
return "edit/description";
}
@RequestMapping(value = "describeInfo/{pid}", method = RequestMethod.GET, produces = {"application/json; text/*; charset=UTF-8"})
public @ResponseBody
Map<String, Object> editDescription(@PathVariable("pid") String pid, HttpServletResponse response) {
response.setContentType("application/json");
Map<String, Object> results = new LinkedHashMap<String, Object>();
AccessGroupSet accessGroups = GroupsThreadStore.getGroups();
// Retrieve the record for the object being edited
SimpleIdRequest objectRequest = new SimpleIdRequest(pid, accessGroups);
BriefObjectMetadataBean resultObject = queryLayer.getObjectById(objectRequest);
if (resultObject == null) {
throw new InvalidRecordRequestException();
}
for (TagProvider provider : tagProviders) {
provider.addTags(resultObject, accessGroups);
}
results.put("resultObject", resultObject);
// Structure vocabulary info into a map usable by the editor
Map<String, Object> vocabConfigs = new HashMap<>();
// xpath selectors for each vocabulary
Map<String, String> selectors = new HashMap<>();
// map of vocabulary names to their term values
Map<String, Object> perVocabConfigs = new HashMap<>();
Set<VocabularyHelper> helpers = vocabularies.getHelpers(new PID(pid));
if (helpers != null) {
for (VocabularyHelper helper : helpers) {
Map<String, Object> vocabConfig = new HashMap<>();
vocabConfig.put("values", helper.getVocabularyTerms());
perVocabConfigs.put(helper.getVocabularyURI(), vocabConfig);
if (helper.getSelector() != null) {
selectors.put(helper.getSelector(), helper.getVocabularyURI());
}
}
}
vocabConfigs.put("xpathSelectors", selectors);
vocabConfigs.put("vocabularies", perVocabConfigs);
vocabConfigs.put("xpathNamespaces", namespaces);
results.put("vocabularyConfigs", vocabConfigs);
return results;
}
/**
* Retrieves the MD_DESCRIPTIVE datastream, containing MODS, for this item if one is present. If it is not present,
* then returns a blank MODS document.
*
* @param idPrefix
* @param id
* @return
*/
@RequestMapping(value = "{pid}/mods", method = RequestMethod.GET, produces = {"application/json; text/*; charset=UTF-8"})
public @ResponseBody
String getMods(@PathVariable("pid") String pid) {
String mods = "";
String dataUrl = swordUrl + "em/" + pid + "/" + ContentModelHelper.Datastream.MD_DESCRIPTIVE;
CloseableHttpClient client = HttpClientUtil.getAuthenticatedClient(null, swordUsername, swordPassword);
HttpGet method = new HttpGet(dataUrl);
// Pass the users groups along with the request
AccessGroupSet groups = GroupsThreadStore.getGroups();
method.addHeader(HttpClientUtil.FORWARDED_GROUPS_HEADER, groups.joinAccessGroups(";"));
try (CloseableHttpResponse httpResp = client.execute(method)) {
int statusCode = httpResp.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) {
try {
mods = EntityUtils.toString(httpResp.getEntity(), "UTF-8");
} catch (IOException e) {
log.info("Problem uploading MODS for " + pid + ": " + e.getMessage());
}
} else {
if (statusCode == HttpStatus.SC_BAD_REQUEST || statusCode == HttpStatus.SC_NOT_FOUND) {
// Ensure that the object actually exists
PID existingPID = tripleStoreQueryService.verify(new PID(pid));
if (existingPID == null) {
throw new Exception("Unable to retrieve MODS. Object " + pid + " does not exist in the repository.");
}
} else {
throw new Exception("Failure to retrieve fedora content due to response of: "
+ httpResp.getStatusLine() + "\nPath was: " + method.getURI());
}
}
} catch (Exception e) {
log.error("Error while attempting to stream Fedora content for " + pid, e);
}
return mods;
}
/**
* Pushes a MODS document to the target object
*
* @param idPrefix
* @param id
* @param model
* @param request
* @return
*/
@RequestMapping(value = "describe/{pid}", method = RequestMethod.POST, produces = {"application/json; text/*; charset=UTF-8"})
public @ResponseBody
String updateDescription(@PathVariable("pid") String pid, Model model,
HttpServletRequest request, HttpServletResponse response) {
String datastream = Datastream.MD_DESCRIPTIVE.getName();
return this.updateDatastream(pid, datastream, request, response);
}
public void setSwordUrl(String swordUrl) {
this.swordUrl = swordUrl;
}
public void setSwordUsername(String swordUsername) {
this.swordUsername = swordUsername;
}
public void setSwordPassword(String swordPassword) {
this.swordPassword = swordPassword;
}
public void setTripleStoreQueryService(TripleStoreQueryService tripleStoreQueryService) {
this.tripleStoreQueryService = tripleStoreQueryService;
}
}