Nikita Ryanov
Nikita Ryanov

Reputation: 1570

How to inject spring resources into Apache Ignite classes?

I have a problem with injection spring beans into some ignite's classes. I'm trying to create this: Client -> Apache Ignite -> Spring-Data -> DataBase Maybe it is wrong, i'm not sure.

So, at this moment my classes look like: AppConfiguration

@Configuration
@ComponentScan(basePackages = arrayOf("com.ignite.cache"))
open class AppConfiguration : Serializable {
    private val logger: Logger = Logger.getLogger(AppConfiguration::class.java)

    @Bean
    open fun igniteInstance(): Ignite {
        val cfg = IgniteConfiguration()

        cfg.igniteInstanceName = "springDataNode"

        cfg.isPeerClassLoadingEnabled = true


        var clientCache: CacheConfiguration<Long, Client> = CacheConfiguration("ClientCache")
        clientCache.apply {
            setIndexedTypes(Long::class.java, Client::class.java)
            setCacheStoreFactory(FactoryBuilder.factoryOf(ClientStore::class.java))
            isReadThrough = true
            isWriteThrough = true
        }

        cfg.setCacheConfiguration(clientCache)

        return Ignition.start(cfg)
    }
}

DataSourceConfiguration:

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = arrayOf("com.ignite.cache.model.repositories.springdatarepository"))
@EnableIgniteRepositories(basePackages = arrayOf("com.ignite.cache.model.repositories.igniterepository"))
@ComponentScan(basePackages = arrayOf("com.ignite.cache.model"))
open class DataSourceConfiguration : Serializable {

    @Bean
    open fun entityManagerFactory(): LocalContainerEntityManagerFactoryBean {
        var entityManagerFactory: LocalContainerEntityManagerFactoryBean = LocalContainerEntityManagerFactoryBean()

        entityManagerFactory.apply {
            dataSource = dataSource()
            setPackagesToScan("com.ignite.cache.model")

            var vendorAdapter: HibernateJpaVendorAdapter = HibernateJpaVendorAdapter()

            vendorAdapter.apply {
                setGenerateDdl(true)
                setShowSql(true)
            }

            var properties: Properties = Properties()

            properties.apply {
                put("database.dialet", "org.hibernate.dialect.PostgreSQL95Dialect")
                put("database.globally_quoted_identifiers", "false")
                put("database.enable_lazy_load_no_trans", "true")
                put("database.show_sql", "true")
            }

            jpaVendorAdapter = vendorAdapter
            setJpaProperties(properties)
        }

        return entityManagerFactory
    }

    @Bean
    open fun dataSource(): DataSource {
        var source: ComboPooledDataSource = ComboPooledDataSource()

        source.apply {
            driverClass = "org.postgresql.Driver"
            jdbcUrl = "jdbc:postgresql://localhost:5432/ignite"
            user = "postgres"
            password = "1111"
            acquireIncrement = 5
            idleConnectionTestPeriod = 60
            maxPoolSize = 20
            minPoolSize = 10
            initialPoolSize = 10
        }

        return source
    }

    @Bean
    open fun transactionManager() : PlatformTransactionManager {
        var manager: JpaTransactionManager = JpaTransactionManager()

        manager.apply {
            entityManagerFactory = entityManagerFactory().nativeEntityManagerFactory
        }

        return manager
    }

    @Bean
    open fun exceptionTranslator(): PersistenceExceptionTranslationPostProcessor = PersistenceExceptionTranslationPostProcessor()
}

Entity:

@Entity
@Table(name = "client")
data class Client
(
        @Id
        @Column(name = "id")
        @GeneratedValue(generator = "increment")
        @GenericGenerator(name = "increment", strategy = "increment")
        var id: Long = 0,
        @Column(name = "email", nullable = false, unique = true)
        var email: String = "",
        @Column(name = "login", nullable = false, unique = true)
        var login: String = ""
) : Serializable

Repositories:

@RepositoryConfig(cacheName = "ClientCache")
interface IgniteClientRepository : IgniteRepository<Client, Long> {
}
@Repository
interface ClientRepository : CrudRepository<Client, Long>

Standart implemenation for service classes and CacheStore for ignite:

public class ClientStore implements CacheStore<Long, Client>, Serializable {
    private Logger logger = Logger.getLogger(ClientStore.class);

    @SpringResource
    private IClientService clientRepository; // <- error is here (NPE)

    @Override
    public void loadCache(IgniteBiInClosure<Long, Client> igniteBiInClosure, @Nullable Object... objects) throws CacheLoaderException {
        Iterable<Client> clients = clientRepository.findAll();

        for(Client client : clients) {
            igniteBiInClosure.apply(client.getId(), client);
        }
    }
...
}

Main:

public class Main {
    private static Logger logger = Logger.getLogger(Main.class);

    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfiguration.class, DataSourceConfiguration.class);
        Ignite ignite = context.getBean(Ignite.class);

        (ignite.getOrCreateCache("ClientCache")).loadCache(null);

        IgniteClientRepository clientRepository = context.getBean(IgniteClientRepository.class);

        Iterable<Client> clients = clientRepository.findAll();
        for(Client client : clients) {
            logger.info(client);
        }

        logger.info("Finish");
    }
}

But when i try to load some data from database into cache i get error NPE:

Exception in thread "main" javax.cache.integration.CacheLoaderException: java.lang.NullPointerException
    at org.apache.ignite.internal.processors.cache.store.GridCacheStoreManagerAdapter.loadCache(GridCacheStoreManagerAdapter.java:528)
    at org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtCacheAdapter.localLoadCache(GridDhtCacheAdapter.java:486)
    at org.apache.ignite.internal.processors.cache.GridCacheProxyImpl.localLoadCache(GridCacheProxyImpl.java:217)
    at org.apache.ignite.internal.processors.cache.GridCacheAdapter$LoadCacheJob.localExecute(GridCacheAdapter.java:5439)
    at org.apache.ignite.internal.processors.cache.GridCacheAdapter$LoadCacheJobV2.localExecute(GridCacheAdapter.java:5488)
    at org.apache.ignite.internal.processors.cache.GridCacheAdapter$TopologyVersionAwareJob.execute(GridCacheAdapter.java:6103)
    at org.apache.ignite.compute.ComputeJobAdapter.call(ComputeJobAdapter.java:132)
    at org.apache.ignite.internal.processors.closure.GridClosureProcessor$C2.execute(GridClosureProcessor.java:1842)
    at org.apache.ignite.internal.processors.job.GridJobWorker$2.call(GridJobWorker.java:566)
    at org.apache.ignite.internal.util.IgniteUtils.wrapThreadLoader(IgniteUtils.java:6621)
    at org.apache.ignite.internal.processors.job.GridJobWorker.execute0(GridJobWorker.java:560)
    at org.apache.ignite.internal.processors.job.GridJobWorker.body(GridJobWorker.java:489)
    at org.apache.ignite.internal.util.worker.GridWorker.run(GridWorker.java:110)
    at org.apache.ignite.internal.processors.job.GridJobProcessor.processJobExecuteRequest(GridJobProcessor.java:1114)
    at org.apache.ignite.internal.processors.task.GridTaskWorker.sendRequest(GridTaskWorker.java:1379)
    at org.apache.ignite.internal.processors.task.GridTaskWorker.processMappedJobs(GridTaskWorker.java:640)
    at org.apache.ignite.internal.processors.task.GridTaskWorker.body(GridTaskWorker.java:532)
    at org.apache.ignite.internal.util.worker.GridWorker.run(GridWorker.java:110)
    at org.apache.ignite.internal.processors.task.GridTaskProcessor.startTask(GridTaskProcessor.java:743)
    at org.apache.ignite.internal.processors.task.GridTaskProcessor.execute(GridTaskProcessor.java:443)
    at org.apache.ignite.internal.processors.closure.GridClosureProcessor.callAsync(GridClosureProcessor.java:447)
    at org.apache.ignite.internal.processors.closure.GridClosureProcessor.callAsync(GridClosureProcessor.java:418)
    at org.apache.ignite.internal.processors.closure.GridClosureProcessor.callAsync(GridClosureProcessor.java:402)
    at org.apache.ignite.internal.processors.cache.GridCacheAdapter.globalLoadCacheAsync(GridCacheAdapter.java:3681)
    at org.apache.ignite.internal.processors.cache.GridCacheAdapter.globalLoadCache(GridCacheAdapter.java:3657)
    at org.apache.ignite.internal.processors.cache.IgniteCacheProxy.loadCache(IgniteCacheProxy.java:387)
    at com.ignite.cache.Main.main(Main.java:22)
Caused by: java.lang.NullPointerException
    at com.ignite.cache.model.service.ClientStore.loadCache(ClientStore.java:30)
    at org.apache.ignite.internal.processors.cache.store.GridCacheStoreManagerAdapter.loadCache(GridCacheStoreManagerAdapter.java:502)
    ... 26 more

I still can't figure out why my client service doesn't inject into CacheStore class. Maybe i should use xml config instead of java-class config for ignite?

Upvotes: 2

Views: 2965

Answers (2)

Valentin Kulichenko
Valentin Kulichenko

Reputation: 8390

When you start Ignite using Ignition#start with IgniteConfiguration object, it's not aware of Spring context at all. You need to use IgniteSpring#start methods instead to provide context explicitly. Another option is to utilize IgniteSpringBean that already implements ApplicationContextAware and starts Ignite instance properly.

Also note that you will need to provide either bean name or bean class as a parameter to @SpringResource annotation.

Upvotes: 5

Jens Schauder
Jens Schauder

Reputation: 81907

I don't know Ignite and I don't know the programming language you are using but it looks like Ignite and not Spring is creating your ClientStore instances. Therefore you need to inject the dependencies manually.

I'm not really familiar with the FactoryBuilder used there, so there might be nice solutions if you can use a constructor with arguments or even a lambda, but if that doesn' work, you can store a reference to the repository in static field and get it from there in the constructor of the ClientStore.

Upvotes: 0

Related Questions