How to use Infinispan query with JBoss7.1

2019-09-13 13:26发布

问题:

I have an Infinispan cache that I created through JBoss7.1 web interface. It is configured as an indexed, distributed cache.

In my jboss-deployment-structure.xml file I have added dependencies on org.infinispan and org.hibernate so I have access to my cache. I have also added a maven dependency on the following:

  <dependency>
     <groupId>org.infinispan</groupId>
     <artifactId>infinispan-core</artifactId>
     <version>5.1.7.Final</version>
     <scope>provided</scope>
  </dependency>
  <dependency>
     <groupId>org.infinispan</groupId>
     <artifactId>infinispan-query</artifactId>
     <version>5.1.7.Final</version>
  </dependency>

5.1.7.Final is the version included in the org.infinispan module in JBoss7.1.3 which I am using. This pulls in all the necessary dependencies (including lucene and hibernate-search-engine) so I do have the necessary libs in my project. However when doing the initial step mentioned here:

  SearchManager searchManager = Search.getSearchManager( cache );

It calls ComponentRegistryUtils.getComponent(cache, SearchFactoryIntegrator.class) which fails throwing IllegalArgumentException:

Indexing was not enabled on this cache. interface org.hibernate.search.spi.SearchFactoryIntegrator not found in registry

My cache has indexing enabled as can be seen by cache.getCacheConfiguration().indexing().enabled() returning true. But the application thinks it is not. Maybe this is because the cache's ComponentRegistry does not have access to the org.hibernate.search.spi.SearchFactoryIntegrator class (the cache being a JBoss global component, while the hibernate search lib is in my WAR's WEB-INF/lib directory).

Is there another way I should be doing this?

回答1:

JBoss AS 7 includes an org.infinispan module as it's used internally by the clustering subsystem, but this module does not include the lucene and hibernate-search-engine dependencies.

By specifying those dependencies in your application you are (correctly) adding the missing dependencies, but the included org.infinispan doesn't "see" the extensions as the module can not load extension points from your application's classpath.

So a possible solution is to add those dependencies to the AS7 modules and patch the org.infinispan module to import these resources from your custom module.

An alternative solution is to not rely on the org.infinispan module included by the AS but include it all in your application. This way you also have more flexibility on using a different version, possibly a more recent one.



回答2:

I ended up excluding infinispan and hibernate (rather not including them, which amounts to the same thing) from the jboss-deployment-structure.xml file.

Then I added a dependency in my pom.xml file on org.infinispan:infinispan-query:5.2.1.Final to pull all the jars into my WAR artifact's WEB-INF/lib directory.

Then I built the cache programmatically:

package com.myproduct.cache;

import org.infinispan.Cache;
import org.infinispan.configuration.cache.CacheMode;
import org.infinispan.configuration.cache.Configuration;
import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.configuration.cache.ConfigurationChildBuilder;
import org.infinispan.configuration.global.GlobalConfiguration;
import org.infinispan.configuration.global.GlobalConfigurationBuilder;
import org.infinispan.configuration.global.GlobalConfigurationChildBuilder;
import org.infinispan.eviction.EvictionStrategy;
import org.infinispan.manager.DefaultCacheManager;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.transaction.LockingMode;
import org.infinispan.transaction.TransactionMode;
import org.infinispan.transaction.lookup.GenericTransactionManagerLookup;
import org.infinispan.util.concurrent.IsolationLevel;
import org.jetbrains.annotations.NotNull;

class MyObjectCacheFactory
{
   private static EmbeddedCacheManager m_cacheManager = null;
   private static Cache<String, MyObject> m_cache = null;

   @NotNull
   public static Cache<String, MyObject> getMyObjectCache ()
   {
      if( m_cache == null )
         createMyObjectCache();
      return m_cache;
   }

   private static synchronized void createMyObjectCache ()
   {
      if( m_cacheManager == null )
         createCacheManager();

      if( !m_cacheManager.cacheExists( "MyObjects" ) )
      {
         Configuration cacheConfig = createMyObjectCacheConfig();
         m_cacheManager.defineConfiguration( "MyObjects", cacheConfig );
      }

      if( !m_cacheManager.isRunning( "MyObjects" ) )
         m_cacheManager.getCache( "MyObjects" ).start();
      m_cache = m_cacheManager.getCache( "MyObjects" );
   }

   private static void createCacheManager ()
   {
      GlobalConfiguration globalConfiguration = createGlobalConfiguration();
      Configuration defaultCacheConfig = createDefaultCacheConfiguration();
      m_cacheManager = new DefaultCacheManager( globalConfiguration, defaultCacheConfig );
   }

   @NotNull
   private static Configuration createDefaultCacheConfiguration ()
   {
      ConfigurationChildBuilder builder = new ConfigurationBuilder();
      builder = builder.jmxStatistics().enable();
      builder = builder.clustering()
         .cacheMode( CacheMode.DIST_SYNC )
         .stateTransfer()
         .timeout( 100 );
      builder = builder.transaction()
         .transactionMode( TransactionMode.TRANSACTIONAL )
         .autoCommit( false )
         .lockingMode( LockingMode.OPTIMISTIC );
      return builder.build();
   }

   @NotNull
   private static GlobalConfiguration createGlobalConfiguration ()
   {
      GlobalConfigurationChildBuilder builder = new GlobalConfigurationBuilder().clusteredDefault();
      builder = builder.globalJmxStatistics()
         .enable()
         .cacheManagerName( "MyCacheManager" )
         .jmxDomain( "com.myproduct.cache" );
      return builder.build();
   }

   @NotNull
   private static Configuration createMyObjectCacheConfig ()
   {
      ConfigurationChildBuilder builder = new ConfigurationBuilder();
      builder = builder.jmxStatistics().enable();
      builder = builder.clustering().cacheMode( CacheMode.DIST_SYNC );
      builder = builder.transaction()
         .transactionMode( TransactionMode.TRANSACTIONAL )
         .autoCommit( false )
         .lockingMode( LockingMode.OPTIMISTIC )
         .transactionManagerLookup( new GenericTransactionManagerLookup() );
      builder = builder.locking().isolationLevel( IsolationLevel.REPEATABLE_READ );
      builder = builder.eviction().maxEntries( 100 ).strategy( EvictionStrategy.LRU );
      builder = builder.expiration().maxIdle( 30000 ).lifespan( -1 ).enableReaper();
      builder = builder.loaders().passivation( true ).addFileCacheStore().purgeOnStartup( true );
      builder = builder.indexing().enable().addProperty( "default.directory_provider", "ram" );
      return builder.build();
   }
}

and added @Field annotation to MyObject:

package com.myproduct.cache;

import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Indexed;

import java.io.Serializable;

@Indexed
public class MyObject
   implements Serializable
{
   @NotNull private String m_id;

   @Field(name = "searchNumber")
   private int m_searchNumber;

   public MyObject (
      @NotNull String id,
      int searchNumber )
   {
      m_id = id;
      m_searchNumber = searchNumber;
   }

   @NotNull
   public String getId ()
   {
      return m_id;
   }

   public int getSearchNumber ()
   {
      return m_searchNumber;
   }
}

and the search method:

import org.apache.lucene.search.Query;
import org.hibernate.search.query.dsl.QueryBuilder;
import org.infinispan.Cache;
import org.infinispan.query.CacheQuery;
import org.infinispan.query.Search;
import org.infinispan.query.SearchManager;

[...]

   private Cache<String, MyObject> m_cache;

   @PostConstruct
   public void setup ()
   {
      m_cache = MyObjectCacheFactory.getMyObjectCache();
   }

   @NotNull
   public List<MyObject> getMyObjects ( int searchNumber )
   {
      SearchManager searchManager = Search.getSearchManager( m_cache );
      QueryBuilder queryBuilder = searchManager.buildQueryBuilderForClass( MyObject.class ).get();
      Query luceneQuery = queryBuilder.keyword().onField( "searchNumber" ).matching( searchNumber ).createQuery();
      CacheQuery cacheQuery = searchManager.getQuery( luceneQuery, MyObject.class );
      //noinspection unchecked
      return (List)cacheQuery.list();
   }


回答3:

I've found: https://community.jboss.org/message/807112#807112 I hope, it could be possibly helpful for you as well.