blob: 970a8dbe42227ef49088dde1eec4fd940779487b [file] [log] [blame]
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"[
<!ENTITY imgroot "images/version_3_users_guide/migrate/">
<!ENTITY % uimaents SYSTEM "../../target/docbook-shared/entities.ent">
%uimaents;
]>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<chapter id="uv3.migration">
<title>Migrating to UIMA Version 3</title>
<titleabbrev>Migrating to V3</titleabbrev>
<section id="uv3.migration.big_picture">
<title>Migrating: the big picture</title>
<para>Although UIMA V3 is designed to be backwards compatible with UIMA V2, there are some migration steps
needed. These fall into two broad use cases:
<itemizedlist>
<listitem><para>if you have an existing UIMA pipeline / application you wish to upgrade to use V3</para></listitem>
<listitem><para>if you are "consuming" the Maven artifacts for the core SDK, as part of another project</para></listitem>
</itemizedlist>
</para>
</section>
<section id="uv3.migration.migrating_pipeline">
<title>How to migrate an existing UIMA pipeline to V3</title>
<titleabbrev>How to migrate</titleabbrev>
<para>
UIMA V3 is designed to be binary compatible with existing UIMA V2 pipelines, so compiled and/or JAR-ed up classes
representing a V2 pipeline should run with UIMA v3, with three changes:
<itemizedlist>
<listitem><para>Java 8 is required. (If you're already using Java 8, nothing need be done.)</para></listitem>
<listitem><para>Any defined JCas cover classes must be migrated or regenerated, and used instead.
(If you do not define any JCas classes or don't use JCas in your pipeline, then nothing need be done.)
A quick way to do this is to create a Jar with the migrated JCas classes, and put it into the classpath
ahead of the other JCas class definitions.</para></listitem>
<listitem><para>The runtime classpath needs to include the slf4j-api Jar, and an appropriate slf4j bridging Jar,
for details, see next.
</para></listitem>
</itemizedlist>
</para>
<para>Some adjustments may need to be made to logging setup, typically by including additional Jars
(provided in the UIMA Binary distribution) in your
application's classpath. If you are using the standard UIMA Launch scripts, this is already done.
For custom application setups, insure that the classpath includes the (now) required jar
"slf4j-api-xxxx.jar" (replace xxxx with the version).
If you were using the standard UIMA based logging,
to get the similar behavior, include the slf4j-jdk14-xxxx.jar; this
enables the standard Java Utility Logging facility.
</para>
<para>Some Maven projects use the JCasGen maven plugin; these projects' JCasGen maven plugin,
if switched to UIMA V3, automatically generate the V3 versions. For proper operation, please run
maven clean install; the clean operation ought to remove the previously generated JCas class, including the
UIMA V2 <code>xxx_Type</code> classes. These are no longer used, and won't compile in V3.
</para>
<para>You can use any of the methods of invoking JCasGen to generate the new V3 versions.
If using the Eclipse plugins (i.e., pushing the <code>JCasGen</code>) button in the
configuration editor, etc.), the V3 version of the plugin must be the one installed into Eclipse.
</para>
<para>
If you have the source or class files, you can also migrate those using the migration tool described in this section.
This approach is useful when you've customized the JCas class, and wish to preserve those customizations,
while converting the v2 style to the v3 style.
</para>
<!--
<para>For simple testing, after users have migrated or generated any user-supplied JCas classes,
users typically will JAR-up these migrated classes,
and then place that JAR in the class path ahead of the original V2 pipeline's classes so these will replace
the corresponding classes.
</para>
-->
<!--
<section id="uv3.migration.maven-cookbook">
<title>Modifying a Maven project to support both v2 &amp; v3</title>
<titleabbrev>Maven v2/v3 simultaneous support</titleabbrev>
<para>When migrating an existing Maven project to v3, you can of course, just change the dependencies, upgrade
to Java 8 if needed, and migrate/regenerate any user-defined JCas class definitions. Nothing special is needed
for this approach.</para>
<para>If you want to simultaneously support both v2 and v3, you can take advantage of the binary compatibility
support in v3, and have one set of maven artifacts for both (compiled with Java 7), plus an additional
Maven project just for the generated JCas classes v3-style. This additional maven project would
specify Java 8 and UIMA v3 dependencies, and produce a Jar file with the V3 version, either from migrated Java sources,
or using the JCasGen maven plugin, generating from the type system description.</para>
<para>
The using community would see the original output artifacts, plus one new Jar artifact, which, if they were
wanting to use V3, they would need to place ahead of the original artifacts in the running pipeline's classpath.
</para>
</section>
-->
</section>
<section id="uv3.migration.jcas">
<title>Migrating JCas classes</title>
<!-- repetitious
<para>Some projects are built using Maven, and use the JCasGen Maven plugin as part of the build.
These builds, when switched to depend on version 3, will automatically generate the new JCas
class definitions, so nothing special need be done.
</para>
-->
<para>If you have customized JCasGen classes, these can be migrated by running the migration tool, which is available
as a stand-alone command line tool (<code>runV3migrateJCas.sh or ...bat</code>), or
as Eclipse launch configurations.</para>
<para>This tool can migrate either sets of
<itemizedlist>
<listitem><para>Java source files (xxx.java) or </para></listitem>
<listitem><para>Compiled Java class files (including those contained in JARs or PEARs)</para></listitem>
</itemizedlist>
Usually, if you have the source code it is best to migrate the sources. Otherwise, you can migrate the compiled classes.
</para>
<para>When migrating <emphasis role="strong">source</emphasis> files, you specify one or more "roots" - places in a file directory,
and the tool scans those
directories recursively (including inside Jars and PEARs), looking for JCas source files. When it finds one, it copies it to the output spot
and migrates it. The output is arranged in parallel directories (before and after migration),
for easy side-by-side comparing in a tool such as Eclipse file compare.</para>
<para>After checking the migration results, including comparing the files, you replace the original source with
the migrated versions. Also, the original V2 source would contain a source file for each JCas class ending in
"_Type"; these are not used in version 3 and should be deleted.</para>
<para>You may also migrate <emphasis role="strong">class</emphasis> files; this can be used when the source files are not available.
This option has a decompilation step, to produce the source to be migrated and requires
a classpath (passed as the <code>migrationClasspath</code> parameter);
this classpath is used to resolve symbols during the decompilation, and should be the classpath used when running those classes.
For class files, the migration tool
attempts to compile the results and, for Jars and PEARs, to update those migrated classes
in a copy of the original packaging (meaning, within Jars or PEARs):
<itemizedlist spacing="compact">
<listitem><para>The <emphasis role="strong">classesRoots</emphasis> are used to locate .class files, perhaps within Jars and PEARs.</para></listitem>
<listitem><para>These are decompiled, using special versions of the migrateClasspath.</para></listitem>
<listitem><para>The resultant sources are migrated.</para></listitem>
<listitem><para>The migrated sources are compiled.</para></listitem>
<listitem><para>If the original classes came from Jars or PEARs, copies of these are made with the
migrated classes replaced.</para></listitem>
</itemizedlist>
</para>
<!--
<para>The migration tool makes a list of all the places in the sourcesRoots or classRoots which contain
one or more JCas classes. It outputs a table of these places with numbered entries called
<emphasis role="strong">root-ids</emphasis>; the root-ids are used
when outputting the results, so that output can be tied to where it originated in the
directory roots. Root-ids are sequentially incrementing integers starting with 1, and are suffixed
with a J or a P, if the root-id is for a Jar or a Pear.
</para>
<para>Each root-id has an associated value, consisting of a path plus 0 or more other root ids, preceding the path.
The root-id's value is the location of the Java class (excluding its package prefix). For example, the
location for a class in a directory tree at /a/b/c/x/y/z/classname.java, where the fully qualified class name was
<code>x.y.z.classname</code>, would be /a/b/c.
</para>
<para>The value of a root-id may include 0 or more other root-ids; these additional root-ids are for the purpose of
identifying a containing Jar or PEAR location; a PEAR containing a Jar would have two additional root-ids.</para>
-->
<para>When scanning directories from source or class roots, if a Jar or a PEAR is encountered, it is recursively scanned.</para>
<para>When migrating from compiled classes:
<itemizedlist>
<listitem><para>The class is decompiled, and the resulting source is migrated.</para>
</listitem>
<listitem><para>The next 2 steps are skipped if no Java compiler is available. A compiler is available if
the migrate utility is being run using a JDK (as opposed to a JRE version of Java).</para></listitem>
<listitem><para>The migrated classes are compiled.
During this processes, the classpath used is the same as the decompile classpath, except
that the uima-core Jar for version 3 (from the classpath used to run the migration tool) is prepended
so that the migrated version can be compiled.
</para></listitem>
<listitem><para>Finally, if the original "packaging" of the class files is a Jar or PEAR, it
is copied and updated with the migrated classes (provided there was no compile error).
</para>
</listitem>
</itemizedlist>
</para>
<para>The results of the migration include the migrated files, a set of logs, and for classesRoots: the
compiled classes, and repackaging of them into copies of original Jars and/or PEARs.
The migration operation is summarized in the console
output, detailing anything that might need inspection to verify the migration was done correctly.
</para>
<blockquote><para>
If all is OK, the migration will say that it "finished with no unusual conditions", at the end.
</para></blockquote>
<para>To complete the migration, fix any reported issues that need fixing, and then
update your UIMA application to use these classes/Jars/PEARs
in place of the version 2 ones.
</para>
<para>
The actual migration step is a source-to-source transformation, done using a parse of the source files.
The parts in the source which are version 2 specific are replaced with the equivalent version 3 code.
Only those parts which need updating are modified;
other code and comments which are part of the source file are left unchanged. This is intended to preserve
any user customization that may have been done.
</para>
<!-- <section id="uv3.migration.automatic">
<title>Automatic migration</title>
<para>It is sometimes possible to have this migration done automatically, when a pipeline is started up. Although
convenient, it has some drawbacks, the main ones being that it may not work correctly for more complex
customized JCas sources, and it slows down the launch of pipelines. Ideally, the migration utility would be used
and the results checked before proceeding, and the migrated classes replaced in the pipeline(s), as a one time
migration process.</para>
<para>The automatic migration works by detecting version 2 classes, decompiling them, migrating them, compiling
the migrated version, and then loading them in place of the version 2 classes.</para>
<para>The automatic migration will throw a Runtime Exception
if an unusual condition occurs for any reason during this process.
</para>
</section>
-->
<note><para>After running the tool, it is important to examining the console output and logs.
You can confirm that the migration completed without any unusual conditions, or, if something
unusual was encountered, you can take corrective action.
</para></note>
<section id="uv3.migration.tool_guide.running">
<title>Running the migration tool</title>
<para>The tool can be run as a stand-alone command, using the launcher scripts <code>runV3migrateJCas</code>;
there are two versions of this &mdash; one for windows (ending it ".bat")
and one for linux / mac (ending in ".sh").
If you run this without any arguments, it will show a brief help for the arguments.
</para>
<para>There are also a pair of Eclipse launch configurations
(one for migrating source files, the other for compiled classes and JARs and PEARs),
which are available if you have the uimaj-examples project
(included in the binary distribution of UIMA) in your Eclipse workspace.
</para>
<section id="uv3.migration.tool_guide.running.eclipse">
<title>Using Eclipse to run the migration tool</title>
<para>There are two Eclipse launch configurations; one works with source code, the other with compiled classes
or Jars or PEARs. The launch configurations are named:
<itemizedlist spacing="compact">
<listitem><para>UIMA Run V3 migrate JCas from sources roots</para></listitem>
<listitem><para>UIMA Run V3 migrate JCas from classes roots</para></listitem>
</itemizedlist>
When running from class directory roots, the classes must not have compile errors, and may contain Jars and PEARs.
Both launchers write their output to a temporary directory, whose name is printed in the Eclipse console log.
</para>
<para>
To use the Eclipse launcher to migrate from source code,
<itemizedlist spacing="compact">
<listitem><para>First select the eclipse project containing the source code to transform;
this project's "build path" will also supply the
classpath used during migration.</para></listitem>
<listitem><para>run the migrate-from-sources launcher.
</para></listitem>
</itemizedlist>
This will scan the directory tree of the project, looking for source files which are JCas files, and
migrate them. No existing files are modified; everything is written to the output directory.
</para>
<para>
To use the launcher for compiled code,
<itemizedlist spacing="compact">
<listitem><para>First select the eclipse project that provides the classpath for the compiled code.
This is required for proper "decompiling" of the classes and
recompiling the transformed results.
</para></listitem>
<listitem><para>The launcher will additionally prompt you for another directory
which the migration tool will use as the top of a tree to scan for compiled Java JCas classes to be migrated.
</para></listitem>
</itemizedlist>
</para>
</section>
<section id="uv3.migration.tool_guide.running.cmd_line">
<title>Running from the command line</title>
<section id="uv3.migration.tool_guide.running.inputs">
<title>Command line: Specifying input sources</title>
<para>Input is specified using these arguments:
<variablelist>
<varlistentry>
<term><emphasis role="strong">"-sourcesRoots"</emphasis></term>
<listitem>
<para>a list of one or more directories, separated by the
a path separator character (";" for Windows, ":" for others).
</para>
<para>Migrates each candidate source file found in any of the file tree roots,
skipping over non-JCas classes.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><emphasis role="strong">"-classesRoots"</emphasis></term>
<listitem>
<para>a list of one or more directories
containing class files or Jars or PEARs, separated by the
a path separator character (";" for Windows, ":" for others).
</para>
<para>Decompiles, then migrates each candidate class file found in any of the file tree roots
(skipping over non-JCas classes).
</para>
</listitem>
</varlistentry>
</variablelist>
You can specify either of these, but not both.
</para>
</section>
<section id="uv3.migration.tool_guide.classpath">
<title>Command line: Specifying a classpath for the migration</title>
<para>When migrating from compiled classes, a classpath is required to locate and decompile
the JCas classes to be migrated. This classpath should include the JCas classes
to be decompiled. The compiled classes must not have compile errors.
</para>
<para>When migrating from sourcesRoots, this argument is required only if the JCas classes
have references to other non-migrated classes (other than core UIMA classes). For example,
if your JCas class had a reference to a user defined Utility class, that would need to be in the classpath.
For plain, non-customized JCas classes, this argument is unnecessary.
</para>
<para>To specify this parameter, use the argument <code>-migrateClasspath</code>.
The Eclipse launcher "UIMA run V3 migrate JCas from classes roots" sets this argument using
the selected Eclipse project's classpath.
When migrating within a PEAR, the migration tool automatically adds the
classpath specified by the PEAR (if any) to the classpath.
</para>
</section>
</section>
<section id="uv3.migration.tool_guide.duplicates">
<title>Handling duplicate definitions</title>
<para>Sometimes, a classpath or directory tree may contain multiple instances of the same JCas class.
These might be identical, or they might be different versions.
</para>
<para>The migration utility handles this by migrating each instance.
<!--
detects this, except for this case:
<itemizedlist spacing="compact">
<listitem><para>migrating from classes (meaning the classes are decompiled), and</para></listitem>
<listitem><para>the multiple instances defining the classes are not in a Jar or a PEAR, or</para></listitem>
<listitem><para>if in a PEAR, the multiple instances are not in a Jar within the PEAR</para></listitem>
</itemizedlist>
In this case, the decompilation gets the definition from the migrateClasspath, by classname, which means
that even though there may be multiple definitions, only the one (the first one in the classpath) is found.
</para>
-->
The migrated forms are
stored in the output directory prefixed by the root-id (see above), as the parent directory.
The different versions can then be conveniently compared using tooling such as Eclipse's file compare.
</para>
</section>
</section>
<section id="uv3.migration.tool_guide.reports">
<title>Understanding the reports</title>
<para>The output directory contains a logs directory with additional information.
A summary is also written to System.out.
</para>
<para>Each file translated has both a v2 source and a v3 source. When the input is ".class" files,
the v2 source is the result of the decompilation step, prior to any migration.
</para>
<para>The process of scanning directories to find JCas class to migrate may come across multiple instances of
the same class. There are two subcases:
<itemizedlist>
<listitem><para>The instances are the same.</para></listitem>
<listitem><para>The instances are different (two non-identical definitions for the same class).
Sometimes these arise when migrating from compiled classes, where the compilation was done by different
versions of the Java compiler, and the resulting decompilations are logically equal but have some fields or
methods in a different order.</para></listitem>
</itemizedlist></para>
<para>This diagram illustrates some of the potentials for identical and non-identical duplicate definitions
for the same classname, that the tool may encounter. The blue boxes represent ordinary file directories
or Jars, and the other boxes with labels Cn1 and Cn2 represent the definitions for a classes named Cn1
and Cn2; the different colors represent non-identical definitions, as an example. Note that a definition
for a class might appear sometimes not within a Jar (or a PEAR, not shown here), as well as with that.
<mediaobject>
<imageobject>
<imagedata width="5.7in" format="PNG" fileref="&imgroot;multiples.png"/>
</imageobject>
<textobject><phrase>Example of some possible duplicate class definitions</phrase>
</textobject>
</mediaobject>
The migration tool allows for all of these variants. It will
migrate all versions, and will (when migrating from compiled Jars and PEARs) compile and reassemble these.</para>
<para>The output directories prefix the package/classname holding the source code with a prefix of
"a0", "a1", etc. The "a" stands for alternative, and the 0 is for the first alternative, and the 1, 2, ...
are for other non-equal alternatives.</para>
<para>When the migration is run from compiled classes, then, if possible,
the resulting migrated classes are recompiled and if from Jars or PEARs, reassembled into copies of those artifacts.
The compilation for the same classname, with the same sourcecode, could be different for different containers
because each compilation is done with that container's classpath (e.g. Jar or Pear) and with respect to the
compilation units of that container.
</para>
<para>Because of this, the compiled results for a given source instance, are done separately, and kept in output
directories, indexed additionally by the container number, as "c0", "c1", ... .
A list of all container numbers and the migrated
classes within those containers, is printed out to enable correlating these by hand when necessary.
</para>
<para>The overall directory output directory tree looks like:
<programlisting>Directory structure, starting at -outputDirectory
converted/
v2/
a0/pkg/name.../Classname.java
/Classname2.java etc.
a1/pkg/name.../Classname.java if there are multiple
different versions
...
v3/
a0/pkg/name.../Classname.java
/Classname2.java etc.
a1/pkg/name.../Classname.java if there are multiple
different versions
...
v3-classes/ for Jars and PEARs, the compiled class
// xyz is the path in the container to the
// start of the pkg/name.../Classname.class
// the "a0", "a1", ... is extra but serves to
// identify which alternative of the source
23/a0/xyz/pkg/name.../Classname.class
33/a0/xyz/pkg/name.../Classname.class
42/a0/xyz/pkg/name.../Classname.class
...
pears/
// xyz_updated_pear_copy is the path
// relative to the container, of the PEAR
33/xyz_updated_pear_copy.pear
...
jars/
// xyz_updated_jar_copy is the path
// relative to the container, of the Jar
42/xyz_updated_jar_copy.jar
...
not-converted/
logs/
processed.txt
failed.txt
skippedBuiltins.txt
nonJCasFiles.txt
workaroundDir.txt
deletedCheckModified.txt
manualInspection.txt
pearFileUpdates.txt
jarFileUpdates.txt
...</programlisting>
</para>
<para>
The converted subtree holds all the sources and migrated versions that were successfully migrated.
The not-converted subtree hold the sources that failed in some way the migration.
The logs contain many kinds of entries for different issues encountered:
<variablelist>
<varlistentry>
<term><emphasis role="strong">processed.txt</emphasis></term>
<listitem>
<para>List of successfully processed classes
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><emphasis role="strong">failed.txt</emphasis></term>
<listitem>
<para>List of classes that failed to migrate
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><emphasis role="strong">skippedBuiltins.txt</emphasis></term>
<listitem>
<para>List of classes representing built-ins that were skipped. These need
manual inspection to see how to merge with new v3 built-ins.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><emphasis role="strong">NonJCasFiles.txt</emphasis></term>
<listitem>
<para>List of files that were thought to be JCas classes but
upon further analysis appear to not be. These need
manual inspection to confirm.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><emphasis role="strong">deletedCheckModified.txt</emphasis></term>
<listitem>
<para>List of class where a version 2 if statement doing the "featOkTst"
was apparently modified. In the migrated code, this statement was deleted,
perhaps incorrectly. These need manual inspection to confirm.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><emphasis role="strong">manualInspection.txt</emphasis></term>
<listitem>
<para>List of files where the migration found a get or set method, where
the version 2 code was accessing a casFeatCode with the
feature name not matching. These need manual inspection.
</para>
</listitem>
</varlistentry>
<!--
<varlistentry>
<term><emphasis role="strong">workaroundDir.txt</emphasis></term>
<listitem>
<para>When running conversions on a windows system for files from a linux system,
sometimes there is a clash caused by the fact that Windows doesn't recognize
upper vs lower case in file names. When this happens, an entry is logged here,
and the conflicting name is suffixed with a "_c".
</para>
</listitem>
</varlistentry>
-->
<varlistentry>
<term><emphasis role="strong">jarsFileUpdates.txt</emphasis></term>
<listitem>
<para>List of Jar files and classes which were replace in them.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><emphasis role="strong">pearsFileUpdates.txt</emphasis></term>
<listitem>
<para>List of Pear files and classes which were replace in them.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</section>
<section id="uv3.migration.tool_guide.cookbook">
<title>Examples</title>
<para>Run the command line tool:
<programlisting>cd $UIMA_HOME
bin/runV3migrateJCas.sh
-migrateClasspath /home/me/myproj/xyz.jar:$UIMA_HOME/lib/uima-core.jar
-classesRoots /home/me/myproj/xyz.jar:/home/me/myproj/target/classes
-outputDirectory /temp/migratejcas
</programlisting>
</para>
<para>Run the Eclipse launcher:</para>
<para>First, make sure you've installed the V3 UIMA plugins into Eclipse!</para>
<programlisting>Startup an Eclipse workspace containing the project
with JCas source files to be migrated.
Select the Java project with the JCas sources to be migrated.
Eclipse -&gt; menu -&gt; Run -&gt; Run configurations
Use the search box to find
"UIMA run V3 migrate JCas from sources" launcher.
</programlisting>
<para>Please read the console output summarization to see where the output went, and about any
conditions found during migration which need manual inspection and fixup.</para>
</section>
</section>
<section id="uv3.migration.consuming">
<title>Consuming V3 Maven artifacts</title>
<!--
<para>There are two issues which may affect other projects which consume V3:
<itemizedlist spacing="compact">
<listitem><para>default logging is now a no-op slf4j logger, and </para></listitem>
<listitem><para>issues using the <code>maven-bundle-plugin.</code></para></listitem>
</itemizedlist>
</para>
-->
<para>Projects may have tests which write to the UIMA log. Because V3 switched to SLF4J as the default logger,
unless SLF4J can find an adapter to some back-end logger, it will issue a message and substitute a "NO-OP"
back-end logger. If your test cases depend on having the V2 default logger (which is the one built into Java),
you need to add a "test" dependency that specifies the SLF4J-to-JDK14 adapter to your POM. Here's the xml for that:</para>
<programlisting><![CDATA[<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.7.24</version> <!-- or some version you need -->
<scope>test</scope>
</dependency>]]></programlisting>
<!--
<para>If you build OSGi or Eclipse plugins using the <code>maven-bundle-plugin</code>, it will by default
look to include the slf4j artifacts. Instead of this, your run-time OSGi environment could frequenly
already include these artifacts, and you can instruct OSGi to "hook up" to them.
You can block the attempt to include slf4j directly in your plugin by adding a line to your
bundle commands such as &lt;import-package&gt; that exclude this package by adding</para>
<programlisting>!org.slf4j</programlisting>
<para>to the package list; the "!" says to exclude it.</para>
<para>Alternatively, you can include it in the bundle by adding a dependency to the version you which to include.</para>
-->
</section>
</chapter>