Skip to content

Commit

Permalink
DATAGEODE-4 - Polish.
Browse files Browse the repository at this point in the history
  • Loading branch information
jxblum committed May 3, 2017
1 parent d018192 commit 5523c12
Show file tree
Hide file tree
Showing 16 changed files with 92 additions and 79 deletions.
Expand Up @@ -26,7 +26,6 @@
import org.apache.geode.IncompatibleSystemException;
import org.apache.geode.InternalGemFireException;
import org.apache.geode.InvalidValueException;
import org.apache.geode.LicenseException;
import org.apache.geode.NoSystemException;
import org.apache.geode.SystemConnectException;
import org.apache.geode.SystemIsRunningException;
Expand Down Expand Up @@ -194,9 +193,6 @@ public static DataAccessException convertGemfireAccessException(GemFireException
if (ex instanceof CopyException) {
return new GemfireSystemException(ex);
}
if (ex instanceof org.apache.geode.cache.EntryNotFoundInRegion) {
return new DataRetrievalFailureException(ex.getMessage(), ex);
}
if (ex instanceof FunctionException) {
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
}
Expand Down Expand Up @@ -224,9 +220,6 @@ public static DataAccessException convertGemfireAccessException(GemFireException
if (ex instanceof LeaseExpiredException) {
return new PessimisticLockingFailureException(ex.getMessage(), ex);
}
if (ex instanceof LicenseException) {
return new GemfireSystemException(ex);
}
if (ex instanceof NoSystemException) {
return new GemfireSystemException(ex);
}
Expand Down
Expand Up @@ -13,17 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.data.gemfire.repository;

import org.springframework.data.domain.Sort;
import org.springframework.data.repository.CrudRepository;

/**
* Gemfire-specific extension of the {@link CrudRepository} interface.
* GemFire specific extension of the Spring Data {@link CrudRepository} interface.
*
* @author Oliver Gierke
* @author John Blum
* @see java.io.Serializable
* @see org.springframework.data.repository.CrudRepository
*/
public interface GemfireRepository<T, ID> extends CrudRepository<T, ID> {
Expand Down
Expand Up @@ -13,19 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.data.gemfire.repository;

import lombok.NonNull;
import lombok.Value;

/**
* Simple value object to hold an entity alongside an external key the entity shall be stored under.
*
* Simple value object holding an entity along with the external key in which the entity will be mapped.
*
* @author Oliver Gierke
*/
@Value
public class Wrapper<T, KEY> {

T entity;
@NonNull KEY key;

}
Expand Up @@ -21,8 +21,8 @@
import org.springframework.data.repository.core.support.PersistentEntityInformation;

/**
* Implementation of {@link GemfireEntityInformation} to return the region name stored in the backing
* {@link PersistentEntity}.
* Implementation of {@link GemfireEntityInformation} and Spring Data's {@link PersistentEntityInformation}
* that returns the Region name associated with the {@link PersistentEntity}.
*
* @author Oliver Gierke
* @author John Blum
Expand Down Expand Up @@ -53,5 +53,4 @@ public DefaultGemfireEntityInformation(GemfirePersistentEntity<T> entity) {
public String getRegionName() {
return entity.getRegionName();
}

}
Expand Up @@ -13,15 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.data.gemfire.repository.query;

import org.apache.geode.cache.Region;
import org.springframework.data.repository.core.EntityInformation;

/**
* {@link EntityInformation} to capture Gemfire specific information.
* {@link EntityInformation} capturing GemFire specific information.
*
* @author Oliver Gierke
* @see org.springframework.data.repository.core.EntityInformation
*/
public interface GemfireEntityInformation<T, ID> extends EntityInformation<T, ID> {

Expand All @@ -31,4 +33,5 @@ public interface GemfireEntityInformation<T, ID> extends EntityInformation<T, ID
* @return the name of the {@link Region} the entity is held in.
*/
String getRegionName();

}
Expand Up @@ -16,7 +16,8 @@

package org.springframework.data.gemfire.repository.support;

import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.*;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalStateException;

import java.io.Serializable;
import java.lang.reflect.Method;
Expand Down Expand Up @@ -82,9 +83,10 @@ public GemfireRepositoryFactory(Iterable<Region<?, ?>> regions,
@Override
@SuppressWarnings("unchecked")
public <T, ID> GemfireEntityInformation<T, ID> getEntityInformation(Class<T> domainClass) {

GemfirePersistentEntity<T> entity = (GemfirePersistentEntity<T>) mappingContext.getPersistentEntity(domainClass)
.orElseThrow(() -> newIllegalArgumentException("Unable to resolve PersistentEntity for type [%s]", domainClass));
.orElseThrow(() -> newIllegalArgumentException("Unable to resolve PersistentEntity for type [%s]",
domainClass));

return new DefaultGemfireEntityInformation<>(entity);
}
Expand All @@ -95,37 +97,39 @@ public <T, ID> GemfireEntityInformation<T, ID> getEntityInformation(Class<T> dom
*/
@Override
protected Object getTargetRepository(RepositoryInformation repositoryInformation) {
GemfireEntityInformation<?, Serializable> entityInformation = getEntityInformation(
repositoryInformation.getDomainType());

GemfireEntityInformation<?, Serializable> entityInformation =
getEntityInformation(repositoryInformation.getDomainType());

GemfireTemplate gemfireTemplate = getTemplate(repositoryInformation);

return getTargetRepositoryViaReflection(repositoryInformation, gemfireTemplate, entityInformation);
}

GemfireTemplate getTemplate(RepositoryMetadata metadata) {

GemfirePersistentEntity<?> entity = mappingContext.getPersistentEntity(metadata.getDomainType())
.orElseThrow(() -> newIllegalArgumentException("Unable to resolve PersistentEntity for type [%s]",
metadata.getDomainType()));

String entityRegionName = entity.getRegionName();
String repositoryRegionName = getRepositoryRegionName(metadata.getRepositoryInterface());
String regionName = (StringUtils.hasText(repositoryRegionName) ? repositoryRegionName : entityRegionName);
String resolvedRegionName = StringUtils.hasText(repositoryRegionName) ? repositoryRegionName : entityRegionName;

Region<?, ?> region = regions.getRegion(regionName);
Region<?, ?> region = regions.getRegion(resolvedRegionName);

if (region == null) {
throw new IllegalStateException(String.format("No Region '%1$s' found for domain class %2$s;"
throw newIllegalStateException("No Region [%1$s] was found for domain class [%2$s];"
+ " Make sure you have configured a GemFire Region of that name in your application context",
regionName, metadata.getDomainType().getName()));
resolvedRegionName, metadata.getDomainType().getName());
}

Class<?> regionKeyType = region.getAttributes().getKeyConstraint();
Class<?> entityIdType = metadata.getIdType();

if (regionKeyType != null && entity.getIdProperty() != null) {
Assert.isTrue(regionKeyType.isAssignableFrom(entityIdType), String.format(
"The Region referenced only supports keys of type %1$s, but the entity to be stored has an id of type %2$s",
"The Region referenced only supports keys of type [%1$s], but the entity to be stored has an id of type [%2$s]",
regionKeyType.getName(), entityIdType.getName()));
}

Expand Down
Expand Up @@ -16,7 +16,6 @@

package org.springframework.data.gemfire.repository.support;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
Expand Down Expand Up @@ -54,7 +53,7 @@
* @see org.apache.geode.cache.Cache
* @see org.apache.geode.cache.Region
*/
public class SimpleGemfireRepository<T, ID extends Serializable> implements GemfireRepository<T, ID> {
public class SimpleGemfireRepository<T, ID> implements GemfireRepository<T, ID> {

private final EntityInformation<T, ID> entityInformation;

Expand All @@ -80,7 +79,6 @@ public SimpleGemfireRepository(GemfireTemplate template, EntityInformation<T, ID
*/
@Override
public <U extends T> U save(U entity) {

ID id = entityInformation.getRequiredId(entity);

template.put(id, entity);
Expand All @@ -94,13 +92,10 @@ public <U extends T> U save(U entity) {
*/
@Override
public <U extends T> Iterable<U> saveAll(Iterable<U> entities) {

Map<ID, U> entitiesToSave = new HashMap<>();

entities.forEach(entity -> {
entitiesToSave.put(entityInformation.getRequiredId(entity), entity);
});

entities.forEach(entity -> entitiesToSave.put(entityInformation.getRequiredId(entity), entity));

template.putAll(entitiesToSave);

return entitiesToSave.values();
Expand All @@ -113,7 +108,9 @@ public <U extends T> Iterable<U> saveAll(Iterable<U> entities) {
@Override
public T save(Wrapper<T, ID> wrapper) {
T entity = wrapper.getEntity();

template.put(wrapper.getKey(), entity);

return entity;
}

Expand Down Expand Up @@ -180,10 +177,9 @@ public Iterable<T> findAll(Sort sort) {
*/
@Override
public Collection<T> findAllById(Iterable<ID> ids) {

List<ID> parameters = Streamable.of(ids).stream().collect(StreamUtils.toUnmodifiableList());
List<ID> keys = Streamable.of(ids).stream().collect(StreamUtils.toUnmodifiableList());

return CollectionUtils.<ID, T>nullSafeMap(template.getAll(parameters)).values().stream()
return CollectionUtils.<ID, T>nullSafeMap(template.getAll(keys)).values().stream()
.filter(Objects::nonNull).collect(Collectors.toList());
}

Expand Down
Expand Up @@ -10,9 +10,10 @@
* 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.data.gemfire.client;

import static org.assertj.core.api.Assertions.*;
import static org.assertj.core.api.Assertions.assertThat;

import java.util.Arrays;
import java.util.List;
Expand Down
Expand Up @@ -16,7 +16,7 @@

package org.springframework.data.gemfire.repository.sample;

import static org.assertj.core.api.Assertions.*;
import static org.assertj.core.api.Assertions.assertThat;

import java.util.Optional;

Expand All @@ -27,20 +27,20 @@
import org.springframework.test.context.junit4.SpringRunner;

/**
* The AnimalRepositoryTest class is a test suite of test cases testing the functionality behind PR #55 involving
* persisting application domain object/entities to multiple Regions in GemFire's Cache.
* Integration test testing the functionality behind PR #55 involving persisting application domain object/entities
* to multiple Regions in a GemFire Cache.
*
* @author Stuart Williams
* @author John Blum
* @see org.junit.Test
* @see org.junit.runner.RunWith
* @see org.springframework.test.context.ContextConfiguration
* @see org.springframework.test.context.junit4.SpringJUnit4ClassRunner
* @since 1.4.0
* @see org.springframework.test.context.junit4.SpringRunner
* @link https://github.com/spring-projects/spring-data-gemfire/pull/55
* @since 1.4.0
*/
@ContextConfiguration
@RunWith(SpringRunner.class)
@ContextConfiguration
@SuppressWarnings("unused")
public class AnimalRepositoryTest {

Expand All @@ -58,7 +58,7 @@ protected static Animal newAnimal(long id, String name) {
}

@Test
public void testEntityStoredInMultipleRegions() {
public void entityStoredInMultipleRegionsIsSuccessful() {
Animal felix = newAnimal(1, "Felix");
Animal leo = newAnimal(2, "Leo");
Animal cerberus = newAnimal(3, "Cerberus");
Expand Down
Expand Up @@ -39,15 +39,16 @@
*/
public class IncompatibleRegionKeyEntityIdAnimalRepositoryTest {

protected static final String APPLICATION_CONTEXT_CONFIG_LOCATION = String.format("%1$s%2$s%1$s%3$s",
private static final String APPLICATION_CONTEXT_CONFIG_LOCATION = String.format("%1$s%2$s%1$s%3$s",
File.separator, AnimalRepositoryTest.class.getPackage().getName().replace('.', File.separatorChar),
"IncompatibleRegionKeyEntityIdAnimalRepositoryTest-context.xml");
String.format("%s-context.xml", IncompatibleRegionKeyEntityIdAnimalRepositoryTest.class.getSimpleName()));

@Test(expected = IllegalArgumentException.class)
public void storeAnimalHavingLongIdInRabbitsRegionWithStringKey() {
try {
ConfigurableApplicationContext applicationContext = new ClassPathXmlApplicationContext(
APPLICATION_CONTEXT_CONFIG_LOCATION);
ConfigurableApplicationContext applicationContext =
new ClassPathXmlApplicationContext(APPLICATION_CONTEXT_CONFIG_LOCATION);

applicationContext.getBean(RabbitRepository.class);
}
// NOTE the ClassCastException thrown from GemFire is unexpected; this is not correct and the identifying type
Expand All @@ -62,8 +63,9 @@ public void storeAnimalHavingLongIdInRabbitsRegionWithStringKey() {
catch (BeanCreationException expected) {
//expected.printStackTrace(System.err);
assertTrue(expected.getCause() instanceof IllegalArgumentException);
assertEquals(String.format("The Region referenced only supports keys of type %1$s, but the entity to be stored has an id of type %2$s",
assertEquals(String.format("The Region referenced only supports keys of type [%1$s], but the entity to be stored has an id of type [%2$s]",
String.class.getName(), Long.class.getName()), expected.getCause().getMessage());

throw (IllegalArgumentException) expected.getCause();
}
}
Expand Down
Expand Up @@ -38,24 +38,26 @@
*/
public class PlantRepositoryTest {

protected static final String APPLICATION_CONTEXT_CONFIG_LOCATION = String.format("%1$s%2$s%1$s%3$s",
private static final String APPLICATION_CONTEXT_CONFIG_LOCATION = String.format("%1$s%2$s%1$s%3$s",
File.separator, PlantRepositoryTest.class.getPackage().getName().replace('.', File.separatorChar),
"PlantRepositoryTest-context.xml");

@Test(expected = IllegalArgumentException.class)
public void storePlantHavingStringIdInPlantsRegionWithLongKey() {
try {
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext(
APPLICATION_CONTEXT_CONFIG_LOCATION);
ConfigurableApplicationContext context =
new ClassPathXmlApplicationContext(APPLICATION_CONTEXT_CONFIG_LOCATION);

context.getBean(PlantRepository.class);
}
// NOTE technically, the IllegalArgumentException for incompatible Region 'Key' and Entity ID is thrown
// when the Spring container starts up and the Repository beans are created.
catch (BeanCreationException expected) {
//expected.printStackTrace(System.err);
assertTrue(expected.getCause() instanceof IllegalArgumentException);
assertEquals(String.format("The Region referenced only supports keys of type %1$s, but the entity to be stored has an id of type %2$s",
assertEquals(String.format("The Region referenced only supports keys of type [%1$s], but the entity to be stored has an id of type [%2$s]",
Long.class.getName(), String.class.getName()), expected.getCause().getMessage());

throw (IllegalArgumentException) expected.getCause();
}
}
Expand Down

0 comments on commit 5523c12

Please sign in to comment.