1

I am building a JavaFX application in Spring Boot with hibernate. It connects to the database to display some data, currently it takes the connection details from properties file and loads sessionFactory, datasource and transaction manager beans using pure Java config. However, I have multiple databases sitting on multiple remote machines, each has a different IP and user details. Ideally I would like to display a login form which prompts for db username and password on the application startup. I do not want to read those details from the file. It possible? I would really appreciate some help with this issue.

Edit: Managed to achieve this, in my login controller I simply implement ApplicationContextAware and then load register beans manually using data from textfields.

2
  • Possible duplicate: hibernate - how to change properties at runtime. This google query will return other similar answers. Commented Jan 8, 2020 at 18:31
  • I want to configure hibernate at runtime, it's totally different than only changing it's properties. Commented Jan 10, 2020 at 11:20

2 Answers 2

1

You can use a Spring Boot Active Profile features

Depending on your current profile PROD, DEV, PRE-PROD you can active a certain configration with a given application.properties file. You can find here a complete How to

EDIT 2 :

If you want to change the whole configuration base on user input (for example it's credentials) you have to change dynamically properties and it appears that @RefreshScope does the work.

Bad news is that this annotation aappears to only exists in Spring Cloud

Sign up to request clarification or add additional context in comments.

5 Comments

But in my case environment(I just have different machines with same db which I want to be able to access) will be determined at runtime, spring app is started and beans are initialized. I don't want to store any details in the file, I want to open a login window after app is started and then ask user for credentials. Based on these credentials I want to connect to the db therefore initialize sessionFactory, datasource and transactionManager. I also want these object to work with autowired in my dao.
I do not want to change configuration, I want to create this configuration based on user input and then make it visible for dao that uses autowiring.
As far as i know it is impossible unless your are working with spring cloud and using @RefreshScope. See my EDIT 2.
Managed to achieve this without spring cloud see edit
Sounds. Good. I'm eager how you managed to do that in details with code. Maybe better if you post your own answer
0

That is my solution, the only drawback is that I am not able to log in after unsuccessful login attempt. It works fine but if I first use incorrect login credentials and then correct ones it throws an exception saying that EntityManagerFactory is closed. (I do remove bean definitions in my catch block, just wanted to make code shorter)

@Component
public class LoginController implements Initializable, ApplicationContextAware{

    @FXML
    private AnchorPane login;
    @FXML
    private JFXTextField dbUsernameTextField;
    @FXML
    private JFXPasswordField dbPasswordTextField;
    @FXML
    private JFXTextField boxUsernameTextField;
    @FXML
    private JFXPasswordField boxPasswordTextField;
    @FXML
    private JFXComboBox<ComboItem> environmentComboBox;
    @FXML
    private JFXButton loginButton;
    @Autowired 
    private Environment environment;

    @Autowired
    private OrderService orderService;

    private AnnotationConfigApplicationContext context;
    @Override
    public void initialize(URL location, ResourceBundle resources) {
        loginButton.setDisable(true);
        List<ComboItem> envs=new ArrayList<ComboItem>();
        String[]environments=environment.getProperty("environments").split(",");
        for(String s:environments) {
            environmentComboBox.getItems().add(new ComboItem(s.toUpperCase(),s));
        }
        environmentComboBox.setConverter(new StringConverter<ComboItem>() {
            @Override
            public String toString(ComboItem object) {
                return object.getKey();
            }
            @Override
            public ComboItem fromString(String string) {
                return null;
            }
        });
    }

    @FXML
    public void selectEnvironment() {
        if(!environmentComboBox.getSelectionModel().isEmpty())
            loginButton.setDisable(false);
    }

    @FXML
    public void authenticate(ActionEvent actionEvent) {

        String boxUsername=boxUsernameTextField.getText();
        String boxPassword=boxPasswordTextField.getText();
        try {
            context.registerBean("dataSource",DataSource.class,()->dataSource());
            context.registerBean("sessionFactory", LocalSessionFactoryBean.class,()->sessionFactory());     
            context.registerBean("transactionManager",HibernateTransactionManager.class,()->getTransactionManager());

            Order order=orderService.findById("");

            FXMLLoader fxmlLoader=new FXMLLoader(getClass().getResource("/fxml/Main.fxml"));
            fxmlLoader.setControllerFactory(context::getBean);
            Parent rootNode=fxmlLoader.load();
            Stage stage=(Stage) login.getScene().getWindow();
            Scene scene=new Scene(rootNode,400,300);
            stage.setScene(scene);
            stage.setTitle("Login");
            stage.setMaximized(true);
            stage.show();
            stage.setOnCloseRequest(event->JSchConnection.close());
        }catch(Exception e) {
        context.removeBeanDefinition("dataSource");
        context.removeBeanDefinition("sessionFactory");
        context.removeBeanDefinition("transactionManager");

            e.printStackTrace();
        }

    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context=(AnnotationConfigApplicationContext) applicationContext;       
    }

    private  Properties hibernateProperties() {
        Properties properties = new Properties();
        properties.put("hibernate.dialect", "org.hibernate.dialect.Oracle10gDialect");
        properties.put("hibernate.show_sql", "false");
        properties.put("hibernate.format_sql", "true");
        properties.put("hibernate.hbm2ddl.auto", "none");
        return properties;
    }

    public  DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("oracle.jdbc.OracleDriver");
        dataSource.setUrl("myurl");
        dataSource.setUsername(dbUsernameTextField.getText());
        dataSource.setPassword(dbPasswordTextField.getText());
        return dataSource;
    }

    public  LocalSessionFactoryBean sessionFactory() {
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        sessionFactory.setPackagesToScan(new String[] { "com.mypackage" });
        sessionFactory.setHibernateProperties(hibernateProperties());
        return sessionFactory;
    }

    public HibernateTransactionManager getTransactionManager() {
        HibernateTransactionManager transactionManager = new HibernateTransactionManager();
        transactionManager.setSessionFactory(context.getBean(SessionFactory.class,"sessionFactory"));
        return transactionManager;
    }

}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.