001/**
002 * Copyright (C) 2007 - 2016, Jens Lehmann
003 *
004 * This file is part of DL-Learner.
005 *
006 * DL-Learner is free software; you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published by
008 * the Free Software Foundation; either version 3 of the License, or
009 * (at your option) any later version.
010 *
011 * DL-Learner is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014 * GNU General Public License for more details.
015 *
016 * You should have received a copy of the GNU General Public License
017 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
018 */
019package org.dllearner.algorithms.pattern;
020
021import com.google.common.collect.HashMultiset;
022import com.google.common.collect.Multiset;
023import joptsimple.OptionParser;
024import joptsimple.OptionSet;
025import joptsimple.OptionSpec;
026import org.apache.commons.io.FileUtils;
027import org.dllearner.kb.dataset.OWLOntologyDataset;
028import org.dllearner.kb.repository.LocalDirectoryOntologyRepository;
029import org.dllearner.kb.repository.OntologyRepository;
030import org.dllearner.kb.repository.OntologyRepositoryEntry;
031import org.dllearner.utilities.ProgressBar;
032import org.dllearner.utilities.owl.ManchesterOWLSyntaxOWLObjectRendererImplExt;
033import org.ini4j.IniPreferences;
034import org.semanticweb.owlapi.apibinding.OWLManager;
035import org.semanticweb.owlapi.functional.renderer.FunctionalSyntaxObjectRenderer;
036import org.semanticweb.owlapi.io.OWLObjectRenderer;
037import org.semanticweb.owlapi.io.ToStringRenderer;
038import org.semanticweb.owlapi.io.UnparsableOntologyException;
039import org.semanticweb.owlapi.model.*;
040import org.semanticweb.owlapi.model.parameters.Imports;
041import org.semanticweb.owlapi.reasoner.ConsoleProgressMonitor;
042import org.slf4j.Logger;
043import org.slf4j.LoggerFactory;
044
045import java.io.*;
046import java.net.URI;
047import java.sql.*;
048import java.util.*;
049import java.util.concurrent.ExecutorService;
050import java.util.concurrent.Executors;
051import java.util.concurrent.TimeUnit;
052import java.util.concurrent.atomic.AtomicInteger;
053import java.util.prefs.Preferences;
054import java.util.stream.Collectors;
055
056public class OWLAxiomPatternFinder {
057        
058        private static final Logger LOGGER = LoggerFactory.getLogger(OWLAxiomPatternFinder.class);
059        
060        private OntologyRepository repository;
061        private OWLOntologyManager manager;
062        private OWLDataFactory dataFactory;
063        
064        private Connection conn;
065        private PreparedStatement selectOntologyIdPs;
066        private PreparedStatement insertOntologyPs;
067        private PreparedStatement insertOntologyImportPs;
068        private PreparedStatement insertOntologyErrorPs;
069
070        private PreparedStatement selectPatternIdPs;
071        private PreparedStatement insertPatternIdPs;
072        private PreparedStatement insertOntologyPatternPs;
073
074        private PreparedStatement insertPatternGeneralizationPs;
075        private PreparedStatement insertPatternToPatternGeneralizationPs;
076        private PreparedStatement selectGeneralizedPatternIdPs;
077
078        private OWLObjectRenderer axiomRenderer = new ManchesterOWLSyntaxOWLObjectRendererImplExt();
079        
080        private boolean randomOrder = false;
081
082        private boolean multithreadedEnabled = false;
083        private int numThreads = 4;//Runtime.getRuntime().availableProcessors() - 1
084
085        public OWLAxiomPatternFinder(OWLOntologyDataset dataset) {
086                
087        }
088        
089        public OWLAxiomPatternFinder(OntologyRepository repository) {
090                this.repository = repository;
091                manager = OWLManager.createOWLOntologyManager();
092                dataFactory = manager.getOWLDataFactory();
093                
094                initDBConnection();
095                prepare();
096        }
097        
098        public OWLAxiomPatternFinder(OntologyRepository repository, Connection conn) {
099                this.repository = repository;
100                this.conn = conn;
101                manager = OWLManager.createOWLOntologyManager();
102                dataFactory = manager.getOWLDataFactory();
103                
104                prepare();
105        }
106
107        /**
108         * Start the pattern detection.
109         */
110        public void start() {
111                final ExecutorService tp = Executors.newFixedThreadPool(multithreadedEnabled ? numThreads : 1);
112
113                Collection<OntologyRepositoryEntry> entries = repository.getEntries();
114                if(randomOrder){
115                        List<OntologyRepositoryEntry> entryList = new ArrayList<>(repository.getEntries());
116                        Collections.shuffle(entryList);
117                        entries = entryList;
118                }
119
120                final Multiset<OWLAxiom> allAxiomPatterns = HashMultiset.create();
121
122                AtomicInteger i = new AtomicInteger(0);
123
124                manager = OWLManager.createConcurrentOWLOntologyManager();
125
126                entries = entries.stream().filter(e -> e.getOntologyShortName().equals("NIDM-RESULTS")).collect(Collectors.toList());
127
128                for (OntologyRepositoryEntry entry : entries) {
129                        tp.execute(() -> {
130                                        OWLAxiomRenamer renamer = new OWLAxiomRenamer(dataFactory);
131
132                                        URI uri = entry.getPhysicalURI();
133                                        LOGGER.info(i.incrementAndGet() + ": " + entry.getOntologyShortName() + " (" +
134                                                                                           FileUtils.byteCountToDisplaySize(new File(uri).length()) + ")");
135//                                      if(uri.toString().startsWith("http://rest.bioontology.org/bioportal/ontologies/download/42764")){
136                                        if (true) {//!ontologyProcessed(uri)) {
137                                                LOGGER.info("Loading \"" + entry.getOntologyShortName() + "\" from " + uri + " ...");
138                                                try {
139
140                                                        OWLOntologyManager manager = OWLManager.createOWLOntologyManager();
141
142                                                        OWLOntology ontology = manager.loadOntology(IRI.create(uri));
143                                                        Set<OWLLogicalAxiom> logicalAxioms = ontology.getLogicalAxioms(Imports.EXCLUDED);
144                                                        LOGGER.info("   finished loading \"" + entry.getOntologyShortName() + "\". #Axioms: " + logicalAxioms.size());
145                                                        addOntology(uri, ontology, Imports.EXCLUDED);
146
147                                                        LOGGER.info("Running pattern detection for \"" + entry.getOntologyShortName() + "\" ...");
148                                                        Multiset<OWLAxiom> axiomPatterns = HashMultiset.create();
149                                                        int cnt = 0;
150                                                        ProgressBar mon = new ProgressBar();
151                                                        for (OWLAxiom axiom : logicalAxioms) {
152//                                                              if(axiom.isOfType(AxiomType.SUBCLASS_OF)) {
153//                                                                      System.out.println(MaximumModalDepthDetector.getMaxModalDepth(axiom));
154//                                                                      System.out.println(((OWLSubClassOfAxiom)axiom).getSuperClass());
155//                                                                      OWLClassExpression sup = ((OWLSubClassOfAxiom) axiom).getSuperClass();
156//                                                                      if(sup instanceof OWLObjectIntersectionOf) {
157//                                                                              List<OWLClassExpression> operands = ((OWLObjectIntersectionOf) sup).getOperandsAsList();
158//                                                                              System.out.println("OPs: " + operands.size());
159//                                                                              if(operands.get(0).toString().equals("Oxidative-Phosphorylation")) {
160//                                                                                      manager.createOntology(Sets.newHashSet(axiom)).saveOntology(
161//                                                                                                      new RDFXMLDocumentFormat(),
162//                                                                                                      new FileOutputStream("/tmp/longaxiom.owl"));
163//                                                                                      System.exit(0);
164//                                                                              }
165//                                                                      }
166//                                                              }
167
168                                                                OWLAxiom renamedAxiom = renamer.rename(axiom);
169                                                                axiomPatterns.add(renamedAxiom);
170                                                                cnt++;
171                                                                if(cnt % 100 == 0) {
172                                                                        mon.update(cnt, logicalAxioms.size());
173                                                                }
174                                                        }
175
176                                                        LOGGER.info("   finished pattern detection for \"" + entry.getOntologyShortName() + "\". #Patterns: " +
177                                                                                                axiomPatterns.elementSet().size());
178//                                                      allAxiomPatterns.addAll(axiomPatterns);
179                                                        addOntologyPatterns(uri, ontology, axiomPatterns);
180//                                                      for (OWLAxiom owlAxiom : Multisets.copyHighestCountFirst(allAxiomPatterns).elementSet()) {
181//                                                              System.out.println(owlAxiom + ": " + allAxiomPatterns.count(owlAxiom));
182//                                                      }
183
184                                                        // process the imports separately
185                                                        Set<OWLOntology> imports = ontology.getImports();
186                                                        if(!imports.isEmpty()) {
187                                                                LOGGER.info("Processing the imports of \"" + entry.getOntologyShortName() + "\" ...");
188                                                        }
189                                                        imports.stream().forEach(importedOntology -> {
190                                                                IRI iri = importedOntology.getOntologyID().getOntologyIRI().or(manager.getOntologyDocumentIRI(importedOntology));
191                                                                System.out.println(iri.toString());
192
193                                                                // check if it was already processed before
194                                                                if(!ontologyProcessed(iri.toURI())) {
195                                                                        addOntology(iri.toURI(), importedOntology, Imports.INCLUDED);
196                                                                        LOGGER.info("Running pattern detection for import from " + iri + " ...");
197                                                                        axiomPatterns.clear();
198                                                                        importedOntology.getLogicalAxioms(Imports.INCLUDED).stream().forEach(axiom -> {
199                                                                                OWLAxiom renamedAxiom = renamer.rename(axiom);
200                                                                                axiomPatterns.add(renamedAxiom);
201                                                                        });
202                                                                        addOntologyPatterns(iri.toURI(), importedOntology, axiomPatterns);
203                                                                        addOntologyImport(uri, ontology, iri.toURI(), importedOntology);
204                                                                        LOGGER.info("   finished pattern detection for import from " + iri + ". #Patterns: " +
205                                                                                                                axiomPatterns.elementSet().size());
206                                                                } else {
207                                                                        LOGGER.info("Import " + iri + " already processed.");
208                                                                }
209
210                                                        });
211
212
213
214                                                        manager.removeOntology(ontology);
215                                                } catch (OWLOntologyAlreadyExistsException e) {
216                                                        e.printStackTrace();
217                                                } catch (UnloadableImportException e) {
218                                                        LOGGER.error("Import loading failed.", e.getMessage());
219                                                        addOntologyError(uri, e);
220                                                } catch(UnparsableOntologyException e) {
221                                                        e.printStackTrace();
222                                                        LOGGER.error("Parsing of ontology failed.", e.getMessage());
223                                                        addOntologyError(uri, e);
224                                                } catch (Exception e) {
225                                                        e.printStackTrace();
226                                                        LOGGER.error("Ontology processing failed", e);
227                                                        addOntologyError(uri, e);
228                                                }
229                                        } else {
230                                                LOGGER.info("Already processed.");
231                                        }
232                                });
233                }
234
235                try {
236                        tp.shutdown();
237                        tp.awaitTermination(600, TimeUnit.MINUTES);
238                } catch (InterruptedException e) {
239                        System.err.println("tasks interrupted");
240
241                        // Preserve interrupt status
242                        Thread.currentThread().interrupt();
243                } finally {
244                        if (!tp.isTerminated()) {
245                                System.err.println("cancel non-finished tasks");
246                        }
247                        tp.shutdownNow();
248                        System.out.println("shutdown finished");
249                }
250
251
252                computeAndAddGeneralizedPatterns();
253
254                try {
255                        conn.close();
256                } catch (SQLException e) {
257                        LOGGER.error("Failed to close DB connection.", e);
258                }
259        }
260
261        public void setMultithreadedEnabled(boolean multithreadedEnabled) {
262                this.multithreadedEnabled = multithreadedEnabled;
263        }
264
265        public void setNumThreads(int numThreads) {
266                this.numThreads = numThreads;
267                if(numThreads < 0) {
268                        numThreads = Runtime.getRuntime().availableProcessors() - 1;
269                }
270        }
271
272        private void prepare(){
273                createTables();
274                try {
275                        selectOntologyIdPs = conn.prepareStatement("SELECT id FROM Ontology WHERE url=?");
276                        insertOntologyPs = conn.prepareStatement("INSERT INTO Ontology (url, iri, repository, logical_axioms, tbox_axioms, rbox_axioms" +
277                                        ", abox_axioms, classes, object_properties, data_properties, individuals) VALUES(?,?,?,?,?,?,?,?,?,?,?)");
278
279                        insertOntologyImportPs = conn.prepareStatement("INSERT INTO Ontology_Import (ontology_id1, ontology_id2) VALUES(?,?)");
280                        insertOntologyErrorPs = conn.prepareStatement("INSERT INTO Ontology_Error (url, repository, error) VALUES(?,?,?)");
281
282                        selectPatternIdPs = conn.prepareStatement("SELECT id FROM Pattern WHERE pattern=?");
283                        insertPatternIdPs = conn.prepareStatement("INSERT INTO Pattern (pattern,pattern_pretty,axiom_type) VALUES(?,?,?)");
284                        insertOntologyPatternPs = conn.prepareStatement("INSERT INTO Ontology_Pattern (ontology_id, pattern_id, occurrences) VALUES(?,?,?)");
285
286                        insertPatternGeneralizationPs = conn.prepareStatement("INSERT INTO Pattern_Generalized (pattern,pattern_pretty,axiom_type) VALUES(?,?,?)");
287                        insertPatternToPatternGeneralizationPs = conn.prepareStatement("INSERT INTO Pattern_Pattern_Generalized (pattern_id, generalized_pattern_id) VALUES(?,?)");
288                        selectGeneralizedPatternIdPs = conn.prepareStatement("SELECT id FROM Pattern_Generalized WHERE pattern=?");
289
290                } catch (SQLException e) {
291                        e.printStackTrace();
292                }
293        }
294        
295        private String render(OWLAxiom axiom){
296                try {
297                        OWLOntologyManager man = OWLManager.createOWLOntologyManager();
298                        OWLOntology ontology = man.createOntology();
299                        man.addAxiom(ontology, axiom);
300                        StringWriter sw = new StringWriter();
301                        FunctionalSyntaxObjectRenderer r = new FunctionalSyntaxObjectRenderer(ontology, sw);
302                        axiom.accept(r);
303                        return sw.toString();
304                } catch (OWLOntologyCreationException e) {
305                        e.printStackTrace();
306                }
307                return null;
308        }
309        
310        private void initDBConnection() {
311                try {
312                        InputStream is = this.getClass().getClassLoader().getResourceAsStream(
313                                        "org/dllearner/algorithms/pattern/db_settings.ini");
314                        Preferences prefs = new IniPreferences(is);
315                        String dbServer = prefs.node("database").get("server", null);
316                        String dbName = prefs.node("database").get("name", null);
317                        String dbUser = prefs.node("database").get("user", null);
318                        String dbPass = prefs.node("database").get("pass", null);
319
320                        String url = "jdbc:mysql://" + dbServer + "/" + dbName;
321                        conn = DriverManager.getConnection(url, dbUser, dbPass);
322                } catch (IOException e) {
323                        LOGGER.error("Failed to settings.", e);
324                } catch (SQLException e) {
325                        LOGGER.error("Failed to setup database connection.", e);
326                }
327        }
328        
329        private void createTables(){
330                try (Statement statement = conn.createStatement()){
331                        statement.execute("CREATE TABLE IF NOT EXISTS Pattern ("
332                                + "id MEDIUMINT NOT NULL AUTO_INCREMENT,"
333                                        + "pattern TEXT NOT NULL,"
334                                        + "pattern_pretty TEXT NOT NULL,"
335                                        + "axiom_type VARCHAR(15) NOT NULL,"
336                                        + "PRIMARY KEY(id),"
337                                        + "INDEX(pattern(1000))) DEFAULT CHARSET=utf8");
338                        
339                        statement.execute("CREATE TABLE IF NOT EXISTS Ontology (" 
340                                + "id MEDIUMINT NOT NULL AUTO_INCREMENT,"
341                                        + "url VARCHAR(1000) NOT NULL,"
342                                        + "iri VARCHAR(2000) NOT NULL,"
343                                        + "repository VARCHAR(200) NOT NULL,"
344                                        + "logical_axioms MEDIUMINT DEFAULT 0,"
345                                        + "tbox_axioms MEDIUMINT DEFAULT 0,"
346                                        + "rbox_axioms MEDIUMINT DEFAULT 0,"
347                                        + "abox_axioms MEDIUMINT DEFAULT 0,"
348                                        + "classes MEDIUMINT DEFAULT 0,"
349                                        + "object_properties MEDIUMINT DEFAULT 0,"
350                                        + "data_properties MEDIUMINT DEFAULT 0,"
351                                        + "individuals MEDIUMINT DEFAULT 0,"
352                                        + "PRIMARY KEY(id),"
353                                        + "INDEX(url)) DEFAULT CHARSET=utf8");
354
355                        statement.execute("CREATE TABLE IF NOT EXISTS Ontology_Import ("
356                                                                          + "ontology_id1 MEDIUMINT NOT NULL,"
357                                                                          + "ontology_id2 MEDIUMINT NOT NULL,"
358                                                                          + "PRIMARY KEY(ontology_id1, ontology_id2))"
359                                                                          );
360
361                        statement.execute("CREATE TABLE IF NOT EXISTS Ontology_Error ("
362                                                                          + "url VARCHAR(1000) NOT NULL,"
363                                                                          + "repository VARCHAR(200) NOT NULL,"
364                                                                          + "error VARCHAR(2000) NOT NULL,"
365                                                                          + "PRIMARY KEY(url, repository))"
366                        );
367
368                        statement.execute("CREATE TABLE IF NOT EXISTS Ontology_Pattern (" 
369                                + "ontology_id MEDIUMINT NOT NULL,"
370                                        + "pattern_id MEDIUMINT NOT NULL,"
371                                        + "occurrences INTEGER(8) NOT NULL,"
372                                        + "FOREIGN KEY (ontology_id) REFERENCES Ontology(id) ON DELETE CASCADE,"
373                                        + "FOREIGN KEY (pattern_id) REFERENCES Pattern(id) ON DELETE CASCADE,"
374                                        + "PRIMARY KEY(ontology_id, pattern_id)) DEFAULT CHARSET=utf8");
375
376                        statement.execute("CREATE TABLE IF NOT EXISTS Pattern_Generalized ("
377                                        + "id MEDIUMINT NOT NULL AUTO_INCREMENT,"
378                                        + "pattern TEXT NOT NULL,"
379                                        + "pattern_pretty TEXT NOT NULL,"
380                                        + "axiom_type VARCHAR(15) NOT NULL,"
381                                        + "PRIMARY KEY(id),"
382                                        + "INDEX(pattern(1000))) DEFAULT CHARSET=utf8");
383
384                        statement.execute("CREATE TABLE IF NOT EXISTS Pattern_Pattern_Generalized ("
385                                        + "pattern_id MEDIUMINT NOT NULL,"
386                                        + "generalized_pattern_id MEDIUMINT NOT NULL,"
387                                        + "FOREIGN KEY (pattern_id) REFERENCES Pattern(id) ON DELETE CASCADE,"
388                                        + "FOREIGN KEY (generalized_pattern_id) REFERENCES Pattern_Generalized(id) ON DELETE CASCADE,"
389                                        + "PRIMARY KEY(pattern_id, generalized_pattern_id)) DEFAULT CHARSET=utf8");
390
391
392                } catch (SQLException e) {
393                        LOGGER.error("Failed to setup database tables.", e);
394                }
395        }
396
397        OWLAxiomGeneralizer generalizer = new OWLAxiomGeneralizer();
398
399        private void computeAndAddGeneralizedPatterns() {
400                // get all patterns from DB
401                String sql = "SELECT id, pattern FROM Pattern";
402                try(Statement stmt = conn.createStatement()) {
403                        try(ResultSet rs = stmt.executeQuery(sql)){
404                                while(rs.next()) {
405                                        int id = rs.getInt(1);
406                                        String patternStr = rs.getString(2);
407
408                                        // parse to OWLAxiom
409                                        OWLAxiom axiom = parse(patternStr);
410
411                                        // compute generalizations
412                                        System.out.println(axiom);
413                                        Set<OWLAxiom> generalizations = generalizer.generalize(axiom);
414
415                                        // add to DB
416                                        generalizations.forEach(gen -> {
417                                                // add generalized pattern if not exist and get ID
418                                                int genID = addGeneralizedPattern(gen);
419
420                                                // add mapping from pattern to generalized pattern
421                                                try {
422                                                        insertPatternToPatternGeneralizationPs.setInt(1, id);
423                                                        insertPatternToPatternGeneralizationPs.setInt(2, genID);
424                                                        insertPatternToPatternGeneralizationPs.addBatch();
425                                                } catch (SQLException e) {
426                                                        LOGGER.error("Failed to insert pattern to gen. pattern mapping.", e);
427                                                }
428                                        });
429                                        insertPatternToPatternGeneralizationPs.executeBatch();
430                                }
431                        } catch(SQLException e) {
432                                LOGGER.error("Failed to get patterns from DB.", e);
433                        }
434                } catch (SQLException e) {
435                        LOGGER.error("Failed to create statement.", e);
436                }
437
438        }
439
440        private OWLAxiom parse(String axiomStr) {
441                String ontologyStr = "Ontology (" + axiomStr + ")";
442                try {
443                        OWLOntology ont = manager
444                                        .loadOntologyFromOntologyDocument(new ByteArrayInputStream(ontologyStr.getBytes()));
445                        return ont.getLogicalAxioms().iterator().next();
446                } catch (OWLOntologyCreationException e) {
447                        LOGGER.error("Failed to parse axiom from " + axiomStr, e);
448                }
449                return null;
450        }
451
452        private int addGeneralizedPattern(OWLAxiom axiom){
453                String axiomString = render(axiom);
454
455                // check for existing entry
456                Integer patternID = getGeneralizedPatternID(axiom);
457                if(patternID != null) {
458                        return patternID;
459                }
460
461                // otherwise, add pattern entry
462                try {
463                        insertPatternGeneralizationPs.setString(1, axiomString);
464                        insertPatternGeneralizationPs.setString(2, axiomRenderer.render(axiom));
465                        insertPatternGeneralizationPs.setString(3, getAxiomType(axiom));
466                        insertPatternGeneralizationPs.execute();
467                } catch (SQLException e) {
468                        LOGGER.error("Failed to insert pattern. Maybe too long with a length of " + axiomString.length() + "?", e);
469                }
470
471                // get the pattern ID after insertion
472                return getGeneralizedPatternID(axiom);
473        }
474
475        private Integer getGeneralizedPatternID(OWLAxiom axiom) {
476                try {
477                        selectGeneralizedPatternIdPs.setString(1, render(axiom));
478                        try(ResultSet rs = selectGeneralizedPatternIdPs.executeQuery()){
479                                if(rs.next()){
480                                        return rs.getInt(1);
481                                }
482                        }
483                } catch (SQLException e) {
484                        LOGGER.error("Failed to get pattern ID.", e);
485                }
486                return null;
487        }
488        
489        
490        private int addPattern(OWLAxiom axiom){
491                String axiomString = render(axiom);
492
493                // check for existing entry
494                Integer patternID = getPatternID(axiom);
495                if(patternID != null) {
496                        return patternID;
497                }
498
499                // otherwise, add pattern entry
500                try {
501                        insertPatternIdPs.setString(1, axiomString);
502                        insertPatternIdPs.setString(2, axiomRenderer.render(axiom));
503                        insertPatternIdPs.setString(3, getAxiomType(axiom));
504                        insertPatternIdPs.execute();
505                } catch (SQLException e) {
506                        LOGGER.error("Failed to insert pattern. Maybe too long with a length of " + axiomString.length() + "?", e);
507                }
508
509                // get the pattern ID after insertion
510                return getPatternID(axiom);
511        }
512
513        private Integer getPatternID(OWLAxiom axiom) {
514                try {
515                        selectPatternIdPs.setString(1, render(axiom));
516                        try(ResultSet rs = selectPatternIdPs.executeQuery()) {
517                                if(rs.next()){
518                                        return rs.getInt(1);
519                                }
520                        }
521                } catch (SQLException e) {
522                        LOGGER.error("Failed to get pattern ID.", e);
523                }
524                return null;
525        }
526
527        private String getAxiomType(OWLAxiom axiom) {
528                AxiomType<?> type = axiom.getAxiomType();
529                String s;
530                if (AxiomType.TBoxAxiomTypes.contains(type)) {
531                        s = "TBox";
532                } else if (AxiomType.RBoxAxiomTypes.contains(type)) {
533                        s = "RBox";
534                } else if (AxiomType.ABoxAxiomTypes.contains(type)) {
535                        s = "ABox";
536                } else {
537                        System.out.println(axiom + "-" + type);
538                        //should not happen
539                        s = "Non-Logical";
540                }
541                return s;
542        }
543        
544        private synchronized boolean ontologyProcessed(URI uri){
545                //check if ontology was already processed
546                try {
547                        selectOntologyIdPs.setString(1, uri.toString());
548                        try(ResultSet rs = selectOntologyIdPs.executeQuery()) {
549                                return rs.next();
550                        }
551                } catch (SQLException e) {
552                        e.printStackTrace();
553                }
554                return false;
555        }
556        
557        private synchronized void addOntologyError(URI physicalURI, Exception ex){
558                String url = physicalURI.toString();
559                //add ontology loading/parsing/... error entry
560                try {
561                        insertOntologyErrorPs.setString(1, url);
562                        String errorMessage = "ERROR:" + ex.getClass().getSimpleName();
563                        if(!(ex instanceof UnparsableOntologyException)){
564                                errorMessage += (ex.getMessage() != null ? ("->" + ex.getMessage()) : "");
565                        }
566                        if(errorMessage.length() > 1900){
567                                errorMessage = errorMessage.substring(0, 1900);
568                        }
569                        insertOntologyErrorPs.setString(2, repository.getName());
570                        insertOntologyErrorPs.setString(3, errorMessage);
571                        insertOntologyErrorPs.execute();
572                } catch (SQLException e) {
573                        LOGGER.error("Failed to insert ontology error statement.", e);
574                }
575        }
576        
577        private synchronized int addOntology(URI physicalURI, OWLOntology ontology, Imports imports){
578                String url = physicalURI.toString();
579                String ontologyIRI = "Anonymous";
580                if(!ontology.getOntologyID().isAnonymous()){
581                        ontologyIRI = ontology.getOntologyID().getOntologyIRI().get().toString();
582                }
583                // check for existing entry
584                Integer ontologyID = getOntologyID(physicalURI, ontology);
585                if(ontologyID != null) {
586                        return ontologyID;
587                }
588
589                // add ontology entry
590                try {
591                        insertOntologyPs.setString(1, url);
592                        insertOntologyPs.setString(2, ontologyIRI);
593                        insertOntologyPs.setString(3, repository.getName());
594                        Set<OWLAxiom> tbox = ontology.getTBoxAxioms(imports);
595                        Set<OWLAxiom> rbox = ontology.getRBoxAxioms(imports);
596                        Set<OWLAxiom> abox = ontology.getABoxAxioms(imports);
597                        
598                        insertOntologyPs.setInt(4, tbox.size() + rbox.size() + abox.size());
599                        insertOntologyPs.setInt(5, tbox.size());
600                        insertOntologyPs.setInt(6, rbox.size());
601                        insertOntologyPs.setInt(7, abox.size());
602                        insertOntologyPs.setInt(8, ontology.getClassesInSignature(Imports.INCLUDED).size());
603                        insertOntologyPs.setInt(9, ontology.getObjectPropertiesInSignature(Imports.INCLUDED).size());
604                        insertOntologyPs.setInt(10, ontology.getDataPropertiesInSignature(Imports.INCLUDED).size());
605                        insertOntologyPs.setInt(11, ontology.getIndividualsInSignature(Imports.INCLUDED).size());
606                        insertOntologyPs.execute();
607                } catch (SQLException e) {
608                        LOGGER.error("Failed to insert ontology.", e);
609                }
610
611                // get and return the auto generated ID
612                return getOntologyID(physicalURI, ontology);
613        }
614
615        private synchronized void addOntologyImport(URI physicalURI1, OWLOntology ontology1, URI physicalURI2, OWLOntology ontology2){
616                // get ID of first ontology
617                Integer ontologyID1 = getOntologyID(physicalURI1, ontology1);
618
619                // get ID of second ontology
620                Integer ontologyID2 = getOntologyID(physicalURI2, ontology2);
621
622                // add ontology entry
623                try {
624                        insertOntologyImportPs.setInt(1, ontologyID1);
625                        insertOntologyImportPs.setInt(2, ontologyID2);
626
627                        insertOntologyImportPs.execute();
628                } catch (SQLException e) {
629                        LOGGER.error("Failed to insert ontology.", e);
630                }
631        }
632
633        private Integer getOntologyID(OWLOntology ontology) {
634                String ontologyIRI = "Anonymous";
635                if(!ontology.getOntologyID().isAnonymous()){
636                        ontologyIRI = ontology.getOntologyID().getOntologyIRI().toString();
637                }
638                //check for existing entry
639                try {
640                        selectOntologyIdPs.setString(1, ontologyIRI);
641                        try(ResultSet rs = selectOntologyIdPs.executeQuery()) {
642                                if(rs.next()){
643                                        return rs.getInt(1);
644                                }
645                        }
646                } catch (SQLException e) {
647                        LOGGER.error("Failed to get ontology ID.", e);
648                }
649                return null;
650        }
651
652        private Integer getOntologyID(URI physicalURI, OWLOntology ontology) {
653                String url = physicalURI.toString();
654                String ontologyIRI = "Anonymous";
655                if(!ontology.getOntologyID().isAnonymous()){
656                        ontologyIRI = ontology.getOntologyID().getOntologyIRI().toString();
657                }
658                //check for existing entry
659                try {
660                        selectOntologyIdPs.setString(1, url);
661                        try(ResultSet rs = selectOntologyIdPs.executeQuery()) {
662                                if(rs.next()){
663                                        return rs.getInt(1);
664                                }
665                        }
666                } catch (SQLException e) {
667                        LOGGER.error("Failed to get ontology ID.", e);
668                }
669                return null;
670        }
671        
672        private synchronized void addOntologyPatterns(URI physicalURI, OWLOntology ontology, Multiset<OWLAxiom> patterns){
673                int ontologyId = getOntologyID(physicalURI, ontology);
674                for (OWLAxiom pattern : patterns.elementSet()) {
675                        try {
676                                int patternId = addPattern(pattern);
677                                int occurrences = patterns.count(pattern);
678                                insertOntologyPatternPs.setInt(1, ontologyId);
679                                insertOntologyPatternPs.setInt(2, patternId);
680                                insertOntologyPatternPs.setInt(3, occurrences);
681                                insertOntologyPatternPs.addBatch();
682                        } catch (SQLException e) {
683                                LOGGER.error("Failed to insert pattern\n" + pattern + "\"", e);
684                        }
685                }
686                try {
687                        insertOntologyPatternPs.executeBatch();
688                } catch (BatchUpdateException e) {
689                        LOGGER.error("Failed to insert some pattern. Reason: {}", e.getMessage());
690                } catch (SQLException e) {
691                        LOGGER.error("Failed to insert patterns.", e);
692                }
693        }
694
695        public static void main(String[] args) throws Exception {
696//              ManchesterOWLSyntaxOWLObjectRendererImplExt renderer = new ManchesterOWLSyntaxOWLObjectRendererImplExt(
697//                              true, true);
698//              ToStringRenderer.getInstance().setRenderer(renderer);
699                // create Options object
700                OptionParser parser = new OptionParser();
701
702                OptionSpec<File> dir =
703                                parser.accepts( "dir" ).withRequiredArg().ofType( File.class ).required();
704
705                OptionSpec<Long> maxFileSize =
706                                parser.accepts( "maxFileSize" ).withRequiredArg().ofType(Long.class).defaultsTo(Long.MAX_VALUE);
707
708                OptionSpec<Boolean> multiThreadedEnabledOpt =
709                                parser.accepts( "multiThreadedEnabled" ).withOptionalArg().ofType(Boolean.class).defaultsTo(false);
710
711                OptionSpec<Integer> numThreadsOpt =
712                                parser.accepts( "numThreads" ).availableIf(multiThreadedEnabledOpt).withRequiredArg().ofType(Integer.class).defaultsTo(4);
713
714                parser.printHelpOn( System.out );
715
716                OptionSet options = parser.parse(args);
717
718                boolean multiThreadedEnabled = options.has(multiThreadedEnabledOpt) &&
719                                (!options.hasArgument(multiThreadedEnabledOpt) || options.valueOf(multiThreadedEnabledOpt));
720                int numThreads = options.valueOf(numThreadsOpt);
721
722                OntologyRepository repository = new LocalDirectoryOntologyRepository(options.valueOf(dir), options.valueOf(maxFileSize));
723                repository.initialize();
724
725                OWLAxiomPatternFinder patternFinder = new OWLAxiomPatternFinder(repository);
726                patternFinder.setMultithreadedEnabled(multiThreadedEnabled);
727                patternFinder.setNumThreads(numThreads);
728                patternFinder.start();
729                
730//              String ontologyURL = "ontologyURL";
731//              OWLOntologyManager man = OWLManager.createOWLOntologyManager();
732//              OWLDataFactory dataFactory = man.getOWLDataFactory();
733//              OWLFunctionalDataPropertyAxiom axiom = dataFactory.getOWLFunctionalDataPropertyAxiom(dataFactory.getOWLDataProperty(IRI.create("http://ex.org/p")));
734//              OWLOntology ontology = man.createOntology();
735//              man.addAxiom(ontology, axiom);
736//              StringWriter sw = new StringWriter();
737//              FunctionalSyntaxObjectRenderer r = new FunctionalSyntaxObjectRenderer(ontology, sw);
738//              axiom.accept(r);
739//              System.out.println(sw.toString());
740//              StringDocumentSource s = new StringDocumentSource("Ontology(<http://www.pattern.org>" + sw.toString() + ")");
741//              OWLFunctionalSyntaxOWLParser p = new OWLFunctionalSyntaxOWLParser();
742//              OWLOntology newOntology = man.createOntology();
743//              p.parse(s, newOntology, new OWLOntologyLoaderConfiguration());
744//              System.out.println(newOntology.getLogicalAxioms());
745
746        }
747}