initial commit
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright 2011-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.cassandra.config;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||
import org.springframework.data.annotation.Persistent;
|
||||
import org.springframework.data.cassandra.convert.CassandraConverter;
|
||||
import org.springframework.data.cassandra.convert.MappingCassandraConverter;
|
||||
import org.springframework.data.cassandra.core.CassandraTemplate;
|
||||
import org.springframework.data.cassandra.core.Keyspace;
|
||||
import org.springframework.data.cassandra.mapping.CassandraMappingContext;
|
||||
import org.springframework.data.cassandra.mapping.CassandraPersistentEntity;
|
||||
import org.springframework.data.cassandra.mapping.CassandraPersistentProperty;
|
||||
import org.springframework.data.cassandra.mapping.Table;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.datastax.driver.core.Cluster;
|
||||
import com.datastax.driver.core.Session;
|
||||
|
||||
/**
|
||||
* Base class for Spring Data Cassandra configuration using JavaConfig.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
@Configuration
|
||||
public abstract class AbstractCassandraConfiguration {
|
||||
|
||||
/**
|
||||
* Return the name of the keyspace to connect to.
|
||||
*
|
||||
* @return must not be {@literal null}.
|
||||
*/
|
||||
protected abstract String getKeyspaceName();
|
||||
|
||||
/**
|
||||
* Return the {@link Cluster} instance to connect to.
|
||||
*
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@Bean
|
||||
public abstract Cluster cluster() throws Exception;
|
||||
|
||||
/**
|
||||
* Creates a {@link Session} to be used by the {@link Keyspace}. Will use the {@link Cluster} instance
|
||||
* configured in {@link #cluster()}.
|
||||
*
|
||||
* @see #cluster()
|
||||
* @see #Keyspace()
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@Bean
|
||||
public Session session() throws Exception {
|
||||
String keyspace = getKeyspaceName();
|
||||
if (StringUtils.hasText(keyspace)) {
|
||||
return cluster().connect(keyspace);
|
||||
}
|
||||
else {
|
||||
return cluster().connect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Keyspace} to be used by the {@link CassandraTemplate}. Will use the {@link Session} instance
|
||||
* configured in {@link #session()} and {@link CassandraConverter} configured in {@link #converter()}.
|
||||
*
|
||||
* @see #cluster()
|
||||
* @see #Keyspace()
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@Bean
|
||||
public Keyspace keyspace() throws Exception {
|
||||
return new Keyspace(getKeyspaceName(), session(), converter());
|
||||
}
|
||||
/**
|
||||
* Return the base package to scan for mapped {@link Table}s. Will return the package name of the configuration
|
||||
* class' (the concrete class, not this one here) by default. So if you have a {@code com.acme.AppConfig} extending
|
||||
* {@link AbstractCassandraConfiguration} the base package will be considered {@code com.acme} unless the method is
|
||||
* overriden to implement alternate behaviour.
|
||||
*
|
||||
* @return the base package to scan for mapped {@link Table} classes or {@literal null} to not enable scanning for
|
||||
* entities.
|
||||
*/
|
||||
protected String getMappingBasePackage() {
|
||||
return getClass().getPackage().getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link CassandraTemplate}.
|
||||
*
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@Bean
|
||||
public CassandraTemplate cassandraTemplate() throws Exception {
|
||||
return new CassandraTemplate(keyspace());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link MappingContext} instance to map Entities to properties.
|
||||
*
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@Bean
|
||||
public MappingContext<? extends CassandraPersistentEntity<?>, CassandraPersistentProperty> mappingContext() {
|
||||
return new CassandraMappingContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link CassandraConverter} instance to convert Rows to Objects.
|
||||
*
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@Bean
|
||||
public CassandraConverter converter() {
|
||||
return new MappingCassandraConverter(mappingContext());
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the mapping base package for classes annotated with {@link Table}.
|
||||
*
|
||||
* @see #getMappingBasePackage()
|
||||
* @return
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
protected Set<Class<?>> getInitialEntitySet() throws ClassNotFoundException {
|
||||
|
||||
String basePackage = getMappingBasePackage();
|
||||
Set<Class<?>> initialEntitySet = new HashSet<Class<?>>();
|
||||
|
||||
if (StringUtils.hasText(basePackage)) {
|
||||
ClassPathScanningCandidateComponentProvider componentProvider = new ClassPathScanningCandidateComponentProvider(
|
||||
false);
|
||||
componentProvider.addIncludeFilter(new AnnotationTypeFilter(Table.class));
|
||||
componentProvider.addIncludeFilter(new AnnotationTypeFilter(Persistent.class));
|
||||
|
||||
for (BeanDefinition candidate : componentProvider.findCandidateComponents(basePackage)) {
|
||||
initialEntitySet.add(ClassUtils.forName(candidate.getBeanClassName(),
|
||||
AbstractCassandraConfiguration.class.getClassLoader()));
|
||||
}
|
||||
}
|
||||
|
||||
return initialEntitySet;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by the original author(s).
|
||||
*
|
||||
* 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.cassandra.config;
|
||||
|
||||
/**
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
public class BeanNames {
|
||||
|
||||
static final String CASSANDRA_CLUSTER = "cassandra-cluster";
|
||||
static final String CASSANDRA_KEYSPACE = "cassandra-keyspace";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 2011-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.cassandra.config;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.data.cassandra.core.CassandraClusterFactoryBean;
|
||||
import org.springframework.data.config.ParsingUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Parser for <cluster;gt; definitions.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
|
||||
public class CassandraClusterParser extends AbstractSimpleBeanDefinitionParser {
|
||||
|
||||
@Override
|
||||
protected Class<?> getBeanClass(Element element) {
|
||||
return CassandraClusterFactoryBean.class;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#resolveId(org.w3c.dom.Element, org.springframework.beans.factory.support.AbstractBeanDefinition, org.springframework.beans.factory.xml.ParserContext)
|
||||
*/
|
||||
@Override
|
||||
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
|
||||
throws BeanDefinitionStoreException {
|
||||
|
||||
String id = super.resolveId(element, definition, parserContext);
|
||||
return StringUtils.hasText(id) ? id : BeanNames.CASSANDRA_CLUSTER;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doParse(Element element, ParserContext parserContext,
|
||||
BeanDefinitionBuilder builder) {
|
||||
|
||||
String contactPoints = element.getAttribute("contactPoints");
|
||||
if (StringUtils.hasText(contactPoints)) {
|
||||
builder.addPropertyValue("contactPoints", contactPoints);
|
||||
}
|
||||
|
||||
String port = element.getAttribute("port");
|
||||
if (StringUtils.hasText(port)) {
|
||||
builder.addPropertyValue("port", port);
|
||||
}
|
||||
|
||||
String compression = element.getAttribute("compression");
|
||||
if (StringUtils.hasText(compression)) {
|
||||
builder.addPropertyValue("compressionType", CompressionType.valueOf(compression));
|
||||
}
|
||||
|
||||
postProcess(builder, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postProcess(BeanDefinitionBuilder builder, Element element) {
|
||||
List<Element> subElements = DomUtils.getChildElements(element);
|
||||
|
||||
// parse nested elements
|
||||
for (Element subElement : subElements) {
|
||||
String name = subElement.getLocalName();
|
||||
|
||||
if ("local-pooling-options".equals(name)) {
|
||||
builder.addPropertyValue("localPoolingOptions", parsePoolingOptions(subElement));
|
||||
}
|
||||
else if ("remote-pooling-options".equals(name)) {
|
||||
builder.addPropertyValue("remotePoolingOptions", parsePoolingOptions(subElement));
|
||||
}
|
||||
else if ("socket-options".equals(name)) {
|
||||
builder.addPropertyValue("socketOptions", parseSocketOptions(subElement));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private BeanDefinition parsePoolingOptions(Element element) {
|
||||
BeanDefinitionBuilder defBuilder = BeanDefinitionBuilder.genericBeanDefinition(PoolingOptionsConfig.class);
|
||||
ParsingUtils.setPropertyValue(defBuilder, element, "min-simultaneous-requests", "minSimultaneousRequests");
|
||||
ParsingUtils.setPropertyValue(defBuilder, element, "max-simultaneous-requests", "maxSimultaneousRequests");
|
||||
ParsingUtils.setPropertyValue(defBuilder, element, "core-connections", "coreConnections");
|
||||
ParsingUtils.setPropertyValue(defBuilder, element, "max-connections", "maxConnections");
|
||||
return defBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
private BeanDefinition parseSocketOptions(Element element) {
|
||||
BeanDefinitionBuilder defBuilder = BeanDefinitionBuilder.genericBeanDefinition(SocketOptionsConfig.class);
|
||||
ParsingUtils.setPropertyValue(defBuilder, element, "connect-timeout-mls", "connectTimeoutMls");
|
||||
ParsingUtils.setPropertyValue(defBuilder, element, "keep-alive", "keepAlive");
|
||||
ParsingUtils.setPropertyValue(defBuilder, element, "reuse-address", "reuseAddress");
|
||||
ParsingUtils.setPropertyValue(defBuilder, element, "so-linger", "soLinger");
|
||||
ParsingUtils.setPropertyValue(defBuilder, element, "tcp-no-delay", "tcpNoDelay");
|
||||
ParsingUtils.setPropertyValue(defBuilder, element, "receive-buffer-size", "receiveBufferSize");
|
||||
ParsingUtils.setPropertyValue(defBuilder, element, "send-buffer-size", "sendBufferSize");
|
||||
return defBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright 2011-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.cassandra.config;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.data.cassandra.core.CassandraKeyspaceFactoryBean;
|
||||
import org.springframework.data.config.ParsingUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Parser for <keyspace;gt; definitions.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
|
||||
|
||||
public class CassandraKeyspaceParser extends AbstractSimpleBeanDefinitionParser {
|
||||
|
||||
@Override
|
||||
protected Class<?> getBeanClass(Element element) {
|
||||
return CassandraKeyspaceFactoryBean.class;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#resolveId(org.w3c.dom.Element, org.springframework.beans.factory.support.AbstractBeanDefinition, org.springframework.beans.factory.xml.ParserContext)
|
||||
*/
|
||||
@Override
|
||||
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
|
||||
throws BeanDefinitionStoreException {
|
||||
|
||||
String id = super.resolveId(element, definition, parserContext);
|
||||
return StringUtils.hasText(id) ? id : BeanNames.CASSANDRA_KEYSPACE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doParse(Element element, ParserContext parserContext,
|
||||
BeanDefinitionBuilder builder) {
|
||||
|
||||
String name = element.getAttribute("name");
|
||||
if (StringUtils.hasText(name)) {
|
||||
builder.addPropertyValue("keyspace", name);
|
||||
}
|
||||
|
||||
String clusterRef = element.getAttribute("cassandra-cluster-ref");
|
||||
if (!StringUtils.hasText(clusterRef)) {
|
||||
clusterRef = BeanNames.CASSANDRA_CLUSTER;
|
||||
}
|
||||
builder.addPropertyReference("cluster", clusterRef);
|
||||
|
||||
String converterRef = element.getAttribute("cassandra-converter-ref");
|
||||
if (StringUtils.hasText(converterRef)) {
|
||||
builder.addPropertyReference("converter", converterRef);
|
||||
}
|
||||
|
||||
postProcess(builder, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postProcess(BeanDefinitionBuilder builder, Element element) {
|
||||
List<Element> subElements = DomUtils.getChildElements(element);
|
||||
|
||||
// parse nested elements
|
||||
for (Element subElement : subElements) {
|
||||
String name = subElement.getLocalName();
|
||||
|
||||
if ("keyspace-attributes".equals(name)) {
|
||||
builder.addPropertyValue("keyspaceAttributes", parseKeyspaceAttributes(subElement));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private BeanDefinition parseKeyspaceAttributes(Element element) {
|
||||
BeanDefinitionBuilder defBuilder = BeanDefinitionBuilder.genericBeanDefinition(KeyspaceAttributes.class);
|
||||
ParsingUtils.setPropertyValue(defBuilder, element, "auto", "auto");
|
||||
ParsingUtils.setPropertyValue(defBuilder, element, "replication-strategy", "replicationStrategy");
|
||||
ParsingUtils.setPropertyValue(defBuilder, element, "replication-factor", "replicationFactor");
|
||||
ParsingUtils.setPropertyValue(defBuilder, element, "durable-writes", "durableWrites");
|
||||
|
||||
List<Element> subElements = DomUtils.getChildElements(element);
|
||||
ManagedList<Object> tables = new ManagedList<Object>(subElements.size());
|
||||
|
||||
// parse nested elements
|
||||
for (Element subElement : subElements) {
|
||||
String name = subElement.getLocalName();
|
||||
|
||||
if ("table".equals(name)) {
|
||||
tables.add(parseTable(subElement));
|
||||
}
|
||||
}
|
||||
if (!tables.isEmpty()) {
|
||||
defBuilder.addPropertyValue("tables", tables);
|
||||
}
|
||||
|
||||
return defBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
private BeanDefinition parseTable(Element element) {
|
||||
BeanDefinitionBuilder defBuilder = BeanDefinitionBuilder.genericBeanDefinition(TableAttributes.class);
|
||||
ParsingUtils.setPropertyValue(defBuilder, element, "entity", "entity");
|
||||
ParsingUtils.setPropertyValue(defBuilder, element, "name", "name");
|
||||
return defBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2011-2013 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.cassandra.config;
|
||||
|
||||
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
|
||||
|
||||
/**
|
||||
* Namespace handler for <cassandra;gt;.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
|
||||
public class CassandraNamespaceHandler extends NamespaceHandlerSupport {
|
||||
|
||||
public void init() {
|
||||
|
||||
registerBeanDefinitionParser("cluster", new CassandraClusterParser());
|
||||
registerBeanDefinitionParser("keyspace", new CassandraKeyspaceParser());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2010-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.cassandra.config;
|
||||
|
||||
/**
|
||||
* Simple enumeration for the various compression types.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
public enum CompressionType {
|
||||
none, snappy;
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2011-2013 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.cassandra.config;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Keyspace attributes are used for manipulation around keyspace at the startup.
|
||||
* Auto property defines the way how to do this. Other attributes used to
|
||||
* ensure or update keyspace settings.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
public class KeyspaceAttributes {
|
||||
|
||||
public static final String DEFAULT_REPLICATION_STRATEGY = "SimpleStrategy";
|
||||
public static final int DEFAULT_REPLICATION_FACTOR = 1;
|
||||
public static final boolean DEFAULT_DURABLE_WRITES = true;
|
||||
|
||||
/*
|
||||
* auto possible values:
|
||||
* validate: validate the keyspace, makes no changes.
|
||||
* update: update the keyspace.
|
||||
* create: creates the keyspace, destroying previous data.
|
||||
* create-drop: drop the keyspace at the end of the session.
|
||||
*/
|
||||
public static final String AUTO_VALIDATE = "validate";
|
||||
public static final String AUTO_UPDATE = "update";
|
||||
public static final String AUTO_CREATE = "create";
|
||||
public static final String AUTO_CREATE_DROP = "create-drop";
|
||||
|
||||
private String auto = AUTO_VALIDATE;
|
||||
private String replicationStrategy = DEFAULT_REPLICATION_STRATEGY;
|
||||
private int replicationFactor = DEFAULT_REPLICATION_FACTOR;
|
||||
private boolean durableWrites = DEFAULT_DURABLE_WRITES;
|
||||
|
||||
private Collection<TableAttributes> tables;
|
||||
|
||||
public String getAuto() {
|
||||
return auto;
|
||||
}
|
||||
|
||||
public void setAuto(String auto) {
|
||||
this.auto = auto;
|
||||
}
|
||||
|
||||
public boolean isValidate() {
|
||||
return AUTO_VALIDATE.equals(auto);
|
||||
}
|
||||
|
||||
public boolean isUpdate() {
|
||||
return AUTO_UPDATE.equals(auto);
|
||||
}
|
||||
|
||||
public boolean isCreate() {
|
||||
return AUTO_CREATE.equals(auto);
|
||||
}
|
||||
|
||||
public boolean isCreateDrop() {
|
||||
return AUTO_CREATE_DROP.equals(auto);
|
||||
}
|
||||
|
||||
public String getReplicationStrategy() {
|
||||
return replicationStrategy;
|
||||
}
|
||||
|
||||
public void setReplicationStrategy(String replicationStrategy) {
|
||||
this.replicationStrategy = replicationStrategy;
|
||||
}
|
||||
|
||||
public int getReplicationFactor() {
|
||||
return replicationFactor;
|
||||
}
|
||||
|
||||
public void setReplicationFactor(int replicationFactor) {
|
||||
this.replicationFactor = replicationFactor;
|
||||
}
|
||||
|
||||
public boolean isDurableWrites() {
|
||||
return durableWrites;
|
||||
}
|
||||
|
||||
public void setDurableWrites(boolean durableWrites) {
|
||||
this.durableWrites = durableWrites;
|
||||
}
|
||||
|
||||
public Collection<TableAttributes> getTables() {
|
||||
return tables;
|
||||
}
|
||||
|
||||
public void setTables(Collection<TableAttributes> tables) {
|
||||
this.tables = tables;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2011-2013 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.cassandra.config;
|
||||
|
||||
/**
|
||||
* Pooling options POJO. Can be remote or local.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
public class PoolingOptionsConfig {
|
||||
|
||||
private Integer minSimultaneousRequests;
|
||||
private Integer maxSimultaneousRequests;
|
||||
private Integer coreConnections;
|
||||
private Integer maxConnections;
|
||||
|
||||
public Integer getMinSimultaneousRequests() {
|
||||
return minSimultaneousRequests;
|
||||
}
|
||||
|
||||
public void setMinSimultaneousRequests(Integer minSimultaneousRequests) {
|
||||
this.minSimultaneousRequests = minSimultaneousRequests;
|
||||
}
|
||||
|
||||
public Integer getMaxSimultaneousRequests() {
|
||||
return maxSimultaneousRequests;
|
||||
}
|
||||
|
||||
public void setMaxSimultaneousRequests(Integer maxSimultaneousRequests) {
|
||||
this.maxSimultaneousRequests = maxSimultaneousRequests;
|
||||
}
|
||||
|
||||
public Integer getCoreConnections() {
|
||||
return coreConnections;
|
||||
}
|
||||
|
||||
public void setCoreConnections(Integer coreConnections) {
|
||||
this.coreConnections = coreConnections;
|
||||
}
|
||||
|
||||
public Integer getMaxConnections() {
|
||||
return maxConnections;
|
||||
}
|
||||
|
||||
public void setMaxConnections(Integer maxConnections) {
|
||||
this.maxConnections = maxConnections;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2011-2013 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.cassandra.config;
|
||||
|
||||
/**
|
||||
* Socket options POJO. Uses to configure Netty.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
public class SocketOptionsConfig {
|
||||
|
||||
private Integer connectTimeoutMls;
|
||||
private Boolean keepAlive;
|
||||
private Boolean reuseAddress;
|
||||
private Integer soLinger;
|
||||
private Boolean tcpNoDelay;
|
||||
private Integer receiveBufferSize;
|
||||
private Integer sendBufferSize;
|
||||
|
||||
public Integer getConnectTimeoutMls() {
|
||||
return connectTimeoutMls;
|
||||
}
|
||||
|
||||
public void setConnectTimeoutMls(Integer connectTimeoutMls) {
|
||||
this.connectTimeoutMls = connectTimeoutMls;
|
||||
}
|
||||
|
||||
public Boolean getKeepAlive() {
|
||||
return keepAlive;
|
||||
}
|
||||
|
||||
public void setKeepAlive(Boolean keepAlive) {
|
||||
this.keepAlive = keepAlive;
|
||||
}
|
||||
|
||||
public Boolean getReuseAddress() {
|
||||
return reuseAddress;
|
||||
}
|
||||
|
||||
public void setReuseAddress(Boolean reuseAddress) {
|
||||
this.reuseAddress = reuseAddress;
|
||||
}
|
||||
|
||||
public Integer getSoLinger() {
|
||||
return soLinger;
|
||||
}
|
||||
|
||||
public void setSoLinger(Integer soLinger) {
|
||||
this.soLinger = soLinger;
|
||||
}
|
||||
|
||||
public Boolean getTcpNoDelay() {
|
||||
return tcpNoDelay;
|
||||
}
|
||||
|
||||
public void setTcpNoDelay(Boolean tcpNoDelay) {
|
||||
this.tcpNoDelay = tcpNoDelay;
|
||||
}
|
||||
|
||||
public Integer getReceiveBufferSize() {
|
||||
return receiveBufferSize;
|
||||
}
|
||||
|
||||
public void setReceiveBufferSize(Integer receiveBufferSize) {
|
||||
this.receiveBufferSize = receiveBufferSize;
|
||||
}
|
||||
|
||||
public Integer getSendBufferSize() {
|
||||
return sendBufferSize;
|
||||
}
|
||||
|
||||
public void setSendBufferSize(Integer sendBufferSize) {
|
||||
this.sendBufferSize = sendBufferSize;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2011-2013 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.cassandra.config;
|
||||
|
||||
/**
|
||||
* Table attributes are used for manipulation around table at the startup (create/update/validate).
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
public class TableAttributes {
|
||||
|
||||
private String entity;
|
||||
private String name;
|
||||
|
||||
public String getEntity() {
|
||||
return entity;
|
||||
}
|
||||
|
||||
public void setEntity(String entity) {
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TableAttributes [entity=" + entity + "]";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2011-2013 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.cassandra.convert;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.core.convert.support.GenericConversionService;
|
||||
import org.springframework.data.convert.EntityInstantiators;
|
||||
|
||||
/**
|
||||
* Base class for {@link CassandraConverter} implementations. Sets up a {@link GenericConversionService} and populates basic
|
||||
* converters.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
public abstract class AbstractCassandraConverter implements CassandraConverter, InitializingBean {
|
||||
|
||||
protected final GenericConversionService conversionService;
|
||||
protected EntityInstantiators instantiators = new EntityInstantiators();
|
||||
|
||||
/**
|
||||
* Creates a new {@link AbstractMongoConverter} using the given {@link GenericConversionService}.
|
||||
*
|
||||
* @param conversionService
|
||||
*/
|
||||
public AbstractCassandraConverter(GenericConversionService conversionService) {
|
||||
this.conversionService = conversionService == null ? new DefaultConversionService() : conversionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers {@link EntityInstantiators} to customize entity instantiation.
|
||||
*
|
||||
* @param instantiators
|
||||
*/
|
||||
public void setInstantiators(EntityInstantiators instantiators) {
|
||||
this.instantiators = instantiators == null ? new EntityInstantiators() : instantiators;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.core.convert.MongoConverter#getConversionService()
|
||||
*/
|
||||
public ConversionService getConversionService() {
|
||||
return conversionService;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
*/
|
||||
public void afterPropertiesSet() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2010-2011 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.cassandra.convert;
|
||||
|
||||
import org.springframework.data.cassandra.mapping.CassandraPersistentEntity;
|
||||
import org.springframework.data.cassandra.mapping.CassandraPersistentProperty;
|
||||
import org.springframework.data.convert.EntityConverter;
|
||||
|
||||
import com.datastax.driver.core.Row;
|
||||
|
||||
/**
|
||||
* Central Cassandra specific converter interface from Object to Row.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
public interface CassandraConverter extends EntityConverter<CassandraPersistentEntity<?>, CassandraPersistentProperty, Object, Row> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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.cassandra.convert;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.springframework.data.cassandra.mapping.CassandraPersistentProperty;
|
||||
import org.springframework.data.mapping.model.DefaultSpELExpressionEvaluator;
|
||||
import org.springframework.data.mapping.model.PropertyValueProvider;
|
||||
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.driver.core.DataType;
|
||||
import com.datastax.driver.core.Row;
|
||||
|
||||
/**
|
||||
* {@link PropertyValueProvider} to read property values from a {@link Row}.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
public class CassandraPropertyValueProvider implements PropertyValueProvider<CassandraPersistentProperty> {
|
||||
|
||||
private final Row source;
|
||||
private final SpELExpressionEvaluator evaluator;
|
||||
|
||||
/**
|
||||
* Creates a new {@link CassandraPropertyValueProvider} with the given {@link Row} and {@link DefaultSpELExpressionEvaluator}.
|
||||
*
|
||||
* @param source must not be {@literal null}.
|
||||
* @param evaluator must not be {@literal null}.
|
||||
*/
|
||||
public CassandraPropertyValueProvider(Row source, DefaultSpELExpressionEvaluator evaluator) {
|
||||
Assert.notNull(source);
|
||||
Assert.notNull(evaluator);
|
||||
|
||||
this.source = source;
|
||||
this.evaluator = evaluator;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.convert.PropertyValueProvider#getPropertyValue(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getPropertyValue(CassandraPersistentProperty property) {
|
||||
|
||||
String expression = property.getSpelExpression();
|
||||
if (expression != null) {
|
||||
return evaluator.evaluate(expression);
|
||||
}
|
||||
|
||||
String columnName = property.getColumnName();
|
||||
if (source.isNull(property.getColumnName())) {
|
||||
return null;
|
||||
}
|
||||
DataType columnType = source.getColumnDefinitions().getType(columnName);
|
||||
ByteBuffer bytes = source.getBytes(columnName);
|
||||
return (T) columnType.deserialize(bytes);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright 2011-2013 by the original author(s).
|
||||
*
|
||||
* 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.cassandra.convert;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.data.cassandra.mapping.CassandraPersistentEntity;
|
||||
import org.springframework.data.cassandra.mapping.CassandraPersistentProperty;
|
||||
import org.springframework.data.convert.EntityInstantiator;
|
||||
import org.springframework.data.mapping.PropertyHandler;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
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.PropertyValueProvider;
|
||||
import org.springframework.data.mapping.model.SpELContext;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
import com.datastax.driver.core.Row;
|
||||
|
||||
/**
|
||||
* {@link CassandraConverter} that uses a {@link MappingContext} to do sophisticated mapping of domain objects to
|
||||
* {@link Row}.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
public class MappingCassandraConverter extends AbstractCassandraConverter implements ApplicationContextAware {
|
||||
|
||||
protected static final Logger log = LoggerFactory.getLogger(MappingCassandraConverter.class);
|
||||
|
||||
protected final MappingContext<? extends CassandraPersistentEntity<?>, CassandraPersistentProperty> mappingContext;
|
||||
protected ApplicationContext applicationContext;
|
||||
private SpELContext spELContext;
|
||||
private boolean useFieldAccessOnly = true;
|
||||
|
||||
/**
|
||||
* Creates a new {@link MappingCassandraConverter} given the new {@link MappingContext}.
|
||||
*
|
||||
* @param mappingContext must not be {@literal null}.
|
||||
*/
|
||||
public MappingCassandraConverter(MappingContext<? extends CassandraPersistentEntity<?>, CassandraPersistentProperty> mappingContext) {
|
||||
super(new DefaultConversionService());
|
||||
this.mappingContext = mappingContext;
|
||||
this.spELContext = new SpELContext(RowReaderPropertyAccessor.INSTANCE);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <R> R read(Class<R> clazz, Row row) {
|
||||
|
||||
TypeInformation<? extends R> type = ClassTypeInformation.from(clazz);
|
||||
//TypeInformation<? extends R> typeToUse = typeMapper.readType(row, type);
|
||||
TypeInformation<? extends R> typeToUse = type;
|
||||
Class<? extends R> rawType = typeToUse.getType();
|
||||
|
||||
if (Row.class.isAssignableFrom(rawType)) {
|
||||
return (R) row;
|
||||
}
|
||||
|
||||
CassandraPersistentEntity<R> persistentEntity = (CassandraPersistentEntity<R>) mappingContext.getPersistentEntity(typeToUse);
|
||||
if (persistentEntity == null) {
|
||||
throw new MappingException("No mapping metadata found for " + rawType.getName());
|
||||
}
|
||||
|
||||
return read(persistentEntity, row);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.convert.EntityConverter#getMappingContext()
|
||||
*/
|
||||
public MappingContext<? extends CassandraPersistentEntity<?>, CassandraPersistentProperty> getMappingContext() {
|
||||
return mappingContext;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
|
||||
*/
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
this.spELContext = new SpELContext(this.spELContext, applicationContext);
|
||||
}
|
||||
|
||||
private <S extends Object> S read(final CassandraPersistentEntity<S> entity, final Row row) {
|
||||
|
||||
final DefaultSpELExpressionEvaluator evaluator = new DefaultSpELExpressionEvaluator(row, spELContext);
|
||||
|
||||
final PropertyValueProvider<CassandraPersistentProperty> propertyProvider = new CassandraPropertyValueProvider(row, evaluator);
|
||||
PersistentEntityParameterValueProvider<CassandraPersistentProperty> parameterProvider = new PersistentEntityParameterValueProvider<CassandraPersistentProperty>(
|
||||
entity, propertyProvider, null);
|
||||
|
||||
EntityInstantiator instantiator = instantiators.getInstantiatorFor(entity);
|
||||
S instance = instantiator.createInstance(entity, parameterProvider);
|
||||
|
||||
final BeanWrapper<CassandraPersistentEntity<S>, S> wrapper = BeanWrapper.create(instance, conversionService);
|
||||
final S result = wrapper.getBean();
|
||||
|
||||
// Set properties not already set in the constructor
|
||||
entity.doWithProperties(new PropertyHandler<CassandraPersistentProperty>() {
|
||||
public void doWithPersistentProperty(CassandraPersistentProperty prop) {
|
||||
|
||||
boolean isConstructorProperty = entity.isConstructorArgument(prop);
|
||||
boolean hasValueForProperty = row.getColumnDefinitions().contains(prop.getColumnName());
|
||||
|
||||
if (!hasValueForProperty || isConstructorProperty) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object obj = propertyProvider.getPropertyValue(prop);
|
||||
wrapper.setProperty(prop, obj, useFieldAccessOnly);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void write(Object source, Row sink) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
public void setUseFieldAccessOnly(boolean useFieldAccessOnly) {
|
||||
this.useFieldAccessOnly = useFieldAccessOnly;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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.cassandra.convert;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.PropertyAccessor;
|
||||
import org.springframework.expression.TypedValue;
|
||||
|
||||
import com.datastax.driver.core.DataType;
|
||||
import com.datastax.driver.core.Row;
|
||||
|
||||
/**
|
||||
* {@link PropertyAccessor} to read values from a {@link Row}.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
enum RowReaderPropertyAccessor implements PropertyAccessor {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.expression.PropertyAccessor#getSpecificTargetClasses()
|
||||
*/
|
||||
public Class<?>[] getSpecificTargetClasses() {
|
||||
return new Class<?>[] { Row.class };
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.expression.PropertyAccessor#canRead(org.springframework.expression.EvaluationContext, java.lang.Object, java.lang.String)
|
||||
*/
|
||||
public boolean canRead(EvaluationContext context, Object target, String name) {
|
||||
return ((Row) target).getColumnDefinitions().contains(name);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.expression.PropertyAccessor#read(org.springframework.expression.EvaluationContext, java.lang.Object, java.lang.String)
|
||||
*/
|
||||
public TypedValue read(EvaluationContext context, Object target, String name) {
|
||||
Row row = (Row) target;
|
||||
if (row.isNull(name)) {
|
||||
return TypedValue.NULL;
|
||||
}
|
||||
DataType columnType = row.getColumnDefinitions().getType(name);
|
||||
ByteBuffer bytes = row.getBytes(name);
|
||||
Object object = columnType.deserialize(bytes);
|
||||
return new TypedValue(object);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.expression.PropertyAccessor#canWrite(org.springframework.expression.EvaluationContext, java.lang.Object, java.lang.String)
|
||||
*/
|
||||
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)
|
||||
*/
|
||||
public void write(EvaluationContext context, Object target, String name, Object newValue) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Copyright 2011-2013 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.cassandra.core;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
import org.springframework.data.cassandra.config.CompressionType;
|
||||
import org.springframework.data.cassandra.config.PoolingOptionsConfig;
|
||||
import org.springframework.data.cassandra.config.SocketOptionsConfig;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.datastax.driver.core.AuthProvider;
|
||||
import com.datastax.driver.core.Cluster;
|
||||
import com.datastax.driver.core.HostDistance;
|
||||
import com.datastax.driver.core.PoolingOptions;
|
||||
import com.datastax.driver.core.ProtocolOptions.Compression;
|
||||
import com.datastax.driver.core.SocketOptions;
|
||||
import com.datastax.driver.core.policies.LoadBalancingPolicy;
|
||||
import com.datastax.driver.core.policies.ReconnectionPolicy;
|
||||
import com.datastax.driver.core.policies.RetryPolicy;
|
||||
|
||||
/**
|
||||
* Convenient factory for configuring a Cassandra Cluster.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
|
||||
public class CassandraClusterFactoryBean implements FactoryBean<Cluster>,
|
||||
InitializingBean, DisposableBean, PersistenceExceptionTranslator {
|
||||
|
||||
private static final int DEFAULT_PORT = 9042;
|
||||
|
||||
private Cluster cluster;
|
||||
|
||||
private String contactPoints;
|
||||
private int port = DEFAULT_PORT;
|
||||
private CompressionType compressionType;
|
||||
|
||||
private PoolingOptionsConfig localPoolingOptions;
|
||||
private PoolingOptionsConfig remotePoolingOptions;
|
||||
private SocketOptionsConfig socketOptions;
|
||||
|
||||
private AuthProvider authProvider;
|
||||
private LoadBalancingPolicy loadBalancingPolicy;
|
||||
private ReconnectionPolicy reconnectionPolicy;
|
||||
private RetryPolicy retryPolicy;
|
||||
|
||||
private boolean metricsEnabled = true;
|
||||
|
||||
private final PersistenceExceptionTranslator exceptionTranslator = new CassandraExceptionTranslator();
|
||||
|
||||
public Cluster getObject() throws Exception {
|
||||
return cluster;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
|
||||
*/
|
||||
public Class<? extends Cluster> getObjectType() {
|
||||
return Cluster.class;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.FactoryBean#isSingleton()
|
||||
*/
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible(java.lang.RuntimeException)
|
||||
*/
|
||||
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
|
||||
return exceptionTranslator.translateExceptionIfPossible(ex);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
*/
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
|
||||
if (!StringUtils.hasText(contactPoints)) {
|
||||
throw new IllegalArgumentException(
|
||||
"at least one server is required");
|
||||
}
|
||||
|
||||
Cluster.Builder builder = Cluster.builder();
|
||||
|
||||
builder.addContactPoints(StringUtils.commaDelimitedListToStringArray(contactPoints)).withPort(port);
|
||||
|
||||
if (compressionType != null) {
|
||||
builder.withCompression(convertCompressionType(compressionType));
|
||||
}
|
||||
|
||||
if (localPoolingOptions != null) {
|
||||
builder.withPoolingOptions(configPoolingOptions(HostDistance.LOCAL, localPoolingOptions));
|
||||
}
|
||||
|
||||
if (remotePoolingOptions != null) {
|
||||
builder.withPoolingOptions(configPoolingOptions(HostDistance.REMOTE, remotePoolingOptions));
|
||||
}
|
||||
|
||||
if (socketOptions != null) {
|
||||
builder.withSocketOptions(configSocketOptions(socketOptions));
|
||||
}
|
||||
|
||||
if (authProvider != null) {
|
||||
builder.withAuthProvider(authProvider);
|
||||
}
|
||||
|
||||
if (loadBalancingPolicy != null) {
|
||||
builder.withLoadBalancingPolicy(loadBalancingPolicy);
|
||||
}
|
||||
|
||||
if (reconnectionPolicy != null) {
|
||||
builder.withReconnectionPolicy(reconnectionPolicy);
|
||||
}
|
||||
|
||||
if (retryPolicy != null) {
|
||||
builder.withRetryPolicy(retryPolicy);
|
||||
}
|
||||
|
||||
if (!metricsEnabled) {
|
||||
builder.withoutMetrics();
|
||||
}
|
||||
|
||||
Cluster cluster = builder.build();
|
||||
|
||||
// initialize property
|
||||
this.cluster = cluster;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.DisposableBean#destroy()
|
||||
*/
|
||||
public void destroy() throws Exception {
|
||||
this.cluster.shutdown();
|
||||
}
|
||||
|
||||
public void setContactPoints(String contactPoints) {
|
||||
this.contactPoints = contactPoints;
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public void setCompressionType(CompressionType compressionType) {
|
||||
this.compressionType = compressionType;
|
||||
}
|
||||
|
||||
public void setLocalPoolingOptions(PoolingOptionsConfig localPoolingOptions) {
|
||||
this.localPoolingOptions = localPoolingOptions;
|
||||
}
|
||||
|
||||
public void setRemotePoolingOptions(PoolingOptionsConfig remotePoolingOptions) {
|
||||
this.remotePoolingOptions = remotePoolingOptions;
|
||||
}
|
||||
|
||||
public void setSocketOptions(SocketOptionsConfig socketOptions) {
|
||||
this.socketOptions = socketOptions;
|
||||
}
|
||||
|
||||
public void setAuthProvider(AuthProvider authProvider) {
|
||||
this.authProvider = authProvider;
|
||||
}
|
||||
|
||||
public void setLoadBalancingPolicy(LoadBalancingPolicy loadBalancingPolicy) {
|
||||
this.loadBalancingPolicy = loadBalancingPolicy;
|
||||
}
|
||||
|
||||
public void setReconnectionPolicy(ReconnectionPolicy reconnectionPolicy) {
|
||||
this.reconnectionPolicy = reconnectionPolicy;
|
||||
}
|
||||
|
||||
public void setRetryPolicy(RetryPolicy retryPolicy) {
|
||||
this.retryPolicy = retryPolicy;
|
||||
}
|
||||
|
||||
public void setMetricsEnabled(boolean metricsEnabled) {
|
||||
this.metricsEnabled = metricsEnabled;
|
||||
}
|
||||
|
||||
private static Compression convertCompressionType(CompressionType type) {
|
||||
switch(type) {
|
||||
case none:
|
||||
return Compression.NONE;
|
||||
case snappy:
|
||||
return Compression.SNAPPY;
|
||||
}
|
||||
throw new IllegalArgumentException("unknown compression type " + type);
|
||||
}
|
||||
|
||||
private static PoolingOptions configPoolingOptions(HostDistance hostDistance, PoolingOptionsConfig config) {
|
||||
PoolingOptions poolingOptions = new PoolingOptions();
|
||||
|
||||
if (config.getMinSimultaneousRequests() != null) {
|
||||
poolingOptions.setMinSimultaneousRequestsPerConnectionThreshold(hostDistance, config.getMinSimultaneousRequests());
|
||||
}
|
||||
if (config.getMaxSimultaneousRequests() != null) {
|
||||
poolingOptions.setMaxSimultaneousRequestsPerConnectionThreshold(hostDistance, config.getMaxSimultaneousRequests());
|
||||
}
|
||||
if (config.getCoreConnections() != null) {
|
||||
poolingOptions.setCoreConnectionsPerHost(hostDistance, config.getCoreConnections());
|
||||
}
|
||||
if (config.getMaxConnections() != null) {
|
||||
poolingOptions.setMaxConnectionsPerHost(hostDistance, config.getMaxConnections());
|
||||
}
|
||||
|
||||
return poolingOptions;
|
||||
}
|
||||
|
||||
private static SocketOptions configSocketOptions(SocketOptionsConfig config) {
|
||||
SocketOptions socketOptions = new SocketOptions();
|
||||
|
||||
if (config.getConnectTimeoutMls() != null) {
|
||||
socketOptions.setConnectTimeoutMillis(config.getConnectTimeoutMls());
|
||||
}
|
||||
if (config.getKeepAlive() != null) {
|
||||
socketOptions.setKeepAlive(config.getKeepAlive());
|
||||
}
|
||||
if (config.getReuseAddress() != null) {
|
||||
socketOptions.setReuseAddress(config.getReuseAddress());
|
||||
}
|
||||
if (config.getSoLinger() != null) {
|
||||
socketOptions.setSoLinger(config.getSoLinger());
|
||||
}
|
||||
if (config.getTcpNoDelay() != null) {
|
||||
socketOptions.setTcpNoDelay(config.getTcpNoDelay());
|
||||
}
|
||||
if (config.getReceiveBufferSize() != null) {
|
||||
socketOptions.setReceiveBufferSize(config.getReceiveBufferSize());
|
||||
}
|
||||
if (config.getSendBufferSize() != null) {
|
||||
socketOptions.setSendBufferSize(config.getSendBufferSize());
|
||||
}
|
||||
|
||||
return socketOptions;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2011-2013 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.cassandra.core;
|
||||
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
|
||||
/**
|
||||
* Cassandra connection exception.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
public class CassandraConnectionFailureException extends DataAccessResourceFailureException {
|
||||
|
||||
public CassandraConnectionFailureException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public CassandraConnectionFailureException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2010-2013 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.cassandra.core;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
|
||||
import com.datastax.driver.core.exceptions.InvalidQueryException;
|
||||
|
||||
/**
|
||||
* Simple {@link PersistenceExceptionTranslator} for Cassandra. Convert the given runtime exception to an appropriate
|
||||
* exception from the {@code org.springframework.dao} hierarchy. Return {@literal null} if no translation is
|
||||
* appropriate: any other exception may have resulted from user code, and should not be translated.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
|
||||
public class CassandraExceptionTranslator implements PersistenceExceptionTranslator {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible(java.lang.RuntimeException)
|
||||
*/
|
||||
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
|
||||
|
||||
// Check for well-known Cassandra subclasses.
|
||||
|
||||
if (ex instanceof InvalidQueryException) {
|
||||
return new DataAccessResourceFailureException(ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
// If we get here, we have an exception that resulted from user code,
|
||||
// rather than the persistence provider, so we return null to indicate
|
||||
// that translation should not occur.
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,345 @@
|
||||
/*
|
||||
* Copyright 2011-2013 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.cassandra.core;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
import org.springframework.data.cassandra.config.KeyspaceAttributes;
|
||||
import org.springframework.data.cassandra.config.TableAttributes;
|
||||
import org.springframework.data.cassandra.convert.CassandraConverter;
|
||||
import org.springframework.data.cassandra.convert.MappingCassandraConverter;
|
||||
import org.springframework.data.cassandra.mapping.CassandraMappingContext;
|
||||
import org.springframework.data.cassandra.mapping.CassandraPersistentEntity;
|
||||
import org.springframework.data.cassandra.mapping.CassandraPersistentProperty;
|
||||
import org.springframework.data.cassandra.util.CQLUtils;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.datastax.driver.core.Cluster;
|
||||
import com.datastax.driver.core.KeyspaceMetadata;
|
||||
import com.datastax.driver.core.Session;
|
||||
import com.datastax.driver.core.TableMetadata;
|
||||
import com.datastax.driver.core.exceptions.NoHostAvailableException;
|
||||
|
||||
/**
|
||||
* Convenient factory for configuring a Cassandra Session.
|
||||
* Session is a thread safe singleton and created per a keyspace.
|
||||
* So, it is enough to have one session per application.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
|
||||
public class CassandraKeyspaceFactoryBean implements FactoryBean<Keyspace>,
|
||||
InitializingBean, DisposableBean, BeanClassLoaderAware, PersistenceExceptionTranslator {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(CassandraKeyspaceFactoryBean.class);
|
||||
|
||||
public static final String DEFAULT_REPLICATION_STRATEGY = "SimpleStrategy";
|
||||
public static final int DEFAULT_REPLICATION_FACTOR = 1;
|
||||
|
||||
private ClassLoader beanClassLoader;
|
||||
|
||||
private Cluster cluster;
|
||||
private Session session;
|
||||
private String keyspace;
|
||||
|
||||
private CassandraConverter converter;
|
||||
private MappingContext<? extends CassandraPersistentEntity<?>, CassandraPersistentProperty> mappingContext;
|
||||
|
||||
private Keyspace keyspaceBean;
|
||||
|
||||
private KeyspaceAttributes keyspaceAttributes;
|
||||
|
||||
private final PersistenceExceptionTranslator exceptionTranslator = new CassandraExceptionTranslator();
|
||||
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.beanClassLoader = classLoader;
|
||||
}
|
||||
|
||||
|
||||
public Keyspace getObject() throws Exception {
|
||||
return keyspaceBean;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
|
||||
*/
|
||||
public Class<? extends Session> getObjectType() {
|
||||
return Session.class;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.FactoryBean#isSingleton()
|
||||
*/
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible(java.lang.RuntimeException)
|
||||
*/
|
||||
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
|
||||
return exceptionTranslator.translateExceptionIfPossible(ex);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
*/
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
|
||||
if (this.converter == null) {
|
||||
this.converter = getDefaultCassandraConverter();
|
||||
}
|
||||
this.mappingContext = this.converter.getMappingContext();
|
||||
|
||||
|
||||
if (cluster == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"at least one cluster is required");
|
||||
}
|
||||
|
||||
Session session = null;
|
||||
session = cluster.connect();
|
||||
|
||||
if (StringUtils.hasText(keyspace)) {
|
||||
|
||||
KeyspaceMetadata keyspaceMetadata = cluster.getMetadata().getKeyspace(keyspace.toLowerCase());
|
||||
boolean keyspaceExists = keyspaceMetadata != null;
|
||||
boolean keyspaceCreated = false;
|
||||
|
||||
if (keyspaceExists) {
|
||||
log.info("keyspace exists " + keyspaceMetadata.asCQLQuery());
|
||||
}
|
||||
|
||||
if (keyspaceAttributes == null) {
|
||||
keyspaceAttributes = new KeyspaceAttributes();
|
||||
}
|
||||
|
||||
// drop the old keyspace if needed
|
||||
if (keyspaceExists && (keyspaceAttributes.isCreate() || keyspaceAttributes.isCreateDrop())) {
|
||||
log.info("Drop keyspace " + keyspace + " on afterPropertiesSet");
|
||||
session.execute("DROP KEYSPACE " + keyspace);
|
||||
keyspaceExists = false;
|
||||
}
|
||||
|
||||
// create the new keyspace if needed
|
||||
if (!keyspaceExists && (keyspaceAttributes.isCreate() || keyspaceAttributes.isCreateDrop() || keyspaceAttributes.isUpdate())) {
|
||||
|
||||
String query = String.format("CREATE KEYSPACE %1$s WITH replication = { 'class' : '%2$s', 'replication_factor' : %3$d } AND DURABLE_WRITES = %4$b",
|
||||
keyspace,
|
||||
keyspaceAttributes.getReplicationStrategy(),
|
||||
keyspaceAttributes.getReplicationFactor(),
|
||||
keyspaceAttributes.isDurableWrites());
|
||||
|
||||
log.info("Create keyspace " + keyspace + " on afterPropertiesSet " + query);
|
||||
|
||||
session.execute(query);
|
||||
keyspaceCreated = true;
|
||||
}
|
||||
|
||||
// update keyspace if needed
|
||||
if (keyspaceAttributes.isUpdate() && !keyspaceCreated) {
|
||||
|
||||
if (compareKeyspaceAttributes(keyspaceAttributes, keyspaceMetadata) != null) {
|
||||
|
||||
String query = String.format("ALTER KEYSPACE %1$s WITH replication = { 'class' : '%2$s', 'replication_factor' : %3$d } AND DURABLE_WRITES = %4$b",
|
||||
keyspace,
|
||||
keyspaceAttributes.getReplicationStrategy(),
|
||||
keyspaceAttributes.getReplicationFactor(),
|
||||
keyspaceAttributes.isDurableWrites());
|
||||
|
||||
log.info("Update keyspace " + keyspace + " on afterPropertiesSet " + query);
|
||||
session.execute(query);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// validate keyspace if needed
|
||||
if (keyspaceAttributes.isValidate()) {
|
||||
|
||||
if (!keyspaceExists) {
|
||||
throw new InvalidDataAccessApiUsageException("keyspace '" + keyspace + "' not found in the Cassandra");
|
||||
}
|
||||
|
||||
String errorField = compareKeyspaceAttributes(keyspaceAttributes, keyspaceMetadata);
|
||||
if (errorField != null) {
|
||||
throw new InvalidDataAccessApiUsageException(errorField + " attribute is not much in the keyspace '" + keyspace + "'");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
session.execute("USE " + keyspace);
|
||||
|
||||
if (!CollectionUtils.isEmpty(keyspaceAttributes.getTables())) {
|
||||
|
||||
for (TableAttributes tableAttributes : keyspaceAttributes.getTables()) {
|
||||
|
||||
String entityClassName = tableAttributes.getEntity();
|
||||
Class<?> entityClass = ClassUtils.forName(entityClassName, this.beanClassLoader);
|
||||
CassandraPersistentEntity<?> entity = determineEntity(entityClass);
|
||||
String useTableName = tableAttributes.getName() != null ? tableAttributes.getName() : entity.getTable();
|
||||
|
||||
if (keyspaceCreated) {
|
||||
createNewTable(session, useTableName, entity);
|
||||
}
|
||||
else if (keyspaceAttributes.isUpdate()) {
|
||||
TableMetadata table = keyspaceMetadata.getTable(useTableName.toLowerCase());
|
||||
if (table == null) {
|
||||
createNewTable(session, useTableName, entity);
|
||||
}
|
||||
else {
|
||||
// alter table columns
|
||||
for (String cql : CQLUtils.alterTable(useTableName, entity, table)) {
|
||||
log.info("Execute on keyspace " + keyspace + " CQL " + cql);
|
||||
session.execute(cql);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (keyspaceAttributes.isValidate()) {
|
||||
TableMetadata table = keyspaceMetadata.getTable(useTableName.toLowerCase());
|
||||
if (table == null) {
|
||||
throw new InvalidDataAccessApiUsageException("not found table " + useTableName + " for entity " + entityClassName);
|
||||
}
|
||||
// validate columns
|
||||
List<String> alter = CQLUtils.alterTable(useTableName, entity, table);
|
||||
if (!alter.isEmpty()) {
|
||||
throw new InvalidDataAccessApiUsageException("invalid table " + useTableName + " for entity " + entityClassName + ". modify it by " + alter);
|
||||
}
|
||||
}
|
||||
|
||||
//System.out.println("tableAttributes, entityClass=" + entityClass + ", table = " + entity.getTable());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// initialize property
|
||||
this.session = session;
|
||||
|
||||
this.keyspaceBean = new Keyspace(keyspace, session, converter);
|
||||
}
|
||||
|
||||
|
||||
private void createNewTable(Session session, String useTableName,
|
||||
CassandraPersistentEntity<?> entity)
|
||||
throws NoHostAvailableException {
|
||||
String cql = CQLUtils.createTable(useTableName, entity);
|
||||
log.info("Execute on keyspace " + keyspace + " CQL " + cql);
|
||||
session.execute(cql);
|
||||
for (String indexCQL : CQLUtils.createIndexes(useTableName, entity)) {
|
||||
log.info("Execute on keyspace " + keyspace + " CQL " + indexCQL);
|
||||
session.execute(indexCQL);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.DisposableBean#destroy()
|
||||
*/
|
||||
public void destroy() throws Exception {
|
||||
|
||||
if (StringUtils.hasText(keyspace) && keyspaceAttributes != null && keyspaceAttributes.isCreateDrop()) {
|
||||
log.info("Drop keyspace " + keyspace + " on destroy");
|
||||
session.execute("USE system");
|
||||
session.execute("DROP KEYSPACE " + keyspace);
|
||||
}
|
||||
this.session.shutdown();
|
||||
}
|
||||
|
||||
public void setKeyspace(String keyspace) {
|
||||
this.keyspace = keyspace;
|
||||
}
|
||||
|
||||
public void setCluster(Cluster cluster) {
|
||||
this.cluster = cluster;
|
||||
}
|
||||
|
||||
public void setKeyspaceAttributes(KeyspaceAttributes keyspaceAttributes) {
|
||||
this.keyspaceAttributes = keyspaceAttributes;
|
||||
}
|
||||
|
||||
public void setConverter(CassandraConverter converter) {
|
||||
this.converter = converter;
|
||||
}
|
||||
|
||||
private static String compareKeyspaceAttributes(KeyspaceAttributes keyspaceAttributes, KeyspaceMetadata keyspaceMetadata) {
|
||||
if (keyspaceAttributes.isDurableWrites() != keyspaceMetadata.isDurableWrites()) {
|
||||
return "durableWrites";
|
||||
}
|
||||
Map<String, String> replication = keyspaceMetadata.getReplication();
|
||||
String replicationFactorStr = replication.get("replication_factor");
|
||||
if (replicationFactorStr == null) {
|
||||
return "replication_factor";
|
||||
}
|
||||
try {
|
||||
int replicationFactor = Integer.parseInt(replicationFactorStr);
|
||||
if (keyspaceAttributes.getReplicationFactor() != replicationFactor) {
|
||||
return "replication_factor";
|
||||
}
|
||||
}
|
||||
catch(NumberFormatException e) {
|
||||
return "replication_factor";
|
||||
}
|
||||
|
||||
String attributesStrategy = keyspaceAttributes.getReplicationStrategy();
|
||||
if (attributesStrategy.indexOf('.') == -1) {
|
||||
attributesStrategy = "org.apache.cassandra.locator." + attributesStrategy;
|
||||
}
|
||||
String replicationStrategy = replication.get("class");
|
||||
if (!attributesStrategy.equals(replicationStrategy)) {
|
||||
return "replication_class";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
CassandraPersistentEntity<?> determineEntity(Class<?> entityClass) {
|
||||
|
||||
if (entityClass == null) {
|
||||
throw new InvalidDataAccessApiUsageException(
|
||||
"No class parameter provided, entity table name can't be determined!");
|
||||
}
|
||||
|
||||
CassandraPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityClass);
|
||||
if (entity == null) {
|
||||
throw new InvalidDataAccessApiUsageException("No Persitent Entity information found for the class "
|
||||
+ entityClass.getName());
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
private static final CassandraConverter getDefaultCassandraConverter() {
|
||||
MappingCassandraConverter converter = new MappingCassandraConverter(new CassandraMappingContext());
|
||||
converter.afterPropertiesSet();
|
||||
return converter;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 2011-2013 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.cassandra.core;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.cassandra.convert.CassandraConverter;
|
||||
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
import com.datastax.driver.core.querybuilder.Update;
|
||||
|
||||
/**
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
public interface CassandraOperations {
|
||||
|
||||
/**
|
||||
* The table name used for the specified class by this template.
|
||||
*
|
||||
* @param entityClass must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
String getTableName(Class<?> entityClass);
|
||||
|
||||
/**
|
||||
* Execute query and return Cassandra ResultSet
|
||||
*
|
||||
* @param query must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
ResultSet executeQuery(String query);
|
||||
|
||||
/**
|
||||
* Execute query and convert ResultSet to the list of entities
|
||||
*
|
||||
* @param query must not be {@literal null}.
|
||||
* @param selectClass must not be {@literal null}, mapped entity type.
|
||||
* @return
|
||||
*/
|
||||
<T> List<T> select(String query, Class<T> selectClass);
|
||||
|
||||
/**
|
||||
* Execute query and convert ResultSet to the entity
|
||||
*
|
||||
* @param query must not be {@literal null}.
|
||||
* @param selectClass must not be {@literal null}, mapped entity type.
|
||||
* @return
|
||||
*/
|
||||
<T> T selectOne(String query, Class<T> selectClass);
|
||||
|
||||
/**
|
||||
* Insert the given object to the table by id.
|
||||
*
|
||||
* @param object
|
||||
*/
|
||||
void insert(Object entity);
|
||||
|
||||
/**
|
||||
* Insert the given object to the table by id.
|
||||
*
|
||||
* @param object
|
||||
*/
|
||||
void insert(Object entity, String tableName);
|
||||
|
||||
/**
|
||||
* Remove the given object from the table by id.
|
||||
*
|
||||
* @param object
|
||||
*/
|
||||
void remove(Object object);
|
||||
|
||||
/**
|
||||
* Removes the given object from the given table.
|
||||
*
|
||||
* @param object
|
||||
* @param table must not be {@literal null} or empty.
|
||||
*/
|
||||
void remove(Object object, String tableName);
|
||||
|
||||
/**
|
||||
* Create a table with the name and fields indicated by the entity class
|
||||
*
|
||||
* @param entityClass class that determines metadata of the table to create/drop.
|
||||
*/
|
||||
void createTable(Class<?> entityClass);
|
||||
|
||||
/**
|
||||
* Create a table with the name and fields indicated by the entity class
|
||||
*
|
||||
* @param entityClass class that determines metadata of the table to create/drop.
|
||||
* @param tableName explicit name of the table
|
||||
*/
|
||||
void createTable(Class<?> entityClass, String tableName);
|
||||
|
||||
/**
|
||||
* Alter table with the name and fields indicated by the entity class
|
||||
*
|
||||
* @param entityClass class that determines metadata of the table to create/drop.
|
||||
*/
|
||||
void alterTable(Class<?> entityClass);
|
||||
|
||||
/**
|
||||
* Alter table with the name and fields indicated by the entity class
|
||||
*
|
||||
* @param entityClass class that determines metadata of the table to create/drop.
|
||||
* @param tableName explicit name of the table
|
||||
*/
|
||||
void alterTable(Class<?> entityClass, String tableName);
|
||||
|
||||
/**
|
||||
* Alter table with the name and fields indicated by the entity class
|
||||
*
|
||||
* @param entityClass class that determines metadata of the table to create/drop.
|
||||
*/
|
||||
void dropTable(Class<?> entityClass);
|
||||
|
||||
/**
|
||||
* Alter table with the name and fields indicated by the entity class
|
||||
*
|
||||
* @param tableName explicit name of the table.
|
||||
*/
|
||||
void dropTable(String tableName);
|
||||
|
||||
/**
|
||||
* Returns the underlying {@link CassandraConverter}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
CassandraConverter getConverter();
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2011-2013 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.cassandra.core;
|
||||
|
||||
import org.springframework.dao.UncategorizedDataAccessException;
|
||||
|
||||
/**
|
||||
* Exception thrown when we can't classify a Cassandra exception into one of Spring generic data access exceptions.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
|
||||
public class CassandraSystemException extends UncategorizedDataAccessException {
|
||||
|
||||
public CassandraSystemException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Copyright 2011-2013 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.cassandra.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
import org.springframework.data.cassandra.convert.CassandraConverter;
|
||||
import org.springframework.data.cassandra.mapping.CassandraPersistentEntity;
|
||||
import org.springframework.data.cassandra.mapping.CassandraPersistentProperty;
|
||||
import org.springframework.data.convert.EntityReader;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
import com.datastax.driver.core.Row;
|
||||
import com.datastax.driver.core.Session;
|
||||
import com.datastax.driver.core.exceptions.NoHostAvailableException;
|
||||
|
||||
/**
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
public class CassandraTemplate implements CassandraOperations {
|
||||
|
||||
private final Session session;
|
||||
private final CassandraConverter cassandraConverter;
|
||||
private final MappingContext<? extends CassandraPersistentEntity<?>, CassandraPersistentProperty> mappingContext;
|
||||
|
||||
private final PersistenceExceptionTranslator exceptionTranslator = new CassandraExceptionTranslator();
|
||||
|
||||
/**
|
||||
* Constructor used for a basic template configuration
|
||||
*
|
||||
* @param keyspace must not be {@literal null}.
|
||||
*/
|
||||
public CassandraTemplate(Keyspace keyspace) {
|
||||
this.session = keyspace.getSession();
|
||||
this.cassandraConverter = keyspace.getCassandraConverter();
|
||||
this.mappingContext = this.cassandraConverter.getMappingContext();
|
||||
}
|
||||
|
||||
public String getTableName(Class<?> entityClass) {
|
||||
return determineTableName(entityClass);
|
||||
}
|
||||
|
||||
public ResultSet executeQuery(String query) {
|
||||
try {
|
||||
return session.execute(query);
|
||||
} catch (NoHostAvailableException e) {
|
||||
throw new CassandraConnectionFailureException("no host available", e);
|
||||
} catch (RuntimeException e) {
|
||||
throw potentiallyConvertRuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public <T> List<T> select(String query, Class<T> selectClass) {
|
||||
return selectInternal(query, new ReadRowCallback<T>(cassandraConverter, selectClass));
|
||||
}
|
||||
|
||||
public <T> T selectOne(String query, Class<T> selectClass) {
|
||||
return selectOneInternal(query, new ReadRowCallback<T>(cassandraConverter, selectClass));
|
||||
}
|
||||
|
||||
|
||||
public void insert(Object entity) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
public void insert(Object entity, String tableName) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
public void remove(Object object) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
public void remove(Object object, String tableName) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
public void createTable(Class<?> entityClass) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
public void createTable(Class<?> entityClass, String tableName) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
public void alterTable(Class<?> entityClass) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
public void alterTable(Class<?> entityClass, String tableName) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
public void dropTable(Class<?> entityClass) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
public void dropTable(String tableName) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
public CassandraConverter getConverter() {
|
||||
return cassandraConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple internal callback to allow operations on a {@link Row}.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
|
||||
private interface RowCallback<T> {
|
||||
|
||||
T doWith(Row object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple {@link RowCallback} that will transform {@link Row} into the given target type using the given
|
||||
* {@link EntityReader}.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
private static class ReadRowCallback<T> implements RowCallback<T> {
|
||||
|
||||
private final EntityReader<? super T, Row> reader;
|
||||
private final Class<T> type;
|
||||
|
||||
public ReadRowCallback(EntityReader<? super T, Row> reader, Class<T> type) {
|
||||
Assert.notNull(reader);
|
||||
Assert.notNull(type);
|
||||
this.reader = reader;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public T doWith(Row object) {
|
||||
T source = reader.read(type, object);
|
||||
return source;
|
||||
}
|
||||
}
|
||||
|
||||
<T> List<T> selectInternal(String query, ReadRowCallback<T> readRowCallback) {
|
||||
try {
|
||||
ResultSet resultSet = session.execute(query);
|
||||
List<T> result = new ArrayList<T>();
|
||||
Iterator<Row> iterator = resultSet.iterator();
|
||||
while(iterator.hasNext()) {
|
||||
Row row = iterator.next();
|
||||
result.add(readRowCallback.doWith(row));
|
||||
}
|
||||
return result;
|
||||
} catch (NoHostAvailableException e) {
|
||||
throw new CassandraConnectionFailureException("no host available", e);
|
||||
} catch (RuntimeException e) {
|
||||
throw potentiallyConvertRuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
<T> T selectOneInternal(String query, ReadRowCallback<T> readRowCallback) {
|
||||
try {
|
||||
ResultSet resultSet = session.execute(query);
|
||||
Iterator<Row> iterator = resultSet.iterator();
|
||||
if (iterator.hasNext()) {
|
||||
Row row = iterator.next();
|
||||
T result = readRowCallback.doWith(row);
|
||||
if (iterator.hasNext()) {
|
||||
throw new DuplicateKeyException("found two or more results in query " + query);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
} catch (NoHostAvailableException e) {
|
||||
throw new CassandraConnectionFailureException("no host available", e);
|
||||
} catch (RuntimeException e) {
|
||||
throw potentiallyConvertRuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
String determineTableName(Class<?> entityClass) {
|
||||
|
||||
if (entityClass == null) {
|
||||
throw new InvalidDataAccessApiUsageException(
|
||||
"No class parameter provided, entity table name can't be determined!");
|
||||
}
|
||||
|
||||
CassandraPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityClass);
|
||||
if (entity == null) {
|
||||
throw new InvalidDataAccessApiUsageException("No Persitent Entity information found for the class "
|
||||
+ entityClass.getName());
|
||||
}
|
||||
return entity.getTable();
|
||||
}
|
||||
|
||||
private RuntimeException potentiallyConvertRuntimeException(
|
||||
RuntimeException ex) {
|
||||
RuntimeException resolved = this.exceptionTranslator.translateExceptionIfPossible(ex);
|
||||
return resolved == null ? ex : resolved;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2011-2013 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.cassandra.core;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import com.datastax.driver.core.DataType;
|
||||
|
||||
/**
|
||||
* Simple Cassandra value of the ByteBuffer with DataType
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
public class CassandraValue {
|
||||
|
||||
private final ByteBuffer value;
|
||||
private final DataType type;
|
||||
|
||||
public CassandraValue(ByteBuffer value, DataType type) {
|
||||
this.value = value;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public ByteBuffer getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public DataType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2011-2013 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.cassandra.core;
|
||||
|
||||
import org.springframework.data.cassandra.convert.CassandraConverter;
|
||||
|
||||
import com.datastax.driver.core.Session;
|
||||
|
||||
/**
|
||||
* Simple Cassandra Keyspace object
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
public class Keyspace {
|
||||
|
||||
private final String keyspace;
|
||||
private final Session session;
|
||||
private final CassandraConverter cassandraConverter;
|
||||
|
||||
/**
|
||||
* Constructor used for a basic keyspace configuration
|
||||
*
|
||||
* @param keyspace, system if {@literal null}.
|
||||
* @param session must not be {@literal null}.
|
||||
* @param cassandraConverter must not be {@literal null}.
|
||||
*/
|
||||
public Keyspace(String keyspace, Session session, CassandraConverter cassandraConverter) {
|
||||
this.keyspace = keyspace;
|
||||
this.session = session;
|
||||
this.cassandraConverter = cassandraConverter;
|
||||
}
|
||||
|
||||
public String getKeyspace() {
|
||||
return keyspace;
|
||||
}
|
||||
|
||||
public Session getSession() {
|
||||
return session;
|
||||
}
|
||||
|
||||
public CassandraConverter getCassandraConverter() {
|
||||
return cassandraConverter;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.springframework.data.cassandra.cql;
|
||||
|
||||
public abstract class CQLBuilder {
|
||||
|
||||
public static CreateTable createTable(String tableName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package org.springframework.data.cassandra.cql;
|
||||
|
||||
public class CreateTable {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2011-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.cassandra.mapping;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.expression.BeanFactoryAccessor;
|
||||
import org.springframework.context.expression.BeanFactoryResolver;
|
||||
import org.springframework.data.cassandra.util.CassandraNamingUtils;
|
||||
import org.springframework.data.mapping.model.BasicPersistentEntity;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.ParserContext;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Cassandra specific {@link BasicPersistentEntity} implementation that adds Cassandra specific meta-data such as the
|
||||
* table name.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
public class BasicCassandraPersistentEntity<T> extends BasicPersistentEntity<T, CassandraPersistentProperty> implements
|
||||
CassandraPersistentEntity<T>, ApplicationContextAware {
|
||||
|
||||
private final String table;
|
||||
private final SpelExpressionParser parser;
|
||||
private final StandardEvaluationContext context;
|
||||
|
||||
/**
|
||||
* Creates a new {@link BasicCassandraPersistentEntity} with the given {@link TypeInformation}. Will default the
|
||||
* table name to the entities simple type name.
|
||||
*
|
||||
* @param typeInformation
|
||||
*/
|
||||
public BasicCassandraPersistentEntity(TypeInformation<T> typeInformation) {
|
||||
|
||||
super(typeInformation, CassandraPersistentPropertyComparator.INSTANCE);
|
||||
|
||||
this.parser = new SpelExpressionParser();
|
||||
this.context = new StandardEvaluationContext();
|
||||
|
||||
Class<?> rawType = typeInformation.getType();
|
||||
String fallback = CassandraNamingUtils.getPreferredTableName(rawType);
|
||||
|
||||
if (rawType.isAnnotationPresent(Table.class)) {
|
||||
Table d = rawType.getAnnotation(Table.class);
|
||||
this.table = StringUtils.hasText(d.name()) ? d.name() : fallback;
|
||||
} else {
|
||||
this.table = fallback;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
|
||||
*/
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
|
||||
context.addPropertyAccessor(new BeanFactoryAccessor());
|
||||
context.setBeanResolver(new BeanFactoryResolver(applicationContext));
|
||||
context.setRootObject(applicationContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the table the entity shall be persisted to.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getTable() {
|
||||
Expression expression = parser.parseExpression(table, ParserContext.TEMPLATE_EXPRESSION);
|
||||
return expression.getValue(context, String.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Comparator} implementation inspecting the {@link CassandraPersistentProperty}'s order.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
static enum CassandraPersistentPropertyComparator implements Comparator<CassandraPersistentProperty> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
|
||||
*/
|
||||
public int compare(CassandraPersistentProperty o1, CassandraPersistentProperty o2) {
|
||||
|
||||
if (o1.isColumnId()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (o2.isColumnId()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return o1.getColumnName().compareTo(o2.getColumnName());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright 2011-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.cassandra.mapping;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.datastax.driver.core.DataType;
|
||||
|
||||
/**
|
||||
* Cassandra specific {@link org.springframework.data.mapping.model.AnnotationBasedPersistentProperty} implementation.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
public class BasicCassandraPersistentProperty extends AnnotationBasedPersistentProperty<CassandraPersistentProperty> implements
|
||||
CassandraPersistentProperty {
|
||||
|
||||
/**
|
||||
* Creates a new {@link BasicCassandraPersistentProperty}.
|
||||
*
|
||||
* @param field
|
||||
* @param propertyDescriptor
|
||||
* @param owner
|
||||
* @param simpleTypeHolder
|
||||
*/
|
||||
public BasicCassandraPersistentProperty(Field field, PropertyDescriptor propertyDescriptor,
|
||||
CassandraPersistentEntity<?> owner, SimpleTypeHolder simpleTypeHolder) {
|
||||
super(field, propertyDescriptor, owner, simpleTypeHolder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Also considers fields that has a RowId annotation.
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public boolean isIdProperty() {
|
||||
|
||||
if (super.isIdProperty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return getField().isAnnotationPresent(RowId.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* For dynamic tables returns true if property value is used as column name.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isColumnId() {
|
||||
return getField().isAnnotationPresent(ColumnId.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the column name to be used to store the value of the property inside the Cassandra.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getColumnName() {
|
||||
Column annotation = getField().getAnnotation(Column.class);
|
||||
return annotation != null && StringUtils.hasText(annotation.value()) ? annotation.value() : field.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data type information if exists.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public DataType getDataType() {
|
||||
Qualify annotation = getField().getAnnotation(Qualify.class);
|
||||
if (annotation != null && annotation.type() != null) {
|
||||
return qualifyAnnotatedType(annotation);
|
||||
}
|
||||
if (isMap()) {
|
||||
List<TypeInformation<?>> args = getTypeInformation().getTypeArguments();
|
||||
ensureTypeArguments(args.size(), 2);
|
||||
return DataType.map(autodetectPrimitiveType(args.get(0).getType()), autodetectPrimitiveType(args.get(1).getType()));
|
||||
}
|
||||
if (isCollectionLike()) {
|
||||
List<TypeInformation<?>> args = getTypeInformation().getTypeArguments();
|
||||
ensureTypeArguments(args.size(), 1);
|
||||
if (Set.class.isAssignableFrom(getType())) {
|
||||
return DataType.set(autodetectPrimitiveType(args.get(0).getType()));
|
||||
}
|
||||
else if (List.class.isAssignableFrom(getType())) {
|
||||
return DataType.list(autodetectPrimitiveType(args.get(0).getType()));
|
||||
}
|
||||
}
|
||||
DataType dataType = CassandraSimpleTypes.autodetectPrimitive(this.getType());
|
||||
if (dataType == null) {
|
||||
throw new InvalidDataAccessApiUsageException("only primitive types and Set,List,Map collections are allowed, unknown type for property '" + this.getName() + "' type is '" + this.getType() + "' in the entity " + this.getOwner().getName());
|
||||
}
|
||||
return dataType;
|
||||
}
|
||||
|
||||
private DataType qualifyAnnotatedType(Qualify annotation) {
|
||||
DataType.Name type = annotation.type();
|
||||
if (type.isCollection()) {
|
||||
switch(type) {
|
||||
case MAP:
|
||||
ensureTypeArguments(annotation.typeArguments().length, 2);
|
||||
return DataType.map(resolvePrimitiveType(annotation.typeArguments()[0]),
|
||||
resolvePrimitiveType(annotation.typeArguments()[1]));
|
||||
case LIST:
|
||||
ensureTypeArguments(annotation.typeArguments().length, 1);
|
||||
return DataType.list(resolvePrimitiveType(annotation.typeArguments()[0]));
|
||||
case SET:
|
||||
ensureTypeArguments(annotation.typeArguments().length, 1);
|
||||
return DataType.set(resolvePrimitiveType(annotation.typeArguments()[0]));
|
||||
default:
|
||||
throw new InvalidDataAccessApiUsageException("unknown collection DataType for property '" + this.getName() + "' type is '" + this.getType() + "' in the entity " + this.getOwner().getName());
|
||||
}
|
||||
}
|
||||
else {
|
||||
return CassandraSimpleTypes.resolvePrimitive(type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the property has secondary index on this column.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isIndexed() {
|
||||
return getField().isAnnotationPresent(Index.class);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.AbstractPersistentProperty#createAssociation()
|
||||
*/
|
||||
@Override
|
||||
protected Association<CassandraPersistentProperty> createAssociation() {
|
||||
return new Association<CassandraPersistentProperty>(this, null);
|
||||
}
|
||||
|
||||
DataType resolvePrimitiveType(DataType.Name typeName) {
|
||||
DataType dataType = CassandraSimpleTypes.resolvePrimitive(typeName);
|
||||
if (dataType == null) {
|
||||
throw new InvalidDataAccessApiUsageException("only primitive types are allowed inside collections for the property '" + this.getName() + "' type is '" + this.getType() + "' in the entity " + this.getOwner().getName());
|
||||
}
|
||||
return dataType;
|
||||
}
|
||||
|
||||
DataType autodetectPrimitiveType(Class<?> javaType) {
|
||||
DataType dataType = CassandraSimpleTypes.autodetectPrimitive(javaType);
|
||||
if (dataType == null) {
|
||||
throw new InvalidDataAccessApiUsageException("only primitive types are allowed inside collections for the property '" + this.getName() + "' type is '" + this.getType() + "' in the entity " + this.getOwner().getName());
|
||||
}
|
||||
return dataType;
|
||||
}
|
||||
|
||||
void ensureTypeArguments(int args, int expected) {
|
||||
if (args != expected) {
|
||||
throw new InvalidDataAccessApiUsageException("expected " + expected + " of typed arguments for the property '" + this.getName() + "' type is '" + this.getType() + "' in the entity " + this.getOwner().getName());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2011-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.cassandra.mapping;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
|
||||
|
||||
/**
|
||||
* {@link CassandraPersistentProperty} caching access to {@link #isIdProperty()} and {@link #getColumnName()}.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
public class CachingCassandraPersistentProperty extends BasicCassandraPersistentProperty {
|
||||
|
||||
private Boolean isIdProperty;
|
||||
private Boolean isColumnId;
|
||||
private String columnName;
|
||||
private Boolean isIndexed;
|
||||
|
||||
/**
|
||||
* Creates a new {@link CachingCassandraPersistentProperty}.
|
||||
*
|
||||
* @param field
|
||||
* @param propertyDescriptor
|
||||
* @param owner
|
||||
* @param simpleTypeHolder
|
||||
*/
|
||||
public CachingCassandraPersistentProperty(Field field, PropertyDescriptor propertyDescriptor,
|
||||
CassandraPersistentEntity<?> owner, SimpleTypeHolder simpleTypeHolder) {
|
||||
super(field, propertyDescriptor, owner, simpleTypeHolder);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.mapping.BasicCassandraPersistentProperty#isIdProperty()
|
||||
*/
|
||||
@Override
|
||||
public boolean isIdProperty() {
|
||||
|
||||
if (this.isIdProperty == null) {
|
||||
this.isIdProperty = super.isIdProperty();
|
||||
}
|
||||
|
||||
return this.isIdProperty;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.mapping.BasicCassandraPersistentProperty#isColumnId()
|
||||
*/
|
||||
@Override
|
||||
public boolean isColumnId() {
|
||||
|
||||
if (this.isColumnId == null) {
|
||||
this.isColumnId = super.isColumnId();
|
||||
}
|
||||
|
||||
return this.isColumnId;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.mapping.BasicCassandraPersistentProperty#getFieldName()
|
||||
*/
|
||||
@Override
|
||||
public String getColumnName() {
|
||||
|
||||
if (this.columnName == null) {
|
||||
this.columnName = super.getColumnName();
|
||||
}
|
||||
|
||||
return this.columnName;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.mapping.BasicCassandraPersistentProperty#isIndexed()
|
||||
*/
|
||||
@Override
|
||||
public boolean isIndexed() {
|
||||
|
||||
if (this.isIndexed == null) {
|
||||
this.isIndexed = super.isIndexed();
|
||||
}
|
||||
|
||||
return this.isIndexed;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2011-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.cassandra.mapping;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.data.mapping.context.AbstractMappingContext;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
/**
|
||||
* Default implementation of a {@link MappingContext} for Cassandra using {@link BasicCassandraPersistentEntity} and
|
||||
* {@link BasicCassandraPersistentProperty} as primary abstractions.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
public class CassandraMappingContext extends AbstractMappingContext<BasicCassandraPersistentEntity<?>, CassandraPersistentProperty>
|
||||
implements ApplicationContextAware {
|
||||
|
||||
private ApplicationContext context;
|
||||
|
||||
/**
|
||||
* Creates a new {@link CassandraMappingContext}.
|
||||
*/
|
||||
public CassandraMappingContext() {
|
||||
setSimpleTypeHolder(CassandraSimpleTypes.HOLDER);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.AbstractMappingContext#createPersistentProperty(java.lang.reflect.Field, java.beans.PropertyDescriptor, org.springframework.data.mapping.MutablePersistentEntity, org.springframework.data.mapping.SimpleTypeHolder)
|
||||
*/
|
||||
@Override
|
||||
public CassandraPersistentProperty createPersistentProperty(Field field, PropertyDescriptor descriptor,
|
||||
BasicCassandraPersistentEntity<?> owner, SimpleTypeHolder simpleTypeHolder) {
|
||||
return new CachingCassandraPersistentProperty(field, descriptor, owner, simpleTypeHolder);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.BasicMappingContext#createPersistentEntity(org.springframework.data.util.TypeInformation, org.springframework.data.mapping.model.MappingContext)
|
||||
*/
|
||||
@Override
|
||||
protected <T> BasicCassandraPersistentEntity<T> createPersistentEntity(TypeInformation<T> typeInformation) {
|
||||
|
||||
BasicCassandraPersistentEntity<T> entity = new BasicCassandraPersistentEntity<T>(typeInformation);
|
||||
|
||||
if (context != null) {
|
||||
entity.setApplicationContext(context);
|
||||
}
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
|
||||
*/
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
|
||||
this.context = applicationContext;
|
||||
super.setApplicationContext(applicationContext);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2011-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.cassandra.mapping;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
|
||||
/**
|
||||
* Cassandra specific {@link PersistentEntity} abstraction.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
public interface CassandraPersistentEntity<T> extends PersistentEntity<T, CassandraPersistentProperty> {
|
||||
|
||||
/**
|
||||
* Returns the table the entity shall be persisted to.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getTable();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2011-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.cassandra.mapping;
|
||||
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
|
||||
import com.datastax.driver.core.DataType;
|
||||
|
||||
/**
|
||||
* Cassandra specific {@link org.springframework.data.mapping.PersistentProperty} extension.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
public interface CassandraPersistentProperty extends PersistentProperty<CassandraPersistentProperty> {
|
||||
|
||||
/**
|
||||
* For dynamic tables returns true if property value is used as column name.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean isColumnId();
|
||||
|
||||
/**
|
||||
* Returns the name of the field a property is persisted to.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getColumnName();
|
||||
|
||||
/**
|
||||
* Returns the data type.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
DataType getDataType();
|
||||
|
||||
/**
|
||||
* Returns true if the property has secondary index on this column.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean isIndexed();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 2010-2013 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.cassandra.mapping;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
import com.datastax.driver.core.DataType;
|
||||
|
||||
/**
|
||||
* Simple constant holder for a {@link SimpleTypeHolder} enriched with Cassandra specific simple types.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
public class CassandraSimpleTypes {
|
||||
|
||||
private static final Map<Class<?>, Class<?>> primitiveWrapperTypeMap = new HashMap<Class<?>, Class<?>>(8);
|
||||
|
||||
private static final Map<Class<?>, DataType> javaClassToDataType = new HashMap<Class<?>, DataType>();
|
||||
|
||||
private static final Map<DataType.Name, DataType> nameToDataType = new HashMap<DataType.Name, DataType>();
|
||||
|
||||
static {
|
||||
|
||||
primitiveWrapperTypeMap.put(Boolean.class, boolean.class);
|
||||
primitiveWrapperTypeMap.put(Byte.class, byte.class);
|
||||
primitiveWrapperTypeMap.put(Character.class, char.class);
|
||||
primitiveWrapperTypeMap.put(Double.class, double.class);
|
||||
primitiveWrapperTypeMap.put(Float.class, float.class);
|
||||
primitiveWrapperTypeMap.put(Integer.class, int.class);
|
||||
primitiveWrapperTypeMap.put(Long.class, long.class);
|
||||
primitiveWrapperTypeMap.put(Short.class, short.class);
|
||||
|
||||
Set<Class<?>> simpleTypes = new HashSet<Class<?>>();
|
||||
for (DataType dataType : DataType.allPrimitiveTypes()) {
|
||||
simpleTypes.add(dataType.asJavaClass());
|
||||
Class<?> javaClass = dataType.asJavaClass();
|
||||
javaClassToDataType.put(javaClass, dataType);
|
||||
Class<?> primitiveJavaClass = primitiveWrapperTypeMap.get(javaClass);
|
||||
if (primitiveJavaClass != null) {
|
||||
javaClassToDataType.put(primitiveJavaClass, dataType);
|
||||
}
|
||||
nameToDataType.put(dataType.getName(), dataType);
|
||||
}
|
||||
javaClassToDataType.put(String.class, DataType.text());
|
||||
CASSANDRA_SIMPLE_TYPES = Collections.unmodifiableSet(simpleTypes);
|
||||
}
|
||||
|
||||
private static final Set<Class<?>> CASSANDRA_SIMPLE_TYPES;
|
||||
public static final SimpleTypeHolder HOLDER = new SimpleTypeHolder(CASSANDRA_SIMPLE_TYPES, true);
|
||||
|
||||
private CassandraSimpleTypes() {
|
||||
}
|
||||
|
||||
public static DataType resolvePrimitive(DataType.Name name) {
|
||||
return nameToDataType.get(name);
|
||||
}
|
||||
|
||||
public static DataType autodetectPrimitive(Class<?> javaClass) {
|
||||
return javaClassToDataType.get(javaClass);
|
||||
}
|
||||
|
||||
public static DataType.Name[] convertPrimitiveTypeArguments(List<TypeInformation<?>> arguments) {
|
||||
DataType.Name[] result = new DataType.Name[arguments.size()];
|
||||
for (int i = 0; i != result.length; ++i) {
|
||||
TypeInformation<?> type = arguments.get(i);
|
||||
DataType dataType = autodetectPrimitive(type.getType());
|
||||
if (dataType == null) {
|
||||
throw new InvalidDataAccessApiUsageException("not found appropriate primitive DataType for type = '" + type.getType());
|
||||
}
|
||||
result[i] = dataType.getName();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.springframework.data.cassandra.mapping;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Annotation to define custom metadata for document fields.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Column {
|
||||
|
||||
/**
|
||||
* The name of the column in the table.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String value() default "";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2010-2013 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.cassandra.mapping;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Uses in dynamic tables where column names are values of this field.
|
||||
* Usually it is a Date/Time field or UUIDTime field.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
@Retention(value=RetentionPolicy.RUNTIME)
|
||||
@Target(value={ElementType.FIELD,ElementType.METHOD,ElementType.ANNOTATION_TYPE})
|
||||
public @interface ColumnId {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2010-2013 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.cassandra.mapping;
|
||||
|
||||
import com.datastax.driver.core.DataType;
|
||||
|
||||
/**
|
||||
* Uses to transfer DataType and attributes for the property.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
public class DataTypeInformation {
|
||||
|
||||
public static DataType.Name[] EMPTY_ATTRIBUTES = {};
|
||||
|
||||
private DataType.Name typeName;
|
||||
private DataType.Name[] typeAttributes;
|
||||
|
||||
public DataTypeInformation(DataType.Name typeName) {
|
||||
this(typeName, EMPTY_ATTRIBUTES);
|
||||
}
|
||||
|
||||
public DataTypeInformation(DataType.Name typeName, DataType.Name[] typeAttributes) {
|
||||
this.typeName = typeName;
|
||||
this.typeAttributes = typeAttributes;
|
||||
}
|
||||
|
||||
public DataType.Name getTypeName() {
|
||||
return typeName;
|
||||
}
|
||||
|
||||
public void setTypeName(DataType.Name typeName) {
|
||||
this.typeName = typeName;
|
||||
}
|
||||
|
||||
public DataType.Name[] getTypeAttributes() {
|
||||
return typeAttributes;
|
||||
}
|
||||
|
||||
public void setTypeAttributes(DataType.Name[] typeAttributes) {
|
||||
this.typeAttributes = typeAttributes;
|
||||
}
|
||||
|
||||
public String toCQL() {
|
||||
if (typeAttributes.length == 0) {
|
||||
return typeName.name();
|
||||
}
|
||||
else {
|
||||
StringBuilder str = new StringBuilder();
|
||||
str.append(typeName.name());
|
||||
str.append('<');
|
||||
for (int i = 0; i != typeAttributes.length; ++i) {
|
||||
if (i != 0) {
|
||||
str.append(',');
|
||||
}
|
||||
str.append(typeAttributes[i].name());
|
||||
}
|
||||
str.append('>');
|
||||
return str.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2010-2013 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.cassandra.mapping;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Identifies a secondary index in the table. Usually it is a field with common dublicate values
|
||||
* for the hole table. such as city, place, educationType, state flags ant etc.
|
||||
*
|
||||
* Using unique fields is not common and has overhead, such as email, username and etc.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
@Retention(value=RetentionPolicy.RUNTIME)
|
||||
@Target(value={ElementType.FIELD,ElementType.METHOD,ElementType.ANNOTATION_TYPE})
|
||||
public @interface Index {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2010-2013 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.cassandra.mapping;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
import com.datastax.driver.core.DataType;
|
||||
|
||||
/**
|
||||
* Qualifies data type as Cassandra type.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Qualify {
|
||||
|
||||
DataType.Name type();
|
||||
|
||||
DataType.Name[] typeArguments() default {};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2010-2013 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.cassandra.mapping;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
|
||||
/**
|
||||
* Identifies row ID in the Cassandra table. Same as @org.springframework.data.annotation.Id
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
@Retention(value=RetentionPolicy.RUNTIME)
|
||||
@Target(value={ElementType.FIELD,ElementType.METHOD,ElementType.ANNOTATION_TYPE})
|
||||
@Id
|
||||
public @interface RowId {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2010-2013 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.cassandra.mapping;
|
||||
|
||||
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;
|
||||
|
||||
import org.springframework.data.annotation.Persistent;
|
||||
|
||||
/**
|
||||
* Identifies a domain object to be persisted to Cassandra as a table.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
@Persistent
|
||||
@Inherited
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.TYPE })
|
||||
public @interface Table {
|
||||
|
||||
String name() default "";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
package org.springframework.data.cassandra.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.cassandra.mapping.CassandraPersistentEntity;
|
||||
import org.springframework.data.cassandra.mapping.CassandraPersistentProperty;
|
||||
import org.springframework.data.mapping.PropertyHandler;
|
||||
|
||||
import com.datastax.driver.core.ColumnMetadata;
|
||||
import com.datastax.driver.core.DataType;
|
||||
import com.datastax.driver.core.TableMetadata;
|
||||
|
||||
|
||||
public abstract class CQLUtils {
|
||||
|
||||
public static String createTable(String tableName, final CassandraPersistentEntity<?> entity) {
|
||||
|
||||
final StringBuilder str = new StringBuilder();
|
||||
str.append("CREATE TABLE ");
|
||||
str.append(tableName);
|
||||
str.append('(');
|
||||
|
||||
final List<String> ids = new ArrayList<String>();
|
||||
final List<String> idColumns = new ArrayList<String>();
|
||||
|
||||
entity.doWithProperties(new PropertyHandler<CassandraPersistentProperty>() {
|
||||
public void doWithPersistentProperty(CassandraPersistentProperty prop) {
|
||||
|
||||
if (str.charAt(str.length()-1) != '(') {
|
||||
str.append(',');
|
||||
}
|
||||
|
||||
String columnName = prop.getColumnName();
|
||||
|
||||
str.append(columnName);
|
||||
str.append(' ');
|
||||
|
||||
DataType dataType = prop.getDataType();
|
||||
|
||||
str.append(toCQL(dataType));
|
||||
|
||||
if (prop.isIdProperty()) {
|
||||
ids.add(prop.getColumnName());
|
||||
}
|
||||
|
||||
if (prop.isColumnId()) {
|
||||
idColumns.add(prop.getColumnName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
if (ids.isEmpty()) {
|
||||
throw new InvalidDataAccessApiUsageException("not found primary ID in the entity " + entity.getType());
|
||||
}
|
||||
|
||||
str.append(",PRIMARY KEY(");
|
||||
|
||||
if (ids.size() > 1) {
|
||||
str.append('(');
|
||||
}
|
||||
|
||||
for (String id: ids) {
|
||||
if (str.charAt(str.length()-1) != '(') {
|
||||
str.append(',');
|
||||
}
|
||||
str.append(id);
|
||||
}
|
||||
|
||||
if (ids.size() > 1) {
|
||||
str.append(')');
|
||||
}
|
||||
|
||||
for (String id: idColumns) {
|
||||
str.append(',');
|
||||
str.append(id);
|
||||
}
|
||||
|
||||
str.append("));");
|
||||
|
||||
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
public static List<String> createIndexes(final String tableName, final CassandraPersistentEntity<?> entity) {
|
||||
final List<String> result = new ArrayList<String>();
|
||||
|
||||
entity.doWithProperties(new PropertyHandler<CassandraPersistentProperty>() {
|
||||
public void doWithPersistentProperty(CassandraPersistentProperty prop) {
|
||||
|
||||
if (prop.isIndexed()) {
|
||||
|
||||
final StringBuilder str = new StringBuilder();
|
||||
str.append("CREATE INDEX ON ");
|
||||
str.append(tableName);
|
||||
str.append(" (");
|
||||
str.append(prop.getColumnName());
|
||||
str.append(");");
|
||||
|
||||
result.add(str.toString());
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static List<String> alterTable(final String tableName, final CassandraPersistentEntity<?> entity, final TableMetadata table) {
|
||||
final List<String> result = new ArrayList<String>();
|
||||
|
||||
entity.doWithProperties(new PropertyHandler<CassandraPersistentProperty>() {
|
||||
public void doWithPersistentProperty(CassandraPersistentProperty prop) {
|
||||
|
||||
String columnName = prop.getColumnName();
|
||||
DataType columnDataType = prop.getDataType();
|
||||
ColumnMetadata columnMetadata = table.getColumn(columnName.toLowerCase());
|
||||
|
||||
if (columnMetadata != null && columnDataType.equals(columnMetadata.getType())) {
|
||||
return;
|
||||
}
|
||||
|
||||
final StringBuilder str = new StringBuilder();
|
||||
str.append("ALTER TABLE ");
|
||||
str.append(tableName);
|
||||
if (columnMetadata == null) {
|
||||
str.append(" ADD ");
|
||||
}
|
||||
else {
|
||||
str.append(" ALTER ");
|
||||
}
|
||||
|
||||
str.append(columnName);
|
||||
str.append(' ');
|
||||
|
||||
if (columnMetadata != null) {
|
||||
str.append("TYPE ");
|
||||
}
|
||||
|
||||
str.append(toCQL(columnDataType));
|
||||
|
||||
str.append(';');
|
||||
result.add(str.toString());
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
//System.out.println("CQL=" + table.asCQLQuery());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String toCQL(DataType dataType) {
|
||||
if (dataType.getTypeArguments().isEmpty()) {
|
||||
return dataType.getName().name();
|
||||
}
|
||||
else {
|
||||
StringBuilder str = new StringBuilder();
|
||||
str.append(dataType.getName().name());
|
||||
str.append('<');
|
||||
for (DataType argDataType : dataType.getTypeArguments()) {
|
||||
if (str.charAt(str.length()-1) != '<') {
|
||||
str.append(',');
|
||||
}
|
||||
str.append(argDataType.getName().name());
|
||||
}
|
||||
str.append('>');
|
||||
return str.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2011 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.cassandra.util;
|
||||
|
||||
|
||||
/**
|
||||
* Helper class featuring helper methods for working with Cassandra tables.
|
||||
* Mainly intended for internal use within the framework.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
public abstract class CassandraNamingUtils {
|
||||
|
||||
/**
|
||||
* Private constructor to prevent instantiation.
|
||||
*/
|
||||
private CassandraNamingUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the table name to use for the provided class
|
||||
*
|
||||
* @param entityClass The class to determine the preferred table name for
|
||||
* @return The preferred collection name
|
||||
*/
|
||||
public static String getPreferredTableName(Class<?> entityClass) {
|
||||
return entityClass.getSimpleName().toLowerCase();
|
||||
}
|
||||
|
||||
}
|
||||
1
src/main/resources/META-INF/spring.handlers
Normal file
1
src/main/resources/META-INF/spring.handlers
Normal file
@@ -0,0 +1 @@
|
||||
http\://www.springframework.org/schema/data/cassandra=org.springframework.data.cassandra.config.CassandraNamespaceHandler
|
||||
2
src/main/resources/META-INF/spring.schemas
Normal file
2
src/main/resources/META-INF/spring.schemas
Normal file
@@ -0,0 +1,2 @@
|
||||
http\://www.springframework.org/schema/data/cassandra/spring-cassandra-1.0.xsd=org/springframework/data/cassandra/config/spring-cassandra-1.0.xsd
|
||||
http\://www.springframework.org/schema/data/cassandra/spring-cassandra.xsd=org/springframework/data/cassandra/config/spring-cassandra-1.0.xsd
|
||||
4
src/main/resources/META-INF/spring.tooling
Normal file
4
src/main/resources/META-INF/spring.tooling
Normal file
@@ -0,0 +1,4 @@
|
||||
# Tooling related information for the jms namespace
|
||||
http\://www.springframework.org/schema/data/cassnadra@name=Cassandra Namespace
|
||||
http\://www.springframework.org/schema/data/cassandra@prefix=cassandra
|
||||
http\://www.springframework.org/schema/data/cassnadra@icon=org/springframework/data/cassandra/config/spring-cassandra.gif
|
||||
@@ -0,0 +1,404 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<xsd:schema xmlns="http://www.springframework.org/schema/data/cassandra"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:tool="http://www.springframework.org/schema/tool"
|
||||
targetNamespace="http://www.springframework.org/schema/data/cassandra"
|
||||
elementFormDefault="qualified" attributeFormDefault="unqualified">
|
||||
|
||||
<xsd:import namespace="http://www.springframework.org/schema/tool"
|
||||
schemaLocation="http://www.springframework.org/schema/tool/spring-tool.xsd" />
|
||||
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Defines the configuration elements for the Spring Data Cassandra support.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
|
||||
<xsd:element name="cluster" type="clusterType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation
|
||||
source="org.springframework.data.cassandra.core.CassandraClusterFactoryBean"><![CDATA[
|
||||
Defines a Cassandra Cluster instance used for accessing Cassandra'.
|
||||
]]></xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation>
|
||||
<tool:exports type="com.datastax.driver.core.Cluster" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:complexType name="clusterType">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="local-pooling-options"
|
||||
type="poolingOptionsType" maxOccurs="1" minOccurs="0">
|
||||
</xsd:element>
|
||||
<xsd:element name="remote-pooling-options"
|
||||
type="poolingOptionsType" maxOccurs="1" minOccurs="0">
|
||||
</xsd:element>
|
||||
<xsd:element name="socket-options" type="socketOptionsType" maxOccurs="1" minOccurs="0"></xsd:element>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="id" type="xsd:ID" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
The name of the Cassandra Cluster definition (by
|
||||
default "cassandra-cluster")
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="contactPoints" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The comma separated hosts to Cassandra servers. Default is localhost
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="port" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The port to connect to Cassandra server as native CQL client. Default is 9042
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="compression" default="none"
|
||||
use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The protocol options compression. Default is 'none'.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:simpleType>
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="none">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
No compression.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:enumeration>
|
||||
<xsd:enumeration value="snappy">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Uses SNAPPY compression algorithm.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:enumeration>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="auth-info-provider" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
AuthInfoProvider implementation.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:simpleType>
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:assignable-to type="com.datastax.driver.core.AuthInfoProvider" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
<xsd:union memberTypes="xsd:string" />
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="load-balancing-policy" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
LoadBalancingPolicy implementation.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:simpleType>
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:assignable-to type="com.datastax.driver.core.policies.LoadBalancingPolicy" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
<xsd:union memberTypes="xsd:string" />
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="reconnection-policy" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
ReconnectionPolicy implementation.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:simpleType>
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:assignable-to type="com.datastax.driver.core.policies.ReconnectionPolicy" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
<xsd:union memberTypes="xsd:string" />
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="retry-policy" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
RetryPolicy implementation.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:simpleType>
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:assignable-to type="com.datastax.driver.core.policies.RetryPolicy" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
<xsd:union memberTypes="xsd:string" />
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:element name="keyspace" type="keyspaceType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation source="org.springframework.data.cassandra.core.CassandraKeyspaceFactoryBean"><![CDATA[
|
||||
Defines a Cassandra Session instance used for accessing Cassandra Keyspace'.
|
||||
]]></xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation>
|
||||
<tool:exports type="com.datastax.driver.core.Session" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:complexType name="keyspaceType">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="keyspace-attributes" type="keyspaceAttributesType" maxOccurs="1" minOccurs="0"></xsd:element>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="id" type="xsd:ID" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
The name of the Keyspace definition (by default
|
||||
"cassandra-keyspace")
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="name" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The keyspace name of the Cassandra database.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="cassandra-cluster-ref" type="clusterRef"
|
||||
use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The reference to a Cassandra Cluster instance. Will default to 'cassandra-cluster'.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="cassandra-converter-ref" type="converterRef"
|
||||
use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The reference to a CassandraConverter instance. Default is null.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:simpleType name="clusterRef">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:assignable-to type="com.datastax.driver.core.Cluster"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
<xsd:union memberTypes="xsd:string"/>
|
||||
</xsd:simpleType>
|
||||
|
||||
<xsd:simpleType name="converterRef">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:assignable-to type="org.springframework.data.cassandra.convert.CassandraConverter"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
<xsd:union memberTypes="xsd:string"/>
|
||||
</xsd:simpleType>
|
||||
|
||||
<xsd:complexType name="poolingOptionsType">
|
||||
<xsd:attribute name="min-simultaneous-requests"
|
||||
type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
if the utilisation of opened connections drops below by this configured threshold, then cassandra drops connections till core-connections.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="max-simultaneous-requests"
|
||||
type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
If the utilisation of connections reaches this configurable threshold, then cassandra creates more connections up to max-connections.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="core-connections" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
For each host, the driver keeps a core amount of connections open at all time.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="max-connections" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
More connections are created up to a configurable maximum number of connections.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="socketOptionsType">
|
||||
<xsd:attribute name="connect-timeout-mls" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Sets connection timeout for client socket in milliseconds.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="keep-alive" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Sets the SO_KEEPALIVE socket option.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="reuse-address" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Sets the SO_REUSEADDR socket option.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="so-linger" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Sets the SO_LINGER socket option.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="tcp-no-delay" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Sets the SO_TCPNODELAY socket option.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="receive-buffer-size" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Sets the SO_RCVBUF socket option.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="send-buffer-size" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Sets the SO_SNDBUF socket option.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="keyspaceAttributesType">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="table" type="tableType" maxOccurs="unbounded" minOccurs="0"></xsd:element>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="auto" default="validate">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The keyspace manipulation operation on startup. Default value is 'validate'.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:simpleType>
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="validate">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Validate the keyspace, makes no changes.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:enumeration>
|
||||
<xsd:enumeration value="update">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Update the keyspace.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:enumeration>
|
||||
<xsd:enumeration value="create">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Creates the keyspace, destroying previous data.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:enumeration>
|
||||
<xsd:enumeration value="create-drop">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Creates and then drop the keyspace at the end of the session.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:enumeration>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="replication-stategy" type="xsd:string"
|
||||
use="optional" default="SimpleStrategy">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Replication strategy of the Cassandra keyspace. Default value is 'SimpleStrategy'.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="replication-factor" type="xsd:string"
|
||||
use="optional" default="1">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Replication factor used by the Cassandra keyspace. Default value is '1'.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="durable-writes" type="xsd:string"
|
||||
use="optional" default="true">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Support durable writes in the Cassandra keyspace. Default value is 'true'.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="tableType">
|
||||
<xsd:attribute name="entity" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Entity class name.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="name" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Table name override.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
</xsd:schema>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 581 B |
Reference in New Issue
Block a user