RE: Change exported packages of com.liferay.portal.search.elasticsearch bun

thumbnail
Dominik Marks, modified 5 Years ago. Regular Member Posts: 149 Join Date: 8/29/12 Recent Posts
I would like to write my own FacetProcessor to influence how a custom field is handled as a facet. In my case I would like to tell elasticsearch to create a facet as date type instead of text.

Therefore I wrote my own component of type com.liferay.portal.search.elasticsearch.internal.facet.FacetProcessor. Because the package com.liferay.portal.search.elasticsearch.internal.facet is not exported from the com.liferay.portal.search.elasticsearch bundle I wrote a Fragment-Host for that bundle and added that package to the exported packages (as shown in this blog post: https://liferay.dev/blogs/-/blogs/fixing-module-package-access-modifiers):
Fragment-Host: com.liferay.portal.search.elasticsearch;bundle-version="[2.0,3)"
Export-Package: \
    com.liferay.portal.search.elasticsearch.internal.facet

However adding that Fragment-Host seems to break the classpath of the elasticsearch bundle. Now every request to the index causes an NoClassDefFoundError as follows:

Caused by: TransportSerializationException[Failed to deserialize response of type [org.elasticsearch.action.admin.cluster.state.ClusterStateResponse]]; nested: NoClassDefFoundError[Could not initialize class org.elasticsearch.common.lucene.Lucene];
        at org.elasticsearch.transport.netty.MessageChannelHandler.handleResponse(MessageChannelHandler.java:152)
        at org.elasticsearch.transport.netty.MessageChannelHandler.messageReceived(MessageChannelHandler.java:124)
        at org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:70)
        at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564)
        at org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:791)
        at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:296)
        at org.jboss.netty.handler.codec.frame.FrameDecoder.unfoldAndFireMessageReceived(FrameDecoder.java:462)
        at org.jboss.netty.handler.codec.frame.FrameDecoder.callDecode(FrameDecoder.java:443)
        at org.jboss.netty.handler.codec.frame.FrameDecoder.messageReceived(FrameDecoder.java:303)
        at org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:70)
        at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564)
        at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:559)
        at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:268)
        at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:255)
        at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:88)
        at org.jboss.netty.channel.socket.nio.AbstractNioWorker.process(AbstractNioWorker.java:108)
        at org.jboss.netty.channel.socket.nio.AbstractNioSelector.run(AbstractNioSelector.java:337)
        at org.jboss.netty.channel.socket.nio.AbstractNioWorker.run(AbstractNioWorker.java:89)
        at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:178)
        at org.jboss.netty.util.ThreadRenamingRunnable.run(ThreadRenamingRunnable.java:108)
        at org.jboss.netty.util.internal.DeadLockProofWorker$1.run(DeadLockProofWorker.java:42)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.elasticsearch.common.lucene.Lucene
        at org.elasticsearch.Version.fromId(Version.java:584)
        at org.elasticsearch.Version.readVersion(Version.java:318)
        at org.elasticsearch.cluster.node.DiscoveryNode.readFrom(DiscoveryNode.java:339)
        at org.elasticsearch.cluster.node.DiscoveryNode.readNode(DiscoveryNode.java:322)
        at org.elasticsearch.cluster.node.DiscoveryNodes.readFrom(DiscoveryNodes.java:594)
        at org.elasticsearch.cluster.node.DiscoveryNodes$Builder.readFrom(DiscoveryNodes.java:674)
        at org.elasticsearch.cluster.ClusterState.readFrom(ClusterState.java:699)
        at org.elasticsearch.cluster.ClusterState$Builder.readFrom(ClusterState.java:677)
        at org.elasticsearch.action.admin.cluster.state.ClusterStateResponse.readFrom(ClusterStateResponse.java:58)
        at org.elasticsearch.transport.netty.MessageChannelHandler.handleResponse(MessageChannelHandler.java:150)

I am using Liferay 7.0.6 GA7 (including the latest security patches).
thumbnail
Dominik Marks, modified 5 Years ago. Regular Member Posts: 149 Join Date: 8/29/12 Recent Posts
Thank you David for your reply. So you are saying that I have to replace the whole elasticsearch bundle to solve the classpath issues? Similar to the "patched" version from Petteri Kattunen (see https://github.com/peerkar/gsearch-elasticsearch-adapter/tree/master/modules/com-liferay-portal-search)?
thumbnail
David H Nebinger, modified 5 Years ago. Liferay Legend Posts: 14933 Join Date: 9/2/06 Recent Posts
No, this is just a way to change the exports so you have available what you want.
thumbnail
Dominik Marks, modified 5 Years ago. Regular Member Posts: 149 Join Date: 8/29/12 Recent Posts
Thank you David. I already did what you wrote on your blog post. I wrote a "Fragment-Host" and added an exported package. In my post above I had the wrong package name in my source code for the bnd.bnd, so maybe you misunderstood my question. I've updated my post above so that the bnd.bnd of my "Fragment-Host" contains the package I want to be exported by the elasticsearch bundle.

So when I deploy that Bundle the package com.liferay.portal.search.elasticsearch.internal.facet is exported by the elasticsearch bundle but now all indexing operations throw a NoClassDefFoundError (see stack trace above).

It seems that my Fragment somehow has an influence on the classloading, so that the required class (org.elasticsearch.common.lucene.Lucene in this case) cannot be loaded anymore.

At last I created a "patched" version of the elasticsearch bundle and blacklisted the original one. That way the package is exported and classloading works properly.

Maybe this is only a "bug"  in the "older" Liferay version 7.0.6 GA7. I did not test the behaviour in later Liferay versions.
thumbnail
David H Nebinger, modified 5 Years ago. Liferay Legend Posts: 14933 Join Date: 9/2/06 Recent Posts
No, if you export a package the implication is that any dependencies that it has (either via import or extends or whatever) will also be visible. Otherwise the classes can't resolve outside of the bundle...