/**
* Copyright or © or Copr. Ministère Français chargé de la Culture
* et de la Communication (2013)
* <p/>
* contact.gincoculture_at_gouv.fr
* <p/>
* This software is a computer program whose purpose is to provide a thesaurus
* management solution.
* <p/>
* This software is governed by the CeCILL license under French law and
* abiding by the rules of distribution of free software. You can use,
* modify and/ or redistribute the software under the terms of the CeCILL
* license as circulated by CEA, CNRS and INRIA at the following URL
* "http://www.cecill.info".
* <p/>
* As a counterpart to the access to the source code and rights to copy,
* modify and redistribute granted by the license, users are provided only
* with a limited warranty and the software's author, the holder of the
* economic rights, and the successive licensors have only limited liability.
* <p/>
* In this respect, the user's attention is drawn to the risks associated
* with loading, using, modifying and/or developing or reproducing the
* software by the user in light of its specific status of free software,
* that may mean that it is complicated to manipulate, and that also
* therefore means that it is reserved for developers and experienced
* professionals having in-depth computer knowledge. Users are therefore
* encouraged to load and test the software's suitability as regards their
* requirements in conditions enabling the security of their systemsand/or
* data to be ensured and, more generally, to use and operate it in the
* same conditions as regards security.
* <p/>
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL license and that you accept its terms.
*/
package fr.mcc.ginco.rest.services;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.cxf.jaxrs.ext.multipart.Attachment;
import org.apache.cxf.jaxrs.ext.multipart.MultipartBody;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import fr.mcc.ginco.audit.utils.AuditContext;
import fr.mcc.ginco.beans.Alignment;
import fr.mcc.ginco.beans.Language;
import fr.mcc.ginco.beans.Role;
import fr.mcc.ginco.beans.Thesaurus;
import fr.mcc.ginco.beans.ThesaurusConcept;
import fr.mcc.ginco.beans.ThesaurusTerm;
import fr.mcc.ginco.enums.TermStatusEnum;
import fr.mcc.ginco.exceptions.BusinessException;
import fr.mcc.ginco.extjs.view.ExtJsonFormLoadData;
import fr.mcc.ginco.extjs.view.ImportedBranchResponse;
import fr.mcc.ginco.extjs.view.ImportedTermsResponse;
import fr.mcc.ginco.extjs.view.ImportedThesaurusResponse;
import fr.mcc.ginco.extjs.view.utils.ThesaurusConceptViewConverter;
import fr.mcc.ginco.imports.IGincoImportService;
import fr.mcc.ginco.imports.ISKOSImportService;
import fr.mcc.ginco.services.ILanguagesService;
import fr.mcc.ginco.services.IThesaurusConceptService;
import fr.mcc.ginco.services.IThesaurusService;
import fr.mcc.ginco.services.IThesaurusTermService;
import fr.mcc.ginco.services.IUserRoleService;
import fr.mcc.ginco.solr.ITermIndexerService;
import fr.mcc.ginco.solr.IThesaurusIndexerService;
/**
* Base REST service intended to be used for SKOS Import the @Produces({
* MediaType.TEXT_HTML}) is no mistake : this rest service is used by an ajax
* call and IE cannot display result if JSOn is returned
*/
@Service
@Path("/importservice")
@Produces({ MediaType.TEXT_HTML })
public class ImportRestService {
private static final String ATTACHMENT_NAME = "import-file-path";
@Inject
@Context
private javax.servlet.ServletContext servletContext;
@Inject
@Named("skosImportService")
private ISKOSImportService skosImportService;
@Inject
@Named("gincoImportService")
private IGincoImportService gincoImportService;
@Inject
@Named("thesaurusIndexerService")
private IThesaurusIndexerService thesaurusIndexerService;
@Inject
@Named("termIndexerService")
private ITermIndexerService termIndexerService;
@Inject
@Named("thesaurusConceptService")
private IThesaurusConceptService thesaurusConceptService;
@Inject
@Named("thesaurusConceptViewConverter")
private ThesaurusConceptViewConverter thesaurusConceptViewConverter;
@Inject
@Named("thesaurusTermService")
private IThesaurusTermService thesaurusTermService;
@Inject
@Named("userRoleService")
private IUserRoleService userRoleService;
@Inject
@Named("thesaurusService")
private IThesaurusService thesaurusService;
@Inject
@Named("languagesService")
private ILanguagesService languageService;
@Value("${ginco.default.language}")
private String defaultLang;
/**
* This method is called to import a SKOS thesaurus the @Produces({
* MediaType.TEXT_HTML}) is no mistake : this rest service is used by an
* ajax call and IE cannot display result if JSOn is returned
*
* @param body
* @param request
* @return The imported thesaurus in JSOn string representig a
* ExtJsonFormLoadData
* @throws IOException
*/
@POST
@Path("/import")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.TEXT_HTML)
@PreAuthorize("hasRole('ROLE_ADMIN')")
public String uploadFile(MultipartBody body,
@Context HttpServletRequest request) throws IOException {
Attachment file = body.getAttachment(ATTACHMENT_NAME);
String content = file.getObject(String.class);
String fileName = file.getDataHandler().getName();
File tempdir = (File) servletContext
.getAttribute("javax.servlet.context.tempdir");
Map<Thesaurus, Set<Alignment>> importResult = skosImportService
.importSKOSFile(content, fileName, tempdir);
Thesaurus thesaurus = importResult.keySet().iterator().next();
thesaurusIndexerService.indexThesaurus(thesaurus);
ImportedThesaurusResponse response = new ImportedThesaurusResponse();
response.setThesaurusTitle(thesaurus.getTitle());
List<String> conceptsMissingAlignments = new ArrayList<String>();
List<String> externalConceptIds = new ArrayList<String>();
Set<Alignment> bannedAlignments = importResult.get(thesaurus);
for (Alignment alignment : bannedAlignments) {
conceptsMissingAlignments.add(thesaurusConceptService
.getConceptLabel(alignment.getSourceConcept()
.getIdentifier()));
externalConceptIds.add(alignment.getTargetConcepts().iterator()
.next().getExternalTargetConcept());
}
response.setConceptsMissingAlignments(conceptsMissingAlignments);
response.setExternalConceptIds(externalConceptIds);
ObjectMapper mapper = new ObjectMapper();
String serialized = mapper.writeValueAsString(new ExtJsonFormLoadData(response));
return StringEscapeUtils.unescapeHtml4(serialized);
}
/**
* This method is called to import a Ginco XML thesaurus. The
*
* @param body
* @param request
* @return The imported thesaurus in JSOn string representing a
* ExtJsonFormLoadData
* @throws IOException
* @Produces({MediaType.TEXT_HTML ) is not a mistake : this rest service is
* used by an ajax call and IE cannot display
* result if JSOn is returned
*/
@POST
@Path("/importGincoXml")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.TEXT_HTML)
@PreAuthorize("hasRole('ROLE_ADMIN')")
public String uploadGincoXmlThesaurusFile(MultipartBody body,
@Context HttpServletRequest request)
throws IOException {
AuditContext.disableAudit();
Attachment file = body.getAttachment(ATTACHMENT_NAME);
String content = file.getObject(String.class);
String fileName = file.getDataHandler().getName();
File tempDir = (File) servletContext
.getAttribute("javax.servlet.context.tempdir");
Map<Thesaurus, Set<Alignment>> importResult = gincoImportService
.importGincoXmlThesaurusFile(content, fileName, tempDir);
Thesaurus thesaurus = importResult.keySet().iterator().next();
thesaurusIndexerService.indexThesaurus(thesaurus);
ImportedThesaurusResponse response = new ImportedThesaurusResponse();
response.setThesaurusTitle(thesaurus.getTitle());
List<String> missingExternalConcepts = new ArrayList<String>();
Set<Alignment> bannedAlignments = importResult.get(thesaurus);
for (Alignment ali : bannedAlignments) {
missingExternalConcepts.add(ali.getSourceConcept().getIdentifier());
}
response.setConceptsMissingAlignments(missingExternalConcepts);
ObjectMapper mapper = new ObjectMapper();
String serialized = mapper.writeValueAsString(new ExtJsonFormLoadData(response));
AuditContext.enableAudit();
return serialized;
}
/**
* This method is called to import a Ginco XML concept branch. The
*
* @param body
* @param request
* @return The imported concept branch in JSOn string representing a
* ExtJsonFormLoadData
* @throws IOException
* @Produces({MediaType.TEXT_HTML ) is not a mistake : this rest service is
* used by an ajax call and IE cannot display
* result if JSOn is returned
*/
@POST
@Path("/importGincoBranchXml")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.TEXT_HTML)
@PreAuthorize("hasPermission(#thesaurusId, '0')")
public String uploadGincoBranchXmlFile(MultipartBody body,
@QueryParam("thesaurusId") String thesaurusId,
@Context HttpServletRequest request)
throws IOException {
Attachment file = body.getAttachment(ATTACHMENT_NAME);
String content = file.getObject(String.class);
String fileName = file.getDataHandler().getName();
File tempDir = (File) servletContext.getAttribute("javax.servlet.context.tempdir");
Map<ThesaurusConcept, Set<Alignment>> importResult = gincoImportService
.importGincoBranchXmlFile(content, fileName, tempDir,
thesaurusId);
Thesaurus thesaurus = thesaurusService.getThesaurusById(thesaurusId);
thesaurusIndexerService.indexThesaurus(thesaurus);
ThesaurusConcept concept = importResult.keySet().iterator().next();
ObjectMapper mapper = new ObjectMapper();
ImportedBranchResponse response = new ImportedBranchResponse();
response.setTitle(thesaurusConceptService.getConceptTitle(concept));
response.setConceptView(thesaurusConceptViewConverter.convert(concept));
if (!importResult.get(concept).isEmpty()) {
response.setTargetInternalConceptsMissing(true);
} else {
response.setTargetInternalConceptsMissing(false);
}
String serialized = mapper.writeValueAsString(new ExtJsonFormLoadData(response));
//Update vocabulary date
thesaurusService.updateThesaurusDate(thesaurus);
return serialized;
}
/**
* Imports a list of terms
*
* @param body
* @param thesaurusId
* @param request
* @return
* @throws IOException
*/
@POST
@Path("/importSandBoxTerms")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.TEXT_HTML)
@PreAuthorize("hasPermission(#thesaurusId, '0') or hasPermission(#thesaurusId, '1')")
public String importSandBoxTerms(MultipartBody body,
@QueryParam("thesaurusId") String thesaurusId,
@Context HttpServletRequest request)
throws IOException {
Attachment file = body.getAttachment(ATTACHMENT_NAME);
String content = file.getObject(String.class);
if (content.contains("<?xml")) {
throw new BusinessException("Unable to import XML file as sandbox terms",
"import-unable-to-read-file");
} else {
String[] termsSplit = content.split("\n|\r\n");
List<String> termsLines = Arrays.asList(termsSplit);
Map<String, Language> terms = new HashMap<String, Language>();
List<String> termsInError = new ArrayList<String>();
for (String termLine : termsLines) {
String[] termSplitted = termLine.split("@");
if (termSplitted.length == 2) {
String lexValue = termSplitted[0];
if (StringUtils.isNotEmpty(lexValue)) {
Language lang = languageService.getLanguageById(termSplitted[1]);
if (lang == null) {
lang = languageService.getLanguageByPart1(termSplitted[1]);
}
if (lang != null) {
terms.put(lexValue, lang);
} else {
termsInError.add(termLine);
}
} else {
termsInError.add(termLine);
}
} else {
String lexValue = termLine;
Language lang = languageService.getLanguageById(defaultLang);
terms.put(lexValue, lang);
}
}
int defaultStatus = TermStatusEnum.VALIDATED.getStatus();
Authentication auth = SecurityContextHolder.getContext()
.getAuthentication();
String username = auth.getName();
if (userRoleService.hasRole(username, thesaurusId, Role.EXPERT)) {
defaultStatus = TermStatusEnum.CANDIDATE.getStatus();
}
List<ThesaurusTerm> sandboxedTerms = thesaurusTermService
.importSandBoxTerms(terms, thesaurusId, defaultStatus);
for (ThesaurusTerm sandboxedTerm : sandboxedTerms) {
termIndexerService.addTerm(sandboxedTerm);
}
ImportedTermsResponse response = new ImportedTermsResponse();
response.setTermsInError(termsInError);
ObjectMapper mapper = new ObjectMapper();
String serialized = mapper.writeValueAsString(new ExtJsonFormLoadData(response));
//Update vocabulary date
Thesaurus thesaurus = thesaurusService.getThesaurusById(thesaurusId);
thesaurusService.updateThesaurusDate(thesaurus);
return serialized;
}
}
}