SGF-82, SGF-83 - Initial draft of repository integration.
Added support for annotation based entity mapping (@Region, @Id, @PersistenceConstructor). Added support for Spring Data repositories (query execution, query derivation).
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
package org.springframework.data.gemfire.config;
|
||||
|
||||
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
|
||||
import org.springframework.data.gemfire.repository.config.GemfireRepositoryParser;
|
||||
|
||||
/**
|
||||
* Namespace handler for GemFire definitions.
|
||||
@@ -40,5 +41,7 @@ class GemfireNamespaceHandler extends NamespaceHandlerSupport {
|
||||
registerBeanDefinitionParser("transaction-manager", new TransactionManagerParser());
|
||||
|
||||
registerBeanDefinitionParser("cq-listener-container", new GemfireListenerContainerParser());
|
||||
|
||||
registerBeanDefinitionParser("repositories", new GemfireRepositoryParser());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2012 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.data.gemfire.mapping;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.springframework.data.mapping.context.AbstractMappingContext;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class GemfireMappingContext extends
|
||||
AbstractMappingContext<GemfirePersistentEntity<?>, GemfirePersistentProperty> {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.AbstractMappingContext#createPersistentEntity(org.springframework.data.util.TypeInformation)
|
||||
*/
|
||||
@Override
|
||||
protected <T> GemfirePersistentEntity<?> createPersistentEntity(TypeInformation<T> typeInformation) {
|
||||
return new GemfirePersistentEntity<T>(typeInformation);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.AbstractMappingContext#createPersistentProperty(java.lang.reflect.Field, java.beans.PropertyDescriptor, org.springframework.data.mapping.model.MutablePersistentEntity, org.springframework.data.mapping.model.SimpleTypeHolder)
|
||||
*/
|
||||
@Override
|
||||
protected GemfirePersistentProperty createPersistentProperty(Field field, PropertyDescriptor descriptor,
|
||||
GemfirePersistentEntity<?> owner, SimpleTypeHolder simpleTypeHolder) {
|
||||
return new GemfirePersistentProperty(field, descriptor, owner, simpleTypeHolder);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2012 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.data.gemfire.mapping;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.model.BasicPersistentEntity;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link PersistentEntity} implementation adding custom Gemfire related metadata, such as the region the entity is
|
||||
* mapped to etc.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class GemfirePersistentEntity<T> extends BasicPersistentEntity<T, GemfirePersistentProperty> {
|
||||
|
||||
private final String regionName;
|
||||
|
||||
/**
|
||||
* Creates a new {@link GemfirePersistentEntity} for the given {@link TypeInformation}.
|
||||
*
|
||||
* @param information must not be {@literal null}.
|
||||
*/
|
||||
public GemfirePersistentEntity(TypeInformation<T> information) {
|
||||
|
||||
super(information);
|
||||
|
||||
Class<T> rawType = information.getType();
|
||||
Region region = rawType.getAnnotation(Region.class);
|
||||
String fallbackName = rawType.getSimpleName();
|
||||
|
||||
this.regionName = region == null || !StringUtils.hasText(region.value()) ? fallbackName : region.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the region the entity shall be stored in.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getRegionName() {
|
||||
return this.regionName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2012 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.data.gemfire.mapping;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
|
||||
/**
|
||||
* {@link PersistentProperty} implementation to for Gemfire related metadata.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class GemfirePersistentProperty extends AnnotationBasedPersistentProperty<GemfirePersistentProperty> {
|
||||
|
||||
/**
|
||||
* @param field
|
||||
* @param propertyDescriptor
|
||||
* @param owner
|
||||
* @param simpleTypeHolder
|
||||
*/
|
||||
public GemfirePersistentProperty(Field field, PropertyDescriptor propertyDescriptor,
|
||||
PersistentEntity<?, GemfirePersistentProperty> owner, SimpleTypeHolder simpleTypeHolder) {
|
||||
super(field, propertyDescriptor, owner, simpleTypeHolder);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.AbstractPersistentProperty#createAssociation()
|
||||
*/
|
||||
@Override
|
||||
protected Association<GemfirePersistentProperty> createAssociation() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2012 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.data.gemfire.mapping;
|
||||
|
||||
import org.springframework.data.mapping.model.PropertyValueProvider;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.gemstone.gemfire.pdx.PdxReader;
|
||||
|
||||
/**
|
||||
* {@link PropertyValueProvider} to read property values from a {@link PdxReader}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
class GemfirePropertyValueProvider implements PropertyValueProvider<GemfirePersistentProperty> {
|
||||
|
||||
private final PdxReader reader;
|
||||
|
||||
/**
|
||||
* Creates a new {@link GemfirePropertyValueProvider} with the given {@link PdxReader}.
|
||||
*
|
||||
* @param reader must not be {@literal null}.
|
||||
*/
|
||||
public GemfirePropertyValueProvider(PdxReader reader) {
|
||||
Assert.notNull(reader);
|
||||
this.reader = reader;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.convert.PropertyValueProvider#getPropertyValue(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getPropertyValue(GemfirePersistentProperty property) {
|
||||
return (T) reader.readObject(property.getName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright 2012 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.data.gemfire.mapping;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.convert.EntityInstantiator;
|
||||
import org.springframework.data.convert.EntityInstantiators;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PropertyHandler;
|
||||
import org.springframework.data.mapping.model.BeanWrapper;
|
||||
import org.springframework.data.mapping.model.DefaultSpELExpressionEvaluator;
|
||||
import org.springframework.data.mapping.model.MappingException;
|
||||
import org.springframework.data.mapping.model.PersistentEntityParameterValueProvider;
|
||||
import org.springframework.data.mapping.model.SpELContext;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.gemstone.gemfire.pdx.PdxReader;
|
||||
import com.gemstone.gemfire.pdx.PdxSerializer;
|
||||
import com.gemstone.gemfire.pdx.PdxWriter;
|
||||
|
||||
/**
|
||||
* {@link PdxSerializer} implementation that uses a {@link GemfireMappingContext} to read and write entities.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class MappingPdxSerializer implements PdxSerializer, ApplicationContextAware {
|
||||
|
||||
private final GemfireMappingContext mappingContext;
|
||||
private final ConversionService conversionService;
|
||||
|
||||
private EntityInstantiators instantiators;
|
||||
private SpELContext context;
|
||||
|
||||
/**
|
||||
* Creates a new {@link MappingPdxSerializer} using the given {@link GemfireMappingContext} and
|
||||
* {@link ConversionService}.
|
||||
*
|
||||
* @param mappingContext must not be {@literal null}.
|
||||
* @param conversionService must not be {@literal null}.
|
||||
*/
|
||||
public MappingPdxSerializer(GemfireMappingContext mappingContext, ConversionService conversionService) {
|
||||
|
||||
Assert.notNull(mappingContext);
|
||||
Assert.notNull(conversionService);
|
||||
|
||||
this.mappingContext = mappingContext;
|
||||
this.conversionService = conversionService;
|
||||
this.instantiators = new EntityInstantiators();
|
||||
this.context = new SpELContext(PdxReaderPropertyAccessor.INSTANCE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the {@link EntityInstantiator}s to be used to create the instances to be read.
|
||||
*
|
||||
* @param gemfireInstantiators must not be {@literal null}.
|
||||
*/
|
||||
public void setGemfireInstantiators(Map<Class<?>, EntityInstantiator> gemfireInstantiators) {
|
||||
Assert.notNull(gemfireInstantiators);
|
||||
this.instantiators = new EntityInstantiators(gemfireInstantiators);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
|
||||
*/
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.context = new SpELContext(context, applicationContext);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see com.gemstone.gemfire.pdx.PdxSerializer#fromData(java.lang.Class, com.gemstone.gemfire.pdx.PdxReader)
|
||||
*/
|
||||
public Object fromData(Class<?> type, final PdxReader reader) {
|
||||
|
||||
final GemfirePersistentEntity<?> entity = mappingContext.getPersistentEntity(type);
|
||||
EntityInstantiator instantiator = instantiators.getInstantiatorFor(entity);
|
||||
GemfirePropertyValueProvider propertyValueProvider = new GemfirePropertyValueProvider(reader);
|
||||
|
||||
PersistentEntityParameterValueProvider<GemfirePersistentProperty> provider = new PersistentEntityParameterValueProvider<GemfirePersistentProperty>(
|
||||
entity, propertyValueProvider);
|
||||
provider.setSpELEvaluator(new DefaultSpELExpressionEvaluator(reader, context));
|
||||
|
||||
Object instance = instantiator.createInstance(entity, provider);
|
||||
|
||||
final BeanWrapper<PersistentEntity<Object, ?>, Object> wrapper = BeanWrapper.create(instance, conversionService);
|
||||
|
||||
entity.doWithProperties(new PropertyHandler<GemfirePersistentProperty>() {
|
||||
public void doWithPersistentProperty(GemfirePersistentProperty persistentProperty) {
|
||||
|
||||
if (entity.isConstructorArgument(persistentProperty)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object value = reader.readField(persistentProperty.getName());
|
||||
|
||||
try {
|
||||
wrapper.setProperty(persistentProperty, value);
|
||||
} catch (Exception e) {
|
||||
throw new MappingException("Could not read value " + value.toString(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return wrapper.getBean();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see com.gemstone.gemfire.pdx.PdxSerializer#toData(java.lang.Object, com.gemstone.gemfire.pdx.PdxWriter)
|
||||
*/
|
||||
public boolean toData(Object value, final PdxWriter writer) {
|
||||
|
||||
GemfirePersistentEntity<?> entity = mappingContext.getPersistentEntity(value.getClass());
|
||||
final BeanWrapper<PersistentEntity<Object, ?>, Object> wrapper = BeanWrapper.create(value, conversionService);
|
||||
|
||||
entity.doWithProperties(new PropertyHandler<GemfirePersistentProperty>() {
|
||||
public void doWithPersistentProperty(GemfirePersistentProperty persistentProperty) {
|
||||
|
||||
try {
|
||||
Object value = wrapper.getProperty(persistentProperty);
|
||||
writer.writeObject(persistentProperty.getName(), value);
|
||||
} catch (Exception e) {
|
||||
throw new MappingException("Could not write value for property " + persistentProperty.toString(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
GemfirePersistentProperty idProperty = entity.getIdProperty();
|
||||
|
||||
if (idProperty != null) {
|
||||
writer.markIdentityField(idProperty.getName());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2012 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.data.gemfire.mapping;
|
||||
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.PropertyAccessor;
|
||||
import org.springframework.expression.TypedValue;
|
||||
|
||||
import com.gemstone.gemfire.pdx.PdxReader;
|
||||
|
||||
/**
|
||||
* {@link PropertyAccessor} to read values from a {@link PdxReader}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
enum PdxReaderPropertyAccessor implements PropertyAccessor {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.expression.PropertyAccessor#getSpecificTargetClasses()
|
||||
*/
|
||||
@Override
|
||||
public Class<?>[] getSpecificTargetClasses() {
|
||||
return new Class<?>[] { PdxReader.class };
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.expression.PropertyAccessor#canRead(org.springframework.expression.EvaluationContext, java.lang.Object, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean canRead(EvaluationContext context, Object target, String name) {
|
||||
return ((PdxReader) target).hasField(name);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.expression.PropertyAccessor#read(org.springframework.expression.EvaluationContext, java.lang.Object, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public TypedValue read(EvaluationContext context, Object target, String name) {
|
||||
Object object = ((PdxReader) target).readObject(name);
|
||||
return object == null ? TypedValue.NULL : new TypedValue(object);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.expression.PropertyAccessor#canWrite(org.springframework.expression.EvaluationContext, java.lang.Object, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean canWrite(EvaluationContext context, Object target, String name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.expression.PropertyAccessor#write(org.springframework.expression.EvaluationContext, java.lang.Object, java.lang.String, java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public void write(EvaluationContext context, Object target, String name, Object newValue) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2012 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.data.gemfire.mapping;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation to define the region an entity will be stored in.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Inherited
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Documented
|
||||
public @interface Region {
|
||||
|
||||
/**
|
||||
* The name of the {@link com.gemstone.gemfire.cache.Region} the entity shall be stored in.
|
||||
*
|
||||
* @return the name of the region the entity shall be persisted in.
|
||||
*/
|
||||
String value() default "";
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2012 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.data.gemfire.mapping;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.gemstone.bp.edu.emory.mathcs.backport.java.util.Collections;
|
||||
import com.gemstone.gemfire.cache.Region;
|
||||
|
||||
/**
|
||||
* Simple value object to abstract access to regions by name and mapped type.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class Regions implements Iterable<Region<?, ?>> {
|
||||
|
||||
private final Map<String, Region<?, ?>> regions;
|
||||
private final MappingContext<? extends GemfirePersistentEntity<?>, ?> context;
|
||||
|
||||
/**
|
||||
* Creates a new {@link Regions} wrapper for the given {@link Region}s and {@link MappingContext}.
|
||||
*
|
||||
* @param regions must not be {@literal null}.
|
||||
* @param context must not be {@literal null}.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Regions(Iterable<Region<?, ?>> regions, MappingContext<? extends GemfirePersistentEntity<?>, ?> context) {
|
||||
|
||||
Assert.notNull(regions);
|
||||
Assert.notNull(context);
|
||||
|
||||
Map<String, com.gemstone.gemfire.cache.Region<?, ?>> regionMap = new HashMap<String, Region<?, ?>>();
|
||||
|
||||
for (Region<?, ?> region : regions) {
|
||||
regionMap.put(region.getName(), region);
|
||||
}
|
||||
|
||||
this.regions = Collections.unmodifiableMap(regionMap);
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Region} the given type is mapped to. Will try to find a {@link Region} with the simple class
|
||||
* name in case no mapping information is found.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> Region<?, T> getRegion(Class<T> type) {
|
||||
|
||||
Assert.notNull(type);
|
||||
|
||||
GemfirePersistentEntity<?> entity = context.getPersistentEntity(type);
|
||||
return (Region<?, T>) (entity == null ? regions.get(type.getSimpleName()) : regions.get(entity.getRegionName()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the region with the given name.
|
||||
*
|
||||
* @param name must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <S, T> Region<S, T> getRegion(String name) {
|
||||
|
||||
Assert.notNull(name);
|
||||
|
||||
return (Region<S, T>) regions.get(name);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Iterable#iterator()
|
||||
*/
|
||||
@Override
|
||||
public Iterator<Region<?, ?>> iterator() {
|
||||
return regions.values().iterator();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2012 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.data.gemfire.repository;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
/**
|
||||
* Gemfire-specific extension of the {@link CrudRepository} interface.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface GemfireRepository<T, ID extends Serializable> extends CrudRepository<T, ID> {
|
||||
|
||||
T save(Wrapper<T, ID> wrapper);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2012 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.data.gemfire.repository;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface Query {
|
||||
|
||||
String value() default "";
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2012 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.data.gemfire.repository;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Simple value object to hold an entity alongside an external key the entity shall be stored under.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public final class Wrapper<T, KEY extends Serializable> {
|
||||
|
||||
private final KEY key;
|
||||
private final T entity;
|
||||
|
||||
/**
|
||||
* The entity to handle as well as the key.
|
||||
*
|
||||
* @param entity
|
||||
* @param key must not be {@literal null}.
|
||||
*/
|
||||
public Wrapper(T entity, KEY key) {
|
||||
|
||||
Assert.notNull(key);
|
||||
|
||||
this.entity = entity;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the key
|
||||
*/
|
||||
public KEY getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the entity
|
||||
*/
|
||||
public T getEntity() {
|
||||
return entity;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object value) {
|
||||
|
||||
if (this == value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(value instanceof Wrapper)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Wrapper<?, ?> that = (Wrapper<?, ?>) value;
|
||||
|
||||
return this.key.equals(that.key) && ObjectUtils.nullSafeEquals(this.entity, that.entity);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
int result = 17;
|
||||
|
||||
result += 31 * key.hashCode();
|
||||
result += 31 * ObjectUtils.nullSafeHashCode(entity);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2012 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.data.gemfire.repository.config;
|
||||
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.data.gemfire.repository.config.SimpleGemfireRepositoryConfiguration.GemfireRepositoryConfiguration;
|
||||
import org.springframework.data.gemfire.repository.support.GemfireRepositoryFactoryBean;
|
||||
import org.springframework.data.repository.config.AbstractRepositoryConfigDefinitionParser;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* {@link BeanDefinitionParser} to create {@link GemfireRepositoryFactoryBean}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class GemfireRepositoryParser extends
|
||||
AbstractRepositoryConfigDefinitionParser<SimpleGemfireRepositoryConfiguration, GemfireRepositoryConfiguration> {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.config.AbstractRepositoryConfigDefinitionParser#getGlobalRepositoryConfigInformation(org.w3c.dom.Element)
|
||||
*/
|
||||
@Override
|
||||
protected SimpleGemfireRepositoryConfiguration getGlobalRepositoryConfigInformation(Element element) {
|
||||
return new SimpleGemfireRepositoryConfiguration(element);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright 2012 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.data.gemfire.repository.config;
|
||||
|
||||
import org.springframework.data.gemfire.GemfireTemplate;
|
||||
import org.springframework.data.gemfire.repository.config.SimpleGemfireRepositoryConfiguration.GemfireRepositoryConfiguration;
|
||||
import org.springframework.data.gemfire.repository.support.GemfireRepositoryFactoryBean;
|
||||
import org.springframework.data.repository.config.AutomaticRepositoryConfigInformation;
|
||||
import org.springframework.data.repository.config.ManualRepositoryConfigInformation;
|
||||
import org.springframework.data.repository.config.RepositoryConfig;
|
||||
import org.springframework.data.repository.config.SingleRepositoryConfigInformation;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Repository configuration implementation.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
class SimpleGemfireRepositoryConfiguration extends
|
||||
RepositoryConfig<GemfireRepositoryConfiguration, SimpleGemfireRepositoryConfiguration> {
|
||||
|
||||
private static final String GEMFIRE_TEMPLATE_REF = "gemfire-template-ref";
|
||||
|
||||
/**
|
||||
* Creates a new {@link SimpleGemfireRepositoryConfiguration} for the given {@link Element}.
|
||||
*
|
||||
* @param repositoriesElement must not be {@literal null}.
|
||||
*/
|
||||
protected SimpleGemfireRepositoryConfiguration(Element repositoriesElement) {
|
||||
super(repositoriesElement, GemfireRepositoryFactoryBean.class.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bean name of the {@link GemfireTemplate} to be used.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getGemfireTemplateRef() {
|
||||
|
||||
String attribute = getSource().getAttribute(GEMFIRE_TEMPLATE_REF);
|
||||
return StringUtils.hasText(attribute) ? attribute : null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.config.GlobalRepositoryConfigInformation#getAutoconfigRepositoryInformation(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public GemfireRepositoryConfiguration getAutoconfigRepositoryInformation(String interfaceName) {
|
||||
return new AutomaticGemfireRepositoryConfiguration(interfaceName, this);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.config.CommonRepositoryConfigInformation#getNamedQueriesLocation()
|
||||
*/
|
||||
@Override
|
||||
public String getNamedQueriesLocation() {
|
||||
return "classpath*:META-INF/gemfire-named-queries.properties";
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.config.RepositoryConfig#createSingleRepositoryConfigInformationFor(org.w3c.dom.Element)
|
||||
*/
|
||||
@Override
|
||||
protected GemfireRepositoryConfiguration createSingleRepositoryConfigInformationFor(Element element) {
|
||||
return new ManualGemfireRepositoryConfiguration(element, this);
|
||||
}
|
||||
|
||||
public interface GemfireRepositoryConfiguration extends
|
||||
SingleRepositoryConfigInformation<SimpleGemfireRepositoryConfiguration> {
|
||||
|
||||
String getGemfireTemplateRef();
|
||||
}
|
||||
|
||||
static class ManualGemfireRepositoryConfiguration extends
|
||||
ManualRepositoryConfigInformation<SimpleGemfireRepositoryConfiguration> implements GemfireRepositoryConfiguration {
|
||||
|
||||
/**
|
||||
* @param element
|
||||
* @param parent
|
||||
*/
|
||||
public ManualGemfireRepositoryConfiguration(Element element, SimpleGemfireRepositoryConfiguration parent) {
|
||||
super(element, parent);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.gemfire.config.GemfireRepositoryParser.SimpleGemfireRepositoryConfiguration.GemfireRepositoryConfiguration#getGemfireTemplateRef()
|
||||
*/
|
||||
@Override
|
||||
public String getGemfireTemplateRef() {
|
||||
return getAttribute(GEMFIRE_TEMPLATE_REF);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class AutomaticGemfireRepositoryConfiguration extends
|
||||
AutomaticRepositoryConfigInformation<SimpleGemfireRepositoryConfiguration> implements
|
||||
GemfireRepositoryConfiguration {
|
||||
|
||||
/**
|
||||
* @param interfaceName
|
||||
* @param parent
|
||||
*/
|
||||
public AutomaticGemfireRepositoryConfiguration(String interfaceName, SimpleGemfireRepositoryConfiguration parent) {
|
||||
super(interfaceName, parent);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.gemfire.config.GemfireRepositoryParser.SimpleGemfireRepositoryConfiguration.GemfireRepositoryConfiguration#getGemfireTemplateRef()
|
||||
*/
|
||||
@Override
|
||||
public String getGemfireTemplateRef() {
|
||||
|
||||
return getParent().getGemfireTemplateRef();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* Implementations of Spring Data COmmons Core repository abstraction.
|
||||
*/
|
||||
package org.springframework.data.gemfire.repository;
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2012 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.data.gemfire.repository.query;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.data.gemfire.mapping.GemfirePersistentEntity;
|
||||
import org.springframework.data.repository.core.support.DelegatingEntityInformation;
|
||||
import org.springframework.data.repository.core.support.ReflectionEntityInformation;
|
||||
|
||||
/**
|
||||
* Implementation of {@link GemfireEntityInformation} using reflection to lookup region names.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class DefaultGemfireEntityInformation<T, ID extends Serializable> extends DelegatingEntityInformation<T, ID>
|
||||
implements GemfireEntityInformation<T, ID> {
|
||||
|
||||
private final GemfirePersistentEntity<T> entity;
|
||||
|
||||
/**
|
||||
* Creates a new {@link DefaultGemfireEntityInformation}.
|
||||
*
|
||||
* @param domainClass must not be {@literal null}.
|
||||
*/
|
||||
public DefaultGemfireEntityInformation(GemfirePersistentEntity<T> entity) {
|
||||
super(new ReflectionEntityInformation<T, ID>(entity.getType()));
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.gemfire.repository.query.GemfireEntityInformation#getRegionName()
|
||||
*/
|
||||
@Override
|
||||
public String getRegionName() {
|
||||
return entity.getRegionName();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2012 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.data.gemfire.repository.query;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.data.repository.core.EntityInformation;
|
||||
|
||||
import com.gemstone.gemfire.cache.Region;
|
||||
|
||||
/**
|
||||
* {@link EntityInformation} to capture Gemfire specific information.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface GemfireEntityInformation<T, ID extends Serializable> extends EntityInformation<T, ID> {
|
||||
|
||||
/**
|
||||
* Returns the name of the {@link Region} the entity is held in.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getRegionName();
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 2012 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.data.gemfire.repository.query;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.gemfire.mapping.GemfirePersistentEntity;
|
||||
import org.springframework.data.repository.query.parser.AbstractQueryCreator;
|
||||
import org.springframework.data.repository.query.parser.Part;
|
||||
import org.springframework.data.repository.query.parser.PartTree;
|
||||
|
||||
/**
|
||||
* Query creator to create {@link QueryString} instances.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
class GemfireQueryCreator extends AbstractQueryCreator<QueryString, Predicates> {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(GemfireQueryCreator.class);
|
||||
|
||||
private final QueryBuilder query;
|
||||
private Iterator<Integer> indexes;
|
||||
|
||||
/**
|
||||
* Creates a new {@link GemfireQueryCreator} using the given {@link PartTree} and domain class.
|
||||
*
|
||||
* @param tree must not be {@literal null}.
|
||||
* @param entity must not be {@literal null}.
|
||||
*/
|
||||
public GemfireQueryCreator(PartTree tree, GemfirePersistentEntity<?> entity) {
|
||||
|
||||
super(tree);
|
||||
|
||||
this.query = new QueryBuilder(entity);
|
||||
this.indexes = new IndexProvider();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.parser.AbstractQueryCreator#createQuery(org.springframework.data.domain.Sort)
|
||||
*/
|
||||
@Override
|
||||
public QueryString createQuery(Sort dynamicSort) {
|
||||
|
||||
this.indexes = new IndexProvider();
|
||||
return super.createQuery(dynamicSort);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.parser.AbstractQueryCreator#create(org.springframework.data.repository.query.parser.Part, java.util.Iterator)
|
||||
*/
|
||||
@Override
|
||||
protected Predicates create(Part part, Iterator<Object> iterator) {
|
||||
return Predicates.create(part, this.indexes);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.parser.AbstractQueryCreator#and(org.springframework.data.repository.query.parser.Part, java.lang.Object, java.util.Iterator)
|
||||
*/
|
||||
@Override
|
||||
protected Predicates and(Part part, Predicates base, Iterator<Object> iterator) {
|
||||
return base.and(Predicates.create(part, this.indexes));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.parser.AbstractQueryCreator#or(java.lang.Object, java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
protected Predicates or(Predicates base, Predicates criteria) {
|
||||
return base.or(criteria);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.parser.AbstractQueryCreator#complete(java.lang.Object, org.springframework.data.domain.Sort)
|
||||
*/
|
||||
@Override
|
||||
protected QueryString complete(Predicates criteria, Sort sort) {
|
||||
|
||||
QueryString result = query.create(criteria);
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Created query: " + result.toString());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static class IndexProvider implements Iterator<Integer> {
|
||||
|
||||
private int index;
|
||||
|
||||
public IndexProvider() {
|
||||
this.index = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.util.Iterator#hasNext()
|
||||
*/
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return index <= Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.util.Iterator#next()
|
||||
*/
|
||||
@Override
|
||||
public Integer next() {
|
||||
return index++;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.util.Iterator#remove()
|
||||
*/
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2012 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.data.gemfire.repository.query;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.data.gemfire.mapping.GemfirePersistentEntity;
|
||||
import org.springframework.data.gemfire.mapping.GemfirePersistentProperty;
|
||||
import org.springframework.data.gemfire.repository.Query;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.query.QueryMethod;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Gemfire specific {@link QueryMethod}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class GemfireQueryMethod extends QueryMethod {
|
||||
|
||||
private final Method method;
|
||||
private final GemfirePersistentEntity<?> entity;
|
||||
|
||||
/**
|
||||
* Creates a new {@link GemfireQueryMethod} from the given {@link Method} and {@link RepositoryMetadata}.
|
||||
*
|
||||
* @param method must not be {@literal null}.
|
||||
* @param metadata must not be {@literal null}.
|
||||
* @param context must not be {@literal null}.
|
||||
*/
|
||||
public GemfireQueryMethod(Method method, RepositoryMetadata metadata,
|
||||
MappingContext<? extends GemfirePersistentEntity<?>, GemfirePersistentProperty> context) {
|
||||
|
||||
super(method, metadata);
|
||||
|
||||
Assert.notNull(context);
|
||||
|
||||
this.method = method;
|
||||
this.entity = context.getPersistentEntity(getDomainClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the query method contains an annotated, non-empty query.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean hasAnnotatedQuery() {
|
||||
return StringUtils.hasText(getAnnotatedQuery());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the entity
|
||||
*/
|
||||
public GemfirePersistentEntity<?> getPersistentEntity() {
|
||||
return entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the query annotated to the query method.
|
||||
*
|
||||
* @return the annotated query or {@literal null} in case it's empty or none available.
|
||||
*/
|
||||
String getAnnotatedQuery() {
|
||||
|
||||
Query query = method.getAnnotation(Query.class);
|
||||
String queryString = query == null ? null : (String) AnnotationUtils.getValue(query);
|
||||
|
||||
return StringUtils.hasText(queryString) ? queryString : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2012 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.data.gemfire.repository.query;
|
||||
|
||||
import org.springframework.data.repository.query.QueryMethod;
|
||||
import org.springframework.data.repository.query.RepositoryQuery;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Base class for GemFire specific {@link RepositoryQuery} implementations.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
abstract class GemfireRepositoryQuery implements RepositoryQuery {
|
||||
|
||||
private final GemfireQueryMethod queryMethod;
|
||||
|
||||
/**
|
||||
* Creates a new {@link GemfireRepositoryQuery} using the given {@link GemfireQueryMethod}.
|
||||
*
|
||||
* @param queryMethod must not be {@literal null}.
|
||||
*/
|
||||
public GemfireRepositoryQuery(GemfireQueryMethod queryMethod) {
|
||||
|
||||
Assert.notNull(queryMethod);
|
||||
this.queryMethod = queryMethod;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.RepositoryQuery#getQueryMethod()
|
||||
*/
|
||||
@Override
|
||||
public QueryMethod getQueryMethod() {
|
||||
return this.queryMethod;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2012 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.data.gemfire.repository.query;
|
||||
|
||||
import org.springframework.data.gemfire.GemfireTemplate;
|
||||
import org.springframework.data.repository.query.ParametersParameterAccessor;
|
||||
import org.springframework.data.repository.query.RepositoryQuery;
|
||||
import org.springframework.data.repository.query.parser.PartTree;
|
||||
|
||||
/**
|
||||
* {@link GemfireRepositoryQuery} backed by a {@link PartTree} and thus, deriving an OQL query from the backing query
|
||||
* method's name.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class PartTreeGemfireRepositoryQuery extends GemfireRepositoryQuery {
|
||||
|
||||
private final GemfireQueryMethod method;
|
||||
private final PartTree tree;
|
||||
private final GemfireTemplate template;
|
||||
|
||||
/**
|
||||
* Creates a new {@link PartTreeGemfireRepositoryQuery} using the given {@link GemfireQueryMethod} and
|
||||
* {@link GemfireTemplate}.
|
||||
*
|
||||
* @param method must not be {@literal null}.
|
||||
* @param template must not be {@literal null}.
|
||||
*/
|
||||
public PartTreeGemfireRepositoryQuery(GemfireQueryMethod method, GemfireTemplate template) {
|
||||
|
||||
super(method);
|
||||
|
||||
Class<?> domainClass = method.getEntityInformation().getJavaType();
|
||||
|
||||
this.tree = new PartTree(method.getName(), domainClass);
|
||||
this.method = method;
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.RepositoryQuery#execute(java.lang.Object[])
|
||||
*/
|
||||
@Override
|
||||
public Object execute(Object[] parameters) {
|
||||
|
||||
ParametersParameterAccessor parameterAccessor = new ParametersParameterAccessor(method.getParameters(), parameters);
|
||||
QueryString query = new GemfireQueryCreator(tree, method.getPersistentEntity()).createQuery(parameterAccessor
|
||||
.getSort());
|
||||
|
||||
RepositoryQuery repositoryQuery = new StringBasedGemfireRepositoryQuery(query.toString(), method, template);
|
||||
|
||||
return repositoryQuery.execute(parameters);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package org.springframework.data.gemfire.repository.query;
|
||||
|
||||
interface Predicate {
|
||||
|
||||
String toString(String alias);
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright 2012 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.data.gemfire.repository.query;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.springframework.data.repository.query.parser.Part;
|
||||
import org.springframework.data.repository.query.parser.Part.Type;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
class Predicates implements Predicate {
|
||||
|
||||
private final Predicate current;
|
||||
|
||||
/**
|
||||
* Creates a new {@link Predicates} wrapper instance.
|
||||
*
|
||||
* @param predicate must not be {@literal null}.
|
||||
*/
|
||||
private Predicates(Predicate predicate) {
|
||||
this.current = predicate;
|
||||
}
|
||||
|
||||
private static Predicates create(Predicate predicate) {
|
||||
return new Predicates(predicate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Predicate for the given {@link Part} and index iterator.
|
||||
*
|
||||
* @param part must not be {@literal null}.
|
||||
* @param value must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static Predicates create(Part part, Iterator<Integer> value) {
|
||||
return create(new AtomicPredicate(part, value));
|
||||
}
|
||||
|
||||
/**
|
||||
* And-concatenates the given {@link Predicate} to the current one.
|
||||
*
|
||||
* @param predicate must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Predicates and(final Predicate predicate) {
|
||||
|
||||
return create(new Predicate() {
|
||||
@Override
|
||||
public String toString(String alias) {
|
||||
return String.format("%s AND %s", Predicates.this.current.toString(alias), predicate.toString(alias));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Or-concatenates the given {@link Predicate} to the current one.
|
||||
*
|
||||
* @param predicate must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public Predicates or(final Predicate predicate) {
|
||||
|
||||
return create(new Predicate() {
|
||||
@Override
|
||||
public String toString(String alias) {
|
||||
return String.format("%s OR %s", Predicates.this.current.toString(alias), predicate.toString(alias));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.gemfire.repository.query.Predicate#toString(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public String toString(String alias) {
|
||||
return current.toString(alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* Predicate to create a predicate expression for a {@link Part}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public static class AtomicPredicate implements Predicate {
|
||||
|
||||
private final Part part;
|
||||
private final Iterator<Integer> value;
|
||||
|
||||
/**
|
||||
* Creates a new {@link AtomicPredicate}.
|
||||
*
|
||||
* @param part must not be {@literal null}.
|
||||
* @param value must not be {@literal null}.
|
||||
*/
|
||||
public AtomicPredicate(Part part, Iterator<Integer> value) {
|
||||
|
||||
Assert.notNull(part);
|
||||
Assert.notNull(value);
|
||||
|
||||
this.part = part;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.gemfire.repository.query.Predicate#toString(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public String toString(String alias) {
|
||||
|
||||
Type type = part.getType();
|
||||
return String.format("%s.%s %s", alias == null ? QueryBuilder.DEFAULT_ALIAS : alias, part.getProperty()
|
||||
.toDotPath(), toClause(type));
|
||||
}
|
||||
|
||||
private String toClause(Type type) {
|
||||
|
||||
switch (type) {
|
||||
case IS_NULL:
|
||||
case IS_NOT_NULL:
|
||||
return String.format("%s NULL", getOperator(type));
|
||||
default:
|
||||
return String.format("%s $%s", getOperator(type), value.next());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the given {@link Type} to an OQL operator.
|
||||
*
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
private String getOperator(Type type) {
|
||||
|
||||
switch (type) {
|
||||
case IN:
|
||||
return "IN SET";
|
||||
case NOT_IN:
|
||||
return "NOT IN SET";
|
||||
case GREATER_THAN:
|
||||
return ">";
|
||||
case GREATER_THAN_EQUAL:
|
||||
return ">=";
|
||||
case LESS_THAN:
|
||||
return "<";
|
||||
case LESS_THAN_EQUAL:
|
||||
return "<=";
|
||||
case IS_NOT_NULL:
|
||||
case NEGATING_SIMPLE_PROPERTY:
|
||||
return "!=";
|
||||
case IS_NULL:
|
||||
case SIMPLE_PROPERTY:
|
||||
return "=";
|
||||
default:
|
||||
throw new IllegalArgumentException(String.format("Unsupported operator %s!", type));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2012 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.data.gemfire.repository.query;
|
||||
|
||||
import org.springframework.data.gemfire.mapping.GemfirePersistentEntity;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
class QueryBuilder {
|
||||
|
||||
static final String DEFAULT_ALIAS = "x";
|
||||
|
||||
private final String query;
|
||||
|
||||
public QueryBuilder(String source) {
|
||||
Assert.hasText(source);
|
||||
this.query = source;
|
||||
}
|
||||
|
||||
public QueryBuilder(GemfirePersistentEntity<?> entity) {
|
||||
this(String.format("SELECT * FROM /%s %s", entity.getRegionName(), DEFAULT_ALIAS));
|
||||
}
|
||||
|
||||
public QueryString create(Predicate predicate) {
|
||||
|
||||
return new QueryString(query + " WHERE " + predicate.toString(DEFAULT_ALIAS));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return query;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2012 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.data.gemfire.repository.query;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.gemstone.gemfire.cache.Region;
|
||||
|
||||
/**
|
||||
* Value object to work with OQL query strings.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
class QueryString {
|
||||
|
||||
private static final String REGION_PATTERN = "(?<=\\/)%s";
|
||||
private static final String IN_PARAMETER_PATTERN = "(?<=IN (SET|LIST) \\$)\\d";
|
||||
private static final String IN_PATTERN = "(?<=IN (SET|LIST) )\\$\\d";
|
||||
|
||||
private final String query;
|
||||
|
||||
/**
|
||||
* Creates a {@link QueryString} from the given {@link String} query.
|
||||
*
|
||||
* @param source
|
||||
*/
|
||||
public QueryString(String source) {
|
||||
|
||||
Assert.hasText(source);
|
||||
this.query = source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@literal SELECT} query for the given domain class.
|
||||
*
|
||||
* @param domainClass must not be {@literal null}.
|
||||
*/
|
||||
public QueryString(Class<?> domainClass) {
|
||||
this(String.format("SELECT * FROM /%s", domainClass.getSimpleName()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the domain classes referenced inside the current query with the given {@link Region}.
|
||||
*
|
||||
* @param domainClass must not be {@literal null}.
|
||||
* @param region must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public QueryString forRegion(Class<?> domainClass, Region<?, ?> region) {
|
||||
|
||||
String pattern = String.format(REGION_PATTERN, domainClass.getSimpleName());
|
||||
return new QueryString(query.replaceAll(pattern, region.getName()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the given values to the {@literal IN} parameter keyword by expanding the given values into a comma-separated
|
||||
* {@link String}.
|
||||
*
|
||||
* @param values the values to bind, returns the {@link QueryString} as is if {@literal null} is given.
|
||||
* @return
|
||||
*/
|
||||
public QueryString bindIn(Collection<?> values) {
|
||||
|
||||
if (values == null) {
|
||||
return this;
|
||||
}
|
||||
|
||||
String valueString = StringUtils.collectionToDelimitedString(values, ", ", "'", "'");
|
||||
return new QueryString(query.replaceFirst(IN_PATTERN, String.format("(%s)", valueString)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parameter indexes used in this query.
|
||||
*
|
||||
* @return the parameter indexes used in this query or an empty {@link Iterable} if none are used.
|
||||
*/
|
||||
public Iterable<Integer> getInParameterIndexes() {
|
||||
|
||||
Pattern pattern = Pattern.compile(IN_PARAMETER_PATTERN);
|
||||
Matcher matcher = pattern.matcher(query);
|
||||
List<Integer> result = new ArrayList<Integer>();
|
||||
|
||||
while (matcher.find()) {
|
||||
result.add(Integer.parseInt(matcher.group()));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return query;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 2012 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.data.gemfire.repository.query;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.springframework.data.gemfire.GemfireTemplate;
|
||||
import org.springframework.data.repository.query.ParametersParameterAccessor;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link GemfireRepositoryQuery} using plain {@link String} based OQL queries.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class StringBasedGemfireRepositoryQuery extends GemfireRepositoryQuery {
|
||||
|
||||
private final QueryString query;
|
||||
private final GemfireQueryMethod method;
|
||||
private final GemfireTemplate template;
|
||||
|
||||
/**
|
||||
* Creates a new {@link StringBasedGemfireRepositoryQuery} using the given {@link GemfireQueryMethod} and
|
||||
* {@link GemfireTemplate}. The actual query {@link String} will be looked up from the query method.
|
||||
*
|
||||
* @param method must not be {@literal null}.
|
||||
* @param template must not be {@literal null}.
|
||||
*/
|
||||
public StringBasedGemfireRepositoryQuery(GemfireQueryMethod method, GemfireTemplate template) {
|
||||
this(method.getAnnotatedQuery(), method, template);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link StringBasedGemfireRepositoryQuery} using the given query {@link String},
|
||||
* {@link GemfireQueryMethod} and {@link GemfireTemplate}.
|
||||
*
|
||||
* @param query will fall back to the query annotated to the given {@link GemfireQueryMethod} if {@literal null} is
|
||||
* given.
|
||||
* @param method must not be {@literal null}.
|
||||
* @param template must not be {@literal null}.
|
||||
*/
|
||||
public StringBasedGemfireRepositoryQuery(String query, GemfireQueryMethod method, GemfireTemplate template) {
|
||||
|
||||
super(method);
|
||||
|
||||
Assert.notNull(template);
|
||||
|
||||
this.query = new QueryString(StringUtils.hasText(query) ? query : method.getAnnotatedQuery());
|
||||
this.method = method;
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.RepositoryQuery#execute(java.lang.Object[])
|
||||
*/
|
||||
@Override
|
||||
public Object execute(Object[] parameters) {
|
||||
|
||||
ParametersParameterAccessor accessor = new ParametersParameterAccessor(method.getParameters(), parameters);
|
||||
QueryString query = this.query.forRegion(method.getEntityInformation().getJavaType(), template.getRegion());
|
||||
|
||||
Iterator<Integer> indexes = query.getInParameterIndexes().iterator();
|
||||
while (indexes.hasNext()) {
|
||||
query = query.bindIn(toCollection(accessor.getBindableValue(indexes.next() - 1)));
|
||||
}
|
||||
|
||||
return template.find(query.toString(), parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given object as collection. Collections will be returned as is, Arrays will be converted into a
|
||||
* collection and all other objects will be wrapped into a single-element collection.
|
||||
*
|
||||
* @param source
|
||||
* @return
|
||||
*/
|
||||
private Collection<?> toCollection(Object source) {
|
||||
|
||||
if (source instanceof Collection) {
|
||||
return (Collection<?>) source;
|
||||
}
|
||||
|
||||
return source.getClass().isArray() ? CollectionUtils.arrayToList(source) : Collections.singleton(source);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright 2012 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.data.gemfire.repository.support;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.data.gemfire.GemfireTemplate;
|
||||
import org.springframework.data.gemfire.mapping.GemfireMappingContext;
|
||||
import org.springframework.data.gemfire.mapping.GemfirePersistentEntity;
|
||||
import org.springframework.data.gemfire.mapping.GemfirePersistentProperty;
|
||||
import org.springframework.data.gemfire.mapping.Regions;
|
||||
import org.springframework.data.gemfire.repository.query.DefaultGemfireEntityInformation;
|
||||
import org.springframework.data.gemfire.repository.query.GemfireEntityInformation;
|
||||
import org.springframework.data.gemfire.repository.query.GemfireQueryMethod;
|
||||
import org.springframework.data.gemfire.repository.query.PartTreeGemfireRepositoryQuery;
|
||||
import org.springframework.data.gemfire.repository.query.StringBasedGemfireRepositoryQuery;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.repository.core.NamedQueries;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
|
||||
import org.springframework.data.repository.query.QueryLookupStrategy;
|
||||
import org.springframework.data.repository.query.QueryLookupStrategy.Key;
|
||||
import org.springframework.data.repository.query.RepositoryQuery;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.gemstone.gemfire.cache.Region;
|
||||
|
||||
/**
|
||||
* {@link RepositoryFactorySupport} implementation creating repository proxies for Gemfire.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class GemfireRepositoryFactory extends RepositoryFactorySupport {
|
||||
|
||||
private final MappingContext<? extends GemfirePersistentEntity<?>, GemfirePersistentProperty> context;
|
||||
private final Regions regions;
|
||||
|
||||
/**
|
||||
* Creates a new {@link GemfireRepositoryFactory}.
|
||||
*
|
||||
* @param regions must not be {@literal null}.
|
||||
* @param context
|
||||
*/
|
||||
public GemfireRepositoryFactory(Iterable<Region<?, ?>> regions,
|
||||
MappingContext<? extends GemfirePersistentEntity<?>, GemfirePersistentProperty> context) {
|
||||
|
||||
Assert.notNull(regions);
|
||||
|
||||
this.context = context == null ? new GemfireMappingContext() : context;
|
||||
this.regions = new Regions(regions, this.context);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getEntityInformation(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T, ID extends Serializable> GemfireEntityInformation<T, ID> getEntityInformation(Class<T> domainClass) {
|
||||
|
||||
GemfirePersistentEntity<T> entity = (GemfirePersistentEntity<T>) context.getPersistentEntity(domainClass);
|
||||
return new DefaultGemfireEntityInformation<T, ID>(entity);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getTargetRepository(org.springframework.data.repository.core.RepositoryMetadata)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
protected Object getTargetRepository(RepositoryMetadata metadata) {
|
||||
|
||||
GemfireEntityInformation<?, Serializable> entityInformation = getEntityInformation(metadata.getDomainClass());
|
||||
GemfireTemplate gemfireTemplate = getTemplate(metadata);
|
||||
|
||||
return new SimpleGemfireRepository(gemfireTemplate, entityInformation);
|
||||
}
|
||||
|
||||
private GemfireTemplate getTemplate(RepositoryMetadata metadata) {
|
||||
|
||||
Class<?> domainClass = metadata.getDomainClass();
|
||||
Region<?, ?> region = regions.getRegion(domainClass);
|
||||
|
||||
GemfirePersistentEntity<?> entity = context.getPersistentEntity(domainClass);
|
||||
|
||||
Class<?> regionKeyType = region.getAttributes().getKeyConstraint();
|
||||
Class<?> entityIdType = metadata.getIdClass();
|
||||
|
||||
if (regionKeyType != null && entity.getIdProperty() != null) {
|
||||
Assert.isTrue(regionKeyType.isAssignableFrom(entityIdType), String.format(
|
||||
"The region referenced only supports keys of type %s but the entity to be stored has an id of type %s!",
|
||||
regionKeyType, entityIdType));
|
||||
}
|
||||
|
||||
return new GemfireTemplate(region);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getRepositoryBaseClass(org.springframework.data.repository.core.RepositoryMetadata)
|
||||
*/
|
||||
@Override
|
||||
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
|
||||
return SimpleGemfireRepository.class;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getQueryLookupStrategy(org.springframework.data.repository.query.QueryLookupStrategy.Key)
|
||||
*/
|
||||
@Override
|
||||
protected QueryLookupStrategy getQueryLookupStrategy(Key key) {
|
||||
return new QueryLookupStrategy() {
|
||||
@Override
|
||||
public RepositoryQuery resolveQuery(Method method, RepositoryMetadata metadata, NamedQueries namedQueries) {
|
||||
|
||||
GemfireQueryMethod queryMethod = new GemfireQueryMethod(method, metadata, context);
|
||||
GemfireTemplate template = getTemplate(metadata);
|
||||
|
||||
if (queryMethod.hasAnnotatedQuery()) {
|
||||
return new StringBasedGemfireRepositoryQuery(queryMethod, template);
|
||||
}
|
||||
|
||||
String namedQueryName = queryMethod.getNamedQueryName();
|
||||
if (namedQueries.hasQuery(namedQueryName)) {
|
||||
return new StringBasedGemfireRepositoryQuery(namedQueries.getQuery(namedQueryName), queryMethod, template);
|
||||
}
|
||||
|
||||
return new PartTreeGemfireRepositoryQuery(queryMethod, template);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2012 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.data.gemfire.repository.support;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.data.gemfire.mapping.GemfirePersistentEntity;
|
||||
import org.springframework.data.gemfire.mapping.GemfirePersistentProperty;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.repository.Repository;
|
||||
import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;
|
||||
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
|
||||
|
||||
import com.gemstone.bp.edu.emory.mathcs.backport.java.util.Collections;
|
||||
import com.gemstone.gemfire.cache.Region;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class GemfireRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable> extends
|
||||
RepositoryFactoryBeanSupport<T, S, ID> implements ApplicationContextAware {
|
||||
|
||||
private MappingContext<? extends GemfirePersistentEntity<?>, GemfirePersistentProperty> context;
|
||||
private Iterable<Region<?, ?>> regions;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
Collection<Region> regions = applicationContext.getBeansOfType(Region.class).values();
|
||||
this.regions = Collections.unmodifiableCollection(regions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param context the context to set
|
||||
*/
|
||||
public void setMappingContext(MappingContext<? extends GemfirePersistentEntity<?>, GemfirePersistentProperty> context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport#createRepositoryFactory()
|
||||
*/
|
||||
@Override
|
||||
protected RepositoryFactorySupport createRepositoryFactory() {
|
||||
return new GemfireRepositoryFactory(regions, context);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
package org.springframework.data.gemfire.repository.support;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.gemfire.GemfireCallback;
|
||||
import org.springframework.data.gemfire.GemfireTemplate;
|
||||
import org.springframework.data.gemfire.repository.GemfireRepository;
|
||||
import org.springframework.data.gemfire.repository.Wrapper;
|
||||
import org.springframework.data.repository.core.EntityInformation;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.gemstone.gemfire.GemFireCheckedException;
|
||||
import com.gemstone.gemfire.GemFireException;
|
||||
import com.gemstone.gemfire.cache.Region;
|
||||
|
||||
/**
|
||||
* Basic repository implementation.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class SimpleGemfireRepository<T, ID extends Serializable> implements GemfireRepository<T, ID> {
|
||||
|
||||
private final GemfireTemplate template;
|
||||
private final EntityInformation<T, ID> entityInformation;
|
||||
|
||||
/**
|
||||
* Creates a new {@link SimpleGemfireRepository}.
|
||||
*
|
||||
* @param template must not be {@literal null}.
|
||||
* @param entityInformation must not be {@literal null}.
|
||||
*/
|
||||
public SimpleGemfireRepository(GemfireTemplate template, EntityInformation<T, ID> entityInformation) {
|
||||
|
||||
Assert.notNull(template);
|
||||
Assert.notNull(entityInformation);
|
||||
|
||||
this.template = template;
|
||||
this.entityInformation = entityInformation;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.Repository#save(java.lang.Object)
|
||||
*/
|
||||
public T save(T entity) {
|
||||
template.put(entityInformation.getId(entity), entity);
|
||||
return entity;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.Repository#save(java.lang.Iterable)
|
||||
*/
|
||||
public Iterable<T> save(Iterable<? extends T> entities) {
|
||||
List<T> result = new ArrayList<T>();
|
||||
for (T entity : entities) {
|
||||
result.add(save(entity));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.Repository#findOne(java.io.Serializable)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public T findOne(ID id) {
|
||||
Object object = template.get(id);
|
||||
return (T) object;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.Repository#exists(java.io.Serializable)
|
||||
*/
|
||||
public boolean exists(ID id) {
|
||||
return findOne(id) != null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.Repository#findAll()
|
||||
*/
|
||||
public Collection<T> findAll() {
|
||||
return template.execute(new GemfireCallback<Collection<T>>() {
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public Collection<T> doInGemfire(Region region) {
|
||||
return region.values();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.CrudRepository#findAll(java.lang.Iterable)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Collection<T> findAll(Iterable<ID> ids) {
|
||||
|
||||
List<ID> parameters = new ArrayList<ID>();
|
||||
for (ID id : ids) {
|
||||
parameters.add(id);
|
||||
}
|
||||
|
||||
return (Collection<T>) template.getAll(parameters).values();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.Repository#count()
|
||||
*/
|
||||
public long count() {
|
||||
return template.execute(new GemfireCallback<Long>() {
|
||||
@SuppressWarnings("rawtypes")
|
||||
public Long doInGemfire(Region region) throws GemFireCheckedException, GemFireException {
|
||||
return Long.valueOf(region.keySet().size());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.Repository#delete(java.lang.Object)
|
||||
*/
|
||||
public void delete(T entity) {
|
||||
template.remove(entityInformation.getId(entity));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.Repository#delete(java.lang.Iterable)
|
||||
*/
|
||||
public void delete(Iterable<? extends T> entities) {
|
||||
for (T entity : entities) {
|
||||
delete(entity);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.Repository#deleteAll()
|
||||
*/
|
||||
public void deleteAll() {
|
||||
|
||||
template.execute(new GemfireCallback<Void>() {
|
||||
@SuppressWarnings("rawtypes")
|
||||
public Void doInGemfire(Region region) {
|
||||
region.clear();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.CrudRepository#delete(java.io.Serializable)
|
||||
*/
|
||||
public void delete(ID id) {
|
||||
template.remove(id);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.gemfire.repository.GemfireRepository#save(org.springframework.data.gemfire.repository.Wrapper)
|
||||
*/
|
||||
@Override
|
||||
public T save(Wrapper<T, ID> wrapper) {
|
||||
return template.put(wrapper.getKey(), wrapper.getEntity());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user