Multiply floating store factories for type safety

This commit is contained in:
René Pfeuffer
2018-12-04 08:56:39 +01:00
parent 33f3216164
commit 3021bea65a
23 changed files with 245 additions and 87 deletions

View File

@@ -74,8 +74,8 @@ public abstract class AbstractRepositoryHandler<C extends RepositoryConfig>
*/
protected AbstractRepositoryHandler(ConfigurationStoreFactory storeFactory) {
this.store = storeFactory
.withName(getType().getName())
.withType(getConfigClass())
.withName(getType().getName())
.build();
}

View File

@@ -32,6 +32,8 @@
package sonia.scm.store;
import sonia.scm.repository.Repository;
/**
* The BlobStoreFactory can be used to create new or get existing
* {@link BlobStore}s.
@@ -42,6 +44,51 @@ package sonia.scm.store;
* @apiviz.landmark
* @apiviz.uses sonia.scm.store.BlobStore
*/
public interface BlobStoreFactory extends StoreFactory<BlobStore> {
public interface BlobStoreFactory {
BlobStore getStore(final StoreParameters storeParameters);
default FloatingStoreParameters.Builder withName(String name) {
return new FloatingStoreParameters(this).new Builder(name);
}
}
final class FloatingStoreParameters implements StoreParameters {
private String name;
private Repository repository;
private final BlobStoreFactory factory;
FloatingStoreParameters(BlobStoreFactory factory) {
this.factory = factory;
}
public Class getType() {
return null;
}
public String getName() {
return name;
}
public Repository getRepository() {
return repository;
}
public class Builder {
Builder(String name) {
FloatingStoreParameters.this.name = name;
}
public FloatingStoreParameters.Builder forRepository(Repository repository) {
FloatingStoreParameters.this.repository = repository;
return this;
}
public BlobStore build(){
return factory.getStore(FloatingStoreParameters.this);
}
}
}

View File

@@ -32,6 +32,8 @@
package sonia.scm.store;
import sonia.scm.repository.Repository;
/**
* The ConfigurationEntryStoreFactory can be used to create new or get existing
* {@link ConfigurationEntryStore}s.
@@ -45,5 +47,59 @@ package sonia.scm.store;
* @apiviz.landmark
* @apiviz.uses sonia.scm.store.ConfigurationEntryStore
*/
public interface ConfigurationEntryStoreFactory extends StoreFactory<ConfigurationEntryStore> {
public interface ConfigurationEntryStoreFactory {
<T> ConfigurationEntryStore<T> getStore(final StoreParameters storeParameters);
default <T> TypedFloatingConfigurationEntryStoreParameters<T>.Builder withType(Class<T> type) {
return new TypedFloatingConfigurationEntryStoreParameters<T>(this).new Builder(type);
}
}
final class TypedFloatingConfigurationEntryStoreParameters<T> implements StoreParameters {
private Class<T> type;
private String name;
private Repository repository;
private final ConfigurationEntryStoreFactory factory;
TypedFloatingConfigurationEntryStoreParameters(ConfigurationEntryStoreFactory factory) {
this.factory = factory;
}
public Class<T> getType() {
return type;
}
public String getName() {
return name;
}
public Repository getRepository() {
return repository;
}
public class Builder {
Builder(Class<T> type) {
TypedFloatingConfigurationEntryStoreParameters.this.type = type;
}
public OptionalRepositoryBuilder withName(String name) {
TypedFloatingConfigurationEntryStoreParameters.this.name = name;
return new OptionalRepositoryBuilder();
}
}
public class OptionalRepositoryBuilder {
public OptionalRepositoryBuilder forRepository(Repository repository) {
TypedFloatingConfigurationEntryStoreParameters.this.repository = repository;
return this;
}
public ConfigurationEntryStore<T> build(){
return factory.getStore(TypedFloatingConfigurationEntryStoreParameters.this);
}
}
}

View File

@@ -33,6 +33,8 @@
package sonia.scm.store;
import sonia.scm.repository.Repository;
/**
* The ConfigurationStoreFactory can be used to create new or get existing
* {@link ConfigurationStore} objects.
@@ -45,4 +47,59 @@ package sonia.scm.store;
* @apiviz.landmark
* @apiviz.uses sonia.scm.store.ConfigurationStore
*/
public interface ConfigurationStoreFactory extends StoreFactory<ConfigurationStore>{}
public interface ConfigurationStoreFactory {
<T> ConfigurationStore<T> getStore(final StoreParameters storeParameters);
default <T> TypedFloatingConfigurationStoreParameters<T>.Builder withType(Class<T> type) {
return new TypedFloatingConfigurationStoreParameters<T>(this).new Builder(type);
}
}
final class TypedFloatingConfigurationStoreParameters<T> implements StoreParameters {
private Class<T> type;
private String name;
private Repository repository;
private final ConfigurationStoreFactory factory;
TypedFloatingConfigurationStoreParameters(ConfigurationStoreFactory factory) {
this.factory = factory;
}
public Class<T> getType() {
return type;
}
public String getName() {
return name;
}
public Repository getRepository() {
return repository;
}
public class Builder {
Builder(Class<T> type) {
TypedFloatingConfigurationStoreParameters.this.type = type;
}
public OptionalRepositoryBuilder withName(String name) {
TypedFloatingConfigurationStoreParameters.this.name = name;
return new OptionalRepositoryBuilder();
}
}
public class OptionalRepositoryBuilder {
public OptionalRepositoryBuilder forRepository(Repository repository) {
TypedFloatingConfigurationStoreParameters.this.repository = repository;
return this;
}
public ConfigurationStore<T> build(){
return factory.getStore(TypedFloatingConfigurationStoreParameters.this);
}
}
}

View File

@@ -32,6 +32,8 @@
package sonia.scm.store;
import sonia.scm.repository.Repository;
/**
* The DataStoreFactory can be used to create new or get existing
* {@link DataStore}s.
@@ -42,4 +44,59 @@ package sonia.scm.store;
* @apiviz.landmark
* @apiviz.uses sonia.scm.store.DataStore
*/
public interface DataStoreFactory extends StoreFactory<DataStore>{}
public interface DataStoreFactory {
<T> DataStore<T> getStore(final StoreParameters storeParameters);
default <T> TypedFloatingDataStoreParameters<T>.Builder withType(Class<T> type) {
return new TypedFloatingDataStoreParameters<T>(this).new Builder(type);
}
}
final class TypedFloatingDataStoreParameters<T> implements StoreParameters {
private Class<T> type;
private String name;
private Repository repository;
private final DataStoreFactory factory;
TypedFloatingDataStoreParameters(DataStoreFactory factory) {
this.factory = factory;
}
public Class<T> getType() {
return type;
}
public String getName() {
return name;
}
public Repository getRepository() {
return repository;
}
public class Builder {
Builder(Class<T> type) {
TypedFloatingDataStoreParameters.this.type = type;
}
public OptionalRepositoryBuilder withName(String name) {
TypedFloatingDataStoreParameters.this.name = name;
return new OptionalRepositoryBuilder();
}
}
public class OptionalRepositoryBuilder {
public OptionalRepositoryBuilder forRepository(Repository repository) {
TypedFloatingDataStoreParameters.this.repository = repository;
return this;
}
public DataStore<T> build(){
return factory.getStore(TypedFloatingDataStoreParameters.this);
}
}
}

View File

@@ -1,58 +0,0 @@
package sonia.scm.store;
import sonia.scm.repository.Repository;
public interface StoreFactory<STORE> {
STORE getStore(final StoreParameters storeParameters);
default FloatingStoreParameters<STORE>.Builder withName(String name) {
return new FloatingStoreParameters<>(this).new Builder(name);
}
}
final class FloatingStoreParameters<STORE> implements StoreParameters {
private Class type;
private String name;
private Repository repository;
private final StoreFactory<STORE> factory;
FloatingStoreParameters(StoreFactory<STORE> factory) {
this.factory = factory;
}
public Class getType() {
return type;
}
public String getName() {
return name;
}
public Repository getRepository() {
return repository;
}
public class Builder {
Builder(String name) {
FloatingStoreParameters.this.name = name;
}
public FloatingStoreParameters<STORE>.Builder withType(Class type) {
FloatingStoreParameters.this.type = type;
return this;
}
public FloatingStoreParameters<STORE>.Builder forRepository(Repository repository) {
FloatingStoreParameters.this.repository = repository;
return this;
}
public STORE build(){
return factory.getStore(FloatingStoreParameters.this);
}
}
}

View File

@@ -8,9 +8,9 @@ import sonia.scm.repository.Repository;
* @author Mohamed Karray
* @since 2.0.0
*/
public interface StoreParameters{
public interface StoreParameters<T> {
Class getType();
Class<T> getType();
String getName();

View File

@@ -66,8 +66,8 @@ public class XmlGroupDAO extends AbstractXmlDAO<Group, XmlGroupDatabase>
@Inject
public XmlGroupDAO(ConfigurationStoreFactory storeFactory) {
super(storeFactory
.withName(STORE_NAME)
.withType(XmlGroupDatabase.class)
.withName(STORE_NAME)
.build());
}

View File

@@ -65,8 +65,8 @@ public class XmlUserDAO extends AbstractXmlDAO<User, XmlUserDatabase>
public XmlUserDAO(ConfigurationStoreFactory storeFactory)
{
super(storeFactory
.withName(STORE_NAME)
.withType(XmlUserDatabase.class)
.withName(STORE_NAME)
.build());
}

View File

@@ -67,7 +67,6 @@ public class FileBlobStoreTest extends BlobStoreTestBase
public void shouldStoreAndLoadInRepository() {
BlobStore store = createBlobStoreFactory()
.withName("test")
.withType(StoreObject.class)
.forRepository(new Repository("id", "git", "ns", "n"))
.build();

View File

@@ -133,8 +133,8 @@ public class JAXBConfigurationEntryStoreTest
store.put("a45", new AssignedPermission("tuser4", "repository:create"));
store = createConfigurationStoreFactory()
.withName(name)
.withType(AssignedPermission.class)
.withName(name)
.build();
AssignedPermission ap = store.get("a45");
@@ -232,8 +232,8 @@ public class JAXBConfigurationEntryStoreTest
copy(resource, name);
return createConfigurationStoreFactory()
.withName(name)
.withType(AssignedPermission.class)
.withName(name)
.build();
}
}

View File

@@ -57,8 +57,8 @@ public class JAXBConfigurationStoreTest extends StoreTestBase {
public void shouldStoreAndLoadInRepository()
{
ConfigurationStore<StoreObject> store = createStoreFactory()
.withName("test")
.withType(StoreObject.class)
.withName("test")
.forRepository(new Repository("id", "git", "ns", "n"))
.build();

View File

@@ -62,8 +62,8 @@ public class JAXBDataStoreTest extends DataStoreTestBase {
@Override
protected DataStore getDataStore(Class type, Repository repository) {
return createDataStoreFactory()
.withName("test")
.withType(type)
.withName("test")
.forRepository(repository)
.build();
}
@@ -71,8 +71,8 @@ public class JAXBDataStoreTest extends DataStoreTestBase {
@Override
protected DataStore getDataStore(Class type) {
return createDataStoreFactory()
.withName("test")
.withType(type)
.withName("test")
.build();
}

View File

@@ -86,7 +86,7 @@ public class GitRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase {
@Before
public void initFactory() {
when(factory.withName(any())).thenCallRealMethod();
when(factory.withType(any())).thenCallRealMethod();
}
@Override

View File

@@ -72,7 +72,7 @@ public class HgRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase {
@Before
public void initFactory() {
when(factory.withName(any())).thenCallRealMethod();
when(factory.withType(any())).thenCallRealMethod();
}
@Override

View File

@@ -107,7 +107,7 @@ public class SvnRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase {
@Test
public void getDirectory() {
when(factory.withName(any())).thenCallRealMethod();
when(factory.withType(any())).thenCallRealMethod();
SvnRepositoryHandler repositoryHandler = new SvnRepositoryHandler(factory,
facade, locationResolver);

View File

@@ -52,16 +52,16 @@ public abstract class ConfigurationEntryStoreTestBase extends KeyValueStoreTestB
@Override
protected ConfigurationEntryStore getDataStore(Class type) {
return this.createConfigurationStoreFactory()
.withName(storeName)
.withType(type)
.withName(storeName)
.build();
}
@Override
protected ConfigurationEntryStore getDataStore(Class type, Repository repository) {
return this.createConfigurationStoreFactory()
.withName(repoStoreName)
.withType(type)
.withName(repoStoreName)
.forRepository(repository)
.build();
}

View File

@@ -65,13 +65,13 @@ public abstract class DataStoreTestBase extends KeyValueStoreTestBase
// TODO
public void shouldStoreRepositorySpecificData()
{
StoreFactory<DataStore > dataStoreFactory = createDataStoreFactory();
DataStoreFactory dataStoreFactory = createDataStoreFactory();
StoreObject obj = new StoreObject("test-1");
Repository repository = RepositoryTestData.createHeartOfGold();
DataStore<StoreObject> store = dataStoreFactory
.withName("test")
.withType(StoreObject.class)
.withName("test")
.forRepository(repository)
.build();

View File

@@ -66,7 +66,7 @@ public abstract class StoreTestBase extends AbstractTestBase
@Test
public void testGet()
{
ConfigurationStore<StoreObject> store = createStoreFactory().withName("test").withType(StoreObject.class).build();
ConfigurationStore<StoreObject> store = createStoreFactory().withType(StoreObject.class).withName("test").build();
assertNotNull(store);
@@ -82,7 +82,7 @@ public abstract class StoreTestBase extends AbstractTestBase
@Test
public void testSet()
{
ConfigurationStore<StoreObject> store = createStoreFactory().withName("test").withType(StoreObject.class).build();
ConfigurationStore<StoreObject> store = createStoreFactory().withType(StoreObject.class).withName("test").build();
assertNotNull(store);

View File

@@ -112,8 +112,8 @@ public class DefaultSecuritySystem implements SecuritySystem
public DefaultSecuritySystem(ConfigurationEntryStoreFactory storeFactory)
{
store = storeFactory
.withName(NAME)
.withType(AssignedPermission.class)
.withName(NAME)
.build();
readAvailablePermissions();
}

View File

@@ -91,8 +91,8 @@ public class SecureKeyResolver extends SigningKeyResolverAdapter
public SecureKeyResolver(ConfigurationEntryStoreFactory storeFactory)
{
store = storeFactory
.withName(STORE_NAME)
.withType(SecureKey.class)
.withName(STORE_NAME)
.build();
}

View File

@@ -67,7 +67,7 @@ public class AutoCompleteResourceTest {
xmlDB = mock(XmlDatabase.class);
when(storeConfig.get()).thenReturn(xmlDB);
when(storeFactory.getStore(any())).thenReturn(storeConfig);
when(storeFactory.withName(any())).thenCallRealMethod();
when(storeFactory.withType(any())).thenCallRealMethod();
XmlUserDAO userDao = new XmlUserDAO(storeFactory);
this.userDao = spy(userDao);
XmlGroupDAO groupDAO = new XmlGroupDAO(storeFactory);

View File

@@ -126,8 +126,8 @@ public class SecureKeyResolverTest
{
ConfigurationEntryStoreFactory factory = mock(ConfigurationEntryStoreFactory.class);
when(factory.withName(any())).thenCallRealMethod();
when(factory.getStore(argThat(storeParameters -> {
when(factory.withType(any())).thenCallRealMethod();
when(factory.<SecureKey>getStore(argThat(storeParameters -> {
assertThat(storeParameters.getName()).isEqualTo(SecureKeyResolver.STORE_NAME);
assertThat(storeParameters.getType()).isEqualTo(SecureKey.class);
return true;