Blogs

Blogs

OSGi Module Dependencies

It's going to happen.  At some point in your LR7 development, you're going to build a module which has runtime dependencies.  How do you satisfy those dependencies though?

In this brief blog entry I'll cover some of the options available...

So let's say you have a module which depends upon iText (and it's dependencies).  It doesn't really matter what your module is doing, but you have this dependency and now have to figure out how to satisfy it.

Option 1 - Make Them Global

This is probably the easiest option but is also probably the worst.  Any jars that are in the global class loader (Tomcat's lib and lib/ext, for example), are classes that can be accessed anywhere, including within the Liferay OSGi container.

But global jars have the typical global problems.  Not only do they need to be global, but all of their dependencies must also be global.  Also global classes are the only versions available, you can't really vary them to allow different consumers to leverage different versions.

Option 2 - Let OSGi Handle Them

This is the second easiest option, but it's likely to not work.  If you declare a runtime dependency in your module and if OSGi has a bundle that satisfies the dependency, it will be automatically available to your module.

This will work when you know the dependency can be satisfied, either because you're leveraging something the portal provides or you've actually deployed the dependency into the OSGi container (some jars also conveniently include OSGi bundle information and can be deployed directly into the container).

For our example, however, it is unlikely that iText will have already been deployed into OSGi as a module, so relying on OSGi to inject it may not end well.

Declaring the runtime dependency is going to be handled in your build.gradle file.  Here's a snippet for the iText runtime dependency:

runtime group: 'com.iowagie', name: 'itext', version: '1.4.8'

If iText (and it's dependencies) have been successfully deployed as an OSGi bundle, your runtime declaration will ensure it is available to your module.  If iText is not available, your module will not start and will report unsatisfied dependencies.

Option 3 - Make An Uber Module

Just like uber jars, uber modules will have all of the dependent classes exploded out of their original jars and are available within the module jar.

This is actually quite easy to do using Gradle and BND.

In your build.gradle file, you should declare your runtime dependencies just as you did for Option 2.

To make the uber module, you also need to include the resources in your bnd.bnd file:

Include-Resource: @itext-1.4.8.jar

So here you include the name of the dependent jar, usually you can see what it is when Gradle is downloading the dependency or by browsing your maven repository.

Note that you must also include any dependent jars in your include statement.  For example, iText 2.0.8 has dependencies on BouncyCastle mail and prov, so those would need to be added:

Include-Resource: @itext-2.0.8.jar,@bcmail-138.jar,@bcprov-138.jar

You may need to add these as runtime dependencies so Gradle will have them available for inclusion.

If you use a zip tool to crack open your module jar, you'll see that all of the individual jars have been exploded and all classes are in the jar.

Option 4 - Include the Jars in the Module

The last option is to include the jars in the module itself, not as an uber module, but just containing the jar files within the module jar.

Similar to option 2 and 3, you will declare your runtime dependencies in the build.gradle file.

The bulk of the work is going to be done in the bnd.bnd file.

First you need to define the Bundle-ClassPath attribute to include classes in the module jar but also the extra dependency jars.  In the example below, I'm indicating that my iText jar will be in a lib directory within the module jar:

Bundle-ClassPath:\
  .,\
  lib/itext.jar

Rather than use the Include-Resource header, we're going to use the -includeresource directive to pull the jars into the bundle:

-includeresource:\
  lib/itext.jar=itext-1.4.8.jar

In this format we're saying that lib/itext.jar will be pulled in from itext-1.4.8.jar (which is one of our runtime dependencies so Gradle will have it available for the build).

This format also supports the use of wildcards so you can leave version selection to the build.gradle file.  Here's an example for including any version of commons-lang:

-includeresource:\
  lib/itext.jar=itext-1.4.8.jar,\
  lib/commons-lang.jar=commons-lang-[0-9]*.jar

If you use a zip tool to crack open your module jar, you'll find there are jars now in the bundle under the lib directory.

Conclusion

So which of these options should you choose?  As with all things Liferay, it depends.

The global option is easy as long as you don't need different versions of jars but have a lot of dependencies on the jar.  For example, if you had 20 different modules all dependent upon iText 1.4.8, global may be the best path with regards to runtime resource consumption.

Option 2 can be an easy solution if the dependent jar is also an OSGi bundle.  In this case you can allow for multiple versions and don't have to worry about bnd file editing.

Option 3 and 4 are going to be the most common route to choose however.  In both of these cases your dependencies are included within the module so the OSGi's class loader is not polluted with different versions of dependent jars.  They are also environment-agnostic; since the modules contain all of their dependencies, the environment does not need to be prepared prior to module deployment.

Personally I stick with Option 4 - uber jars will tend to step on each other when expanding the jars that contain a same path/file in each (usually xml or config info).  Option 4 doesn't suffer from these sorts of issues.

Enjoy!

57
Thanks David, do you have an actual example on github built using gradle?
Not for public consumption - most of the work I do is commercial in nature and is owned by others.

Hopefully though I've provided enough detail to get you started and, of course, if you run into problems you can usually find me in the forums emoticon
ah ok. I have posted a question in the forum. the issue I have is below:

:classes
:jar
[Input file does not exist: jackson-annotations-2.5.0.jar, Input file does not exist: spring-aop-4.2.5.RELEASE.jar, Input file does not exist: spring-beans-4.2.5.RELEASE.jar, Input file does not exist: spring-core-4.2.5.RELEASE.jar]
Hi,

thank you for posting this information. I work for a company that has been building apps (portlets) on Liferay 6.0.x, we use spring+hibernate and a couple of months ago we decided to investigate the possibility of switching to Liferay 7.

The version was not officially released at that point and after 3 weeks of hard work we managed to get a portlet to work on the new platform. However, after updating to the official release we found out that it's not possible anymore to use .war files for packaging/deploy

We've been struggling for another 3 weeks with BND trying to manually configure the portlet's dependencies but failed. We eventually gave up as it was becoming way too expensive for us having already a couple of people working on this for weeks just to get something to deploy.

I don't understand Liferay's decision to go with OSGI since JSR-286 goes down the drain, the building tools are not mature at all and developers should focus on developing NOT configuring dependencies manually.
Hi Ionut. That's not true. You should be able to deploy WAR files as before. Can you post your problem in forums please?
Hi Juan (hey, we have the same name Ionut = John = Juan),

thanks for your reply. I've posted some more details in the forum, perhaps you can help https://web.liferay.com/community/forums/-/message_boards/message/76470778
Option 1 is not completely accurate. Not everything you put into the global class loader of the App Server will be accessible from the OSGi container. We have a fine grained control on what we export; you will need to play with the module.framework.system.packages.extra property in your portal-ext.properties file.

Be careful with Option 3; you can get a few surprises when exploding multiple jar files containing the same files (I am looking at you Service Loader)

Option 4 is really a trade-off, if you have a single dependency it's really easy to do. However, if you get a library with 10s of dependencies, all of them will become your dependencies as well. I would recommend not to overuse this ability, and use it only when your dependencies are minimal and the dependency itself does not belong to your public API.
Yes, I agree. What is missing is a concise, best practices example, of coding a hook as a module and a portlet as a module, that also, depends on spring and other external dependencies. Quick, vague, answers don't help. Maybe they boost Liferay profiles to legend?
Not sure where is the vagueness on my previous response. The post wasn't talking about any concrete application, so I just added some tips I consider to be important.

I don't need to be any legend, and answers like this are the reason I don't usually comment in the forums/blog posts.

Anyway, if you're looking for detailed examples on how to develop different Liferay applications (extensions, Service Builder based applications, ..) you can check the repo https://github.com/liferay/liferay-blade-samples. There you will find applications you can use to learn the fundamentals.
[...] Nam Trương: How to add external jar file in liferay 7 module project? Here you have some hints: https://web.liferay.com/web/26526/blog/-/blogs/osgi-module-dependencies Sign in to vote. Flag Please... [...] Read More
Hi David, thank you for excellent post!

Question: do i need manually create "lib" subfolder with physical copy of JARs?

Right now Liferay 'master' branch does exactly this: having physical JARs in a "lib/". Option 4 doesn't work for me without this.

Thanks,
Actually master does not have the physical jars there...

When you check, for example, https://github.com/liferay/liferay-portal/tree/master/modules/apps/collaboration/document-library/document-library-repository-cmis-impl you can see in the bnd.bnd that it is also using the lib/xxx format, but there is no src/main/resources/lib folder with the actual jars.

All of the jars, however, are referenced in build.gradle file so they will be pulled in at build time.
"document-library-repository-cmis-impl" uses "provided" in its' gradle script; dependency jars are available at runtime from "lib" directory of the portal at runtime:
https://github.com/liferay/liferay-portal/tree/master/lib/portal

Compare this with "lib" folder in your workspace bundles, such as this one:
/java/lp7/liferay-osgi/bundles/tomcat-8.0.32/webapps/ROOT/WEB-INF/lib

I tested: I refer in my gradle script "commons-lang:commons-lang:2.3", and I use

Bundle-ClassPath:\
.,\
lib/commons-lang.jar,\

- and it perfectly works without explicit bundling this JAR. It may even seem as a bug (my portlet can refer JARs fro ROOT/WEB-INF/lib)

I tested, it works.

But if I use commons-lang3:3.4 then I need to download this file explicitly and add it to "lib" subfolder (Option 4 for example)
I believe my custom plugin cannot refer JARs from this 'portal/lib'; it won't work for portlets developed outside "liferay-portal"

I cannot use "provided" in Gradle script for example.
Please ignore last two sentences of my previous post; and some typo; unfortunately I cannot edit it
So, here's the rub - the modules do not have access to ROOT's WEB-INF/lib directory.

So using the com.liferay.document.library.repository.cmis.impl module as an example, in your bundle in osgi/marketplace you'll find the Liferay Collaboration.lpkg file; this file has all the individual modules in it, rename to .zip to open it.

Inside there you'll find the com.liferay.document.library.repository.cmis.impl-x.x.x.jar file which is the bundle jar.

Open this file with a zip utility and you'll see there is a lib folder at the root of the jar and inside of that folder is all of the dependent jars listed in the bnd.bnd file.

These jars are not part of the source for the module, not part of the resources, and not part of ROOT/WEB-INF/lib. During module build time gradle is pulling them down and they are getting included in the lib directory as the jar is being created.
I followed the steps; super interesting, I didn't know that!

However, I did a test: I explicitly use StringUtils from commons-lang in my code, and I use this:

Bundle-ClassPath:\
.,\
lib/commons-lang.jar,\

And this:
compile 'commons-lang:commons-lang:2.6'

And I didn't explicitly create folder "lib" with this file, and it works without it. However, if you try to do the same with commons-lang3-3.4, it won't work. How to explain that?

I believe portlet is able to load classes from ROOT/WEB-INF/lib/commons-lang.jar and this is ***SECURITY VULNERABILITY*** in Liferay 7
org.osgi.framework.BundleException: Could not resolve module: datafeeds-web [486]
Unresolved requirement: Import-Package: org.apache.commons.lang3; version="[3.3.0,4.0.0)"
For commons-lang3, what is the dependency string you're using?

I don't believe it's just open access to commons-lang at all. Liferay does allow some jars to be loaded from global (see the module.framework.system.packages.extra property), but commons-lang 2.6 is also a proper OSGi bundle jar and may actually be in the OSGi container.

I haven't done a deep dive into all of the deployed lpkg files, their subsequent jars and contents, but I tend to believe there's a bundle that is in there that has used option 3 or 4 to include the classes/jar and has, in turn, exported those classes so they are available. OSGi will, of course, bind that module to any that was dependent on the commons-lang stuff and you'd have no clear idea where it was really being provided from.
Ok, I found GoGo command:
g! packages org.apache.commons.lang

It shows it is available in container version 2.6.

g! packages org.apache.commons.lang
osgi.wiring.package; bundle-symbolic-name:List<String>="org.eclipse.osgi,system.bundle"; bundle-versionemoticonersion="3.10.200.v20150831-0856"; versionemoticonersion="2.6.0"; osgi.wiring.package="org.apache.commons.lang"; uses:="org.apache.commons.lang.exception"<org.eclipse.osgi_3.10.200.v20150831-0856 [0]>
com.liferay.portal.search_3.1.2 [286] imports
com.liferay.portal.template.velocity_2.0.3 [326] imports
com.liferay.portal.store.jcr_2.0.1 [321] imports
com.liferay.sync.service_1.0.5 [353] imports
com.liferay.calendar.service_2.0.5 [123] imports
com.liferay.util.taglib_2.4.0 [1] imports
com.liferay.wiki.service_1.1.3 [119] imports
com.liferay.document.library.repository.cmis.impl_2.0.3 [65] imports
datafeeds-web_1.0.0 [486] imports

However, Option4: we need to check if the package already 'exported' by OSGi and reuse it. If it is not available, we must explicitly have "lib" folder with JAR file inside; Gradle won't do that for us.
g! packages org.tukaani.xz
No exported packages

- "xz.jar" is inside ROOT/WEB-INF/lib and it is not visible.
I'm using the folowing dependency:
runtime group: 'org.codehaus.jackson', name: 'jackson-mapper-asl', version: '1.9.13'
I get a compile error:
error: package org.codehaus.jackson.map does not exist
import org.codehaus.jackson.map.ObjectMapper;

On the other hand, when I use "compile" scope I'm able to compile. But after that I have the error:
Can not find JAR file 'jackson-core-asl-1.9.13.jar'

Any ideias?
So these are gradle things, but "compile" scope means you need the dependencies to compile the code. "Runtime" means the dependency is necessary for running the module only.

Are you getting the jar not found when you deploy or are you trying to add as a dependency?
I get a "jar not found" when I try to compile my code:
gradle build

I manage to make it work by adding a new dependecy on gradle:
compile group: 'org.codehaus.jackson', name: 'jackson-core-asl', version: '1.9.13'

But, since jackson-mapper-asl already depends on jackson-core-asl it seems wrong to add that dependency on gradle.

Besides that, I had to include in my bnd.bnd the folowing:
Import-Package: !org.codehaus.jackson, \
!org.codehaus.jackson.annotate, \
!org.codehaus.jackson.format, \
!org.codehaus.jackson.impl, \
!org.codehaus.jackson.io, \
!org.codehaus.jackson.type, \
!org.codehaus.jackson.util, \
!org.joda.time, \
!org.joda.time.format, \
!org.w3c.dom, \
!org.w3c.dom.bootstrap, \
!org.w3c.dom.ls, \
!org.xml.sax, \
*
Is it really necessary?
Sorry, I have a problem. I need you help
build.gradle:
runtime group: 'org.elasticsearch', name: 'elasticsearch', version: '2.2.0'
Include-Resource:\
@jackson-core-2.6.2.jar,\
@jackson-databind-2.6.2.jar,\
@hppc-0.7.1.jar,\
@elasticsearch-2.2.0.jar

I start by gogo shell display: Unresolved requirement: Import-Package: com.fasterxml.jackson.core
[...] The only addition to the file is the Include-Resource BND declaration. As I previously covered in my blog post about OSGi Module Dependencies, this is the declaration used to create an Uber... [...] Read More
[...] The only addition to the file is the Include-Resource BND declaration. As I previously covered in my blog post about OSGi Module Dependencies, this is the declaration used to create an Uber... [...] Read More
Hey Dave,

Happy New Year! I hope you had a nice holiday.

I have run into an issue on Liferay 7 related to the classloader. I'm writing an OSGi module and I'm getting a ClassCastException (ClassA cannot be cast to ClassA - same class) when I pull a custom class I wrote from my jndi context.

I know this error is being thrown because my class is being loaded by 2 separate classloaders.

There are 2 jars deployed which contain this class.

1. One is in the global classpath (tomcat/lib/ext). I need this one to stay there.
2. The other one is deployed as an OSGi module so another OSGI module service can use this class. I am looking for a way to avoid this step. I just want all my OSGi modules to see the jars in the global classpath without having to deploy them explicitly. I believe once I do this, my ClassCastException will go away. I was recommended to use an extension bundle, but after I deployed the bundle, it still does not show up when I do the 'packages' command in gogo shell.

Any ideas that might help?

Thanks - as always.
Clint
If it has to be in the global class loader, follow the model for the JDBC drivers; keep jars in global but add packages to the module.framework.system.packages.extra property in portal-ext.properties.

Note this is not something you want to do regularly as it can lead to a polluted class loader, but it will allow you to use a JNDI resource in this fashion.
Thanks for the quick response Dave!

So are you saying I just add that property, like this

module.framework.system.packages.extra=my.package

then my OSGi container can see that package, and it can be used in other modules as dependencies (which is in the jar inside tomcat\lib\ext)?

If I understand correctly, that sounds very straight forward.

Thanks again!
Thanks David, this was really usefull.
However I have one futher question:

When I try to add a jar with a lot of dependencies, for example: 'com.microsoft.sqlserver:mssql-jdbc:6.1.0.jre8'

Do i really have to add all the necessary dependencies manually to build.gradle and bnd.bnd?

Is there no way to tell the build process to also include all the dependencies of said jar?
I mean, while running the 'dependencies'-task the output will show me all necessary jar files and the Explorer of Eclise also shows all the need jars, which are already downloaded...

From the exmplanation I've read:
compile('com.microsoft.sqlserver:mssql-jdbc:6.1.0.jre8') {
transitive = true;
}
setting transitive to true (which should also be the default) should dor the trick... but not for me however.

It just does not feel right to load every dependency on your own...
I'm pretty sure there is a possiblity to recursively load all the dependencies, I just did not ran into it yet.


Many Thanks in advance!

Best Regards
Cloud
So this is actually a common misconception - there is a difference between building in gradle using the dependency manager and the OSGi runtime environment that does not have a similar dependency manager.

OSGi purposely does not download dependencies, especially transitive dependencies, as this would lead to an unstable environment.

The build process will include transitive dependencies when compiling your code, but BND is not a compiler it's just building the jar file and including what you tell it to.

So yes, under normal circumstances, you must include all dependencies and transitive dependencies yourself. That said, some projects don't use "optional" markers in their transitive dependencies so OSGi sees them as must-haves. You have to add the classpath declaration in the BND file to forcibly exclude those packages that you really don't want.

This is definitely a PITA, but it's that way for a reason. The OSGi environment is your runtime environment and it is one that you want to actively manage and be aware of. As an administrator you want to know what your modules are using and manage deployments appropriately. From an administrative perspective, you wouldn't want the environment just downloading things on it's own (and often times this is not not possible in production environments anyway).

One final suggestion - use JNDI and data sources for your database connection. You can access a DataSource in your OSGi module without including the driver and all of the relevant dependencies in your own module...
Hi DAVID H NEBINGER

I am trying to download file from "S3 AWS" Using below dependency, but module is not started.

1. Added following dependency
compile group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.6.6'
compile group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: '2.6.0'
compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.6.6'
compile group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-cbor', version: '2.6.6'
compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.2'
compile group: 'org.apache.httpcomponents', name: 'httpcore', version: '4.4'
compile group: 'com.amazonaws', name: 'aws-java-sdk-core', version: '1.11.119'
compile group: 'com.amazonaws', name: 'aws-java-sdk-iot', version: '1.11.119'
compile group: 'com.amazonaws', name: 'aws-java-sdk-s3', version: '1.11.119'

runtime group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.6.6'
runtime group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: '2.6.0'
runtime group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.6.6'
runtime group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-cbor', version: '2.6.6'
runtime group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.2'
runtime group: 'org.apache.httpcomponents', name: 'httpcore', version: '4.4'
runtime group: 'com.amazonaws', name: 'aws-java-sdk-core', version: '1.11.119'
runtime group: 'com.amazonaws', name: 'aws-java-sdk-iot', version: '1.11.119'
runtime group: 'com.amazonaws', name: 'aws-java-sdk-s3', version: '1.11.119'

2. included the resources in bnd.bn

Liferay-Service: true

Bundle-ClassPath:\
.,\
lib/aws-java-sdk-s3.jar,\
lib/aws-java-sdk-core.jar,\
lib/aws-java-sdk-iot.jar,\
lib/httpclient.jar,
lib/jackson-core.jar,\
lib/jackson-databind.jar,\
lib/jackson-dataformat.jar

-includeresource:\
lib/aws-java-sdk-s3.jar=aws-java-sdk-s3-1.11.119.jar, \
lib/aws-java-sdk-core.jar=aws-java-sdk-core-1.11.119.jar, \
lib/aws-java-sdk-iot.jar=aws-java-sdk-iot-1.11.119.jar, \
lib/httpclient.jar=httpclient-4.5.2.jar, \
lib/jackson-core.jar=jackson-core-2.6.6.jar, \
lib/jackson-databind.jar=jackson-databind-2.6.6.jar, \
lib/jackson-dataformat.jar=jackson-dataformat-cbor-2.6.6.jar

3. Deployed my module.
4. Restarted liferay portal server.

Thank You.
Did you try to start your module? If so, it probably reports what the problem is, likely that will be some sort of direct or transitive dependency.
HI DAVID H NEBINGER

Thanks for the reply.

I Tried this diag <bundle ID> in Felix Gogo shell, I got this

Unresolved requirement: Import-Package: com.amazonaws.auth
Below is my bnd.bnd file

Bundle-Name: LotDetails
Bundle-SymbolicName: com.lotdetails
Bundle-Version: 2.0.0
-jsp: *.jsp,*.jspf
-plugin.bundle: com.liferay.ant.bnd.resource.bundle.ResourceBundleLoaderAnalyzerPlugin
-plugin.jsp: com.liferay.ant.bnd.jsp.JspAnalyzerPlugin
-sources: true
Bundle-ClassPath:\
.,\
lib/jackson-annotations.jar
-includeresource:\
lib/jackson-annotations.jar=jackson-annotations-2.8.8.jar
below is my bundle.gradle file

dependencies {
compileOnly group: "com.liferay.portal", name: "com.liferay.portal.kernel", version: "2.0.0"
compileOnly group: "com.liferay.portal", name: "com.liferay.util.taglib", version: "2.0.0"
compileOnly group: "javax.portlet", name: "portlet-api", version: "2.0"
compileOnly group: "javax.servlet", name: "javax.servlet-api", version: "3.0.1"
compileOnly group: "jstl", name: "jstl", version: "1.2"
compileOnly group: "org.osgi", name: "osgi.cmpn", version: "6.0.0"
compileOnly group: "org.osgi", name: "org.osgi.service.component.annotations", version: "1.3.0"
compileOnly group: "commons-httpclient", name: "commons-httpclient", version: "3.1"
compileOnly group: "commons-lang", name: "commons-lang", version: "2.6"

compileOnly group: "junit", name: "junit", version: "4.12"
compileOnly group: "com.fasterxml.jackson.core", name: "jackson-core", version: "2.8.8"
compileOnly group: "com.fasterxml.jackson.core", name: "jackson-databind", version: "2.8.8"
compileOnly group: "com.fasterxml.jackson.core", name: "jackson-annotations", version: "2.8.8"
}

still getting the below message

dependencies {
compileOnly group: "com.liferay.portal", name: "com.liferay.portal.kernel", version: "2.0.0"
compileOnly group: "com.liferay.portal", name: "com.liferay.util.taglib", version: "2.0.0"
compileOnly group: "javax.portlet", name: "portlet-api", version: "2.0"
compileOnly group: "javax.servlet", name: "javax.servlet-api", version: "3.0.1"
compileOnly group: "jstl", name: "jstl", version: "1.2"
compileOnly group: "org.osgi", name: "osgi.cmpn", version: "6.0.0"
compileOnly group: "org.osgi", name: "org.osgi.service.component.annotations", version: "1.3.0"
compileOnly group: "commons-httpclient", name: "commons-httpclient", version: "3.1"
compileOnly group: "commons-lang", name: "commons-lang", version: "2.6"

compileOnly group: "junit", name: "junit", version: "4.12"
compileOnly group: "com.fasterxml.jackson.core", name: "jackson-core", version: "2.8.8"
compileOnly group: "com.fasterxml.jackson.core", name: "jackson-databind", version: "2.8.8"
compileOnly group: "com.fasterxml.jackson.core", name: "jackson-annotations", version: "2.8.8"
}


Help me out on it.
[...] So if you've started developing for Liferay 7 CE / Liferay DXP, I'm sure you've been hit at one point or another with the old "unresolved reference" issue that prevents your bundle from starting.... [...] Read More
[...] Christoph Rabel: I fully agree with you, the documentation could be better here. Maybe it is crystal clear for people who work for years with OSGI, but it took me quite a while to figure it out... [...] Read More
[...] Check my blog: http://web.liferay.com/web/user.26526/blog/-/blogs/osgi-module-dependencies Come meet me at Devcon 2017 or 2017 LSNA! Sign in to vote. Flag Please sign in to flag this as... [...] Read More
I am trying to get this problem sorted out using option #4 and I'm running into a problem- I posted a description on the forums: https://web.liferay.com/community/forums/-/message_boards/message/92655806
[...] Hi everyone! I am faising the following issue. Let me write about my portlet first: My portlet code is: 1 2*** 3import com.liferay.portal.kernel.portlet.bridges.mvc.MVCPortlet; 4*** ... [...] Read More
I am tried as per the post to generate pdf and below is the build.gradle dependency

compileOnly group: "com.lowagie", name: "itext", version: "4.2.2", ext: "pom"
compileOnly group: "com.itextpdf", name: "itextpdf", version: "5.5.12"
compileOnly group: "org.bouncycastle", name: "bcmail-jdk15", version: "1.46"
compileOnly group: "org.bouncycastle", name: "bcprov-jdk16", version: "1.46"

while deply got the below exception
---------------------------------------------------------------------------------------------------------
:modules:pdftest:compileJavaD:\liferay7\lr7work\modules\pdftest\src\main\java\com\pdf\test\portlet\PdfTestPortlet.java:4: error: package com.itextpdf.text does not exist
import com.itextpdf.text.Document;
^
D:\liferay7\lr7work\modules\pdftest\src\main\java\com\pdf\test\portlet\PdfTestPortlet.java:5: error: package com.itextpdf.text does not exist
import com.itextpdf.text.DocumentException;
^
D:\liferay7\lr7work\modules\pdftest\src\main\java\com\pdf\test\portlet\PdfTestPortlet.java:6: error: package com.itextpdf.text does not exist
import com.itextpdf.text.Font;
^
D:\liferay7\lr7work\modules\pdftest\src\main\java\com\pdf\test\portlet\PdfTestPortlet.java:7: error: package com.itextpdf.text does not exist
import com.itextpdf.text.Header;
^
D:\liferay7\lr7work\modules\pdftest\src\main\java\com\pdf\test\portlet\PdfTestPortlet.java:8: error: package com.itextpdf.text does not exist
import com.itextpdf.text.PageSize;
^
D:\liferay7\lr7work\modules\pdftest\src\main\java\com\pdf\test\portlet\PdfTestPortlet.java:9: error: package com.itextpdf.text does not exist
import com.itextpdf.text.Paragraph;
^
D:\liferay7\lr7work\modules\pdftest\src\main\java\com\pdf\test\portlet\PdfTestPortlet.java:10: error: package com.itextpdf.text does not exist
import com.itextpdf.text.Rectangle;
^
D:\liferay7\lr7work\modules\pdftest\src\main\java\com\pdf\test\portlet\PdfTestPortlet.java:11: error: package com.itextpdf.text.pdf does not exist
import com.itextpdf.text.pdf.PdfPageEvent;
^
D:\liferay7\lr7work\modules\pdftest\src\main\java\com\pdf\test\portlet\PdfTestPortlet.java:12: error: package com.itextpdf.text.pdf does not exist
import com.itextpdf.text.pdf.PdfWriter;
^
D:\liferay7\lr7work\modules\pdftest\src\main\java\com\pdf\test\portlet\PdfTestPortlet.java:51: error: cannot find symbol
Document document = new Document(PageSize.A4, 30, 30, 50, 50);
^
symbol: class Document
location: class PdfTestPortlet
D:\liferay7\lr7work\modules\pdftest\src\main\java\com\pdf\test\portlet\PdfTestPortlet.java:51: error: cannot find symbol
Document document = new Document(PageSize.A4, 30, 30, 50, 50);
^
symbol: class Document
location: class PdfTestPortlet
D:\liferay7\lr7work\modules\pdftest\src\main\java\com\pdf\test\portlet\PdfTestPortlet.java:51: error: cannot find symbol
Document document = new Document(PageSize.A4, 30, 30, 50, 50);
^
symbol: variable PageSize
location: class PdfTestPortlet
D:\liferay7\lr7work\modules\pdftest\src\main\java\com\pdf\test\portlet\PdfTestPortlet.java:54: error: cannot find symbol
PdfWriter writer;
^
symbol: class PdfWriter
location: class PdfTestPortlet
D:\liferay7\lr7work\modules\pdftest\src\main\java\com\pdf\test\portlet\PdfTestPortlet.java:57: error: cannot find symbol
writer = PdfWriter.getInstance(document, byteArrayOutputStream);
^
symbol: variable PdfWriter
location: class PdfTestPortlet
D:\liferay7\lr7work\modules\pdftest\src\main\java\com\pdf\test\portlet\PdfTestPortlet.java:58: error: cannot find symbol
Header event = new Header("HEADR","Welcome");
^
symbol: class Header
location: class PdfTestPortlet
D:\liferay7\lr7work\modules\pdftest\src\main\java\com\pdf\test\portlet\PdfTestPortlet.java:58: error: cannot find symbol
Header event = new Header("HEADR","Welcome");
^
symbol: class Header
location: class PdfTestPortlet
D:\liferay7\lr7work\modules\pdftest\src\main\java\com\pdf\test\portlet\PdfTestPortlet.java:59: error: cannot find symbol
writer.setBoxSize("art", new Rectangle(500,700));
^
symbol: class Rectangle
location: class PdfTestPortlet
D:\liferay7\lr7work\modules\pdftest\src\main\java\com\pdf\test\portlet\PdfTestPortlet.java:60: error: cannot find symbol
writer.setPageEvent((PdfPageEvent) event);
^
symbol: class PdfPageEvent
location: class PdfTestPortlet
D:\liferay7\lr7work\modules\pdftest\src\main\java\com\pdf\test\portlet\PdfTestPortlet.java:61: error: cannot find symbol
Font fontOne = new Font() ;
^
symbol: class Font
location: class PdfTestPortlet
D:\liferay7\lr7work\modules\pdftest\src\main\java\com\pdf\test\portlet\PdfTestPortlet.java:61: error: cannot find symbol
Font fontOne = new Font() ;
^
symbol: class Font
location: class PdfTestPortlet
D:\liferay7\lr7work\modules\pdftest\src\main\java\com\pdf\test\portlet\PdfTestPortlet.java:64: error: cannot find symbol
fontOne.setStyle(Font.BOLD);
^
symbol: variable Font
location: class PdfTestPortlet
D:\liferay7\lr7work\modules\pdftest\src\main\java\com\pdf\test\portlet\PdfTestPortlet.java:65: error: cannot find symbol
Paragraph paragraphOne = new Paragraph("PARGARPH TEST", fontOne);
^
symbol: class Paragraph
location: class PdfTestPortlet
D:\liferay7\lr7work\modules\pdftest\src\main\java\com\pdf\test\portlet\PdfTestPortlet.java:65: error: cannot find symbol
Paragraph paragraphOne = new Paragraph("PARGARPH TEST", fontOne);
^
symbol: class Paragraph
location: class PdfTestPortlet
D:\liferay7\lr7work\modules\pdftest\src\main\java\com\pdf\test\portlet\PdfTestPortlet.java:66: error: cannot find symbol
paragraphOne.setAlignment(Paragraph.ALIGN_RIGHT);
^
symbol: variable Paragraph
location: class PdfTestPortlet
D:\liferay7\lr7work\modules\pdftest\src\main\java\com\pdf\test\portlet\PdfTestPortlet.java:81: error: cannot find symbol
} catch (DocumentException e) {
^
symbol: class DocumentException
location: class PdfTestPortlet
25 errors
FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':modules:pdftest:compileJava'.
> Compilation failed; see the compiler error output for details.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
-------------------------------------------------------

can someone assist me where i am wrong ?