001package conexp.fx.core.importer;
002
003/*
004 * #%L
005 * Concept Explorer FX
006 * %%
007 * Copyright (C) 2010 - 2019 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;
058import 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;
064import conexp.fx.core.dl.Signature;
065import conexp.fx.core.dl.deprecated.OWLInterpretation;
066
067public class RDFImporter {
068
069  public static final void readCSV(final Repository repository, final File file)
070      throws RepositoryException, RDFParseException, IOException {
071    final RepositoryConnection connection = repository.getConnection();
072    final ValueFactory f = new ValueFactoryImpl();
073    Files
074        .lines(file.toPath())
075        .map(line -> line.split(";"))
076        .map(
077            tuple -> new StatementImpl(
078                f.createURI(file.getName() + ":", tuple[0]),
079                f.createURI(file.getName() + ":", tuple[1]),
080                f.createURI(file.getName() + ":", tuple[2])))
081        .forEach(statement -> {
082          try {
083            connection.add(statement);
084          } catch (RepositoryException e) {
085            throw new RuntimeException(e);
086          }
087        });
088    connection.commit();
089    connection.close();
090  }
091
092  public static final Repository read(final File file) throws RepositoryException, RDFParseException, IOException {
093    final Repository repository = new SailRepository(new MemoryStore());
094    read(repository, file);
095    return repository;
096  }
097
098  public static final void read(final Repository repository, final File file)
099      throws RepositoryException, RDFParseException, IOException {
100    final RepositoryConnection connection = repository.getConnection();
101    connection.add(file, null, RDFFormat.forFileName(file.getName(), RDFFormat.RDFXML));
102    connection.commit();
103    connection.close();
104  }
105
106  public static final Repository read(final URL url) throws RepositoryException, RDFParseException, IOException {
107    final Repository repository = new SailRepository(new MemoryStore());
108    read(repository, url);
109    return repository;
110  }
111
112  public static final void read(final Repository repository, final URL url)
113      throws RepositoryException, RDFParseException, IOException {
114    final RepositoryConnection connection = repository.getConnection();
115    connection.add(url, null, RDFFormat.forFileName(url.toString(), RDFFormat.RDFXML));
116    connection.commit();
117    connection.close();
118  }
119
120  private static final class ContextTupleQueryResultHandler implements TupleQueryResultHandler {
121
122    private final MatrixContext<String, String> context;
123    private boolean                             objectTuples          = true;
124    private boolean                             attributeTuples       = true;
125    private final List<String>                  objectBindingNames    = new ArrayList<String>();
126    private final List<String>                  attributeBindingNames = new ArrayList<String>();
127    private final SetList<String>               objects               = new HashSetArrayList<String>();
128    private final SetList<String>               attributes            = new HashSetArrayList<String>();
129    private final Set<Pair<String, String>>     crosses               = new HashSet<Pair<String, String>>();
130
131    private ContextTupleQueryResultHandler(final MatrixContext<String, String> context) {
132      this.context = context;
133//    context.lock();
134      context.rowHeads().add("null");
135      context.colHeads().add("null");
136    }
137
138    public void handleBoolean(final boolean value) throws QueryResultHandlerException {
139      System.out.println("handle boolean " + value);
140    }
141
142    public void handleLinks(final List<String> linkUrls) throws QueryResultHandlerException {
143      System.out.println("handle links " + linkUrls);
144    }
145
146    public final void startQueryResult(final List<String> bindingNames) throws TupleQueryResultHandlerException {
147      for (String bindingName : bindingNames)
148        if (bindingName.toLowerCase().startsWith("object"))
149          objectBindingNames.add(bindingName);
150        else if (bindingName.toLowerCase().startsWith("attribute"))
151          attributeBindingNames.add(bindingName);
152      if (objectBindingNames.size() == 1)
153        objectTuples = false;
154      if (attributeBindingNames.size() == 1)
155        attributeTuples = false;
156    }
157
158    public final void endQueryResult() throws TupleQueryResultHandlerException {
159      System.out.println("adding " + objects.size() + " objects");
160      context.rowHeads().addAll(0, objects);
161      System.out.println("adding " + attributes.size() + " attributes");
162      context.colHeads().addAll(0, attributes);
163      context.rowHeads().remove("null");
164      context.colHeads().remove("null");
165      System.out.println("adding " + crosses.size() + " crosses");
166      for (Pair<String, String> p : crosses)
167        context.addFastSilent(p.x(), p.y());
168      // context.unlock();
169      context.pushAllChangedEvent();
170    }
171
172    public final void handleSolution(final BindingSet bindingSet) throws TupleQueryResultHandlerException {
173      String object = "", attribute = "";
174      if (objectTuples) {
175        for (String objectBindingName : objectBindingNames)
176          object += bindingSet.getBinding(objectBindingName).getValue().stringValue() + "; ";
177        object = object.substring(0, object.length() - 2);
178      } else
179        object = bindingSet.getBinding(objectBindingNames.get(0)).getValue().stringValue();
180      if (attributeTuples) {
181        for (String attributeBindingName : attributeBindingNames)
182          attribute += bindingSet.getBinding(attributeBindingName).getValue().stringValue() + "; ";
183        attribute = attribute.substring(0, attribute.length() - 2);
184      } else
185        attribute = bindingSet.getBinding(attributeBindingNames.get(0)).getValue().stringValue();
186      objects.add(object);
187      attributes.add(attribute);
188      crosses.add(Pair.of(object, attribute));
189    }
190  }
191
192  public static void importXML(final MatrixContext<String, String> context, String url, String query) {
193    try {
194      final SPARQLResultsXMLParser parser = new SPARQLResultsXMLParser();
195      parser.setTupleQueryResultHandler(new ContextTupleQueryResultHandler(context));
196      final String queryURL = new String(url).replace("<QUERY>", URLEncoder.encode(query, "UTF-8"));
197      System.out.println("reading " + queryURL);
198      final InputStream stream = new URL(queryURL).openStream();
199      System.out.println("parsing results");
200      parser.parseQueryResult(stream);
201      System.out.println("parse done");
202    } catch (QueryResultParseException | QueryResultHandlerException | IOException e) {
203      e.printStackTrace();
204    }
205  }
206
207  public static void importRepository(MatrixContext<String, String> context, Repository repo, String query) {
208    try {
209      final RepositoryConnection connection = repo.getConnection();
210      connection.prepareTupleQuery(QueryLanguage.SPARQL, query).evaluate(new ContextTupleQueryResultHandler(context));
211      connection.close();
212    } catch (QueryEvaluationException | RepositoryException | MalformedQueryException
213        | TupleQueryResultHandlerException e) {
214      e.printStackTrace();
215    }
216  }
217
218  public static void importFile(MatrixContext<String, String> context, File file, String query) {
219    try {
220      importRepository(context, read(file), query);
221    } catch (RepositoryException | RDFParseException | IOException e) {
222      e.printStackTrace();
223    }
224  }
225
226  public static void importURL(MatrixContext<String, String> context, String url, String query) {
227    try {
228      importRepository(context, read(new URL(url)), query);
229    } catch (RepositoryException | RDFParseException | IOException e) {
230      e.printStackTrace();
231    }
232  }
233
234  public static final OWLInterpretation extractInterpretation(final List<Statement> triples) {
235    return extractInterpretation(triples, IRI.create(RDF.TYPE.stringValue()));
236  }
237
238  public static final OWLInterpretation
239      extractInterpretation(final List<Statement> triples, final IRI selectedIsARoleName) {
240    final List<IRI> roleNames =
241        triples.parallelStream().map(triple -> IRI.create(triple.getPredicate().stringValue())).distinct().collect(
242            Collectors.toList());
243    if (!roleNames.contains(selectedIsARoleName))
244      throw new IllegalArgumentException();
245    roleNames.remove(selectedIsARoleName);
246    final List<IRI> conceptNames = triples
247        .parallelStream()
248        .filter(triple -> IRI.create(triple.getPredicate().stringValue()).equals(selectedIsARoleName))
249        .map(triple -> IRI.create(triple.getObject().stringValue()))
250        .collect(Collectors.toList());
251    return extractInterpretation(triples, conceptNames, roleNames, selectedIsARoleName);
252  }
253
254  public static final OWLInterpretation extractInterpretation(
255      final List<Statement> triples,
256      final List<IRI> selectedConceptNames,
257      final List<IRI> selectedRoleNames,
258      final IRI selectedIsARoleName) {
259    final Signature signature = new Signature(null);
260    signature.getConceptNames().addAll(selectedConceptNames);
261    signature.getRoleNames().addAll(selectedRoleNames);
262    signature.getIndividualNames().addAll(
263        triples
264            .parallelStream()
265            .filter(
266                triple -> IRI.create(triple.getPredicate().stringValue()).equals(selectedIsARoleName)
267                    && signature.getConceptNames().contains(IRI.create(triple.getObject().stringValue())))
268            .map(triple -> IRI.create(triple.getSubject().stringValue()))
269            .collect(Collectors.toSet()));
270    final OWLInterpretation i = new OWLInterpretation(signature);
271    triples.stream().forEach(triple -> {
272      if (IRI.create(triple.getPredicate().stringValue()).equals(selectedIsARoleName)) {
273        if (signature.getConceptNames().contains(IRI.create(triple.getObject().stringValue()))
274            && signature.getIndividualNames().contains(IRI.create(triple.getSubject().stringValue()))) {
275          i.addConceptNameAssertion(
276              IRI.create(triple.getObject().stringValue()),
277              IRI.create(triple.getSubject().stringValue()));
278        }
279      } else if (signature.getRoleNames().contains(IRI.create(triple.getPredicate().stringValue()))
280          && signature.getIndividualNames().contains(IRI.create(triple.getSubject().stringValue()))
281          && signature.getIndividualNames().contains(IRI.create(triple.getObject().stringValue()))) {
282        i.addRoleNameAssertion(
283            IRI.create(triple.getPredicate().stringValue()),
284            IRI.create(triple.getSubject().stringValue()),
285            IRI.create(triple.getObject().stringValue()));
286      }
287    });
288    return i;
289  }
290
291}