/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2013, Geomatys
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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.
*/
package org.geotoolkit.index.tree.manager;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.NoSuchAlgorithmException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import javax.sql.DataSource;
import org.geotoolkit.index.tree.StoreIndexException;
import org.geotoolkit.index.tree.Tree;
import org.geotoolkit.index.tree.TreeElementMapper;
import org.geotoolkit.index.tree.manager.postgres.LucenePostgresSQLTreeEltMapper;
import org.geotoolkit.index.tree.manager.postgres.PGDataSource;
import org.geotoolkit.index.tree.manager.postgres.PGTreeWrapper;
import org.geotoolkit.index.tree.star.FileStarRTree;
import org.geotoolkit.internal.sql.DefaultDataSource;
import org.geotoolkit.internal.tree.TreeAccessSQLByteArray;
/**
*
* @author Guilhem Legal (Geomatys)
*/
public class SQLRtreeManager extends AbstractRtreeManager {
public final static String JDBC_TYPE_KEY = "org.geotoolkit.index.tree.manager.SQLRtreeManager.type";
public static synchronized Tree<NamedEnvelope> get(final Path directory, final Object owner) {
Tree<NamedEnvelope> tree = CACHED_TREES.get(directory);
if (tree == null || tree.isClosed()) {
if (existTree(directory)) {
if (System.getProperty(JDBC_TYPE_KEY)!= null){
// postgres
if (System.getProperty(JDBC_TYPE_KEY).equals("postgres")) {
try {
DataSource ds = PGDataSource.getDataSource();
TreeElementMapper treeMapper = new LucenePostgresSQLTreeEltMapper(DEFAULT_CRS, ds, directory);
byte[] data = TreeAccessSQLByteArray.getData(directory, ds);
tree = new PGTreeWrapper(data, directory, ds, treeMapper);
} catch ( SQLException | StoreIndexException | IOException | ClassNotFoundException | NoSuchAlgorithmException e) {
LOGGER.log(Level.SEVERE, null, e);
return null;
}
// other DB not yet implemented
} else {
throw new IllegalArgumentException("Unexpected JDBC type: " + JDBC_TYPE_KEY);
}
} else {
// derby DB as default
try {
final Path treeFile = directory.resolve("tree.bin");
DataSource ds = LuceneDerbySQLTreeEltMapper.getDataSource(directory);
TreeElementMapper treeMapper = new LuceneDerbySQLTreeEltMapper(DEFAULT_CRS, ds);
tree = new FileStarRTree<>(treeFile.toFile().toPath(), treeMapper);
} catch (ClassNotFoundException | IllegalArgumentException | StoreIndexException | IOException e) {
LOGGER.log(Level.SEVERE, null, e);
return null;
}
}
} else {
tree = buildNewTree(directory);
}
final List<Object> owners = new ArrayList<>();
owners.add(owner);
TREE_OWNERS.put(directory, owners);
CACHED_TREES.put(directory, tree);
} else {
//look if the owner is already registered
final List<Object> owners = TREE_OWNERS.get(directory);
if (!owners.contains(owner)) {
owners.add(owner);
}
}
return tree;
}
private static Tree buildNewTree(final Path directory) {
if (Files.exists(directory)) {
try {
//creating tree (R-Tree)------------------------------------------------
final Path treeFile = directory.resolve("tree.bin");
Files.createFile(treeFile);
// postgres
if ("postgres".equals(System.getProperty(JDBC_TYPE_KEY))) {
TreeElementMapper treeMapper = LucenePostgresSQLTreeEltMapper.createTreeEltMapperWithDB(directory);
return new PGTreeWrapper(directory, PGDataSource.getDataSource(), treeMapper, DEFAULT_CRS);
} else {
TreeElementMapper treeMapper = LuceneDerbySQLTreeEltMapper.createTreeEltMapperWithDB(directory);
return new FileStarRTree(treeFile.toFile().toPath(), 5, DEFAULT_CRS, treeMapper);
}
} catch (IOException ex) {
LOGGER.log(Level.WARNING, "Unable to create file to write Tree", ex);
} catch (SQLException ex) {
LOGGER.log(Level.WARNING, "Exception while creating treemap database", ex);
} catch (org.geotoolkit.index.tree.StoreIndexException ex) {
LOGGER.log(Level.WARNING, "Unable to create Tree", ex);
}
}
return null;
}
public static Tree resetTree(final Path directory, final Tree tree, final Object owner) throws StoreIndexException, IOException, SQLException {
if (tree != null) {
tree.flush();
tree.clear();
}
if ("postgres".equals(System.getProperty(JDBC_TYPE_KEY))) {
LucenePostgresSQLTreeEltMapper.resetDB(directory);
} else {
final Path mapperDir = directory.resolve("treemap-db");
if (Files.exists(mapperDir)) {
tree.getTreeElementMapper().clear();
}
}
return tree;
}
private static boolean existTree(final Path directory) {
if (System.getProperty(JDBC_TYPE_KEY) != null) {
// postgres
if (System.getProperty(JDBC_TYPE_KEY).equals("postgres")) {
DataSource ds = PGDataSource.getDataSource();
return LucenePostgresSQLTreeEltMapper.treeExist(ds, directory);
// other DB not yet implemented
} else {
throw new IllegalArgumentException("Unexpected JDBC type: " + JDBC_TYPE_KEY);
}
} else {
// derby DB as default
final Path treeFile = directory.resolve("tree.bin");
return Files.exists(treeFile);
}
}
}