INT-1527 MetadataStore refactoring

This commit is contained in:
Mark Fisher
2010-10-26 18:39:52 -04:00
parent ce0e9f4e0a
commit 7412bc239c
14 changed files with 439 additions and 362 deletions

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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());
}
}
}
}

View File

@@ -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);
}
}

View File

@@ -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"));
}
}