What it does
- Parses a BusinessWorks 5 project:
.processfiles, their activities, transitions, groups and the shared resources they reference. - Builds an intermediate model: a typed step list per process, independent of both BusinessWorks and Camel, which is what makes the same input emit either Java DSL or YAML.
- Generates Camel routes, one Maven module per component or per entry operation, plus the Spring beans the routes reference.
- Emits a coverage report: for every activity type it met, whether a rule exists, whether that rule emitted a marker, and how often the type occurs. The catalog on this site and the cost calculator both read that report.
- Marks what it cannot translate, in the code rather than in a side document. An
activity with no rule becomes a
TODO_HUMANcomment and a warning that names the activity and its type, so an unported step is visible in the generated source.
Getting the jar
There is no binary release yet, so build it. Java 21 is what the tool itself needs.
export JAVA_HOME=$(/usr/libexec/java_home -v 21)
mvn -q -DskipTests package The jar lands in esbexit-bootstrap/target/esbexit-bootstrap-0.1.0-SNAPSHOT.jar.
Everything below assumes it is aliased:
alias esbexit='java -jar esbexit-bootstrap/target/esbexit-bootstrap-0.1.0-SNAPSHOT.jar' Building the generated modules needs a JDK matching platform.java.version,
which defaults to 25. Nothing else: no TIBCO installation, no running engine, no network.
Migrating a component
esbexit migrate \
--source /path/to/tibco/sources \
--component sample-adapter \
--out ./out/components/sample-adapter \
--config ./my-estate.properties | Option | Required | Meaning |
|---|---|---|
| --source | yes | Root of the TIBCO source tree: the directory holding the components and the project libraries. |
| --component | yes | Component name. If the name is not unique in the tree, give it as group/component. |
| --out | yes | Output directory for the generated module. |
| --config | no | Properties file with generation settings. Defaults apply when omitted. |
| --granularity | no | component, the default, or entry. |
| --operation | with entry | The entry operation: a process starter or a SOAP service. |
| --library | no | The source is a project library rather than a component. |
| --tibco-version | no | BusinessWorks version. Defaults to 5.15. |
It prints what it produced and exits 0. Exit 2 means a missing or contradictory option.
Generated <n> files in ./out/components/sample-adapter
Coverage: <percent>% report: ./out/components/sample-adapter/docs/migration-report.md
Open issues: <n> Choosing the granularity
--granularity component, the default, makes the whole TIBCO component one Maven
module. This is what you want for an estate-wide run: the module map matches the component
map, so people who know the old system can find their way around the new one.
--granularity entry makes one module per entry operation, pulling in everything
reachable from it. Use it when a single component is too large to deploy as a unit, or when
one operation has to move to production before the rest. It needs --operation.
--library is for project libraries, the shared .projlib sources.
Their routes are published under global addresses derived from their paths, so components
that call into them resolve. Generate the libraries before the components that depend on
them.
What you get
sample-adapter/
pom.xml
src/main/java/<package.prefix>/sample_adapter/... routes, mappers, endpoint config
src/main/resources/
application.yml
mappers/*.xslt
tibco/... schemas and WSDLs, as in the source
docs/migration-report.md
docs/operation-summary.md migration-report.md is the one to read. It carries step coverage, field-mapping
coverage and every open issue with its location. An activity the generator could not
translate is a TODO_HUMAN marker in the route and a line in that report. It is
never silently dropped or approximated.
A whole estate
Once the modules exist, scaffold writes the parent pom at the root and rebuilds
the module list from what is actually on disk. It expects components/ and
shared/projlibs/ under --root, which is where migrate
puts them. Run it again after adding modules; it rewrites the module list rather than
appending to it.
# libraries first, so the components that call into them resolve
for lib in $(ls /path/to/tibco/sources/projlibs); do
esbexit migrate --source /path/to/tibco/sources/projlibs --component "$lib" \
--out "./out/shared/projlibs/$lib" --config ./my-estate.properties --library
done
for comp in $(cd /path/to/tibco/sources/components && find . -mindepth 2 -maxdepth 2 -type d | sed 's|^\./||'); do
esbexit migrate --source /path/to/tibco/sources --component "$comp" \
--out "./out/components/$(echo "$comp" | tr '/ ' '__')" --config ./my-estate.properties
done
esbexit scaffold --root ./out --config ./my-estate.properties
cd out && mvn -q compile Each migrate is independent, so this parallelises with xargs -P
without any coordination.
The config file
Everything that varies per estate lives in one properties file. Give only the keys you override; the rest keep their defaults. A misspelled key stops the run with a list of unknown keys, because a silently ignored setting would hand you a module that looks right and is built on the wrong coordinates.
package.prefix=org.acme.integration
maven.group-id=org.acme.integration
maven.parent.artifact-id=acme-integration-parent | Key | Default | Sets |
|---|---|---|
| package.prefix | com.example.camel | Java package prefix in the generated module, and the logging.level entry in application.yml. |
| maven.group-id | com.example.camel | groupId of the parent and of dependencies between generated modules. |
| maven.parent.artifact-id | integration-parent | artifactId of the parent pom. |
| platform.spring-boot.version | 4.1.0 | Spring Boot version in a module with no parent from your estate. |
| platform.camel.version | 4.20.0 | Camel version in the same case. |
| platform.java.version | 25 | maven.compiler.release of the generated module. |
| layout.components-dir | components | Where components sit inside --source. If the directory is absent, components are taken to sit in the source root. |
| layout.libraries-dir | projlibs | Where project libraries sit. Relative to --source, or an absolute path when they live outside the component tree. |
| jms.client.dependency | spring-boot-starter-artemis | JMS client added alongside camel-jms, which brings no ConnectionFactory of its own. Empty disables it. |
| route.dsl | java | java or yaml. The YAML renderer is experimental. |
Those are the ones worth knowing before the first run. Maven coordinates, parent paths, snapshot repositories and the diagnostics dependencies have defaults that work, and the full list ships with the tool.
package.prefix and maven.group-id default to
com.example.camel on purpose: example is the namespace IANA reserves
for placeholders, so no real project can collide with it. Set your own before generating
anything you intend to keep. Values may reference other keys, and substitution is recursive
and detects cycles.
Where your sources sit
A source tree holding components/ and projlibs/ is one estate's
convention rather than a rule, so both names are settings. If the libraries live somewhere
else entirely, give an absolute path.
layout.components-dir=apps
layout.libraries-dir=/srv/tibco/shared-libraries If the libraries directory does not exist, no libraries are resolved. Components still
generate, but calls into library processes end up as direct: addresses with no
route behind them, so check this setting first if a module comes out with dangling routes.
Driver and library coordinates
When a process calls the estate's own Java classes, or a JDBC resource names a driver, the
generated pom needs coordinates for them. Give one java-library. entry per
package prefix.
java-library.oracle.jdbc=com.oracle.database.jdbc:ojdbc11
java-library.org.acme.common=org.acme:acme-common:2.4.0 Without the entry the module still generates, but the report says so and the dependency is missing from the pom.
What has actually been verified
Two things. The output compiles: on the last full run every generated component built under javac with no errors, none excepted. And a generated Spring Boot application starts: the Camel context comes up and its routes reach the started state, which means every component URI resolved, every property placeholder was found and every bean reference bound. That is a class of generation bug compiling does not catch. The figures here are from a run against one private estate.
It is still not equivalence. No message has been pushed through a started route, and no output has been compared against the BusinessWorks original. Compiling is not running, running is not correct, and correct is not equivalent. Until a harness exists this page will not claim otherwise.
The two coverage figures measure something earlier than that, and neither is a success rate.
98.64% of activity occurrences are of a type the generator has a rule for, and 96.37% of the
Camel steps it emitted are real steps rather than a TODO_HUMAN marker. Both are
counted at generation time: they say how much of the estate the generator had an answer for,
not how much of it compiles, and certainly not how much of it behaves. The gap between the two
is rules that fire but flag a condition they cannot resolve, and the
catalog says which, type by type.