2012-09-27 3 views
2

Я пишу приложение для рабочего стола для среды без сетевого подключения. Я пытаюсь хранить данные приложения так же надежно, как я могу, в зашифрованном in-process hsqldb, с незашифрованной информацией пользователя hsqldb. Hsqldb требует, чтобы crypto_key устанавливался в jdbcurl при создании соединения. Мое приложение использует hibernate для сохранения, а Spring - для настройки и вставки.Изменение SessionFactory datasource jdbcurl в конце выполнения

Моя нынешняя схема - хранить имя пользователя, пароль хэша, соль и зашифрованную базу данных crypto_key в незашифрованной пользовательской таблице. Crypto_key защищен асимметричным шифрованием с использованием пароля пользователя в качестве ключа. Таким образом, приложение не знает, что такое crypto_key для данных приложения, до тех пор, пока он не будет работать достаточно долго, чтобы загрузить gui и аутентифицировать пользователя.

Вот мой текущий applicationContext.xml. Spring использует его, чтобы заставить Hibernate работать и функционировать.

<?xml version="1.0" encoding="UTF-8"?> 
    <beans xmlns="http://www.springframework.org/schema/beans" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:context="http://www.springframework.org/schema/context" 
xmlns:tx="http://www.springframework.org/schema/tx" 
xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 
http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context-3.1.xsd 
http://www.springframework.org/schema/tx 
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd"> 

<context:component-scan base-package="com.company.domain" /> 
<context:component-scan base-package="com.company.service" /> 

<tx:annotation-driven /> 

<bean id="userDataSource" 
    class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 
    <property name="driverClassName" value="org.hsqldb.jdbcDriver" /> 
    <property name="url" 
     value="jdbc:hsqldb:./ReviewDatabase/users" /> 
    <property name="username" value="reviewer" /> 
    <property name="password" value="$kelatonKey" /> 
</bean> 


<bean id="mainDataSource" 
    class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 
    <property name="driverClassName" value="org.hsqldb.jdbcDriver" /> 
    <property name="url" 
     value="jdbc:hsqldb:./ReviewDatabase/data" /> <!-- TODO: ;crypt_key=;crypt_type=AES --> 
    <property name="username" value="reviewer" /> 
    <property name="password" value="$kelatonKey" /> 
</bean> 

<bean id="userSessionFactory" 
    class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> 
    <property name="dataSource" ref="userDataSource" /> 
    <property name="annotatedClasses"> 
     <list> 
      <value>com.company.domain.AppUser</value> 
     </list> 
    </property> 
    <property name="hibernateProperties"> 
     <props> 
      <prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop> 
      <prop key="hibernate.show_sql">true</prop> 
      <prop key="hibernate.hbm2ddl.auto">update</prop> 
     </props> 
    </property> 
</bean> 

<bean id="mainSessionFactory" 
    class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> 
    <property name="dataSource" ref="mainDataSource" /> 
    <property name="annotatedClasses"> 
     <list> 
<!--    <value>com.companu.domain.Person</value> --> 
<!--    <value>com.company.domain.Thing</value> --> 
<!--    <value>com.company.domain.Thing1</value> --> 
<!--    <value>com.company.domain.Thing2</value> --> 
<!--    <value>com.company.domain.Review</value> --> 
     </list> 
    </property> 
    <property name="hibernateProperties"> 
     <props> 
      <pro key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop> 
      <prop key="hibernate.show_sql">true</prop> 
      <prop key="hibernate.hbm2ddl.auto">update</prop> 
     </props> 
    </property> 
</bean> 


<bean id="mainTransactionManager" 
    class="org.springframework.orm.hibernate4.HibernateTransactionManager"> 
    <property name="sessionFactory" ref="mainSessionFactory" /> 
</bean> 

<bean id="userTransactionManager" 
    class="org.springframework.orm.hibernate4.HibernateTransactionManager"> 
    <property name="sessionFactory" ref="userSessionFactory" /> 
</bean> 
</beans> 

Вот пример класса, в котором я хотел бы иметь SessionFactory впрыскивается

@Repository("ReviewDao") 
public class HibernateReviewDao implements ReviewDao{ 

private SessionFactory mainSessionFactory; 

@Autowired 
public void setMainSessionFactory(
     SessionFactory mainSessionFactory){ 
    this.mainSessionFactory = mainSessionFactory; 
} 

@Override 
@Transactional(value = "mainTransactionManager") 
public void store(Review review) { 
    mainSessionFactory.getCurrentSession().saveOrUpdate(review); 

} 

@Override 
@Transactional(value = "mainTransactionManager") 
public void delete(Long reviewId) { 
    Review review = (Review)mainSessionFactory.getCurrentSession() 
      .get(Review.class, reviewId); 
    mainSessionFactory.getCurrentSession().delete(review); 
} 
} 

И, наконец, вот что я пытался сделать после аутентификации пользователя и получить, что crypto_key.

String jdbcUrl = "jdbc:hsqldb:./ReviewDatabase/data2;crypt_key=" + secret + ";crypt_type=AES"; 
    ServiceRegistry serviceRegistry = new ServiceRegistryBuilder() 
    .applySetting("hibernate.dialect", "org.hibernate.dialect.HSQLDialect") 
    .applySetting("hibernate.show_sql", "true") 
    .applySetting("hibernate.hbm2ddl.auto","update") 
    .applySetting("hibernate.connection.driver_class", "org.hsqldb.jdbcDriver") 
    .applySetting("hibernate.connection.url", jdbcUrl) 
    .applySetting("hibernate.connection.username", "reviewer") 
    .applySetting("hibernate.connection.password", "$kelatonKey") 
    .buildServiceRegistry(); 

    SessionFactory mainSessionFactory = new MetadataSources(serviceRegistry) 
     .addAnnotatedClass(com.company.domain.Review.class) 
     .addAnnotatedClass(com.company.domain.Person.class) 
     .addAnnotatedClass(com.company.domain.Thing.class) 
     .addAnnotatedClass(com.company.domain.Thing1.class) 
     .addAnnotatedClass(com.company.domain.Thing2.class) 
     .buildMetadata() 
     .buildSessionFactory(); 
    org.springframework.orm.hibernate4.HibernateTransactionManager htm = 
      (HibernateTransactionManager)context.getBean("mainTransactionManager"); 
    context.getAutowireCapableBeanFactory().initializeBean(mainSessionFactory, "mainSessionFactory"); 
    htm.setSessionFactory(mainSessionFactory); 

Однако с этим, первый запрос к выше результатов объекта в org.hibernate.HibernateException: No Session found for current thread

Как я могу изменить JDBCURL долго после спящего режима инициализации, зависимостей были введены и другие различные виды Томь-Foolery произошло? Я откладываю эту часть разработки, надеясь, что Google в конце концов придет, но у меня нет идей для поиска. Все ответы будут приниматься с застенчивым смирением :)

ответ

0

Интересно, может ли это помочь, Can I replace a Spring bean definition at runtime?, вы могли бы фикчировать свойства bean, чтобы начать с, а затем сменить bean-компонент во время выполнения.

+0

Спустя 24 часа я придумал что-то, что работает, но ответ позади этой ссылки может применяться гораздо шире (в хорошем смысле). Добавьте это с идеей использования LocalSessionFactoryBean, и я бы назвал это решением. –

+0

Thats довольно прохладно – drobson

0

Итак, недостающий бит рецепта был LocalSessionFactoryBean. Он получил настройку sessionFactory, чтобы я мог просто заменить sessionFactories, созданные при инициализации. Вот код, который я должен был перейти от вопроса

org.springframework.orm.hibernate4.HibernateTransactionManager htm = 
      (HibernateTransactionManager)context.getBean("mainTransactionManager"); 
    Class<?>[] classes = new Class<?>[5]; 
    classes[0] = com.company.domain.Thing1.class; 
    classes[1] = com.company.domain.Thing2.class; 
    classes[2] = com.company.domain.Person.class; 
    classes[3] = com.company.domain.Thing.class; 
    classes[4] = com.company.domain.Review.class; 

    String jdbcUrl = "jdbc:hsqldb:./ReviewDatabase/data3;crypt_key=" + secret + ";crypt_type=AES"; 

    java.util.Properties hibernateProperties = new java.util.Properties(); 
    hibernateProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.HSQLDialect"); 
    hibernateProperties.setProperty("hibernate.show_sql", "true"); 
    hibernateProperties.setProperty("hibernate.hbm2ddl.auto","update"); 
    hibernateProperties.setProperty("hibernate.connection.driver_class", "org.hsqldb.jdbcDriver"); 
    hibernateProperties.setProperty("hibernate.connection.url", jdbcUrl); 
    hibernateProperties.setProperty("hibernate.connection.username", "reviewer"); 
    hibernateProperties.setProperty("hibernate.connection.password", "$kelatonKey"); 


    LocalSessionFactoryBean slfb = new LocalSessionFactoryBean(); 
    slfb.setHibernateProperties(hibernateProperties); 
    slfb.setAnnotatedClasses(classes); 
    try { 
     slfb.afterPropertiesSet(); 
    } catch (IOException e) { 
     Log.warn("Cannot connection to application database"); 
     Log.write(e.getLocalizedMessage()); 
     Log.write(e.getStackTrace()); 
     return; 
    } 
    SessionFactory mainSessionFactory = slfb.getObject(); 
    context.getAutowireCapableBeanFactory().initializeBean(mainSessionFactory, "mainSessionFactory"); 

    htm.setSessionFactory(mainSessionFactory); 
    for(ListenForNewSessionFactory dao : daos){ 
     dao.setNewSessionFactory(mainSessionFactory); 
    } 

я имел каждый Dao реализовать интерфейс для установки SessionFactory, и имел каждый из них добавить себя статический список инициализации. Он не очень многоразовый, но он работает.

0

Я использовал следующий хак - везде, где мне нужен SessionFactory, вместо этого я использовал SessionFactoryFactory (ниже) - делегирует только тот метод SessionFactory, который я фактически использую.

@Component 
public class SessionFactoryFactory { 
    @Autowired 
    private LocalSessionFactoryBean sessionFactoryBean; 

    @Autowired 
    private DriverManagerDataSource dataSource; 

    private SessionFactory sessionFactory; 

    private SessionFactory getSessionFactory() { 
     if (null == sessionFactory) { 
      sessionFactory = sessionFactoryBean.getObject(); 
     } 
     return sessionFactory; 
    } 

    public Session openSession() { 
     return getSessionFactory().openSession(); 
    } 

    public void updateDataSourceUrl() throws IOException { 
     sessionFactory = null; 
     sessionFactoryBean.afterPropertiesSet(); 
    } 
} 
Смежные вопросы