вторник, 18 декабря 2012 г.

hibernate-configuration-3.0.dtd

Обнаружил вчера WTF в старом проекте:

Заголовок файла hibernate.cfg.xml

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "/usr/local/etc/hibernate-configuration-3.0.dtd">

При попытке выполнить локально естественно все падает с ошибкой с очень длинным стеком вызовов, но упирается все в:

Caused by: org.hibernate.HibernateException: Could not parse configuration: /hibernate.cfg.xml
    at org.hibernate.cfg.Configuration.doConfigure(Configuration.java:1586)
~[hibernate-core-3.5.6-Final.jar:3.5.6-Final]
...
Caused by: org.dom4j.DocumentException: /usr/local/etc/hibernate-configuration-3.0.dtd (No such file or directory) Nested exception: /usr/local/etc/hibernate-configuration-3.0.dtd (No such file or directory)
    at org.dom4j.io.SAXReader.read(SAXReader.java:484) ~[dom4j-1.6.1.jar:1.6.1]
    at org.hibernate.cfg.Configuration.doConfigure(Configuration.java:1576) ~[hibernate-core-3.5.6-Final.jar:3.5.6-Final]

Собственно все правильно, с чего бы там лежать этому файлу? Меняю на

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

Компилирую, запускаю, работает. На всякий случай отключаю сеть, проверяю, работает.
Лезу в историю svn, вижу мучительные попытки заставить код работать. Первая версия содержала правильный заголовок. Далее идут попытки что-то исправить: переключиться на http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd, убрать ссылку на dtd вовсе, подставить относительный путь к файлу, и в завершении - захардкодить абсолютный путь к файлу. Что пытались исправить, непонятно, но проблема явно была где-то в другом месте.

Ссылка на исходники DTDEntityResolver версии 3.5
и javadoc

В hibernate 3.6 поменяли url с http://hibernate.sourceforge.net на http://www.hibernate.org, но старый url все еще можно использовать, правда в лог выведется предупреждение о том, что вы используете старую версию.

среда, 5 декабря 2012 г.

Maven и определяемые на этапе сборки параметры проекта

Недавно прикрутил для своего маленького maven проекта сборку через Jenkins. В целом процесс занял совсем немного времени, Jenkins очень удобная и простая вещь. Единственной проблемой оказались настроечные параметры (параметры соединения с базой данных, RMI хост-порт и т.п), которые отличаются для девелоперского и продакшн окружения.

После непродолжительного гугления родилась такая схема:

1. Создаем файл, в котором хранятся все возможные настроечные параметры, назовем его dev.properties, например
jdbc.url=jdbc:postgresql://localhost/test
jdbc.username=test_user
jdbc.password=test_password

2. Определяем файлы, в которые должны быть на этапе сборки проставлены данные параметры. В терминах maven этот процесс носит название фильтрация ресурсов. В нужных файлах проставляем плэйсхолдеры, к примеру в файле config.properties:
jdbc.url=${jdbc.url}
jdbc.username=${jdbc.username}
jdbc.password=${jdbc.password}
3. Теперь самая хитрая часть. Поскольку свойства maven проекта по сути синглетоны (как и у ant), то они сохраняют переданное при инициализации значение. Т.е если вызывать maven с параметрами командной строки -Djdbc.username=test, а в pom.xml определить <jdbc.username>xxx</jdbc.username> то параметр jdbc.username будет иметь значение test.
4. Создадим фильтр, чтобы не хранить свойства в pom.xml. Для этого используем файл, созданный на шаге 1.
<filters>
   <filter>src/main/resources/dev.properties</filter>
</filters>
Теперь по умолчанию наши свойства проекта будут грузиться из dev.config, но их можно будет переопределить через параметры командной строки.

5. Последний штрих - фильтрация ресурсов. Для этого версия maven-resources-plugin должна быть не меньше 2.3
<resources>
   <resource>
       <includes>
          <include>config.properties</include>
          <include>logback.xml</include>
       </includes>
       <directory>src/main/resources</directory>
       <filtering>true</filtering>
   </resource>
   <resource>
      <directory>src/main/resources</directory>
         <excludes>
           <exclude>dev.properties</exclude>
         </excludes>
       <filtering>false</filtering>
   </resource>
</resources>
6. Настраиваем Jenkins, подставляя нужные значения в поле MAVEN_OPTS (build->advanced->MAVEN_OPTS)
полезные ссылки: Пример фильтрации ресурсов в maven