001package conexp.fx.core.importer;
002
003/*
004 * #%L
005 * Concept Explorer FX
006 * %%
007 * Copyright (C) 2010 - 2023 Francesco Kriegel
008 * %%
009 * This program is free software: you can redistribute it and/or modify
010 * it under the terms of the GNU General Public License as
011 * published by the Free Software Foundation, either version 3 of the
012 * License, or (at your option) any later version.
013 * 
014 * This program is distributed in the hope that it will be useful,
015 * but WITHOUT ANY WARRANTY; without even the implied warranty of
016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
017 * GNU General Public License for more details.
018 * 
019 * You should have received a copy of the GNU General Public
020 * License along with this program.  If not, see
021 * <http://www.gnu.org/licenses/gpl-3.0.html>.
022 * #L%
023 */
024
025import java.io.File;
026import java.io.IOException;
027import java.io.InputStream;
028import java.net.URL;
029import java.net.URLEncoder;
030import java.nio.file.Files;
031import java.util.ArrayList;
032import java.util.HashSet;
033import java.util.List;
034import java.util.Set;
035import java.util.stream.Collectors;
036
037import org.openrdf.model.Statement;
038import org.openrdf.model.ValueFactory;
039import org.openrdf.model.impl.StatementImpl;
040import org.openrdf.model.impl.ValueFactoryImpl;
041import org.openrdf.model.vocabulary.RDF;
042import org.openrdf.query.BindingSet;
043import org.openrdf.query.MalformedQueryException;
044import org.openrdf.query.QueryEvaluationException;
045import org.openrdf.query.QueryLanguage;
046import org.openrdf.query.QueryResultHandlerException;
047import org.openrdf.query.TupleQueryResultHandler;
048import org.openrdf.query.TupleQueryResultHandlerException;
049import org.openrdf.query.resultio.QueryResultParseException;
050import org.openrdf.query.resultio.sparqlxml.SPARQLResultsXMLParser;
051import org.openrdf.repository.Repository;
052import org.openrdf.repository.RepositoryConnection;
053import org.openrdf.repository.RepositoryException;
054import org.openrdf.repository.sail.SailRepository;
055import org.openrdf.rio.RDFFormat;
056import org.openrdf.rio.RDFParseException;
057import org.openrdf.sail.memory.MemoryStore;
058//import org.semanticweb.owlapi.model.IRI;
059
060import conexp.fx.core.collections.Pair;
061import conexp.fx.core.collections.setlist.HashSetArrayList;
062import conexp.fx.core.collections.setlist.SetList;
063import conexp.fx.core.context.MatrixContext;
064//import conexp.fx.core.dl.Signature;
065
066public class RDFImporter {
067
068  public static final void readCSV(final Repository repository, final File file)
069      throws RepositoryException, RDFParseException, IOException {
070    final RepositoryConnection connection = repository.getConnection();
071    final ValueFactory f = new ValueFactoryImpl();
072    Files
073        .lines(file.toPath())
074        .map(line -> line.split(";"))
075        .map(
076            tuple -> new StatementImpl(
077                f.createURI(file.getName() + ":", tuple[0]),
078                f.createURI(file.getName() + ":", tuple[1]),
079                f.createURI(file.getName() + ":", tuple[2])))
080        .forEach(statement -> {
081          try {
082            connection.add(statement);
083          } catch (RepositoryException e) {
084            throw new RuntimeException(e);
085          }
086        });
087    connection.commit();
088    connection.close();
089  }
090
091  public static final Repository read(final File file) throws RepositoryException, RDFParseException, IOException {
092    final Repository repository = new SailRepository(new MemoryStore());
093    read(repository, file);
094    return repository;
095  }
096
097  public static final void read(final Repository repository, final File file)
098      throws RepositoryException, RDFParseException, IOException {
099    final RepositoryConnection connection = repository.getConnection();
100    connection.add(file, null, RDFFormat.forFileName(file.getName(), RDFFormat.RDFXML));
101    connection.commit();
102    connection.close();
103  }
104
105  public static final Repository read(final URL url) throws RepositoryException, RDFParseException, IOException {
106    final Repository repository = new SailRepository(new MemoryStore());
107    read(repository, url);
108    return repository;
109  }
110
111  public static final void read(final Repository repository, final URL url)
112      throws RepositoryException, RDFParseException, IOException {
113    final RepositoryConnection connection = repository.getConnection();
114    connection.add(url, null, RDFFormat.forFileName(url.toString(), RDFFormat.RDFXML));
115    connection.commit();
116    connection.close();
117  }
118
119  private static final class ContextTupleQueryResultHandler implements TupleQueryResultHandler {
120
121    private final MatrixContext<String, String> context;
122    private boolean                             objectTuples          = true;
123    private boolean                             attributeTuples       = true;
124    private final List<String>                  objectBindingNames    = new ArrayList<String>();
125    private final List<String>                  attributeBindingNames = new ArrayList<String>();
126    private final SetList<String>               objects               = new HashSetArrayList<String>();
127    private final SetList<String>               attributes            = new HashSetArrayList<String>();
128    private final Set<Pair<String, String>>     crosses               = new HashSet<Pair<String, String>>();
129
130    private ContextTupleQueryResultHandler(final MatrixContext<String, String> context) {
131      this.context = context;
132//    context.lock();
133      context.rowHeads().add("null");
134      context.colHeads().add("null");
135    }
136
137    public void handleBoolean(final boolean value) throws QueryResultHandlerException {
138      System.out.println("handle boolean " + value);
139    }
140
141    public void handleLinks(final List<String> linkUrls) throws QueryResultHandlerException {
142      System.out.println("handle links " + linkUrls);
143    }
144
145    public final void startQueryResult(final List<String> bindingNames) throws TupleQueryResultHandlerException {
146      for (String bindingName : bindingNames)
147        if (bindingName.toLowerCase().startsWith("object"))
148          objectBindingNames.add(bindingName);
149        else if (bindingName.toLowerCase().startsWith("attribute"))
150          attributeBindingNames.add(bindingName);
151      if (objectBindingNames.size() == 1)
152        objectTuples = false;
153      if (attributeBindingNames.size() == 1)
154        attributeTuples = false;
155    }
156
157    public final void endQueryResult() throws TupleQueryResultHandlerException {
158      System.out.println("adding " + objects.size() + " objects");
159      context.rowHeads().addAll(0, objects);
160      System.out.println("adding " + attributes.size() + " attributes");
161      context.colHeads().addAll(0, attributes);
162      context.rowHeads().remove("null");
163      context.colHeads().remove("null");
164      System.out.println("adding " + crosses.size() + " crosses");
165      for (Pair<String, String> p : crosses)
166        context.addFastSilent(p.x(), p.y());
167      // context.unlock();
168      context.pushAllChangedEvent();
169    }
170
171    public final void handleSolution(final BindingSet bindingSet) throws TupleQueryResultHandlerException {
172      String object = "", attribute = "";
173      if (objectTuples) {
174        for (String objectBindingName : objectBindingNames)
175          object += bindingSet.getBinding(objectBindingName).getValue().stringValue() + "; ";
176        object = object.substring(0, object.length() - 2);
177      } else
178        object = bindingSet.getBinding(objectBindingNames.get(0)).getValue().stringValue();
179      if (attributeTuples) {
180        for (String attributeBindingName : attributeBindingNames)
181          attribute += bindingSet.getBinding(attributeBindingName).getValue().stringValue() + "; ";
182        attribute = attribute.substring(0, attribute.length() - 2);
183      } else
184        attribute = bindingSet.getBinding(attributeBindingNames.get(0)).getValue().stringValue();
185      objects.add(object);
186      attributes.add(attribute);
187      crosses.add(Pair.of(object, attribute));
188    }
189  }
190
191  public static void importXML(final MatrixContext<String, String> context, String url, String query) {
192    try {
193      final SPARQLResultsXMLParser parser = new SPARQLResultsXMLParser();
194      parser.setTupleQueryResultHandler(new ContextTupleQueryResultHandler(context));
195      final String queryURL = new String(url).replace("<QUERY>", URLEncoder.encode(query, "UTF-8"));
196      System.out.println("reading " + queryURL);
197      final InputStream stream = new URL(queryURL).openStream();
198      System.out.println("parsing results");
199      parser.parseQueryResult(stream);
200      System.out.println("parse done");
201    } catch (QueryResultParseException | QueryResultHandlerException | IOException e) {
202      e.printStackTrace();
203    }
204  }
205
206  public static void importRepository(MatrixContext<String, String> context, Repository repo, String query) {
207    try {
208      final RepositoryConnection connection = repo.getConnection();
209      connection.prepareTupleQuery(QueryLanguage.SPARQL, query).evaluate(new ContextTupleQueryResultHandler(context));
210      connection.close();
211    } catch (QueryEvaluationException | RepositoryException | MalformedQueryException
212        | TupleQueryResultHandlerException e) {
213      e.printStackTrace();
214    }
215  }
216
217  public static void importFile(MatrixContext<String, String> context, File file, String query) {
218    try {
219      importRepository(context, read(file), query);
220    } catch (RepositoryException | RDFParseException | IOException e) {
221      e.printStackTrace();
222    }
223  }
224
225  public static void importURL(MatrixContext<String, String> context, String url, String query) {
226    try {
227      importRepository(context, read(new URL(url)), query);
228    } catch (RepositoryException | RDFParseException | IOException e) {
229      e.printStackTrace();
230    }
231  }
232
233//  public static final OWLInterpretation extractInterpretation(final List<Statement> triples) {
234//    return extractInterpretation(triples, IRI.create(RDF.TYPE.stringValue()));
235//  }
236//
237//  public static final OWLInterpretation
238//      extractInterpretation(final List<Statement> triples, final IRI selectedIsARoleName) {
239//    final List<IRI> roleNames =
240//        triples.parallelStream().map(triple -> IRI.create(triple.getPredicate().stringValue())).distinct().collect(
241//            Collectors.toList());
242//    if (!roleNames.contains(selectedIsARoleName))
243//      throw new IllegalArgumentException();
244//    roleNames.remove(selectedIsARoleName);
245//    final List<IRI> conceptNames = triples
246//        .parallelStream()
247//        .filter(triple -> IRI.create(triple.getPredicate().stringValue()).equals(selectedIsARoleName))
248//        .map(triple -> IRI.create(triple.getObject().stringValue()))
249//        .collect(Collectors.toList());
250//    return extractInterpretation(triples, conceptNames, roleNames, selectedIsARoleName);
251//  }
252//
253//  public static final OWLInterpretation extractInterpretation(
254//      final List<Statement> triples,
255//      final List<IRI> selectedConceptNames,
256//      final List<IRI> selectedRoleNames,
257//      final IRI selectedIsARoleName) {
258//    final Signature signature = new Signature(null);
259//    signature.getConceptNames().addAll(selectedConceptNames);
260//    signature.getRoleNames().addAll(selectedRoleNames);
261//    signature.getIndividualNames().addAll(
262//        triples
263//            .parallelStream()
264//            .filter(
265//                triple -> IRI.create(triple.getPredicate().stringValue()).equals(selectedIsARoleName)
266//                    && signature.getConceptNames().contains(IRI.create(triple.getObject().stringValue())))
267//            .map(triple -> IRI.create(triple.getSubject().stringValue()))
268//            .collect(Collectors.toSet()));
269//    final OWLInterpretation i = new OWLInterpretation(signature);
270//    triples.stream().forEach(triple -> {
271//      if (IRI.create(triple.getPredicate().stringValue()).equals(selectedIsARoleName)) {
272//        if (signature.getConceptNames().contains(IRI.create(triple.getObject().stringValue()))
273//            && signature.getIndividualNames().contains(IRI.create(triple.getSubject().stringValue()))) {
274//          i.addConceptNameAssertion(
275//              IRI.create(triple.getObject().stringValue()),
276//              IRI.create(triple.getSubject().stringValue()));
277//        }
278//      } else if (signature.getRoleNames().contains(IRI.create(triple.getPredicate().stringValue()))
279//          && signature.getIndividualNames().contains(IRI.create(triple.getSubject().stringValue()))
280//          && signature.getIndividualNames().contains(IRI.create(triple.getObject().stringValue()))) {
281//        i.addRoleNameAssertion(
282//            IRI.create(triple.getPredicate().stringValue()),
283//            IRI.create(triple.getSubject().stringValue()),
284//            IRI.create(triple.getObject().stringValue()));
285//      }
286//    });
287//    return i;
288//  }
289
290}