wip: beginning to move appropriate config to spring-cassandra
This commit is contained in:
@@ -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.cassandra.config;
|
||||
|
||||
/**
|
||||
* Simple enumeration for the various compression types.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
*/
|
||||
public enum CompressionType {
|
||||
NONE, SNAPPY;
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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.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.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.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.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 + "]";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cassandra.config;
|
||||
package org.springframework.cassandra.config.java;
|
||||
|
||||
import org.springframework.cassandra.core.CassandraOperations;
|
||||
import org.springframework.cassandra.core.CassandraTemplate;
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.cassandra.config.xml;
|
||||
|
||||
/**
|
||||
* @author Alex Shvid
|
||||
* @author David Webb
|
||||
*/
|
||||
public final class BeanNames {
|
||||
|
||||
private BeanNames() {
|
||||
}
|
||||
|
||||
public static final String CASSANDRA_CLUSTER = "cassandra-cluster";
|
||||
public static final String CASSANDRA_KEYSPACE = "cassandra-keyspace";
|
||||
public static final String CASSANDRA_SESSION = "cassandra-session";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* 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.cassandra.config.xml;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.cassandra.config.CompressionType;
|
||||
import org.springframework.cassandra.config.PoolingOptionsConfig;
|
||||
import org.springframework.cassandra.config.SocketOptionsConfig;
|
||||
import org.springframework.cassandra.support.CassandraExceptionTranslator;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
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
|
||||
* @author Matthew T. Adams
|
||||
*/
|
||||
|
||||
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,126 @@
|
||||
/*
|
||||
* 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.cassandra.config.xml;
|
||||
|
||||
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.cassandra.config.CompressionType;
|
||||
import org.springframework.cassandra.config.PoolingOptionsConfig;
|
||||
import org.springframework.cassandra.config.SocketOptionsConfig;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Parser for <cluster;gt; definitions.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
* @author Matthew T. Adams
|
||||
*/
|
||||
|
||||
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 builder = BeanDefinitionBuilder.genericBeanDefinition(PoolingOptionsConfig.class);
|
||||
|
||||
// TODO
|
||||
// ParsingUtils.setPropertyValue(builder, element, "min-simultaneous-requests", "minSimultaneousRequests");
|
||||
// ParsingUtils.setPropertyValue(builder, element, "max-simultaneous-requests", "maxSimultaneousRequests");
|
||||
// ParsingUtils.setPropertyValue(builder, element, "core-connections", "coreConnections");
|
||||
// ParsingUtils.setPropertyValue(builder, element, "max-connections", "maxConnections");
|
||||
|
||||
return builder.getBeanDefinition();
|
||||
}
|
||||
|
||||
private BeanDefinition parseSocketOptions(Element element) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(SocketOptionsConfig.class);
|
||||
|
||||
// TODO
|
||||
// ParsingUtils.setPropertyValue(builder, element, "connect-timeout-mls", "connectTimeoutMls");
|
||||
// ParsingUtils.setPropertyValue(builder, element, "keep-alive", "keepAlive");
|
||||
// ParsingUtils.setPropertyValue(builder, element, "reuse-address", "reuseAddress");
|
||||
// ParsingUtils.setPropertyValue(builder, element, "so-linger", "soLinger");
|
||||
// ParsingUtils.setPropertyValue(builder, element, "tcp-no-delay", "tcpNoDelay");
|
||||
// ParsingUtils.setPropertyValue(builder, element, "receive-buffer-size", "receiveBufferSize");
|
||||
// ParsingUtils.setPropertyValue(builder, element, "send-buffer-size", "sendBufferSize");
|
||||
|
||||
return builder.getBeanDefinition();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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.cassandra.config.xml;
|
||||
|
||||
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.cassandra.config.KeyspaceAttributes;
|
||||
import org.springframework.cassandra.config.TableAttributes;
|
||||
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 CassandraSessionFactoryBean.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);
|
||||
|
||||
// TODO
|
||||
// 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 builder = BeanDefinitionBuilder.genericBeanDefinition(TableAttributes.class);
|
||||
|
||||
// TODO
|
||||
// ParsingUtils.setPropertyValue(builder, element, "entity", "entity");
|
||||
// ParsingUtils.setPropertyValue(builder, element, "name", "name");
|
||||
|
||||
return builder.getBeanDefinition();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.cassandra.config.xml;
|
||||
|
||||
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());
|
||||
registerBeanDefinitionParser("session", new CassandraSessionParser());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* 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.cassandra.config.xml;
|
||||
|
||||
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.cassandra.config.KeyspaceAttributes;
|
||||
import org.springframework.cassandra.support.CassandraExceptionTranslator;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.datastax.driver.core.Cluster;
|
||||
import com.datastax.driver.core.KeyspaceMetadata;
|
||||
import com.datastax.driver.core.Session;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @author Matthew T. Adams
|
||||
*/
|
||||
|
||||
public class CassandraSessionFactoryBean implements FactoryBean<Session>, InitializingBean, DisposableBean,
|
||||
BeanClassLoaderAware, PersistenceExceptionTranslator {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(CassandraSessionFactoryBean.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 KeyspaceAttributes keyspaceAttributes;
|
||||
|
||||
private final PersistenceExceptionTranslator exceptionTranslator = new CassandraExceptionTranslator();
|
||||
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.beanClassLoader = classLoader;
|
||||
}
|
||||
|
||||
public Session getObject() {
|
||||
return session;
|
||||
}
|
||||
|
||||
/*
|
||||
* (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 (cluster == null) {
|
||||
throw new IllegalArgumentException("at least one cluster is required");
|
||||
}
|
||||
|
||||
this.session = StringUtils.hasText(this.keyspace) ? cluster.connect(keyspace) : cluster.connect();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.DisposableBean#destroy()
|
||||
*/
|
||||
public void destroy() throws Exception {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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.cassandra.config.xml;
|
||||
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
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.cassandra.core.SessionFactoryBean;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Parser for <session;gt; definitions.
|
||||
*
|
||||
* @author David Webb
|
||||
*/
|
||||
|
||||
public class CassandraSessionParser extends AbstractSimpleBeanDefinitionParser {
|
||||
|
||||
@Override
|
||||
protected Class<?> getBeanClass(Element element) {
|
||||
return SessionFactoryBean.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_SESSION;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
|
||||
String keyspaceRef = element.getAttribute("cassandra-keyspace-ref");
|
||||
if (!StringUtils.hasText(keyspaceRef)) {
|
||||
keyspaceRef = BeanNames.CASSANDRA_KEYSPACE;
|
||||
}
|
||||
builder.addPropertyReference("keyspace", keyspaceRef);
|
||||
|
||||
postProcess(builder, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postProcess(BeanDefinitionBuilder builder, Element element) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
http\://www.springframework.org/schema/cassandra=org.springframework.cassandra.config.xml.CassandraNamespaceHandler
|
||||
@@ -0,0 +1,2 @@
|
||||
http\://www.springframework.org/schema/cassandra/spring-cassandra-1.0.xsd=org/springframework/cassandra/config/spring-cassandra-1.0.xsd
|
||||
http\://www.springframework.org/schema/cassandra/spring-cassandra.xsd=org/springframework/cassandra/config/spring-cassandra-1.0.xsd
|
||||
@@ -0,0 +1,4 @@
|
||||
# Tooling related information for the cassandra namespace
|
||||
http\://www.springframework.org/schema/cassandra@name=Spring Cassandra Namespace
|
||||
http\://www.springframework.org/schema/cassandra@prefix=cassandra
|
||||
http\://www.springframework.org/schema/cassandra@icon=org/springframework/data/cassandra/config/spring-cassandra.gif
|
||||
@@ -0,0 +1,453 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<xsd:schema xmlns="http://www.springframework.org/schema/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/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 Spring Cassandra support.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
|
||||
<xsd:element name="session" type="sessionType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation
|
||||
source="org.springframework.cassandra.core.SessionFactoryBean"><![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: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" final="union">
|
||||
<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:complexType name="sessionType">
|
||||
<xsd:attribute name="id" type="xsd:ID" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The name of the Session definition; "cassandra-session" by default.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="cassandra-keyspace-ref" type="keyspaceRef"
|
||||
use="required">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The reference to a Cassandra Keyspace instance. Will default to 'cassandra-keyspace'.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:simpleType name="keyspaceRef">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:assignable-to type="com.datastax.driver.core.Session" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
<xsd:union memberTypes="xsd:string" />
|
||||
</xsd:simpleType>
|
||||
</xsd:schema>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 581 B |
@@ -20,8 +20,7 @@ import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.cassandra.config.AbstractCassandraConfiguration;
|
||||
import org.springframework.cassandra.core.CassandraOperations;
|
||||
import org.springframework.cassandra.config.java.AbstractCassandraConfiguration;
|
||||
import org.springframework.cassandra.core.CassandraTemplate;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
|
||||
@@ -41,7 +40,6 @@ 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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,340 @@
|
||||
/*
|
||||
* 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.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.cassandra.support.CassandraExceptionTranslator;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
import org.springframework.data.cassandra.convert.CassandraConverter;
|
||||
import org.springframework.data.cassandra.convert.MappingCassandraConverter;
|
||||
import org.springframework.data.cassandra.core.SpringDataKeyspace;
|
||||
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<SpringDataKeyspace>, 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 SpringDataKeyspace keyspaceBean;
|
||||
|
||||
private KeyspaceAttributes keyspaceAttributes;
|
||||
|
||||
private final PersistenceExceptionTranslator exceptionTranslator = new CassandraExceptionTranslator();
|
||||
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.beanClassLoader = classLoader;
|
||||
}
|
||||
|
||||
public SpringDataKeyspace getObject() {
|
||||
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 SpringDataKeyspace(keyspace, session, converter);
|
||||
}
|
||||
|
||||
private void createNewTable(Session session, String useTableName, CassandraPersistentEntity<?> entity)
|
||||
throws NoHostAvailableException {
|
||||
String cql = CqlUtils.createTable(useTableName, entity, converter);
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
# Tooling related information for the cassandra namespace
|
||||
http\://www.springframework.org/schema/data/cassandra@name=Cassandra Namespace
|
||||
http\://www.springframework.org/schema/data/cassandra@name=Spring Data Cassandra Namespace
|
||||
http\://www.springframework.org/schema/data/cassandra@prefix=cassandra
|
||||
http\://www.springframework.org/schema/data/cassandra@icon=org/springframework/data/cassandra/config/spring-cassandra.gif
|
||||
|
||||
Reference in New Issue
Block a user