diff --git a/spring-data-cassandra/pom.xml b/spring-data-cassandra/pom.xml new file mode 100644 index 0000000000..13c5c18529 --- /dev/null +++ b/spring-data-cassandra/pom.xml @@ -0,0 +1,110 @@ + + 4.0.0 + + org.baeldung + spring-data-cassandra + 0.0.1-SNAPSHOT + jar + + spring-data-cassandra + + + UTF-8 + 1.3.1.RELEASE + 4.2.2.RELEASE + 4.11 + 1.7.12 + 1.1.3 + 2.1.5 + 2.1.9.2 + 2.1.9.2 + 2.0-0 + + + + + org.springframework.data + spring-data-cassandra + ${org.springframework.data.version} + + + org.springframework + spring-core + ${org.springframework.version} + + + junit + junit-dep + ${junit.version} + test + + + org.springframework + spring-test + ${org.springframework.version} + test + + + org.cassandraunit + cassandra-unit-spring + ${cassandra-unit-spring.version} + test + + + org.cassandraunit + cassandra-unit + + + + + org.cassandraunit + cassandra-unit-shaded + ${cassandra-unit-shaded} + test + + + org.hectorclient + hector-core + ${hector-core.version} + + + com.datastax.cassandra + cassandra-driver-core + ${cassandra-driver-core.version} + true + + + org.slf4j + slf4j-api + ${org.slf4j.version} + + + ch.qos.logback + logback-classic + ${logback.version} + + + org.slf4j + jcl-over-slf4j + ${org.slf4j.version} + + + org.slf4j + log4j-over-slf4j + ${org.slf4j.version} + + + + + + maven-compiler-plugin + 2.3.2 + + 1.7 + 1.7 + + + + + diff --git a/spring-data-cassandra/src/main/java/org/baeldung/spring/data/cassandra/config/CassandraConfig.java b/spring-data-cassandra/src/main/java/org/baeldung/spring/data/cassandra/config/CassandraConfig.java new file mode 100644 index 0000000000..5f2c4c6d47 --- /dev/null +++ b/spring-data-cassandra/src/main/java/org/baeldung/spring/data/cassandra/config/CassandraConfig.java @@ -0,0 +1,43 @@ +package org.baeldung.spring.data.cassandra.config; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.core.env.Environment; +import org.springframework.data.cassandra.config.CassandraClusterFactoryBean; +import org.springframework.data.cassandra.config.java.AbstractCassandraConfiguration; +import org.springframework.data.cassandra.mapping.BasicCassandraMappingContext; +import org.springframework.data.cassandra.mapping.CassandraMappingContext; +import org.springframework.data.cassandra.repository.config.EnableCassandraRepositories; + +@Configuration +@PropertySource(value = { "classpath:cassandra.properties" }) +@EnableCassandraRepositories(basePackages = "org.baeldung.spring.data.cassandra.repository") +public class CassandraConfig extends AbstractCassandraConfiguration { + + private static final Log LOGGER = LogFactory.getLog(CassandraConfig.class); + @Autowired + private Environment environment; + + @Override + protected String getKeyspaceName() { + return environment.getProperty("cassandra.keyspace"); + } + + @Bean + public CassandraClusterFactoryBean cluster() { + CassandraClusterFactoryBean cluster = new CassandraClusterFactoryBean(); + cluster.setContactPoints(environment.getProperty("cassandra.contactpoints")); + cluster.setPort(Integer.parseInt(environment.getProperty("cassandra.port"))); + LOGGER.info("Cluster created with contact points [" + environment.getProperty("cassandra.contactpoints") + "] " + "& port [" + Integer.parseInt(environment.getProperty("cassandra.port")) + "]."); + return cluster; + } + + @Bean + public CassandraMappingContext cassandraMapping() throws ClassNotFoundException { + return new BasicCassandraMappingContext(); + } +} \ No newline at end of file diff --git a/spring-data-cassandra/src/main/java/org/baeldung/spring/data/cassandra/model/Book.java b/spring-data-cassandra/src/main/java/org/baeldung/spring/data/cassandra/model/Book.java new file mode 100644 index 0000000000..ebb619c456 --- /dev/null +++ b/spring-data-cassandra/src/main/java/org/baeldung/spring/data/cassandra/model/Book.java @@ -0,0 +1,63 @@ +package org.baeldung.spring.data.cassandra.model; + +import org.springframework.cassandra.core.Ordering; +import org.springframework.cassandra.core.PrimaryKeyType; +import org.springframework.data.cassandra.mapping.Column; +import org.springframework.data.cassandra.mapping.PrimaryKeyColumn; +import org.springframework.data.cassandra.mapping.Table; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +@Table +public class Book { + @PrimaryKeyColumn(name = "isbn", ordinal = 2, type = PrimaryKeyType.CLUSTERED, ordering = Ordering.DESCENDING) + private UUID id; + @PrimaryKeyColumn(name = "title", ordinal = 0, type = PrimaryKeyType.PARTITIONED) + private String title; + + @PrimaryKeyColumn(name = "publisher", ordinal = 1, type = PrimaryKeyType.PARTITIONED) + private String publisher; + @Column + private Set tags = new HashSet<>(); + + public Book(UUID id, String title, String publisher, Set tags) { + this.id = id; + this.title = title; + this.publisher = publisher; + this.tags.addAll(tags); + } + + public UUID getId() { + return id; + } + + public String getTitle() { + return title; + } + + public String getPublisher() { + return publisher; + } + + public Set getTags() { + return tags; + } + + public void setId(UUID id) { + this.id = id; + } + + public void setTitle(String title) { + this.title = title; + } + + public void setPublisher(String publisher) { + this.publisher = publisher; + } + + public void setTags(Set tags) { + this.tags = tags; + } +} diff --git a/spring-data-cassandra/src/main/java/org/baeldung/spring/data/cassandra/repository/BookRepository.java b/spring-data-cassandra/src/main/java/org/baeldung/spring/data/cassandra/repository/BookRepository.java new file mode 100644 index 0000000000..e37ae78b59 --- /dev/null +++ b/spring-data-cassandra/src/main/java/org/baeldung/spring/data/cassandra/repository/BookRepository.java @@ -0,0 +1,12 @@ +package org.baeldung.spring.data.cassandra.repository; + +import org.baeldung.spring.data.cassandra.model.Book; +import org.springframework.data.cassandra.repository.CassandraRepository; +import org.springframework.data.cassandra.repository.Query; +import org.springframework.stereotype.Repository; + +@Repository +public interface BookRepository extends CassandraRepository { + @Query("select * from book where title = ?0 and publisher=?1") + Iterable findByTitleAndPublisher(String title, String publisher); +} diff --git a/spring-data-cassandra/src/main/resources/cassandra.properties b/spring-data-cassandra/src/main/resources/cassandra.properties new file mode 100644 index 0000000000..1550cdea4e --- /dev/null +++ b/spring-data-cassandra/src/main/resources/cassandra.properties @@ -0,0 +1,3 @@ +cassandra.contactpoints=127.0.0.1 +cassandra.port=9142 +cassandra.keyspace=testKeySpace \ No newline at end of file diff --git a/spring-data-cassandra/src/main/resources/logback.xml b/spring-data-cassandra/src/main/resources/logback.xml new file mode 100644 index 0000000000..215eeede64 --- /dev/null +++ b/spring-data-cassandra/src/main/resources/logback.xml @@ -0,0 +1,20 @@ + + + + + web - %date [%thread] %-5level %logger{36} - %message%n + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-data-cassandra/src/main/resources/test.png b/spring-data-cassandra/src/main/resources/test.png new file mode 100644 index 0000000000..c3b5e80276 Binary files /dev/null and b/spring-data-cassandra/src/main/resources/test.png differ diff --git a/spring-data-cassandra/src/test/java/org/baeldung/spring/data/cassandra/repository/BookRepositoryIntegrationTest.java b/spring-data-cassandra/src/test/java/org/baeldung/spring/data/cassandra/repository/BookRepositoryIntegrationTest.java new file mode 100644 index 0000000000..2451f14f4a --- /dev/null +++ b/spring-data-cassandra/src/test/java/org/baeldung/spring/data/cassandra/repository/BookRepositoryIntegrationTest.java @@ -0,0 +1,117 @@ +package org.baeldung.spring.data.cassandra.repository; + +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.Session; +import com.datastax.driver.core.utils.UUIDs; +import com.google.common.collect.ImmutableSet; +import org.apache.cassandra.exceptions.ConfigurationException; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.thrift.transport.TTransportException; +import org.baeldung.spring.data.cassandra.config.CassandraConfig; +import org.baeldung.spring.data.cassandra.model.Book; +import org.cassandraunit.utils.EmbeddedCassandraServerHelper; +import org.junit.*; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cassandra.core.cql.CqlIdentifier; +import org.springframework.data.cassandra.core.CassandraAdminOperations; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import java.io.IOException; +import java.util.HashMap; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = CassandraConfig.class) +public class BookRepositoryIntegrationTest { + + private static final Log LOGGER = LogFactory.getLog(BookRepositoryIntegrationTest.class); + + public static final String KEYSPACE_CREATION_QUERY = "CREATE KEYSPACE IF NOT EXISTS testKeySpace WITH replication = { 'class': 'SimpleStrategy', 'replication_factor': '3' };"; + + public static final String KEYSPACE_ACTIVATE_QUERY = "USE testKeySpace;"; + + public static final String DATA_TABLE_NAME = "book"; + + @Autowired + private BookRepository bookRepository; + + @Autowired + private CassandraAdminOperations adminTemplate; + + @BeforeClass + public static void startCassandraEmbedded() throws InterruptedException, TTransportException, ConfigurationException, IOException { + EmbeddedCassandraServerHelper.startEmbeddedCassandra(); + Cluster cluster = Cluster.builder().addContactPoints("127.0.0.1") + .withPort(9142).build(); + LOGGER.info("Server Started at 127.0.0.1:9142... "); + Session session = cluster.connect(); + session.execute(KEYSPACE_CREATION_QUERY); + session.execute(KEYSPACE_ACTIVATE_QUERY); + LOGGER.info(session.execute("Select * from Book").all().toArray()); + Thread.sleep(5000); + LOGGER.info("KeySpace created and activated."); + } + + @Before + public void createTable() throws InterruptedException, TTransportException, ConfigurationException, IOException { + adminTemplate.createTable(true, CqlIdentifier.cqlId(DATA_TABLE_NAME), Book.class, new HashMap()); + } + + @Test + public void whenSavingBook_thenAvailableOnRetrieval() { + Book javaBook = new Book(UUIDs.timeBased(), "Head First Java", + "O'Reilly Media", ImmutableSet.of("Computer", "Software")); + bookRepository.save(ImmutableSet.of(javaBook)); + Iterable books = bookRepository.findByTitleAndPublisher("Head First Java", "O'Reilly Media"); + assertEquals(javaBook.getId(), books.iterator().next().getId()); + } + + @Test + public void whenUpdatingBooks_thenAvailableOnRetrieval() { + Book javaBook = new Book(UUIDs.timeBased(), "Head First Java", "O'Reilly Media", ImmutableSet.of("Computer", "Software")); + bookRepository.save(ImmutableSet.of(javaBook)); + Iterable books = bookRepository.findByTitleAndPublisher("Head First Java", "O'Reilly Media"); + javaBook.setTitle("Head First Java Second Edition"); + bookRepository.save(ImmutableSet.of(javaBook)); + Iterable updateBooks = bookRepository.findByTitleAndPublisher("Head First Java Second Edition", "O'Reilly Media"); + assertEquals(javaBook.getTitle(), updateBooks.iterator().next().getTitle()); + } + + @Test(expected = java.util.NoSuchElementException.class) + public void whenDeletingExistingBooks_thenNotAvailableOnRetrieval() { + Book javaBook = new Book(UUIDs.timeBased(), "Head First Java", "O'Reilly Media", ImmutableSet.of("Computer", "Software")); + bookRepository.save(ImmutableSet.of(javaBook)); + bookRepository.delete(javaBook); + Iterable books = bookRepository.findByTitleAndPublisher("Head First Java", "O'Reilly Media"); + assertNotEquals(javaBook.getId(), books.iterator().next().getId()); + } + + @Test + public void whenSavingBooks_thenAllShouldAvailableOnRetrieval() { + Book javaBook = new Book(UUIDs.timeBased(), "Head First Java", + "O'Reilly Media", ImmutableSet.of("Computer", "Software")); + Book dPatternBook = new Book(UUIDs.timeBased(), "Head Design Patterns", + "O'Reilly Media", ImmutableSet.of("Computer", "Software")); + bookRepository.save(ImmutableSet.of(javaBook)); + bookRepository.save(ImmutableSet.of(dPatternBook)); + Iterable books = bookRepository.findAll(); + int bookCount = 0; + for (Book book : books) bookCount++; + assertEquals(bookCount, 2); + } + + @After + public void dropTable() { + adminTemplate.dropTable(CqlIdentifier.cqlId(DATA_TABLE_NAME)); + } + + @AfterClass + public static void stopCassandraEmbedded() { + EmbeddedCassandraServerHelper.cleanEmbeddedCassandra(); + } +} diff --git a/spring-security-oauth/spring-security-oauth-server/src/main/java/org/baeldung/config/ServerSecurityConfig.java b/spring-security-oauth/spring-security-oauth-server/src/main/java/org/baeldung/config/ServerSecurityConfig.java index 5a09bb7e03..3e1a8a8ccb 100644 --- a/spring-security-oauth/spring-security-oauth-server/src/main/java/org/baeldung/config/ServerSecurityConfig.java +++ b/spring-security-oauth/spring-security-oauth-server/src/main/java/org/baeldung/config/ServerSecurityConfig.java @@ -28,7 +28,7 @@ public class ServerSecurityConfig extends WebSecurityConfigurerAdapter { http.authorizeRequests() .antMatchers("/login").permitAll() .anyRequest().authenticated() - // .and().formLogin().permitAll() + .and().formLogin().permitAll() ; // @formatter:on } diff --git a/spring-security-oauth/spring-security-oauth-ui-implicit/src/main/java/org/baeldung/config/UiWebConfig.java b/spring-security-oauth/spring-security-oauth-ui-implicit/src/main/java/org/baeldung/config/UiWebConfig.java index 2ee0585615..71197ce5d2 100644 --- a/spring-security-oauth/spring-security-oauth-ui-implicit/src/main/java/org/baeldung/config/UiWebConfig.java +++ b/spring-security-oauth/spring-security-oauth-ui-implicit/src/main/java/org/baeldung/config/UiWebConfig.java @@ -26,8 +26,9 @@ public class UiWebConfig extends WebMvcConfigurerAdapter { @Override public void addViewControllers(final ViewControllerRegistry registry) { super.addViewControllers(registry); - registry.addViewController("/index"); + registry.addViewController("/").setViewName("forward:/index"); registry.addViewController("/oauthTemp"); + registry.addViewController("/index"); } @Override diff --git a/spring-security-oauth/spring-security-oauth-ui-implicit/src/main/resources/templates/header.html b/spring-security-oauth/spring-security-oauth-ui-implicit/src/main/resources/templates/header.html index f56ff0ce99..a62bce9747 100644 --- a/spring-security-oauth/spring-security-oauth-ui-implicit/src/main/resources/templates/header.html +++ b/spring-security-oauth/spring-security-oauth-ui-implicit/src/main/resources/templates/header.html @@ -12,7 +12,7 @@ diff --git a/spring-security-oauth/spring-security-oauth-ui-password/src/main/java/org/baeldung/config/UiWebConfig.java b/spring-security-oauth/spring-security-oauth-ui-password/src/main/java/org/baeldung/config/UiWebConfig.java index 46e7f6db42..0732182354 100644 --- a/spring-security-oauth/spring-security-oauth-ui-password/src/main/java/org/baeldung/config/UiWebConfig.java +++ b/spring-security-oauth/spring-security-oauth-ui-password/src/main/java/org/baeldung/config/UiWebConfig.java @@ -26,6 +26,7 @@ public class UiWebConfig extends WebMvcConfigurerAdapter { @Override public void addViewControllers(final ViewControllerRegistry registry) { super.addViewControllers(registry); + registry.addViewController("/").setViewName("forward:/index"); registry.addViewController("/index"); registry.addViewController("/login"); }