You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by nt...@apache.org on 2017/10/25 11:43:20 UTC
ignite git commit: IGNITE-6555 When a CacheStore with a
@SpringResource annotated field is configured Ignite fails to start via
igniteSpringBean. This closes #2893.
Repository: ignite
Updated Branches:
refs/heads/master 1816fb920 -> dde348607
IGNITE-6555 When a CacheStore with a @SpringResource annotated field is configured Ignite fails to start via igniteSpringBean. This closes #2893.
Signed-off-by: nikolay_tikhonov <nt...@gridgain.com>
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/dde34860
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/dde34860
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/dde34860
Branch: refs/heads/master
Commit: dde348607ed266f87bf594cb2a221ec39d84cfdb
Parents: 1816fb9
Author: Alexander Fedotov <al...@gmail.com>
Authored: Wed Oct 25 14:43:16 2017 +0300
Committer: nikolay_tikhonov <nt...@gridgain.com>
Committed: Wed Oct 25 14:43:16 2017 +0300
----------------------------------------------------------------------
.../org/apache/ignite/IgniteSpringBean.java | 32 ++-
.../GridSpringBeanSerializationSelfTest.java | 4 +-
.../ignite/internal/IgniteSpringBeanTest.java | 2 +-
.../GridServiceInjectionSpringResourceTest.java | 10 +-
...teSpringBeanSpringResourceInjectionTest.java | 215 +++++++++++++++++++
.../ignite/spring/injection/spring-bean.xml | 84 ++++++++
.../testsuites/IgniteSpringTestSuite.java | 2 +
7 files changed, 334 insertions(+), 15 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ignite/blob/dde34860/modules/spring/src/main/java/org/apache/ignite/IgniteSpringBean.java
----------------------------------------------------------------------
diff --git a/modules/spring/src/main/java/org/apache/ignite/IgniteSpringBean.java b/modules/spring/src/main/java/org/apache/ignite/IgniteSpringBean.java
index 4cba76e..95fceec 100644
--- a/modules/spring/src/main/java/org/apache/ignite/IgniteSpringBean.java
+++ b/modules/spring/src/main/java/org/apache/ignite/IgniteSpringBean.java
@@ -38,9 +38,10 @@ import org.apache.ignite.plugin.PluginNotFoundException;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
-import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.event.ContextRefreshedEvent;
/**
* Ignite Spring bean allows to bypass {@link Ignition} methods.
@@ -48,9 +49,20 @@ import org.springframework.context.ApplicationContextAware;
* Spring configuration file directly without invoking static
* {@link Ignition} methods. This class can be wired directly from
* Spring and can be referenced from within other Spring beans.
- * By virtue of implementing {@link DisposableBean} and {@link InitializingBean}
+ * By virtue of implementing {@link DisposableBean} and {@link SmartInitializingSingleton}
* interfaces, {@code IgniteSpringBean} automatically starts and stops underlying
* grid instance.
+ *
+ * <p>
+ * A note should be taken that Ignite instance is started after all other
+ * Spring beans have been initialized and right before Spring context is refreshed.
+ * That implies that it's not valid to reference IgniteSpringBean from
+ * any kind of Spring bean init methods like {@link javax.annotation.PostConstruct}.
+ * If it's required to reference IgniteSpringBean for other bean
+ * initialization purposes, it should be done from a {@link ContextRefreshedEvent}
+ * listener method declared in that bean.
+ * </p>
+ *
* <p>
* <h1 class="header">Spring Configuration Example</h1>
* Here is a typical example of describing it in Spring file:
@@ -79,7 +91,7 @@ import org.springframework.context.ApplicationContextAware;
* </pre>
* <p>
*/
-public class IgniteSpringBean implements Ignite, DisposableBean, InitializingBean,
+public class IgniteSpringBean implements Ignite, DisposableBean, SmartInitializingSingleton,
ApplicationContextAware, Externalizable {
/** */
private static final long serialVersionUID = 0L;
@@ -145,7 +157,6 @@ public class IgniteSpringBean implements Ignite, DisposableBean, InitializingBea
/** {@inheritDoc} */
@Override public void destroy() throws Exception {
- // If there were some errors when afterPropertiesSet() was called.
if (g != null) {
// Do not cancel started tasks, wait for them.
G.stop(g.name(), false);
@@ -153,11 +164,16 @@ public class IgniteSpringBean implements Ignite, DisposableBean, InitializingBea
}
/** {@inheritDoc} */
- @Override public void afterPropertiesSet() throws Exception {
+ @Override public void afterSingletonsInstantiated() {
if (cfg == null)
cfg = new IgniteConfiguration();
- g = IgniteSpring.start(cfg, appCtx);
+ try {
+ g = IgniteSpring.start(cfg, appCtx);
+ }
+ catch (IgniteCheckedException e) {
+ throw new IgniteException("Failed to start IgniteSpringBean", e);
+ }
}
/** {@inheritDoc} */
@@ -620,7 +636,9 @@ public class IgniteSpringBean implements Ignite, DisposableBean, InitializingBea
protected void checkIgnite() throws IllegalStateException {
if (g == null) {
throw new IllegalStateException("Ignite is in invalid state to perform this operation. " +
- "It either not started yet or has already being or have stopped " +
+ "It either not started yet or has already being or have stopped.\n" +
+ "Make sure that IgniteSpringBean is not referenced from any kind of Spring bean init methods " +
+ "like @PostConstruct}.\n" +
"[ignite=" + g + ", cfg=" + cfg + ']');
}
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/dde34860/modules/spring/src/test/java/org/apache/ignite/internal/GridSpringBeanSerializationSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/spring/src/test/java/org/apache/ignite/internal/GridSpringBeanSerializationSelfTest.java b/modules/spring/src/test/java/org/apache/ignite/internal/GridSpringBeanSerializationSelfTest.java
index 6f7d27a..6a72213 100644
--- a/modules/spring/src/test/java/org/apache/ignite/internal/GridSpringBeanSerializationSelfTest.java
+++ b/modules/spring/src/test/java/org/apache/ignite/internal/GridSpringBeanSerializationSelfTest.java
@@ -53,7 +53,7 @@ public class GridSpringBeanSerializationSelfTest extends GridCommonAbstractTest
bean.setConfiguration(cfg);
- bean.afterPropertiesSet();
+ bean.afterSingletonsInstantiated();
}
/**
@@ -97,4 +97,4 @@ public class GridSpringBeanSerializationSelfTest extends GridCommonAbstractTest
assert bean0.cluster().localNode() != null;
assert bean0.cluster().localNode().<Boolean>attribute(ATTR_KEY);
}
-}
\ No newline at end of file
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/dde34860/modules/spring/src/test/java/org/apache/ignite/internal/IgniteSpringBeanTest.java
----------------------------------------------------------------------
diff --git a/modules/spring/src/test/java/org/apache/ignite/internal/IgniteSpringBeanTest.java b/modules/spring/src/test/java/org/apache/ignite/internal/IgniteSpringBeanTest.java
index d465904..c7f0d59 100644
--- a/modules/spring/src/test/java/org/apache/ignite/internal/IgniteSpringBeanTest.java
+++ b/modules/spring/src/test/java/org/apache/ignite/internal/IgniteSpringBeanTest.java
@@ -31,7 +31,7 @@ public class IgniteSpringBeanTest extends GridCommonAbstractTest {
try (IgniteSpringBean bean = new IgniteSpringBean()) {
bean.setConfiguration(getConfiguration("test"));
- bean.afterPropertiesSet();
+ bean.afterSingletonsInstantiated();
bean.compute();
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/dde34860/modules/spring/src/test/java/org/apache/ignite/spring/injection/GridServiceInjectionSpringResourceTest.java
----------------------------------------------------------------------
diff --git a/modules/spring/src/test/java/org/apache/ignite/spring/injection/GridServiceInjectionSpringResourceTest.java b/modules/spring/src/test/java/org/apache/ignite/spring/injection/GridServiceInjectionSpringResourceTest.java
index c6a6d05..891c42e 100644
--- a/modules/spring/src/test/java/org/apache/ignite/spring/injection/GridServiceInjectionSpringResourceTest.java
+++ b/modules/spring/src/test/java/org/apache/ignite/spring/injection/GridServiceInjectionSpringResourceTest.java
@@ -26,10 +26,11 @@ import org.apache.ignite.resources.SpringResource;
import org.apache.ignite.services.Service;
import org.apache.ignite.services.ServiceContext;
import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.springframework.context.event.ContextRefreshedEvent;
+import org.springframework.context.event.EventListener;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
-import javax.annotation.PostConstruct;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
@@ -234,12 +235,11 @@ public class GridServiceInjectionSpringResourceTest extends GridCommonAbstractTe
/**
* @throws Exception If failed.
*/
- @PostConstruct
- public void init() throws Exception {
+ @EventListener
+ public void init(ContextRefreshedEvent evt) throws Exception {
DummyService srv = ignite.services().serviceProxy(SERVICE_NAME, DummyService.class, false);
assertNotNull(srv);
}
}
-
-}
\ No newline at end of file
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/dde34860/modules/spring/src/test/java/org/apache/ignite/spring/injection/IgniteSpringBeanSpringResourceInjectionTest.java
----------------------------------------------------------------------
diff --git a/modules/spring/src/test/java/org/apache/ignite/spring/injection/IgniteSpringBeanSpringResourceInjectionTest.java b/modules/spring/src/test/java/org/apache/ignite/spring/injection/IgniteSpringBeanSpringResourceInjectionTest.java
new file mode 100644
index 0000000..2a06deb
--- /dev/null
+++ b/modules/spring/src/test/java/org/apache/ignite/spring/injection/IgniteSpringBeanSpringResourceInjectionTest.java
@@ -0,0 +1,215 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.spring.injection;
+
+import java.io.Serializable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import javax.cache.Cache;
+import javax.cache.integration.CacheLoaderException;
+import javax.cache.integration.CacheWriterException;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.cache.store.CacheStoreAdapter;
+import org.apache.ignite.resources.SpringResource;
+import org.apache.ignite.services.Service;
+import org.apache.ignite.services.ServiceContext;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+/**
+ * Test checking injections of {@link SpringResource} annotated fields.
+ */
+public class IgniteSpringBeanSpringResourceInjectionTest extends GridCommonAbstractTest {
+ /** */
+ private static final String SPRING_CFG_LOCATION = "/org/apache/ignite/spring/injection/spring-bean.xml";
+
+ /** */
+ private static final String BEAN_TO_INJECT_NAME = "beanToInject";
+
+ /**
+ * Cache store with {@link SpringResource} fields to be injected.
+ */
+ public static class IgniteCacheStoreWithSpringResource<K, V> extends CacheStoreAdapter<K, V>
+ implements Serializable
+ {
+ /** */
+ private static final long serialVersionUID = 0L;
+
+ /** */
+ @SpringResource(resourceClass = Integer.class)
+ private transient Integer injectedSpringFld;
+
+ /**
+ * @return Injected Spring field.
+ */
+ public Integer getInjectedSpringField() {
+ return injectedSpringFld;
+ }
+
+ /** {@inheritDoc} */
+ @Override public V load(K key) throws CacheLoaderException {
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void write(Cache.Entry<? extends K, ? extends V> entry) throws CacheWriterException {
+ // No-op.
+ }
+
+ /** {@inheritDoc} */
+ @Override public void delete(Object key) throws CacheWriterException {
+ // No-op.
+ }
+ }
+
+ /**
+ * Interface of a service with {@link SpringResource} fields to be injected.
+ */
+ public interface ServiceWithSpringResource {
+ /**
+ * @return Injected Spring field.
+ */
+ Integer getInjectedSpringField();
+ }
+
+ /**
+ * Service with {@link SpringResource} fields to be injected.
+ */
+ public static class ServiceWithSpringResourceImpl implements ServiceWithSpringResource, Service {
+ /** */
+ private static final long serialVersionUID = 0L;
+ /** */
+ @SpringResource(resourceClass = Integer.class)
+ private transient Integer injectedSpringFld;
+
+ /** {@inheritDoc} */
+ @Override public Integer getInjectedSpringField() {
+ return injectedSpringFld;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void cancel(ServiceContext ctx) {
+ // No-op.
+ }
+
+ /** {@inheritDoc} */
+ @Override public void init(ServiceContext ctx) throws Exception {
+ // No-op.
+ }
+
+ /** {@inheritDoc} */
+ @Override public void execute(ServiceContext ctx) throws Exception {
+ // No-op.
+ }
+ }
+
+ /**
+ *
+ */
+ private abstract static class TestSpringResourceInjectedRunnable implements Runnable {
+ /** */
+ private final String springCfgLocation;
+
+ /** */
+ private final String beanToInjectName;
+
+ /** */
+ protected BeanFactory appCtx;
+
+ /**
+ * Constructor.
+ *
+ * @param springCfgLocation Spring config location.
+ * @param beanToInjectName Bean to inject name.
+ */
+ protected TestSpringResourceInjectedRunnable(String springCfgLocation, String beanToInjectName) {
+ this.springCfgLocation = springCfgLocation;
+ this.beanToInjectName = beanToInjectName;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void run() {
+ appCtx = new ClassPathXmlApplicationContext(springCfgLocation);
+
+ Integer beanToInject = (Integer)appCtx.getBean(beanToInjectName);
+
+ assertEquals(beanToInject, getInjectedBean());
+ }
+
+ /**
+ * @return Injected bean to check.
+ */
+ abstract Integer getInjectedBean();
+ }
+
+ /** */
+ private void doTestSpringResourceInjected(Runnable testRunnable) throws Exception {
+ ExecutorService executorSvc = Executors.newSingleThreadExecutor();
+
+ Future<?> fut = executorSvc.submit(testRunnable);
+
+ try {
+ fut.get(5, TimeUnit.SECONDS);
+ }
+ catch (TimeoutException ignored) {
+ fail("Failed to wait for completion. Deadlock is possible");
+ }
+ finally {
+ executorSvc.shutdownNow();
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void afterTest() throws Exception {
+ stopAllGrids(true);
+ }
+
+ /** */
+ public void testSpringResourceInjectedInCacheStore() throws Exception {
+ doTestSpringResourceInjected(
+ new TestSpringResourceInjectedRunnable(SPRING_CFG_LOCATION, BEAN_TO_INJECT_NAME) {
+ /** {@inheritDoc} */
+ @Override Integer getInjectedBean() {
+ IgniteCacheStoreWithSpringResource cacheStore =
+ appCtx.getBean(IgniteCacheStoreWithSpringResource.class);
+
+ return cacheStore.getInjectedSpringField();
+ }
+ }
+ );
+ }
+
+ /** */
+ public void testSpringResourceInjectedInService() throws Exception {
+ doTestSpringResourceInjected(
+ new TestSpringResourceInjectedRunnable(SPRING_CFG_LOCATION, BEAN_TO_INJECT_NAME) {
+ /** {@inheritDoc} */
+ @Override Integer getInjectedBean() {
+ Ignite ignite = appCtx.getBean(Ignite.class);
+ ServiceWithSpringResource svc = ignite.services().service("ServiceWithSpringResource");
+
+ return svc.getInjectedSpringField();
+ }
+ }
+ );
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/dde34860/modules/spring/src/test/java/org/apache/ignite/spring/injection/spring-bean.xml
----------------------------------------------------------------------
diff --git a/modules/spring/src/test/java/org/apache/ignite/spring/injection/spring-bean.xml b/modules/spring/src/test/java/org/apache/ignite/spring/injection/spring-bean.xml
new file mode 100644
index 0000000..d40f152
--- /dev/null
+++ b/modules/spring/src/test/java/org/apache/ignite/spring/injection/spring-bean.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="
+ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
+
+ <bean id="beanToInject" class="java.lang.Integer">
+ <constructor-arg value="111" type="int"/>
+ </bean>
+
+ <bean id="cacheStore" class="org.apache.ignite.spring.injection.IgniteSpringBeanSpringResourceInjectionTest.IgniteCacheStoreWithSpringResource"/>
+
+ <bean id="serviceWithSpringResource"
+ class="org.apache.ignite.spring.injection.IgniteSpringBeanSpringResourceInjectionTest.ServiceWithSpringResourceImpl"/>
+
+ <bean id="igniteSpringBean" class="org.apache.ignite.IgniteSpringBean">
+ <property name="configuration">
+ <bean id="ignite.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
+ <property name="peerClassLoadingEnabled" value="true"/>
+
+ <property name="cacheConfiguration">
+ <list>
+ <bean class="org.apache.ignite.configuration.CacheConfiguration">
+ <property name="name" value="cache1"/>
+ <property name="cacheStoreFactory">
+ <bean class="javax.cache.configuration.FactoryBuilder" factory-method="factoryOf">
+ <constructor-arg ref="cacheStore"/>
+ </bean>
+ </property>
+
+ <property name="readThrough" value="true"/>
+ <property name="writeThrough" value="true"/>
+ </bean>
+ </list>
+ </property>
+
+ <property name="serviceConfiguration">
+ <list>
+ <bean class="org.apache.ignite.services.ServiceConfiguration">
+ <property name="name" value="ServiceWithSpringResource"/>
+ <property name="maxPerNodeCount" value="1"/>
+ <property name="totalCount" value="1"/>
+ <property name="service">
+ <ref bean="serviceWithSpringResource"/>
+ </property>
+ </bean>
+ </list>
+ </property>
+
+ <property name="discoverySpi">
+ <bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
+ <property name="ipFinder">
+ <bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder">
+ <property name="addresses">
+ <list>
+ <value>127.0.0.1:47500..47509</value>
+ </list>
+ </property>
+ </bean>
+ </property>
+ </bean>
+ </property>
+ </bean>
+ </property>
+ </bean>
+</beans>
http://git-wip-us.apache.org/repos/asf/ignite/blob/dde34860/modules/spring/src/test/java/org/apache/ignite/testsuites/IgniteSpringTestSuite.java
----------------------------------------------------------------------
diff --git a/modules/spring/src/test/java/org/apache/ignite/testsuites/IgniteSpringTestSuite.java b/modules/spring/src/test/java/org/apache/ignite/testsuites/IgniteSpringTestSuite.java
index 9ebb784..ff96c7b 100644
--- a/modules/spring/src/test/java/org/apache/ignite/testsuites/IgniteSpringTestSuite.java
+++ b/modules/spring/src/test/java/org/apache/ignite/testsuites/IgniteSpringTestSuite.java
@@ -21,6 +21,7 @@ import junit.framework.TestSuite;
import org.apache.ignite.cache.spring.GridSpringCacheManagerSelfTest;
import org.apache.ignite.cache.spring.SpringCacheManagerContextInjectionTest;
import org.apache.ignite.cache.spring.SpringCacheTest;
+import org.apache.ignite.spring.injection.IgniteSpringBeanSpringResourceInjectionTest;
import org.apache.ignite.internal.IgniteSpringBeanTest;
import org.apache.ignite.cache.store.jdbc.CacheJdbcBlobStoreFactorySelfTest;
import org.apache.ignite.cache.store.jdbc.CacheJdbcPojoStoreFactorySelfTest;
@@ -77,6 +78,7 @@ public class IgniteSpringTestSuite extends TestSuite {
suite.addTestSuite(GridSpringTransactionManagerSelfTest.class);
suite.addTestSuite(GridServiceInjectionSpringResourceTest.class);
+ suite.addTestSuite(IgniteSpringBeanSpringResourceInjectionTest.class);
suite.addTestSuite(GridTransformSpringInjectionSelfTest.class);