Java tutorial
/** * Constellio, Open Source Enterprise Search * Copyright (C) 2010 DocuLibre inc. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU * Lesser General Public License, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution; if not, write to: * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ package com.doculibre.constellio.services; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.logging.Logger; import javax.persistence.EntityManager; import javax.persistence.Query; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.lang.StringUtils; import org.jaxen.JaxenException; import org.jaxen.SimpleNamespaceContext; import org.jaxen.jdom.JDOMXPath; import org.jdom.Attribute; import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; import org.jdom.Namespace; import org.jdom.input.SAXBuilder; import com.doculibre.analyzer.AccentApostropheCleaner; import com.doculibre.constellio.entities.Categorization; import com.doculibre.constellio.entities.skos.SkosConcept; import com.doculibre.constellio.entities.skos.SkosConceptAltLabel; import com.doculibre.constellio.entities.skos.Thesaurus; import com.doculibre.constellio.lucene.impl.SkosIndexHelper; import com.doculibre.constellio.utils.ClasspathUtils; import com.doculibre.constellio.utils.ConstellioSpringUtils; import com.doculibre.constellio.utils.ProgressInfo; import com.doculibre.constellio.utils.persistence.ConstellioPersistenceContext; public class SkosServicesImpl extends BaseCRUDServicesImpl<Thesaurus> implements SkosServices { private static final Logger LOGGER = Logger.getLogger(SkosServicesImpl.class.getName()); private static final String SKOS_CONCEPT_SCHEME = "//skos:ConceptScheme"; private static final String SKOS_HAS_TOP_CONCEPT_XPATH = "skos:hasTopConcept"; private static final String DC_TITLE_XPATH = "dc:title"; private static final String DC_DESCRIPTION_XPATH = "dc:description"; private static final String DC_CREATOR_XPATH = "dc:creator"; private static final String DC_DATE_XPATH = "dc:date"; private static final String DC_LANGUAGE_XPATH = "dc:language"; private static final String SKOS_CONCEPT_XPATH = "//skos:Concept"; private static final String RDF_ABOUT_ATTR_XPATH = "@rdf:about"; private static final String SKOS_PREF_LABEL_XPATH = "skos:prefLabel"; private static final String SKOS_NOTES_XPATH = "skos:notes"; private static final String SKOS_BROADER_XPATH = "skos:broader"; private static final String SKOS_ALT_LABEL_XPATH = "skos:altLabel"; private static final String SKOS_RELATED_XPATH = "skos:related"; private static final String SKOS_NARROWER_XPATH = "skos:narrower"; private static final Namespace rdfNs = Namespace.getNamespace("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"); public SkosServicesImpl(EntityManager entityManager) { super(Thesaurus.class, entityManager); } @SuppressWarnings("unchecked") @Override public Thesaurus importThesaurus(InputStream input, ProgressInfo progressInfo, List<String> errorMessages) { Thesaurus thesaurus = new Thesaurus(); Map<String, SkosConcept> parsedConcepts = new HashMap<String, SkosConcept>(); try { SAXBuilder builder = new SAXBuilder(); builder.setValidation(false); Document skosJdom = builder.build(input); SimpleNamespaceContext namespaceContext = new SimpleNamespaceContext(); collectNamespaces(skosJdom, namespaceContext); // Parsing thesaurus tag JDOMXPath currentXPath; // Concept scheme currentXPath = new JDOMXPath(SKOS_CONCEPT_SCHEME); currentXPath.setNamespaceContext(namespaceContext); Element conceptSchemeElement = (Element) currentXPath.selectSingleNode(skosJdom); // rdf about currentXPath = new JDOMXPath(RDF_ABOUT_ATTR_XPATH); currentXPath.setNamespaceContext(namespaceContext); Attribute thesaurusRdfAboutAttribute = (Attribute) currentXPath.selectSingleNode(conceptSchemeElement); if (thesaurusRdfAboutAttribute != null) { String thesaurusRdfAbout = thesaurusRdfAboutAttribute.getValue(); thesaurus.setRdfAbout(thesaurusRdfAbout); } // Title currentXPath = new JDOMXPath(DC_TITLE_XPATH); currentXPath.setNamespaceContext(namespaceContext); Element titleElement = (Element) currentXPath.selectSingleNode(conceptSchemeElement); if (titleElement != null) { String dcTitle = titleElement.getValue(); dcTitle = StringEscapeUtils.unescapeXml(dcTitle); thesaurus.setDcTitle(dcTitle); } // Description currentXPath = new JDOMXPath(DC_DESCRIPTION_XPATH); currentXPath.setNamespaceContext(namespaceContext); Element descriptionElement = (Element) currentXPath.selectSingleNode(conceptSchemeElement); if (descriptionElement != null) { String dcDescription = descriptionElement.getValue(); dcDescription = StringEscapeUtils.unescapeXml(dcDescription); thesaurus.setDcDescription(dcDescription); } // Creator currentXPath = new JDOMXPath(DC_CREATOR_XPATH); currentXPath.setNamespaceContext(namespaceContext); Element creatorElement = (Element) currentXPath.selectSingleNode(conceptSchemeElement); if (creatorElement != null) { String dcCreator = creatorElement.getValue(); dcCreator = StringEscapeUtils.unescapeXml(dcCreator); thesaurus.setDcCreator(dcCreator); } // Date currentXPath = new JDOMXPath(DC_DATE_XPATH); currentXPath.setNamespaceContext(namespaceContext); Element dateElement = (Element) currentXPath.selectSingleNode(conceptSchemeElement); if (dateElement != null) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Date dcDate = sdf.parse(dateElement.getValue()); thesaurus.setDcDate(dcDate); } // Language currentXPath = new JDOMXPath(DC_LANGUAGE_XPATH); currentXPath.setNamespaceContext(namespaceContext); Element languageElement = (Element) currentXPath.selectSingleNode(conceptSchemeElement); if (languageElement != null) { Locale dcLanguage = new Locale(languageElement.getValue()); thesaurus.setDcLanguage(dcLanguage); } LOGGER.finest("First pass of skos:Concept tags (collecting labels)"); currentXPath = new JDOMXPath(SKOS_CONCEPT_XPATH); currentXPath.setNamespaceContext(namespaceContext); List<Element> skosConceptElements = currentXPath.selectNodes(skosJdom); // 2 passes progressInfo.setTotal(skosConceptElements.size() * 2); for (Element skosConceptElement : skosConceptElements) { currentXPath = new JDOMXPath(RDF_ABOUT_ATTR_XPATH); currentXPath.setNamespaceContext(namespaceContext); Attribute rdfAboutAttribute = (Attribute) currentXPath.selectSingleNode(skosConceptElement); // rcupration de l'ID String rdfAbout = rdfAboutAttribute.getValue(); LOGGER.finest("Collecting labels for " + rdfAbout); SkosConcept skosConcept = new SkosConcept(); skosConcept.setThesaurus(thesaurus); parsedConcepts.put(rdfAbout, skosConcept); skosConcept.setRdfAbout(rdfAbout); // recupration du descripteur de la langue du thesaurus et les // quivalent sont dans une autre langue currentXPath = new JDOMXPath(SKOS_PREF_LABEL_XPATH); currentXPath.setNamespaceContext(namespaceContext); List<Element> prefLabelElements = currentXPath.selectNodes(skosConceptElement); for (Element prefLabelElement : prefLabelElements) { String lang = prefLabelElement.getAttributeValue("lang", Namespace.XML_NAMESPACE); Locale prefLabelLocale = lang != null ? new Locale(lang) : Locale.ENGLISH; String prefLabel = prefLabelElement.getValue(); prefLabel = StringEscapeUtils.unescapeXml(prefLabel); skosConcept.setPrefLabel(prefLabel, prefLabelLocale); } // Notes currentXPath = new JDOMXPath(SKOS_NOTES_XPATH); currentXPath.setNamespaceContext(namespaceContext); Element skosNotesElement = (Element) currentXPath.selectSingleNode(skosConceptElement); if (skosNotesElement != null) { String skosNotes = skosNotesElement.getTextTrim(); skosNotes = StringEscapeUtils.unescapeXml(skosNotes); skosConcept.setSkosNotes(skosNotes); } // Rejected forms currentXPath = new JDOMXPath(SKOS_ALT_LABEL_XPATH); currentXPath.setNamespaceContext(namespaceContext); List<Element> altLabelElements = currentXPath.selectNodes(skosConceptElement); for (Element altLabelElement : altLabelElements) { String lang = altLabelElement.getAttributeValue("lang", Namespace.XML_NAMESPACE); Locale altLabelLocale = lang != null ? new Locale(lang) : Locale.ENGLISH; String altLabel = altLabelElement.getValue(); altLabel = StringEscapeUtils.unescapeXml(altLabel); skosConcept.getAltLabels(altLabelLocale).add(altLabel); } progressInfo.incrementCurrentIndex(); } LOGGER.finest("Second pass of skos:Concept tags (identifying relationships)"); for (Element skosConceptElement : skosConceptElements) { currentXPath = new JDOMXPath(RDF_ABOUT_ATTR_XPATH); currentXPath.setNamespaceContext(namespaceContext); Attribute rdfAboutAttribute = (Attribute) currentXPath.selectSingleNode(skosConceptElement); // recupration de l'ID String rdfAbout = rdfAboutAttribute.getValue(); LOGGER.finest("Processing relationships for " + rdfAbout); SkosConcept skosConcept = parsedConcepts.get(rdfAbout); // recupration des termes gnriques rdf:resource currentXPath = new JDOMXPath(SKOS_BROADER_XPATH); currentXPath.setNamespaceContext(namespaceContext); List<Element> broaderElements = currentXPath.selectNodes(skosConceptElement); for (Element broaderElement : broaderElements) { String resource = broaderElement.getAttributeValue("resource", rdfNs); SkosConcept broader = parsedConcepts.get(resource); if (broader != null) { skosConcept.addBroader(broader); broader.addNarrower(skosConcept); } else { StringBuffer errorMsg = new StringBuffer(); errorMsg.append("Concept "); errorMsg.append(rdfAbout); errorMsg.append(" has a missing broader concept :"); errorMsg.append(resource); LOGGER.severe(errorMsg.toString()); // throw new RuntimeException(errorMsg.toString()); } } // No broader element, therefore this is a top concept if (skosConcept.getBroader().isEmpty()) { thesaurus.addTopConcept(skosConcept); } // Associes currentXPath = new JDOMXPath(SKOS_RELATED_XPATH); currentXPath.setNamespaceContext(namespaceContext); List<Element> relatedElements = currentXPath.selectNodes(skosConceptElement); for (Element relatedElement : relatedElements) { String resource = relatedElement.getAttributeValue("resource", rdfNs); SkosConcept related = parsedConcepts.get(resource); skosConcept.addRelated(related); } progressInfo.incrementCurrentIndex(); } LOGGER.finest("Validating skos:hasTopConcept tags"); // Validate top concepts currentXPath = new JDOMXPath(SKOS_HAS_TOP_CONCEPT_XPATH); currentXPath.setNamespaceContext(namespaceContext); List<Element> hasTopConceptElements = currentXPath.selectNodes(skosJdom); for (Element hasTopConceptElement : hasTopConceptElements) { String resource = hasTopConceptElement.getAttributeValue("resource", rdfNs); SkosConcept topConcept = parsedConcepts.get(resource); if (!topConcept.getBroader().isEmpty()) { StringBuffer errorMsg = new StringBuffer(); errorMsg.append("Top concept "); errorMsg.append(resource); errorMsg.append(" has broader concept(s) ("); for (Iterator<SkosConcept> it = topConcept.getBroader().iterator(); it.hasNext();) { SkosConcept broaderConcept = it.next(); errorMsg.append(broaderConcept.getRdfAbout()); if (it.hasNext()) { errorMsg.append(", "); } } errorMsg.append(")"); throw new RuntimeException(errorMsg.toString()); } else { LOGGER.finest(resource + " is a valid top concept"); } } LOGGER.finest("Third pass of skos:Concept tags (validating relationships)"); for (Element skosConceptElement : skosConceptElements) { currentXPath = new JDOMXPath(RDF_ABOUT_ATTR_XPATH); currentXPath.setNamespaceContext(namespaceContext); Attribute rdfAboutAttribute = (Attribute) currentXPath.selectSingleNode(skosConceptElement); // recupration de l'ID String rdfAbout = rdfAboutAttribute.getValue(); SkosConcept skosConcept = parsedConcepts.get(rdfAbout); // Rcupration des termes spcifiques // recupration des termes spcifiques avec rdf:resource currentXPath = new JDOMXPath(SKOS_NARROWER_XPATH); currentXPath.setNamespaceContext(namespaceContext); List<Element> narrowerElements = currentXPath.selectNodes(skosConceptElement); for (Element narrowerElement : narrowerElements) { String resource = narrowerElement.getAttributeValue("resource", rdfNs); SkosConcept narrower = parsedConcepts.get(resource); if (narrower != null) { if (narrower.getBroader().isEmpty()) { StringBuffer errorMsg = new StringBuffer(); errorMsg.append("Le concept "); errorMsg.append(rdfAbout); errorMsg.append(" possde un concept spcifique (narrower) ("); errorMsg.append(narrower.getRdfAbout()); errorMsg.append( ") qui ne possde pas un concept gnrique (broader) correspondant."); LOGGER.severe(errorMsg.toString()); errorMessages.add(errorMsg.toString()); // throw new RuntimeException(errorMsg.toString()); } else if (!narrower.getBroader().contains(skosConcept)) { StringBuffer errorMsg = new StringBuffer(); errorMsg.append("Le concept "); errorMsg.append(rdfAbout); errorMsg.append(" possde au moins un concept spcifique (narrower) ("); errorMsg.append(narrower.getRdfAbout()); errorMsg.append( ") qui ne possde pas un concept gnrique (broader) correspondant. ("); for (Iterator<SkosConcept> it = narrower.getBroader().iterator(); it.hasNext();) { SkosConcept narrowerConcept = it.next(); errorMsg.append(narrowerConcept.getRdfAbout()); if (it.hasNext()) { errorMsg.append(", "); } } errorMsg.append(")"); LOGGER.severe(errorMsg.toString()); errorMessages.add(errorMsg.toString()); // throw new RuntimeException(errorMsg.toString()); } else { LOGGER.finest(resource + " has a valid broader/narrower relationship"); } } else { StringBuffer errorMsg = new StringBuffer(); errorMsg.append("Il manque un concept spcifique (narrower) au concept gnrique : "); errorMsg.append(rdfAbout); LOGGER.severe(errorMsg.toString()); errorMessages.add(errorMsg.toString()); // throw new RuntimeException(errorMsg.toString()); } // FIXME!!! // if (narrower != null) { // if (narrower.getBroader() == null) { // StringBuffer errorMsg = new StringBuffer(); // errorMsg.append("Concept "); // errorMsg.append(rdfAbout); // errorMsg.append(" has a narrower concept ("); // errorMsg.append(narrower.getRdfAbout()); // errorMsg.append(") that doesn't have the inverse broader relation."); // LOGGER.severe(errorMsg.toString()); //// throw new RuntimeException(errorMsg.toString()); // } else if (!narrower.getBroader().equals(skosConcept)) { // StringBuffer errorMsg = new StringBuffer(); // errorMsg.append("Concept "); // errorMsg.append(rdfAbout); // errorMsg.append(" has a narrower concept ("); // errorMsg.append(narrower.getRdfAbout()); // errorMsg.append(") which has a broader relation that doesn't match ("); // errorMsg.append(narrower.getBroader().getRdfAbout()); // errorMsg.append(")"); //// throw new RuntimeException(errorMsg.toString()); // LOGGER.severe(errorMsg.toString()); // } else { // LOGGER.finest(resource + " has a valid broader/narrower relationship"); // } // } else { // StringBuffer errorMsg = new StringBuffer(); // errorMsg.append("Concept "); // errorMsg.append(rdfAbout); // errorMsg.append(" has a missing narrower concept :"); // LOGGER.severe(errorMsg.toString()); //// throw new RuntimeException(errorMsg.toString()); // } } } } catch (JDOMException e) { //FIXME Report exception "Invalid document" to UI.... throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } catch (JaxenException e) { throw new RuntimeException(e); } catch (ParseException e) { throw new RuntimeException(e); } finally { IOUtils.closeQuietly(input); } return thesaurus; } private static void collectNamespaces(Document doc, SimpleNamespaceContext namespaceContext) { List<String> collectedNamespaces = new ArrayList<String>(); processChildren(doc.getRootElement(), collectedNamespaces, namespaceContext); } @SuppressWarnings("unchecked") private static void processChildren(Element element, List<String> collectedNamespaces, SimpleNamespaceContext namespaceContext) { Namespace currentNamespace = (Namespace) element.getNamespace(); String nsUri = (currentNamespace.getURI()); if (!exist(collectedNamespaces, nsUri)) { collectedNamespaces.add(nsUri.trim()); namespaceContext.addNamespace(currentNamespace.getPrefix(), currentNamespace.getURI()); } List<Namespace> additionalNs = element.getAdditionalNamespaces(); if (!additionalNs.isEmpty()) copyNsList(additionalNs, collectedNamespaces, namespaceContext); if (element.getChildren().size() > 0) { List<Element> elementChildren = element.getChildren(); for (int i = 0; i < elementChildren.size(); i++) { processChildren(elementChildren.get(i), collectedNamespaces, namespaceContext); } } } private static boolean exist(List<String> collectedNamespaces, String nsUri) { if (collectedNamespaces.isEmpty()) return false; for (int i = 0; i < collectedNamespaces.size(); i++) { if ((collectedNamespaces.get(i)).equals(nsUri)) { return true; } } return false; } private static void copyNsList(List<Namespace> additionalNs, List<String> collectedNamespaces, SimpleNamespaceContext namespaceContext) { for (int i = 0; i < additionalNs.size(); i++) { Namespace ns = additionalNs.get(i); namespaceContext.addNamespace(ns.getPrefix(), ns.getURI()); collectedNamespaces.add(ns.getURI().trim()); } } @Override public List<Categorization> importCategorizations(InputStream input, Thesaurus thesaurus) { // TODO Auto-generated method stub return null; } @Override public Set<SkosConcept> searchPrefLabel(String input, Thesaurus thesaurus, final Locale locale) { List<SkosConcept> returnedSearchResults = new ArrayList<SkosConcept>(); if (StringUtils.isNotBlank(input)) { input = input.trim(); SkosIndexHelper indexHelper = ConstellioSpringUtils.getSkosIndexHelper(); List<SkosConcept> searchResults = indexHelper.searchPrefLabel(input, thesaurus, locale); for (SkosConcept searchResult : searchResults) { returnedSearchResults.add(searchResult); } indexHelper.release(searchResults); } return new HashSet<SkosConcept>(returnedSearchResults); } @Override public Set<SkosConcept> getByPrefLabel(String prefLabel, Thesaurus thesaurus, final Locale locale) { List<SkosConcept> returnedSearchResults = new ArrayList<SkosConcept>(); if (StringUtils.isNotBlank(prefLabel)) { prefLabel = prefLabel.trim().toLowerCase(); String prefLabelWoutAccents = AccentApostropheCleaner.removeAccents(prefLabel); SkosIndexHelper indexHelper = ConstellioSpringUtils.getSkosIndexHelper(); List<SkosConcept> searchResults = indexHelper.searchPrefLabel(prefLabel, thesaurus, locale); for (SkosConcept searchResult : searchResults) { String searchResultPrefLabel = searchResult.getPrefLabel(locale); if (searchResultPrefLabel != null) { searchResultPrefLabel = searchResultPrefLabel.trim().toLowerCase(); searchResultPrefLabel = AccentApostropheCleaner.removeAccents(searchResultPrefLabel); if (searchResultPrefLabel.equals(prefLabelWoutAccents) || searchResultPrefLabel.startsWith(prefLabelWoutAccents) && searchResultPrefLabel.endsWith(")")) { returnedSearchResults.add(searchResult); } } } indexHelper.release(searchResults); } return new HashSet<SkosConcept>(returnedSearchResults); } @Override public Set<SkosConcept> getByAltLabel(String altLabel, Thesaurus thesaurus, Locale locale) { List<SkosConcept> returnedSearchResults = new ArrayList<SkosConcept>(); if (StringUtils.isNotBlank(altLabel)) { altLabel = altLabel.trim().toLowerCase(); String altLabelWoutAccents = AccentApostropheCleaner.removeAccents(altLabel); SkosIndexHelper indexHelper = ConstellioSpringUtils.getSkosIndexHelper(); List<SkosConcept> searchResults = indexHelper.searchAltLabel(altLabel, thesaurus, locale); for (SkosConcept searchResult : searchResults) { loop2: for (String searchResultAltLabel : searchResult.getAltLabels(locale)) { searchResultAltLabel = searchResultAltLabel.trim().toLowerCase(); searchResultAltLabel = AccentApostropheCleaner.removeAccents(searchResultAltLabel); if (searchResultAltLabel.equals(altLabelWoutAccents)) { returnedSearchResults.add(searchResult); break loop2; } } } indexHelper.release(searchResults); } return new HashSet<SkosConcept>(returnedSearchResults); } @Override public Set<SkosConcept> searchAltLabels(String input, Thesaurus thesaurus, Locale locale) { Set<SkosConcept> returnedSearchResults = new HashSet<SkosConcept>(); if (StringUtils.isNotBlank(input)) { input = input.trim(); SkosIndexHelper indexHelper = ConstellioSpringUtils.getSkosIndexHelper(); List<SkosConcept> searchResults = indexHelper.searchAltLabel(input, thesaurus, locale); for (SkosConcept searchResult : searchResults) { returnedSearchResults.add(searchResult); } indexHelper.release(searchResults); } return returnedSearchResults; } @Override public Set<SkosConcept> searchAllLabels(String input, Thesaurus thesaurus, Locale locale) { Set<SkosConcept> returnedSearchResults = new HashSet<SkosConcept>(); if (StringUtils.isNotBlank(input)) { input = input.trim(); SkosIndexHelper indexHelper = ConstellioSpringUtils.getSkosIndexHelper(); List<SkosConcept> searchResults = indexHelper.searchAllLabels(input, thesaurus, locale); for (SkosConcept searchResult : searchResults) { returnedSearchResults.add(searchResult); } indexHelper.release(searchResults); } return returnedSearchResults; } @Override public SkosConcept getSkosConcept(Long id) { return (SkosConcept) getEntityManager().find(SkosConcept.class, id); } @Override public Thesaurus makePersistent(Thesaurus thesaurus) { super.makePersistent(thesaurus); for (SkosConcept topConcept : thesaurus.getTopConcepts()) { makePersistent(topConcept, true); } SkosIndexHelper indexHelper = ConstellioSpringUtils.getSkosIndexHelper(); indexHelper.delete(thesaurus); indexHelper.add(thesaurus); return thesaurus; } private SkosConcept makePersistent(SkosConcept skosConcept, boolean recursive) { getEntityManager().persist(skosConcept); if (recursive) { for (SkosConcept narrowerConcept : skosConcept.getNarrower()) { makePersistent(narrowerConcept, true); // Recursive call } } return skosConcept; } @Override public Thesaurus makeTransient(Thesaurus thesaurus) { // for (SkosConcept topConcept : thesaurus.getTopConcepts()) { // makeTransient(topConcept, false); // } // super.makeTransient(thesaurus); // String sqlRecordTag = "DELETE FROM RecordTag WHERE skosConcept_id IN (SELECT id FROM SkosConcept WHERE thesaurus_id=?)"; // Query sqlQueryRecordTag = getEntityManager().createNativeQuery(sqlRecordTag); // sqlQueryRecordTag.setParameter(1, thesaurus.getId()); // sqlQueryRecordTag.executeUpdate(); String sqlAltLabelValues = "DELETE FROM SkosConceptAltLabel_Values WHERE skosConceptAltLabel_id IN (SELECT id FROM SkosConceptAltLabel WHERE skosConcept_id IN (SELECT id FROM SkosConcept WHERE thesaurus_id=?))"; Query sqlQueryAltLabelValues = getEntityManager().createNativeQuery(sqlAltLabelValues); sqlQueryAltLabelValues.setParameter(1, thesaurus.getId()); sqlQueryAltLabelValues.executeUpdate(); String sqlAltLabel = "DELETE FROM SkosConceptAltLabel WHERE skosConcept_id IN (SELECT id FROM SkosConcept WHERE thesaurus_id=?)"; Query sqlQueryAltLabel = getEntityManager().createNativeQuery(sqlAltLabel); sqlQueryAltLabel.setParameter(1, thesaurus.getId()); sqlQueryAltLabel.executeUpdate(); String sqlLabels = "DELETE FROM SkosConcept_Labels WHERE skosConcept_id IN (SELECT id FROM SkosConcept WHERE thesaurus_id=?)"; Query sqlQueryLabels = getEntityManager().createNativeQuery(sqlLabels); sqlQueryLabels.setParameter(1, thesaurus.getId()); sqlQueryLabels.executeUpdate(); String sqlRelationsSource = "DELETE FROM SkosConcept_Relations WHERE sourceSkosConcept_id IN (SELECT id FROM SkosConcept WHERE thesaurus_id=?)"; Query sqlQueryRelationsSource = getEntityManager().createNativeQuery(sqlRelationsSource); sqlQueryRelationsSource.setParameter(1, thesaurus.getId()); sqlQueryRelationsSource.executeUpdate(); String sqlRelationsRelated = "DELETE FROM SkosConcept_Relations WHERE relatedSkosConcept_id IN (SELECT id FROM SkosConcept WHERE thesaurus_id=?)"; Query sqlQueryRelationsRelated = getEntityManager().createNativeQuery(sqlRelationsRelated); sqlQueryRelationsRelated.setParameter(1, thesaurus.getId()); sqlQueryRelationsRelated.executeUpdate(); String sqlNarrower = "DELETE FROM SkosConcept_Narrower WHERE narrowerSkosConcept_id IN (SELECT id FROM SkosConcept WHERE thesaurus_id=?)"; Query sqlQueryNarrower = getEntityManager().createNativeQuery(sqlNarrower); sqlQueryNarrower.setParameter(1, thesaurus.getId()); sqlQueryNarrower.executeUpdate(); String sqlBroader = "DELETE FROM SkosConcept_Narrower WHERE broaderSkosConcept_id IN (SELECT id FROM SkosConcept WHERE thesaurus_id=?)"; Query sqlQueryBroader = getEntityManager().createNativeQuery(sqlBroader); sqlQueryBroader.setParameter(1, thesaurus.getId()); sqlQueryBroader.executeUpdate(); String sqlSkosConcept = "DELETE FROM SkosConcept WHERE thesaurus_id=?"; Query sqlQuerySkosConcept = getEntityManager().createNativeQuery(sqlSkosConcept); sqlQuerySkosConcept.setParameter(1, thesaurus.getId()); sqlQuerySkosConcept.executeUpdate(); String sqlThesaurus = "DELETE FROM Thesaurus WHERE id=?"; Query sqlQueryThesaurus = getEntityManager().createNativeQuery(sqlThesaurus); sqlQueryThesaurus.setParameter(1, thesaurus.getId()); sqlQueryThesaurus.executeUpdate(); // Will synchronize objects with database getEntityManager().flush(); SkosIndexHelper indexHelper = ConstellioSpringUtils.getSkosIndexHelper(); indexHelper.delete(thesaurus); return thesaurus; } @Override public void makeTransient(SkosConcept deletedConcept) { makeTransient(deletedConcept, true); } public void makeTransient(SkosConcept deletedConcept, boolean saveModifiedNarrower) { for (SkosConcept narrowerConcept : deletedConcept.getNarrower()) { Set<SkosConcept> oppositeBroader = narrowerConcept.getBroader(); if (oppositeBroader.size() == 1 && oppositeBroader.contains(deletedConcept)) { makeTransient(narrowerConcept, saveModifiedNarrower); // Recursive call } else { oppositeBroader.remove(deletedConcept); if (saveModifiedNarrower) { makePersistent(narrowerConcept, false); } } } getEntityManager().remove(deletedConcept); } /** * Copies content modifications from modified thesaurus into initial thesaurus. * * @see com.doculibre.constellio.services.SkosServices#merge(com.doculibre.constellio.entities.skos.Thesaurus, * com.doculibre.constellio.entities.skos.Thesaurus) */ @Override public Set<SkosConcept> merge(Thesaurus initialThesaurus, Thesaurus modifiedThesaurus) { Set<SkosConcept> deletedConcepts = new HashSet<SkosConcept>(); Map<String, SkosConcept> initialConcepts = initialThesaurus.getFlattenedConcepts(); Map<String, SkosConcept> modifiedConcepts = modifiedThesaurus.getFlattenedConcepts(); initialThesaurus.setDcTitle(modifiedThesaurus.getDcTitle()); initialThesaurus.setDcDescription(modifiedThesaurus.getDcDescription()); initialThesaurus.setDcDate(modifiedThesaurus.getDcDate()); initialThesaurus.setDcCreator(modifiedThesaurus.getDcCreator()); // Manage deleted and modified concepts for (SkosConcept initialConcept : initialConcepts.values()) { String rdfAbout = initialConcept.getRdfAbout(); if (!modifiedConcepts.containsKey(rdfAbout)) { deletedConcepts.add(initialConcept); } else { SkosConcept modifiedConcept = modifiedConcepts.get(rdfAbout); initialConcept.setSkosNotes(modifiedConcept.getSkosNotes()); // Broader before modifications Set<SkosConcept> previousBroader = initialConcept.getBroader(); // Broader as found in the modified file Set<SkosConcept> modifiedBroader = modifiedConcept.getBroader(); // Undo previous relationship if (!previousBroader.isEmpty() && !previousBroader.equals(modifiedBroader)) { initialConcept.getBroader().clear(); for (SkosConcept previousBroaderConcept : previousBroader) { previousBroaderConcept.getNarrower().remove(initialConcept); } } // This concept still has a broader concept if (!modifiedBroader.isEmpty()) { for (SkosConcept modifiedBroaderConcept : modifiedBroader) { // Did the modified broader exist initially? SkosConcept existingBroader = initialConcepts.get(modifiedBroaderConcept.getRdfAbout()); if (existingBroader != null) { // Create the relationship if it didn't exist before if (!existingBroader.getNarrower().contains(initialConcept)) { existingBroader.addNarrower(initialConcept); } } else { // Create the broader relationship with the new SkosConcept modifiedBroaderConcept.setThesaurus(initialThesaurus); modifiedBroaderConcept.addNarrower(initialConcept); } } } else if (!initialThesaurus.getTopConcepts().contains(initialConcept)) { // It is now a top concept initialThesaurus.addTopConcept(initialConcept); } // Rebuild related from scratch initialConcept.getRelated().clear(); for (SkosConcept related : modifiedConcept.getRelated()) { SkosConcept existingRelated = initialConcepts.get(related.getRdfAbout()); if (existingRelated != null) { // Add related existing skos concept initialConcept.addRelated(existingRelated); } else { // Add related new skos concept related.setThesaurus(initialThesaurus); initialConcept.addRelated(related); } } // Rebuild pref labels from scratch initialConcept.getPrefLabels().clear(); initialConcept.getPrefLabels().addAll(modifiedConcept.getPrefLabels()); // Rebuild alt labels from scratch initialConcept.getAltLabels().clear(); for (SkosConceptAltLabel altLabel : modifiedConcept.getAltLabels()) { altLabel.setSkosConcept(initialConcept); initialConcept.getAltLabels().add(altLabel); } } } // Will include newly discovered concepts after processing modified and deleted concepts initialConcepts = initialThesaurus.getFlattenedConcepts(); // Manage new concepts // First pass : Attach new concepts to the thesaurus for (SkosConcept modifiedConcept : modifiedConcepts.values()) { String rdfAbout = modifiedConcept.getRdfAbout(); if (!initialConcepts.containsKey(rdfAbout)) { modifiedConcept.setThesaurus(initialThesaurus); } } // Will include newly discovered concepts after first pass initialConcepts = initialThesaurus.getFlattenedConcepts(); // Second pass : Attach new concepts to their broader/narrower/related for (SkosConcept modifiedConcept : modifiedConcepts.values()) { // Newly added if (modifiedConcept.getThesaurus().equals(initialThesaurus)) { // Broader / narrower Set<SkosConcept> broader = modifiedConcept.getBroader(); if (!broader.isEmpty()) { for (SkosConcept broaderConcept : broader) { SkosConcept existingBroader = initialConcepts.get(broaderConcept.getRdfAbout()); if (!existingBroader.getNarrower().contains(modifiedConcept)) { existingBroader.addNarrower(modifiedConcept); } } } else if (!initialThesaurus.getTopConcepts().contains(modifiedConcept)) { initialThesaurus.addTopConcept(modifiedConcept); } // Related Set<SkosConcept> relatedModifiedThesaurus = new HashSet<SkosConcept>(); relatedModifiedThesaurus.addAll(modifiedConcept.getRelated()); // Rebuild from scratch modifiedConcept.getRelated().clear(); for (SkosConcept related : relatedModifiedThesaurus) { SkosConcept existingRelated = initialConcepts.get(related.getRdfAbout()); // Add related existing skos concept modifiedConcept.addRelated(existingRelated); } } } return deletedConcepts; } private static SkosConcept getFirstBroaderConcept(SkosConcept skosConcept) { SkosConcept firstBroaderConcept; Set<SkosConcept> broader = skosConcept.getBroader(); if (!broader.isEmpty()) { firstBroaderConcept = broader.iterator().next(); } else { firstBroaderConcept = null; } return firstBroaderConcept; } private static void printNice(SkosConcept skosConcept) { StringBuffer indent = new StringBuffer(); SkosConcept indentConcept = skosConcept; SkosConcept broaderConcept = getFirstBroaderConcept(indentConcept); while (broaderConcept != null) { indent.append(" "); indentConcept = broaderConcept = getFirstBroaderConcept(indentConcept); } Locale fr = new Locale("fr"); Locale en = new Locale("en"); System.out.println(indent + "rdfAbout : " + skosConcept.getRdfAbout()); System.out.println(indent + "prefLabel (fr) : " + skosConcept.getPrefLabel(fr)); System.out.println(indent + "prefLabel (en) : " + skosConcept.getPrefLabel(en)); for (String altLabel : skosConcept.getAltLabels(fr)) { System.out.println(indent + "altLabel (fr) : " + altLabel); } for (String altLabel : skosConcept.getAltLabels(en)) { System.out.println(indent + "altLabel (en) : " + altLabel); } for (SkosConcept related : skosConcept.getRelated()) { System.out.println(indent + "Related : " + related.getRdfAbout()); } for (SkosConcept narrower : skosConcept.getNarrower()) { System.out.println(indent + "Narrower : "); // Recursive call printNice(narrower); } } public static void main(String[] args) throws Exception { SkosServices skosServices = ConstellioSpringUtils.getSkosServices(); File webinfDir = ClasspathUtils.getWebinfDir(); File skosDir = new File(webinfDir, "skos"); File tagSkosFile = new File(skosDir, "tagskos.rdf"); ProgressInfo progressInfo = new ProgressInfo(); Thesaurus thesaurus = skosServices.importThesaurus(new FileInputStream(tagSkosFile), progressInfo, new ArrayList<String>()); System.out.println(thesaurus.getDcTitle()); System.out.println(thesaurus.getDcDescription()); System.out.println(thesaurus.getDcCreator()); System.out.println(thesaurus.getDcDate()); System.out.println(thesaurus.getDcLanguage()); for (SkosConcept skosConcept : thesaurus.getTopConcepts()) { printNice(skosConcept); } EntityManager entityManager = ConstellioPersistenceContext.getCurrentEntityManager(); if (!entityManager.getTransaction().isActive()) { entityManager.getTransaction().begin(); } skosServices.makePersistent(thesaurus); entityManager.getTransaction().commit(); // // if (!entityManager.getTransaction().isActive()) { // entityManager.getTransaction().begin(); // } // skosServices.makeTransient(thesaurus); // entityManager.getTransaction().commit(); } }