Java tutorial
/* * Copyright 2014 Lukas Benda <lbenda at lbenda.cz>. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package cz.lbenda.dataman.db; import java.io.*; import java.net.URL; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; import cz.lbenda.dataman.UserImpl; import cz.lbenda.dataman.db.dialect.SQLDialect; import cz.lbenda.dataman.rc.DbConfigFactory; import cz.lbenda.dataman.schema.dataman.*; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.concurrent.Task; import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.Nonnull; import javax.xml.bind.*; /** Object of this class define configuration of one database */ public class DbConfig { private static final Logger LOG = LoggerFactory.getLogger(DbConfig.class); private String id; public final String getId() { if (id == null) { id = "<new id>"; } return id; } private JDBCConfiguration jdbcConfiguration; public final JDBCConfiguration getJdbcConfiguration() { if (jdbcConfiguration == null) { this.jdbcConfiguration = new JDBCConfiguration(); } return jdbcConfiguration; } public final void setJdbcConfiguration(final JDBCConfiguration jdbcConfiguration) { this.jdbcConfiguration = jdbcConfiguration; } /** List with path to file with libraries for JDBC driver load */ private final List<String> librariesPaths = new ArrayList<>(); public final List<String> getLibrariesPaths() { return librariesPaths; } /** Showed schemas */ private final ObservableList<CatalogDesc> catalogs = FXCollections.observableArrayList(); public final ObservableList<CatalogDesc> getCatalogs() { return catalogs; } /** Return catalog by name */ public final CatalogDesc getCatalog(@Nonnull String name) { synchronized (catalogs) { List<CatalogDesc> cats = catalogs.stream().filter(catalogDesc -> name.equals(catalogDesc.getName())) .collect(Collectors.toList()); return cats.size() == 0 ? null : cats.get(0); } } /** SQLDialect for this db configuration */ public final SQLDialect getDialect() { return getJdbcConfiguration().getDialect(); } /** Connection provider */ public ConnectionProvider connectionProvider = new ConnectionProvider(this); /** Connection provider */ public @Nonnull ConnectionProvider getConnectionProvider() { return connectionProvider; } /** Object which can modify database row */ private final DbRowManipulator dbRowManipulator = new DbRowManipulator(connectionProvider); /** Manipulator of DB */ public final @Nonnull DbRowManipulator getDbRowManipulator() { return dbRowManipulator; } /** Instance of DB reader for this session */ private DbStructureFactory reader = new DbStructureFactory(this); public final @Nonnull DbStructureFactory getReader() { return reader; } final void setReader(@Nonnull DbStructureFactory reader) { this.reader = reader; } /** Timeout when unused connection will be closed */ private int connectionTimeout; /** Timeout when unused connection will be closed */ public int getConnectionTimeout() { return connectionTimeout; } /** Timeout when unused connection will be closed */ public void setConnectionTimeout(int connectionTimeout) { this.connectionTimeout = connectionTimeout; } private ExtConfFactory extConfFactory = new ExtConfFactory(this); public ExtConfFactory getExtConfFactory() { return extConfFactory; } /** Store to session type * @param srcExConfig path to ex configuration if is null then is insert directly to session configuration * @param srcDbStructure path to db structure configuration if is null, then is insert to session configuration * @return session type */ public final SessionType storeToSessionType(String srcExConfig, String srcDbStructure) { cz.lbenda.dataman.schema.dataman.ObjectFactory of = new cz.lbenda.dataman.schema.dataman.ObjectFactory(); SessionType result = of.createSessionType(); result.setId(getId()); if (this.connectionTimeout > 0) { result.setConnectionTimeout(this.connectionTimeout); } if (jdbcConfiguration != null) { result.setJdbc(jdbcConfiguration.storeToJdbcType()); } result.setLibraries(of.createLibrariesType()); result.getLibraries().getLibrary().addAll(getLibrariesPaths()); result.setExtendedConfig(this.extConfFactory.create()); if (srcDbStructure == null) { result.setStructure(DbStructureFactory.createXMLDatabaseStructure(getCatalogs())); } else { result.setStructure(DbStructureFactory.createXMLDatabaseStructureImport(srcDbStructure)); } return result; } private void loadJdbcConfiguration(JdbcType jdbcType) { jdbcConfiguration = new JDBCConfiguration(); jdbcConfiguration.load(jdbcType); this.getConnectionProvider().setUser(new UserImpl(jdbcConfiguration.getUsername())); } public void fromSessionType(final SessionType session, boolean readId) { if (readId) { setId(session.getId()); } if (session.getConnectionTimeout() != null) { this.connectionTimeout = session.getConnectionTimeout(); } else { connectionTimeout = -1; } loadJdbcConfiguration(session.getJdbc()); this.librariesPaths.clear(); if (session.getLibraries() != null) { session.getLibraries().getLibrary().forEach(this.librariesPaths::add); } DbStructureFactory.loadDatabaseStructureFromXML(session.getStructure(), this); extConfFactory.setExConf(session.getExtendedConfig()); if (connectionProvider.isConnected()) { extConfFactory.load(); } } public final void setId(final String id) { if (id == null) { throw new NullPointerException("The ID of configuration can't be null"); } if ("".equals(id.trim())) { throw new AssertionError("The identifier of configuration can't be blank or empty string."); } if (!id.equals(getId())) { if (DbConfigFactory.getConfigurationIDs().contains(id)) { throw new AssertionError(String.format("The ID '%s' of session is already used.", id)); } this.id = id; } } public void reloadStructure() { reader.generateStructure(); // this.extConfFactory.load(); // FIXME DbConfigFactory.saveConfiguration(); if (connectionProvider.isConnected()) { extConfFactory.load(); } } /** Close connection to database */ @SuppressWarnings("unused") public void close() { try { if (connectionProvider.getConnection() != null && !connectionProvider.getConnection().isClosed()) { ((DatamanConnection) connectionProvider.getConnection()).realyClose(); } } catch (SQLException e) { LOG.warn("The connection can't be closed."); } } /** Save session conf into File * @param writer writer to which is configuration saved */ public void save(Writer writer) throws IOException { cz.lbenda.dataman.schema.dataman.ObjectFactory of = new cz.lbenda.dataman.schema.dataman.ObjectFactory(); SessionType st = storeToSessionType(null, null); try { JAXBContext jc = JAXBContext.newInstance(cz.lbenda.dataman.schema.dataman.ObjectFactory.class); Marshaller m = jc.createMarshaller(); m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); m.marshal(of.createSession(st), writer); } catch (JAXBException e) { LOG.error("Problem with write configuration: " + e.toString(), e); throw new RuntimeException("Problem with write configuration: " + e.toString(), e); } } /** Save session conf into File * @param file file to which is configuration saved */ public void save(File file) { if (StringUtils.isBlank(FilenameUtils.getExtension(file.getAbsolutePath()))) { file = new File(file.getAbsoluteFile() + ".dtm"); } // Append .dtm extension to file which haven't any extension try (FileWriter fw = new FileWriter(file)) { save(fw); } catch (IOException e) { LOG.error("The file is un-writable: " + e.toString(), e); throw new RuntimeException("The file is un-writable: " + e.toString(), e); } } /** Load configuration from given resource which is defined by URL */ @SuppressWarnings("unused") public void load(URL resource) { try (InputStream is = resource.openStream()) { load(is); } catch (IOException e) { LOG.error("Problem with read configuration from XML: " + e.toString(), e); throw new RuntimeException("Problem with read configuration from XML: " + e.toString(), e); } } /** Load configuration from given resource from input stream */ @SuppressWarnings("unchecked") public void load(InputStream inputStream) { load(new InputStreamReader(inputStream), true); } /** Load configuration from given resource from input stream * @param reader reader from which is read configuration * @param readId flag which inform if newId will be reader from reader or is ignored */ public void load(@Nonnull Reader reader, boolean readId) { try { JAXBContext jc = JAXBContext.newInstance(cz.lbenda.dataman.schema.dataman.ObjectFactory.class); Unmarshaller u = jc.createUnmarshaller(); //noinspection unchecked JAXBElement<SessionType> element = (JAXBElement<SessionType>) u.unmarshal(reader); //noinspection ConstantConditions if (element.getValue() instanceof SessionType) { fromSessionType(element.getValue(), readId); } else { LOG.error("The file doesn't contains single session config"); throw new RuntimeException("The file doesn't contains single session config"); } } catch (JAXBException e) { LOG.error("Problem with read configuration from XML: " + e.toString(), e); throw new RuntimeException("Problem with read configuration from XML: " + e.toString(), e); } } /** Load session conf from File */ public void load(File file) { try (FileReader fis = new FileReader(file)) { load(fis, true); } catch (IOException e) { LOG.error("File is unreadable: " + e.toString(), e); throw new RuntimeException("The file is unreadable: " + e.toString(), e); } } @Override public String toString() { return id; } /** Copy configuration of db config. It's not a clone, the connection and loaded data isn't copied. * @return copied object */ public DbConfig copy() { try { StringWriter writer = new StringWriter(); this.save(writer); DbConfig dbConfig = new DbConfig(); StringReader reader = new StringReader(writer.toString()); dbConfig.load(reader, false); return dbConfig; } catch (IOException e) { LOG.error("Problem with create copied version of db config", e); throw new RuntimeException("Problem with create copied version of db config", e); } } public static class Reload extends Task<Void> { private DbConfig dbConfig; public Reload(DbConfig dbConfig) { this.dbConfig = dbConfig; } @Override protected Void call() throws Exception { dbConfig.reloadStructure(); return null; } } }