Hot questions for Using GlassFish in osgi

Question:

I have a bunle which needs the new version of osgi (org.osgi.core 6.0.0). And I need to deploy this bundle in GF 4.1.1 open source version. By default in GF there is an old version of apache felix (4.2.1) so I replaced file glassfish4/glassfish/osgi/felix/bin/felix.jar to version 5.4.0 (I renamed org.apache.felix.framework-5.4.0.jar to felix.jar). After that I cleaned felix cache in domain and started GF. GF seems to work without any problems however I can't deploy my bundle as I get:

[2016-06-13T16:09:04.036+0300] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=287 _ThreadName=Thread-8] [timeMillis: 1465823344036] [levelValue: 800] [[
  org.osgi.framework.BundleException: Unable to resolve com.temp [248](R 248.0): missing requirement [com.temp [248](R 248.0)] osgi.wiring.package; 
(&(osgi.wiring.package=org.osgi.framework)(version>=1.8.0)(!(version>=2.0.0))) Unresolved requirements: [[com.temp [248](R 248.0)] osgi.wiring.package; (&(osgi.wiring.package=org.osgi.framework)(version>=1.8.0)(!(version>=2.0.0)))]
    at org.apache.felix.framework.Felix.resolveBundleRevision(Felix.java:4111)
    at org.apache.felix.framework.Felix.startBundle(Felix.java:2117)
    at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:998)
    at org.apache.felix.fileinstall.internal.DirectoryWatcher.process(DirectoryWatcher.java:1175)
    at org.apache.felix.fileinstall.internal.DirectoryWatcher.process(DirectoryWatcher.java:1153)
    at org.apache.felix.fileinstall.internal.DirectoryWatcher.processAllBundles(DirectoryWatcher.java:1146)
    at org.apache.felix.fileinstall.internal.DirectoryWatcher.process(DirectoryWatcher.java:456)
    at org.apache.felix.fileinstall.internal.DirectoryWatcher.run(DirectoryWatcher.java:263)]]

I've checked org.apache.felix.framework-5.4.0.jar there is default.properties and org.osgi.framework 1.8.0 package is exported. How to fix it?


Answer:

The problem was fixed by editing glassfish4/glassfish/config/osgi.properties file

Question:

As everyone knows jsp can't work with classes outside current osgi web archive bundle. This is a bug in GF. The developers of glassfish for workaround of this bug https://java.net/jira/browse/GLASSFISH-11208 offer to use offline jsp compiler (by other words to compile jsp files not during deployment time but during archive building time). Ok, and I used jspc-maven-plugin to compile my jsp during wab building.

<plugin>
 <groupId>org.codehaus.mojo</groupId>
 <artifactId>jspc-maven-plugin</artifactId>
 <version>1.4.6</version>
 <executions>
     <execution>
         <goals>
             <goal>compile</goal>
         </goals>
         <id>compile</id>
     </execution>
 </executions>
 <configuration>
 </configuration>
</plugin>

The jsp are compiled and I see their .classes in built web archive.

Now the problem - how can I make glassfish use my compiled jsp but not to compile it itself? Because I see that GF ignores compiled .classes and generate .javas and compile them itself.

EDIT 1 What I make up to now: 1) I added to glassfish-web.xml

  <jsp-config>
        <property name="usePrecompiled" value="true"/>
        <!-- to see it doesn't generate .javas -->
        <property name="keepgenerated" value="true" />
    </jsp-config>

2)And when I build my wab archive I have jsp classes in WEB-INF/classes/jsp/... However, I get exception that jsp file not found. When I manually move jsp classes to WEB-INF/classes/org/apache/jsp... I see that container now sees these classes but I get

  StandardWrapperValve[default]: Servlet.service() for servlet default threw exception
java.lang.NoClassDefFoundError: org/apache/jsp/... (wrong name: jsp/...)
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:760)
    at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.defineClass(BundleWiringImpl.java:2370)
    at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.findClass(BundleWiringImpl.java:2154)
    at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1542)
    at org.apache.felix.framework.BundleWiringImpl.access$400(BundleWiringImpl.java:79)
    at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:2018)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at org.apache.felix.framework.Felix.loadBundleClass(Felix.java:1925)
    at org.apache.felix.framework.BundleImpl.loadClass(BundleImpl.java:978)
    at org.glassfish.osgijavaeebase.BundleClassLoader.loadClass(BundleClassLoader.java:79)
    at org.glassfish.osgiweb.OSGiWebDeploymentContext$WABClassLoader.loadClass(OSGiWebDeploymentContext.java:169)
    at org.glassfish.osgiweb.OSGiWebDeploymentContext$WABClassLoader.loadClass(OSGiWebDeploymentContext.java:154)
    at org.apache.jasper.JspCompilationContext.load(JspCompilationContext.java:654)
    at org.apache.jasper.servlet.JspServletWrapper.getServlet(JspServletWrapper.java:202)
    at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:388)
    at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:473)
    at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:377)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
    at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1682)
    at org.apache.catalina.core.ApplicationDispatcher.doInvoke(ApplicationDispatcher.java:875)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:739)
    at org.apache.catalina.core.ApplicationDispatcher.doInclude(ApplicationDispatcher.java:695)
    at org.apache.catalina.core.ApplicationDispatcher.include(ApplicationDispatcher.java:626)

So know this is the right path - org/apache/jsp. The question is how to make maven plugin to output to this direction?

EDIT 2 So I found the settings of this maven plugin -

<plugin>
 <groupId>org.codehaus.mojo</groupId>
 <artifactId>jspc-maven-plugin</artifactId>
 <version>1.4.6</version>
 <executions>
     <execution>
         <goals>
             <goal>compile</goal>
         </goals>
         <id>compile</id>
         <configuration>
             <packageName>org.apache.jsp</packageName>
         </configuration>
     </execution>
 </executions>
 <configuration>
 </configuration>
</plugin>

However, this is the final point but not result. As I get no exception, bute the returned http request is empty (blank page in browser). Seems I should use another maven plugin but which one?


Answer:

So, to all steps which I did and explained in my edit it is necessary to modify web.xml file because plugin will add there mapping for servlets generated from jsp pages. So, the final settings are :

<plugin>
 <groupId>org.codehaus.mojo</groupId>
 <artifactId>jspc-maven-plugin</artifactId>
 <version>1.4.6</version>
 <executions>
     <execution>
         <goals>
             <goal>compile</goal>
         </goals>
         <id>compile</id>
         <configuration>
             <!-- package where the compiled jsp classes will be put -->
             <packageName>org.apache.jsp</packageName>
             <!-- the plugin adds servlets to this web.xml file -->
<outputWebXml>${project.build.directory}/web.xml</outputWebXml>
          <verbose>true</verbose>
         <target>8</target>
         <source>8</source>
         </configuration>
     </execution>
 </executions>
 <configuration>
 </configuration>
</plugin>

EDIT Finally I found out that the version of jasper in GlassFish 4.1 is not known or even can be modified -> I got exceptions that such method not found etc. So I ended with the following - I donwloaded the sources of this plugin and made it use the version of the jasper in glassfish. I did not do any modifications in source code of the plugin, only in pom.xml. So the final pom became:

<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/maven-v4_0_0.xsd">
  <!--<parent>
    <artifactId>mojo</artifactId>
    <groupId>org.codehaus.mojo</groupId>
    <version>11</version>
  </parent>-->
    <modelVersion>4.0.0</modelVersion>
      <groupId>org.codehaus.mojo</groupId>
    <artifactId>jspc-maven-plugin</artifactId>
    <version>1.4.6</version>
    <packaging>maven-plugin</packaging>
    <name>Maven Jspc plugin</name>
    <developers>
        <developer>
            <name>Jeff Genender</name>
            <email>jgenender@apache.org</email>
            <organization>Savoir Technologies</organization>
            <organizationUrl>http://www.savoirtech.com</organizationUrl>
            <timezone>-7</timezone>
        </developer>
    </developers>
    <contributors>
        <contributor>
            <name>Grzegorz Slowikowski</name>
            <email>gs@tiger.com.pl</email>
            <organization>Scott Tiger S.A.</organization>
            <organizationUrl>http://www.tiger.com.pl</organizationUrl>
            <timezone>+1</timezone>
        </contributor>
        <contributor>
            <name>Pawel Pastula</name>
            <email>pablo@tiger.com.pl</email>
            <organization>Scott Tiger S.A.</organization>
            <organizationUrl>http://www.tiger.com.pl</organizationUrl>
            <timezone>+1</timezone>
        </contributor>
    </contributors>

    <dependencies>
        <!-- from glassfish 4.1.1 modules folder we need:
        javax.servlet.jsp.jar
        javax.servlet-api.jar
        javax.servlet.jsp-api.jar
        javax.el.jar
        javax.servlet.jsp.jstl-api.jar
        javax.servlet.jsp.jstl.jar
        what versions of this jar you can find out in parent pom of glassfish
        http://repo.maven.apache.org/maven2/org/glassfish/main/glassfish-parent/4.1.1/glassfish-parent-4.1.1.pom
        and in manifest file
        -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.3.2-b01</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.web</groupId>
            <artifactId>javax.servlet.jsp</artifactId>
            <version>2.3.3-b02</version>
        </dependency>        
        <dependency>
            <groupId>org.glassfish</groupId>
            <artifactId>javax.el</artifactId>
            <version>3.0.0</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp.jstl</groupId>
            <artifactId>javax.servlet.jsp.jstl-api</artifactId>
            <version>1.2.1</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.web</groupId>
            <artifactId>javax.servlet.jsp.jstl</artifactId>
            <version>1.2.4</version>
        </dependency>
        <!-- we need this dependency as it contais tld files for core tag library -->
        <dependency>
            <groupId>org.eclipse.jetty.orbit</groupId>
            <artifactId>org.apache.jasper.glassfish</artifactId>
            <version>2.2.2.v201112011158</version>
        </dependency>
        <dependency>
            <groupId>ant</groupId>
            <artifactId>ant</artifactId>
            <version>1.6.5</version>
        </dependency>        
        <dependency>
            <groupId>org.apache.maven</groupId>
            <artifactId>maven-plugin-api</artifactId>
            <version>2.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.maven</groupId>
            <artifactId>maven-project</artifactId>
            <version>2.0</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.13</version>
            <scope>runtime</scope>
        </dependency>        
    </dependencies>
</project>

When you will compile you bundle you will have to add the following dependencies:

<dependency>
    <groupId>org.glassfish.web</groupId>
    <artifactId>javax.servlet.jsp</artifactId>
    <version>2.3.3-b02</version>
</dependency>       
<dependency>
    <groupId>org.glassfish.web</groupId>
    <artifactId>javax.servlet.jsp.jstl</artifactId>
    <version>1.2.4</version>
</dependency>

Besides you will need to import some packages from glassfish to make it work. So in result you can use precompiled jps files with glassfish, but you need to make some things before it. And as you see you link your code to GF.

The most important thing - you can work with classes from other osgi bundles in jsp! For those who work with osgi in java-ee this can be very important. After doing all these steps I must conclude that GF IS NOT SUPPORTED TO BE USED WITH PRECOMPILED JPS FILES in spite of suggestions from the developers.

I hope at least one will appreciate all the solution, because it seems to me this is the first description in internet how to use precompiled jps pages with GF. By the way if you use osgi and it complains it can't find classes import the necessary packages.

Question:

As I understand right every osgi bundle has its own cdi container. So I have the following situation - I have two bundles: A and B. Bundles are deployed in glassfish4. In bundle A I have cdi beans. In bundle B I don't have beans.xml -> no cdi container for the bundle B is created.

In bundle B I have a reference to bundle A (Bundle bundleA). How can I get in bundle B reference to bundle A cdi container. My current solution (in bundle B):

BeanManager bm = CDI.current().getBeanManager();

throws exception:

StandardWrapperValve[default]: Servlet.service() for servlet default threw exception

org.jboss.weld.exceptions.IllegalStateException: WELD-001328: Unable to identify the correct BeanManager. The calling class com.temp.MyClass is not placed in bean archive
    at org.jboss.weld.SimpleCDI.unsatisfiedBeanManager(SimpleCDI.java:89)
    at org.glassfish.weld.GlassFishWeldProvider$GlassFishEnhancedWeld.unsatisfiedBeanManager(GlassFishWeldProvider.java:89)
    at org.jboss.weld.SimpleCDI$ClassNameToBeanManager.findBeanManager(SimpleCDI.java:67)
    at org.jboss.weld.SimpleCDI$ClassNameToBeanManager.load(SimpleCDI.java:47)
    at org.jboss.weld.SimpleCDI$ClassNameToBeanManager.load(SimpleCDI.java:40)
    at com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3589)
    at com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2374)
    at com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2337)
    at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2252)
    at com.google.common.cache.LocalCache.get(LocalCache.java:3990)
    at com.google.common.cache.LocalCache.getOrLoad(LocalCache.java:3994)
    at com.google.common.cache.LocalCache$LocalLoadingCache.get(LocalCache.java:4878)
    at com.google.common.cache.LocalCache$LocalLoadingCache.getUnchecked(LocalCache.java:4884)
    at org.jboss.weld.SimpleCDI.getBeanManager(SimpleCDI.java:105)
    at org.jboss.weld.SimpleCDI.getBeanManager(SimpleCDI.java:38)

Answer:

Calling BeanManager bm = CDI.current().getBeanManager(); is the correct way to obtain a BeanManager for current bean archive. E.g. the bean archive to which the class where you invoke this belongs. That would be bundle B in your case. And you do not have a beans.xml there hence the exception.

As I understand right every osgi bundle has its own cdi container.

I am not much familiar with OSGI but from Weld perspective that would work. Weld sees any form of archive (jar, war, ...) as bean archive and for one bean archive you have one manager.

If you want a reference to BM from bundle A, obtain it there and expose a getter I suppose. The point is you need to invoke getBeanManager() from the actual archive it belongs to.

Maybe if you elaborated on what do you aim to achieve with that BM, I might help you further. Generaly speaking I would refrain from obtaining references to BMs from other archives. You can always have an exposed API and let the original archive deliver the services to you.

Question:

I am trying to deploy a simple OSGI bundle (hello world) in glassfish 4.1.1 but I got the following error:

Infos:   org.osgi.framework.BundleException: 
Unresolved constraint in bundle com.mycompany.MavenHelloServiceImpl [324]:
  Unable to resolve 324.0: missing requirement [324.0] 
    osgi.wiring.package; (osgi.wiring.package=com.mycompany.mavenhelloserviceapi)
at org.apache.felix.framework.Felix.resolveBundleRevision(Felix.java:3974)

I don't know how to fix the missing package , I already defined "com.mycompany.mavenhelloserviceapi" as a dependency in the bundle MavenHelloServiceImpl and it is present in the dependencies folder in the bundle MavenHelloServiceImpl Any idea how to fix this error ?!


Answer:

Having com.mycompany.mavenhelloserviceapi as a dependency in your pom.xml is not enough : the pom is about compile-time dependencies. you see here an issue about a runtime dependency missing.

You should install com.mycompany.mavenhelloserviceapi in your container.

Question:

I use glassfish 4.0.1 + openjdk 8. All my application is osgi based. I have a wab and jsp in it with scriptlets. These scriplets import some classes. These classes are in another budnles. These classes exist and exported (other bundles, not wab use them without problem).

However I get the following error:

Servlet.service() for servlet jsp threw exception org.apache.jasper.JasperException: PWC6033: Error in Javac compilation for JSP

PWC6199: Generated servlet error: package com.mycom.test does not exist

PWC6197: An error occurred at line: 36 in the jsp file: /index.jsp PWC6199: Generated servlet error: cannot find symbol symbol: class Foo location: class org.apache.jsp....index_jsp

I've checked several times - necessary packages are in Inport-package list. But jasper doesn't see them.

Besides, I have in my pom

 <plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-war-plugin</artifactId>
   <version>2.3</version>
      <configuration>
        <archive>
           <manifestFile>
           ${project.build.outputDirectory}/META-INF/MANIFEST.MF
                        </manifestFile>
           <manifestEntries>
           <Bundle-ClassPath>WEB-INF/classes/</Bundle-ClassPath>
          </manifestEntries>
        </archive>
     <failOnMissingWebXml>false</failOnMissingWebXml>
    </configuration>
 </plugin>

How can I fix it?


Answer:

I found the answer, this is not the solution but the explanation of this bug.

https://www.java.net/forum/topic/glassfish/glassfish/should-jsps-wab-deployment-have-access-external-osgi-bundle-classes

and

https://java.net/jira/browse/GLASSFISH-11208