# MyDBConnectionInfo.java

    /*
     * Copyright (C) 2000 - 2024 Silverpeas
     *
     * This program is free software: you can redistribute it and/or modify it under the terms of the
     * GNU Affero General Public License as published by the Free Software Foundation, either version 3
     * of the License, or (at your option) any later version.
     *
     * As a special exception to the terms and conditions of version 3.0 of the GPL, you may
     * redistribute this Program in connection with Free/Libre Open Source Software ("FLOSS")
     * applications as described in Silverpeas's FLOSS exception. You should have received a copy of the
     * text describing the FLOSS exception, and it is also available here:
     * "http://www.silverpeas.org/docs/core/legal/floss_exception.html"
     *
     * This program 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
     * Affero General Public License for more details.
     *
     * You should have received a copy of the GNU Affero General Public License along with this program.
     * If not, see <https://www.gnu.org/licenses/>.
     */

    package org.silverpeas.components.mydb.model;

    import org.silverpeas.components.mydb.service.MyDBConnectionInfoService;
    import org.silverpeas.components.mydb.service.MyDBException;
    import org.silverpeas.core.persistence.datasource.model.identifier.UniqueIntegerIdentifier;
    import org.silverpeas.core.persistence.datasource.model.jpa.BasicJpaEntity;
    import org.silverpeas.kernel.util.StringUtil;

    import javax.naming.InitialContext;
    import javax.naming.NamingException;
    import jakarta.persistence.Column;
    import jakarta.persistence.Entity;
    import jakarta.persistence.NamedQuery;
    import jakarta.persistence.Table;
    import javax.sql.DataSource;
    import jakarta.validation.constraints.NotNull;
    import java.sql.Connection;
    import java.sql.SQLException;
    import java.util.List;

    /**
     * Information about a connexion to a data source. Such information is the name of the
     * data source and the credentials required to access that data source.
     * @author mmoquillon
     */
    @Entity
    @NamedQuery(name = "MyDBConnectionInfo.findByInstanceId",
        query = "select ds from MyDBConnectionInfo ds where ds.instanceId = :instanceId")
    @NamedQuery(name = "MyDBConnectionInfo.deleteByInstanceId",
        query = "delete from MyDBConnectionInfo d where d.instanceId = :instanceId")
    @Table(name = "sc_mydb_connectinfo")
    public class MyDBConnectionInfo
        extends BasicJpaEntity<MyDBConnectionInfo, UniqueIntegerIdentifier> {

      @Column(length = 250, nullable = false)
      @NotNull
      private String dataSource;
      @Column(length = 250)
      private String login;
      @Column(length = 250)
      private String password;
      @Column(length = 100)
      private String tableName;
      private int rowLimit = 0;
      @Column(length = 50, nullable = false)
      @NotNull
      private String instanceId;

      public static List<MyDBConnectionInfo> getFromComponentInstance(String instanceId) {
        return MyDBConnectionInfoService.get().getConnectionInfoList(instanceId);
      }

      public static void removeFromComponentInstance(String instanceId) {
        MyDBConnectionInfoService.get().removeConnectionInfoOfComponentInstance(instanceId);
      }

      protected MyDBConnectionInfo() {
      }

      public MyDBConnectionInfo(String dataSource, String instanceId) {
        this.dataSource = dataSource;
        this.instanceId = instanceId;
      }

      /**
       * Is this connection information defined? Information about a connection to a data source is
       * defined if both it is related to a myDB application instance and the name of the
       * data source is defined.
       * @return true if the connection is defined. False otherwise.
       */
      public boolean isDefined() {
        return StringUtil.isDefined(this.dataSource) && StringUtil.isDefined(this.instanceId);
      }

      /**
       * Sets the default table to defaultTable from the database with this connection information
       * and returns the latter.
       * @param tableName the name of the table to load by default.
       * @return itself.
       */
      public MyDBConnectionInfo withDefaultTableName(String tableName) {
        setDefaultTableName(tableName.toLowerCase());
        return this;
      }

      public MyDBConnectionInfo withoutAnyDefaultTable() {
        setDefaultTableName(null);
        return this;
      }

      /**
       * Sets the maximum number of data to select when requesting the data source and returns this
       * connection information.
       * @param maxNumber the maximum number of data to return. 0 means all.
       * @return itself.
       */
      public MyDBConnectionInfo withDataMaxNumber(int maxNumber) {
        setDataMaxNumber(maxNumber);
        return this;
      }

      public MyDBConnectionInfo withLoginAndPassword(String login, String password) {
        setLoginAndPassword(login, password);
        return this;
      }

      /**
       * Sets a new data source by its JNDI name to this connection info.
       * @param dataSourceName the JNDI name of the data source to connect to.
       * @return itself.
       */
      public MyDBConnectionInfo withDataSourceName(String dataSourceName) {
        setDataSourceName(dataSourceName);
        return this;
      }

      /**
       * Gets the JNDI name of the data source targeted by this connection information.
       * @return the JNDI name of the data source.
       */
      public String getDataSourceName() {
        return dataSource;
      }

      /**
       * Gets the user identifier used in the data source authentication.
       * @return the login.
       */
      public String getLogin() {
        return (login == null ? "" : login);
      }

      /**
       * Gets the password associated with the login to connect the data source.
       * @return the password.
       */
      public String getPassword() {
        return (password == null ? "" : password);
      }

      /**
       * Gets the name of the table to load with this connexion information.
       * @return the name of the default table.
       */
      public String getDefaultTableName() {
        return tableName;
      }

      /**
       * Gets the maximum number of data to return when requesting the data source.
       * @return the maximum number of data to consider. 0 means all.
       */
      public int getDataMaxNumber() {
        return rowLimit;
      }

      /**
       * Is the name of the default table to load is defined?
       * @return true if the name of a default table is set, false otherwise.
       */
      public boolean isDefaultTableNameDefined() {
        return StringUtil.isDefined(tableName);
      }

      /**
       * Sets a new data source by its JNDI name to this connection info.
       * @param dataSourceName the JNDI name of the data source to connect to.
       */
      public void setDataSourceName(String dataSourceName) {
        this.dataSource = dataSourceName;
      }

      /**
       * Sets the login and the password required to open a connection to the targeted data source.
       * @param login a login.
       * @param password the password associated with the login.
       */
      public void setLoginAndPassword(String login, String password) {
        this.login = login;
        this.password = password;
      }

      /**
       * Sets the name of the default table to load with this connection information.
       * @param tableName the name of a table in the database.
       */
      public void setDefaultTableName(String tableName) {
        this.tableName = tableName;
      }

      /**
       * Sets the maximum number of data to select when requesting the data source.
       * @param maxNumber the maximum number of data to return. 0 means all.
       */
      public void setDataMaxNumber(int maxNumber) {
        this.rowLimit = Math.max(maxNumber, 0);
      }

      /**
       * Saves or updates this connection information into the persistence context in order to be able
       * to retrieve it later.
       */
      public void save() {
        MyDBConnectionInfoService.get().saveConnectionInfo(this);
      }

      /**
       * Opens a connection to the data source targeted by this connection information.
       * @return a connection against the data source referred by this object.
       */
      public Connection openConnection() throws MyDBException {
        try {
          DataSource ds = InitialContext.doLookup(getDataSourceName());
          return ds.getConnection(getLogin(), getPassword());
        } catch (NamingException | SQLException ex) {
          throw new MyDBException(ex.getMessage());
        }
      }

      @Override
      public boolean equals(final Object o) {
        return super.equals(o);
      }

      @Override
      public int hashCode() {
        return super.hashCode();
      }

      /**
       * Checks the connection with the remote data source referred in this
       * {@link MyDBConnectionInfo} instance.
       * <p>
       * If the connection cannot be established with the data source, a
       * {@link org.silverpeas.components.mydb.service.MyDBException}
       * exception is thrown. This occurs when:
       * </p>
       * <ul>
       * <li>no connection information is set for the underlying component instance,</li>
       * <li>the connection information isn't correct,</li>
       * <li>the connection information is correct but the connection with the data source fails at
       * this time.</li>
       * </ul>
       * @throws MyDBException if the connection cannot be established with the data source
       * referred by this {@link MyDBConnectionInfo} instance.
       */
      public void checkConnection() throws MyDBException {
        try (Connection connection = openConnection()) {
          if (!connection.isValid(0)) {
            throw new MyDBException("No valid connexion with the data source " + getDataSourceName());
          }
        } catch (SQLException e) {
          throw new MyDBException(e);
        }
      }
    }