barbitoff programmer`s blog

Здесь я публикую заметки из программерской жизни: грабли, на которые мне случилось наступить, проблемы, для которых было найдено элегантное (или не очень) решение, а также все, с чем мне пришлось столкнуться и чем хотелось бы поделиться =)
PS Если хотите меня поблагодарить - на странице есть 3 места, чтобы это сделать =)

среда, 17 апреля 2013 г.

WSO2 Carbon: сборка car-ников maven`ом

Пусть для примера есть некий проекта типа "Carbon Application Project", с 1 дочерним проектом типа "ESB Config Project", содержащим некоторое число endpoint`ов и прокси-сервисов.  Структура проектов следующая:
MyCarProject
|- pom.xml
|- MyEsbConfigProject
    |- pom.xml
    |- src
        |- main
            |- synapse-config
                |- endpoints
                    |- MyEndpoint.xml
                |- proxy-services
                |- sequences
Хочется, чтобы проект можно было собирать командой:
mvn clean package 
вместо того, чтобы делать это через Carbon Studio.
Более того, есть желание использовать в xml-ках ESB-артифактов переменные, которые будут заменяться некоторыми значениями при сборке (например, будут подставляться реальные URL`ы в endoint`ы). Например, чтобы такой endpoint:
<endpoint xmlns="http://ws.apache.org/ns/synapse" name="MyEndpoint">
    <address format="soap11"
statistics="disable"
trace="disable"
uri="${endpoint.MyEndpoint.url}">
       ...
    </address>
</endpoint>
при сборке превращался в:
<endpoint xmlns="http://ws.apache.org/ns/synapse" name="MyEndpoint">
    <address format="soap11"
statistics="disable"
trace="disable"
uri="http://real.url">
        ...
    </address>
</endpoint>
путем задание URL`а в параметре сборки:
mvn clean package -Dendpoint.MyEndpoint.url=http://real.url
Если просто выполнить "mvn clean package" в папке проекта Carbon Application Project, сборка завалится с ошибкой. Связана она с тем, что pom-ка проекта Carbon имеет зависимости от артифактов, создаваемых при сборке дочернего проекта ESB Config. Однако, т.к. Carbon Application Project никак не связан с дочерним проектом ESB Config, сборка первого не приводит к предварительной сборке последнего, что и приводит к невозможности разрешить зависимости.
Решается эта проблема созданием модульного проекта, родительского по отношению к первым двум (Carbon Application Project и ESB Config):

MyCarProjectRoot
    |- pom.xml
    |- MyCarProject
       |- pom.xml
       |- MyEsbConfigProject
           |- pom.xml
           |- src
               |- main
                   |- synapse-config
                       |- endpoints
                           |- MyEndpoint.xml
                       |- proxy-services
                       |- sequences
Содержимое родительской pom-ки примерно следующее:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>my.group</groupId>
  <artifactId>MyCarProjectRoot</artifactId>
  <version>1.0.0</version>
  <packaging>pom</packaging>
  <name>MyCarProjectRoot</name>
  <modules>
      <module>MyCarProject/MyEsbConfigProject</module>
      <module>MyCarProject</module>
  </modules>
</project>
Теперь, если выполнить mvn clean install для корневой pom-ки, сначала произойдет сборка и установка проекта  MyEsbConfigProject, а затем, уже успешно, проекта MyCarProject, на выходе которого мы получим заветный car-ник. 
Сборка работает, но с ней не всё идеально. Во-первых, pom-ка проекта ESB Config устроена очень хитро. Она сначала запускает плагины wso2-esb-proxy-plugin / wso2-esb-endpoint-plugin и др. для генерации pom-ки для сборки esb-артифактов (сгенерированная pom-ка помещается в ${project.build.directory}), после чего с помощью exec-maven-plugin запускает mvn для сборки этих сгенерированных pom-ок. Все бы ничего, но только при использовании exec-maven-plugin дочерние mvn-процессы не получают параметров, переданных родительскому mvn. Например, если родительскому mvn был передан путь к специфичному settings.xml, который нужно использовать при сборке, дочерние mvn знать о нем не будут (это особенно критично при сборке на build-сервере, когда зачастую разные сборки используют свои settings.xml). Выход их ситуации - замена exec-maven-plugin на maven-invoker-plugin, т.е. вместо:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2</version>
<extensions>true</extensions>
<executions>
 <execution>
<phase>install</phase>
<goals>
 <goal>exec</goal>
</goals>
<configuration>
 <executable>mvn</executable>
 <workingDirectory>${project.build.directory}</workingDirectory>
 <arguments>
<argument>clean</argument>
<argument>install</argument>
<argument>-Dmaven.test.skip=${maven.test.skip}</argument>
 </arguments>
</configuration>
 </execution>
</executions>
<configuration />
  </plugin>
в pom-ку нужно поместить:
<!-- Replaces exec-maven-plugin plugin, used in origin -->
  <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-invoker-plugin</artifactId>
<version>1.8</version>
<configuration>
 <debug>true</debug>
 <pom>${project.build.directory}/pom.xml</pom>
 <goals>
<goal>clean</goal>
<goal>install</goal>
 </goals>
 <properties>
<maven.test.skip>${maven.test.skip}</maven.test.skip>
 </properties>
</configuration>    
<executions>
 <execution>
<phase>install</phase>
<goals>
 <goal>run</goal>
</goals>          
 </execution>
</executions>
  </plugin>  
Эффект будет тот же, но дочерние сборки будут сохранять параметры родительской.
Теперь насчет фильтрации xml-ек esb-артифактов. Во-первых, в pom-ке проекта ESB Config необходимо настроить maven-resources-plugin, добавив:
<!-- Filter ESB artifacts -->
  <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
<configuration>
 <outputDirectory>${project.build.directory}/../capp.filtered</outputDirectory>
 <resources>
<resource>
 <directory>${project.build.directory}</directory>
 <filtering>true</filtering>
</resource>
 </resources>
 <includeEmptyDirs>true</includeEmptyDirs>
 <escapeWindowsPaths>false</escapeWindowsPaths>
</configuration>
<executions>
 <execution>
<id>filter-esb-artifacts</id>
<phase>package</phase>
<goals>
 <goal>copy-resources</goal>
</goals>
 </execution>        
</executions>
  </plugin>
Теперь на фазе package (после того, как была сгенерирована pom-ка для сборки артефактов  а сами артефакты были перемещены в ${project.build.directory}) содержимое ${project.build.directory} копируется в директорию ${project.build.directory}/../capp.filtered с выполнением фильтрации. Теперь нужно настроить maven-invoker-plugin на эту директорию:
  <!-- Replaces exec-maven-plugin plugin, used in origin -->
  <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-invoker-plugin</artifactId>
<version>1.8</version>
<configuration>
 <debug>true</debug>
 <pom>${project.build.directory}/../capp.filtered/pom.xml</pom>
                ...
</configuration>    
        ...
  </plugin> 
Также, чтобы директория capp.filtered чистилась при выполнении clean, нужно добавить соотв. настройки в maven-clean-plugin:
 <!-- Clean settings to clean capp.filtered directiry -->
 <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
<version>2.5</version>
<configuration>
 <filesets>
<fileset>
 <directory>${project.build.directory}/../capp.filtered</directory>
</fileset>
 </filesets>
</configuration>
  </plugin> 
Также, на данный момент properties, устанавливаемые при сборке корневого проекта, не подхватываются сборкой проекта  ESB Config. Причина в том, что хотя коревой проект и ссылается на проект ESB Config как на дочерний, обратная связь не установлена. Чтобы её установить, нужно добавить в pom-ку проекта ESB Config следующее:
  <parent>
    <groupId>ru.project.integration.xxx</groupId>
    <artifactId>MyCarProjectRoot</artifactId>
    <version>1.0.0</version>
    <relativePath>../../</relativePath>
  </parent>
Всё, теперь можно задавать свойства при сборке корневого проекта, и они будут использоваться при фильтрации xml-конфигураций esb-артефактов.
При сборке более сложных carbon-проектов возникают и другие сложности. Например, при закатывании в car-ник java-библиотек (дочерних проектов типа "Java Library Project") сборка непосредственно мавеном генерирует manifest-файлы, не дающие полученному osgi-бандлу установиться на wso2. Проблема связана с тем, что в Import-Package манифеста включаются все без исключения классы, импортируемые внутри библиотеки, и при установке бандла wso2 ругается на недоступность некоторых из них (чтобы увидеть эту ошибку, пришлось изрядно повозиться: http://barbitoff.blogspot.ru/2013/04/wso2-esb-error-defaultappdeployer-error.html). Если же car-ник собирать из Carbon Studio, в получаемом манифесте блока Import-Package вообще нет. 
Исправляется эта проблема внесением соотв. настройки в pom-ку проекта Java Library Project, а именно:
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <groupId>my.group</groupId>
  <artifactId>my-lib</artifactId>
  <version>4.4.0</version>
  <packaging>bundle</packaging>
  <name>my-lib</name>
  <description>my-lib</description>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.felix</groupId>
        <artifactId>maven-bundle-plugin</artifactId>
        <version>2.3.4</version>
        <extensions>true</extensions>
        <configuration>
          <instructions>
            <Bundle-SymbolicName>my-lib</Bundle-SymbolicName>
            <Bundle-Name>my-lib</Bundle-Name>
            <Export-Package>my.package.*</Export-Package>
            <DynamicImport-Package>*</DynamicImport-Package>
            <Import-Package></Import-Package>
          </instructions>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>
Также, если библиотека содержит не только классы, но и ресурсы, Carbon Studio почему-то не включает их пакеты в pom-ку проекта в блок Export-Package настройки плагина maven-bundle-plugin. Соответственно, при сборке в бандл ресурсы не попадают. Лечится проблема добавлением нужных пакетов в Export-Package.
В общем заморочек много, но имхо они того стоят. Во-первых, такой проект можно собрать, не имея Eclipse и Carbon Studio. Во-вторых, он может вообще собираться автоматически на build-сервере, а благодаря maven-car-deploy-plugin - еще и деплоиться прямо оттуда автоматом на wso2 (благо за счет фильтрации мы можем настроить сборку на нужные url'ы / папки, используемые vfs-транспортом / др. прямо во время сборки). Правда, с деплоем уже не все так радостно. Например, для передеплоивания car-ников, содержащих бандлы, зачастую необходим рестарт шины, а тут уже одним maven-car-deploy-plugin не обойдешься.

1 комментарий:

  1. Hi Barbitoff

    I need your help running a assembly build using Maven. I was unsuccessful doing it. Can you help? if so please email me b4babu@gmail.com

    Thank you.

    ОтветитьУдалить