INT-1527 MetadataStore refactoring
This commit is contained in:
@@ -36,20 +36,21 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public abstract class IntegrationContextUtils {
|
||||
|
||||
public static final String METADATA_PERSISTER_BEAN_NAME = "metadataPersister";
|
||||
|
||||
public static final String TASK_SCHEDULER_BEAN_NAME = "taskScheduler";
|
||||
|
||||
public static final String ERROR_CHANNEL_BEAN_NAME = "errorChannel";
|
||||
|
||||
public static final String NULL_CHANNEL_BEAN_NAME = "nullChannel";
|
||||
|
||||
public static final String METADATA_STORE_BEAN_NAME = "metadataStore";
|
||||
|
||||
public static final String INTEGRATION_CONVERSION_SERVICE_BEAN_NAME = "integrationConversionService";
|
||||
|
||||
public static final String DEFAULT_POLLER_METADATA_BEAN_NAME = "org.springframework.integration.context.defaultPollerMetadata";
|
||||
|
||||
public static MetadataStore getMetadataPersister(BeanFactory beanFactory) {
|
||||
return getBeanOfType(beanFactory, METADATA_PERSISTER_BEAN_NAME, MetadataStore.class);
|
||||
|
||||
public static MetadataStore getMetadataStore(BeanFactory beanFactory) {
|
||||
return getBeanOfType(beanFactory, METADATA_STORE_BEAN_NAME, MetadataStore.class);
|
||||
}
|
||||
|
||||
public static MessageChannel getErrorChannel(BeanFactory beanFactory) {
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.integration.context;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.BeanInitializationException;
|
||||
|
||||
@@ -16,26 +16,25 @@
|
||||
|
||||
package org.springframework.integration.context.metadata;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Strategy interface for persisting metadata from certain adapters / endpoints
|
||||
* Strategy interface for storing metadata from certain adapters
|
||||
* to avoid duplicate delivery of messages, for example.
|
||||
*
|
||||
* @author Josh Long
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Mark Fisher
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface MetadataStore {
|
||||
|
||||
/**
|
||||
* Writes metadata as Properties to this store.
|
||||
* Writes a key value pair to this MetadataStore.
|
||||
*/
|
||||
void write(Properties metadata);
|
||||
void put(String key, String value);
|
||||
|
||||
/**
|
||||
* Loads metadata as Properties from this store.
|
||||
* Reads a value for the given key from this MetadataStore.
|
||||
*/
|
||||
Properties load();
|
||||
String get(String key);
|
||||
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.context.metadata;
|
||||
|
||||
import java.io.File;
|
||||
@@ -23,6 +24,8 @@ import java.util.Properties;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.DefaultPropertiesPersister;
|
||||
@@ -34,87 +37,101 @@ import org.springframework.util.DefaultPropertiesPersister;
|
||||
* Files will be written to the 'java.io.tmpdir' + "/spring-integration/".
|
||||
*
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Mark Fisher
|
||||
* @since 2.0
|
||||
*/
|
||||
public class FileBasedPropertiesStore implements MetadataStore, InitializingBean{
|
||||
public class PropertiesPersistingMetadataStore implements MetadataStore, InitializingBean, DisposableBean {
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private final Properties metadata = new Properties();
|
||||
|
||||
private final DefaultPropertiesPersister persister = new DefaultPropertiesPersister();
|
||||
private final String persistentKey;
|
||||
private volatile File persistentFile;
|
||||
|
||||
private volatile File file;
|
||||
|
||||
private volatile String baseDirectory = System.getProperty("java.io.tmpdir") + "/spring-integration/";
|
||||
|
||||
public FileBasedPropertiesStore(String persistentKey){
|
||||
Assert.notNull(persistentKey, "'persistentKey' must not be null");
|
||||
this.persistentKey = persistentKey;
|
||||
}
|
||||
|
||||
|
||||
public void setBaseDirectory(String baseDirectory) {
|
||||
Assert.hasText(baseDirectory, "'baseDirectory' must be non-empty");
|
||||
this.baseDirectory = baseDirectory;
|
||||
}
|
||||
|
||||
public String getBaseDirectory() {
|
||||
return baseDirectory;
|
||||
}
|
||||
|
||||
public void write(Properties metadata) {
|
||||
FileOutputStream fo = null;
|
||||
try {
|
||||
fo = new FileOutputStream(persistentFile);
|
||||
persister.store(metadata, fo, "Last feed entry");
|
||||
}
|
||||
catch (IOException e) {
|
||||
// not fatal for the functionality of the component
|
||||
logger.warn("Failed to persist feed entry. This may result in a duplicate " +
|
||||
"feed entry after this component is restarted", e);
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
if (fo != null){
|
||||
fo.close();
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
// not fatal for the functionality of he component
|
||||
logger.warn("Failed to close FileOutputStream to " + persistentFile.getAbsolutePath(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Properties load() {
|
||||
Properties properties = new Properties();
|
||||
FileInputStream iStream = null;
|
||||
try {
|
||||
iStream = new FileInputStream(persistentFile);
|
||||
persister.load(properties, iStream);
|
||||
} catch (Exception e) {
|
||||
// not fatal for the functionality of the component
|
||||
logger.warn("Failed to load feed entry from the persistent store. This may result in a duplicate " +
|
||||
"feed entry after this component is restarted", e);
|
||||
} finally {
|
||||
try {
|
||||
if (iStream != null){
|
||||
iStream.close();
|
||||
}
|
||||
} catch (Exception e2) {
|
||||
// non fatal
|
||||
logger.warn("Failed to close FileInputStream for: " + persistentFile.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
String fileName = this.persistentKey + ".last.entry";
|
||||
File baseDir = new File(baseDirectory);
|
||||
baseDir.mkdirs();
|
||||
persistentFile = new File(baseDir, fileName);
|
||||
this.file = new File(baseDir, "metadata-store.properties");
|
||||
try {
|
||||
if (!persistentFile.exists()){
|
||||
persistentFile.createNewFile();
|
||||
if (!this.file.exists()) {
|
||||
this.file.createNewFile();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalArgumentException("Failed to create metadata-store file '"
|
||||
+ persistentFile.getAbsolutePath() + "'", e);
|
||||
+ this.file.getAbsolutePath() + "'", e);
|
||||
}
|
||||
this.loadMetadata();
|
||||
}
|
||||
|
||||
public void put(String key, String value) {
|
||||
this.metadata.setProperty(key, value);
|
||||
}
|
||||
|
||||
public String get(String key) {
|
||||
return this.metadata.getProperty(key);
|
||||
}
|
||||
|
||||
public void destroy() throws Exception {
|
||||
this.saveMetadata();
|
||||
}
|
||||
|
||||
private void saveMetadata() {
|
||||
FileOutputStream outputStream = null;
|
||||
try {
|
||||
outputStream = new FileOutputStream(this.file);
|
||||
this.persister.store(this.metadata, outputStream, "Last feed entry");
|
||||
}
|
||||
catch (IOException e) {
|
||||
// not fatal for the functionality of the component
|
||||
logger.warn("Failed to persist feed entry. This may result in a duplicate "
|
||||
+ "feed entry after this component is restarted.", e);
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
if (outputStream != null) {
|
||||
outputStream.close();
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
// not fatal for the functionality of the component
|
||||
logger.warn("Failed to close FileOutputStream to " + this.file.getAbsolutePath(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void loadMetadata() {
|
||||
FileInputStream inputStream = null;
|
||||
try {
|
||||
inputStream = new FileInputStream(this.file);
|
||||
this.persister.load(this.metadata, inputStream);
|
||||
}
|
||||
catch (Exception e) {
|
||||
// not fatal for the functionality of the component
|
||||
logger.warn("Failed to load feed entry from the persistent store. This may result in a duplicate " +
|
||||
"feed entry after this component is restarted", e);
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
if (inputStream != null) {
|
||||
inputStream.close();
|
||||
}
|
||||
}
|
||||
catch (Exception e2) {
|
||||
// non fatal
|
||||
logger.warn("Failed to close FileInputStream for: " + this.file.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.integration.context.metadata;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Simple implementation of {@link MetadataStore} that uses an in-memory map only.
|
||||
* The metadata will not be persisted across application restarts.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @since 2.0
|
||||
*/
|
||||
public class SimpleMetadataStore implements MetadataStore {
|
||||
|
||||
private final Map<String, String> metadata = new HashMap<String, String>();
|
||||
|
||||
|
||||
public void put(String key, String value) {
|
||||
this.metadata.put(key, value);
|
||||
}
|
||||
|
||||
public String get(String key) {
|
||||
return this.metadata.get(key);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.context.metadata;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
@@ -24,47 +25,46 @@ import java.util.Properties;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.core.io.support.PropertiesLoaderUtils;
|
||||
|
||||
/**
|
||||
* @author Oleg Zhurakousky
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @since 2.0
|
||||
*/
|
||||
public class FileBasedPropertiesStoreTests {
|
||||
public class PropertiesPersistingMetadataStoreTests {
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void validateFailureWithNoPersistentKey(){
|
||||
new FileBasedPropertiesStore(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateWithDefaultBaseDir() throws Exception{
|
||||
File file = new File(System.getProperty("java.io.tmpdir") + "/spring-integration/" + "foo.last.entry");
|
||||
public void validateWithDefaultBaseDir() throws Exception {
|
||||
File file = new File(System.getProperty("java.io.tmpdir") + "/spring-integration/metadata-store.properties");
|
||||
file.delete();
|
||||
FileBasedPropertiesStore metaStore = new FileBasedPropertiesStore("foo");
|
||||
metaStore.afterPropertiesSet();
|
||||
PropertiesPersistingMetadataStore metadataStore = new PropertiesPersistingMetadataStore();
|
||||
metadataStore.afterPropertiesSet();
|
||||
assertTrue(file.exists());
|
||||
Properties prop = new Properties();
|
||||
prop.setProperty("foo", "bar");
|
||||
metaStore.write(prop);
|
||||
Properties persistentProperties = metaStore.load();
|
||||
metadataStore.put("foo", "bar");
|
||||
metadataStore.destroy();
|
||||
Properties persistentProperties = PropertiesLoaderUtils.loadProperties(new FileSystemResource(file));
|
||||
assertNotNull(persistentProperties);
|
||||
assertEquals(1, persistentProperties.size());
|
||||
assertEquals("bar", persistentProperties.get("foo"));
|
||||
}
|
||||
@Test
|
||||
public void validateWithCustomBaseDir() throws Exception{
|
||||
File file = new File("foo/" + "foo.last.entry");
|
||||
file.delete();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateWithCustomBaseDir() throws Exception {
|
||||
File file = new File("foo" + "/metadata-store.properties");
|
||||
file.deleteOnExit();
|
||||
FileBasedPropertiesStore metaStore = new FileBasedPropertiesStore("foo");
|
||||
metaStore.setBaseDirectory("foo");
|
||||
metaStore.afterPropertiesSet();
|
||||
PropertiesPersistingMetadataStore metadataStore = new PropertiesPersistingMetadataStore();
|
||||
metadataStore.setBaseDirectory("foo");
|
||||
metadataStore.afterPropertiesSet();
|
||||
metadataStore.put("foo", "bar");
|
||||
metadataStore.destroy();
|
||||
assertTrue(file.exists());
|
||||
Properties prop = new Properties();
|
||||
prop.setProperty("foo", "bar");
|
||||
metaStore.write(prop);
|
||||
Properties persistentProperties = metaStore.load();
|
||||
Properties persistentProperties = PropertiesLoaderUtils.loadProperties(new FileSystemResource(file));
|
||||
assertNotNull(persistentProperties);
|
||||
assertEquals(1, persistentProperties.size());
|
||||
assertEquals("bar", persistentProperties.get("foo"));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user