diff --git a/mongodb/aggregation/pom.xml b/mongodb/aggregation/pom.xml index 58980a3a..bc3fc634 100644 --- a/mongodb/aggregation/pom.xml +++ b/mongodb/aggregation/pom.xml @@ -11,5 +11,14 @@ spring-data-mongodb-examples 1.0.0.BUILD-SNAPSHOT + + + + ${project.groupId} + spring-data-mongodb-utils + ${project.version} + test + + \ No newline at end of file diff --git a/mongodb/aggregation/src/test/java/example/springdata/mongodb/shop/OrderRepositoryIntegrationTests.java b/mongodb/aggregation/src/test/java/example/springdata/mongodb/shop/OrderRepositoryIntegrationTests.java index 92bab42e..d6636d02 100644 --- a/mongodb/aggregation/src/test/java/example/springdata/mongodb/shop/OrderRepositoryIntegrationTests.java +++ b/mongodb/aggregation/src/test/java/example/springdata/mongodb/shop/OrderRepositoryIntegrationTests.java @@ -22,12 +22,15 @@ import static org.junit.Assert.*; import java.util.Date; import org.junit.Before; +import org.junit.ClassRule; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import example.springdata.mongodb.util.RequiresMongoDB; + /** * Integration tests for {@link OrderRepository}. * @@ -38,6 +41,8 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @SpringApplicationConfiguration(classes = ApplicationConfiguration.class) public class OrderRepositoryIntegrationTests { + @ClassRule public static RequiresMongoDB mongodbAvailable = RequiresMongoDB.anyVersion(); + @Autowired OrderRepository repository; private final static LineItem product1 = new LineItem("p1", 1.23); diff --git a/mongodb/example/pom.xml b/mongodb/example/pom.xml index 5c3bebda..c4ee34b3 100644 --- a/mongodb/example/pom.xml +++ b/mongodb/example/pom.xml @@ -12,6 +12,15 @@ 1.0.0.BUILD-SNAPSHOT + + + ${project.groupId} + spring-data-mongodb-utils + ${project.version} + test + + + diff --git a/mongodb/example/src/test/java/example/springdata/mongodb/advanced/AdvancedIntegrationTests.java b/mongodb/example/src/test/java/example/springdata/mongodb/advanced/AdvancedIntegrationTests.java index 1ceb3f44..d832e536 100644 --- a/mongodb/example/src/test/java/example/springdata/mongodb/advanced/AdvancedIntegrationTests.java +++ b/mongodb/example/src/test/java/example/springdata/mongodb/advanced/AdvancedIntegrationTests.java @@ -19,6 +19,7 @@ import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import org.junit.Before; +import org.junit.ClassRule; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -26,6 +27,7 @@ import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.data.domain.Sort; import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.core.query.Meta; +import org.springframework.data.util.Version; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.mongodb.BasicDBObject; @@ -33,6 +35,7 @@ import com.mongodb.DBCursor; import com.mongodb.DBObject; import example.springdata.mongodb.customer.Customer; +import example.springdata.mongodb.util.RequiresMongoDB; /** * @author Christoph Strobl @@ -41,6 +44,8 @@ import example.springdata.mongodb.customer.Customer; @SpringApplicationConfiguration(classes = ApplicationConfiguration.class) public class AdvancedIntegrationTests { + @ClassRule public static RequiresMongoDB mongodbAvailable = RequiresMongoDB.atLeast(new Version(2, 6)); + @Autowired AdvancedRepository repository; @Autowired MongoOperations operations; diff --git a/mongodb/example/src/test/java/example/springdata/mongodb/customer/CustomerRepositoryIntegrationTest.java b/mongodb/example/src/test/java/example/springdata/mongodb/customer/CustomerRepositoryIntegrationTest.java index 5d13027f..df435feb 100644 --- a/mongodb/example/src/test/java/example/springdata/mongodb/customer/CustomerRepositoryIntegrationTest.java +++ b/mongodb/example/src/test/java/example/springdata/mongodb/customer/CustomerRepositoryIntegrationTest.java @@ -15,15 +15,13 @@ */ package example.springdata.mongodb.customer; -import static org.hamcrest.Matchers.closeTo; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.junit.Assert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; import java.util.List; import org.junit.Before; +import org.junit.ClassRule; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -37,6 +35,8 @@ import org.springframework.data.mongodb.core.index.GeospatialIndex; import org.springframework.data.querydsl.QSort; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import example.springdata.mongodb.util.RequiresMongoDB; + /** * Integration test for {@link CustomerRepository}. * @@ -46,6 +46,8 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @SpringApplicationConfiguration(classes = ApplicationConfiguration.class) public class CustomerRepositoryIntegrationTest { + @ClassRule public static RequiresMongoDB mongodbAvailable = RequiresMongoDB.anyVersion(); + @Autowired CustomerRepository repository; @Autowired MongoOperations operations; diff --git a/mongodb/pom.xml b/mongodb/pom.xml index d30642ad..dc079d68 100644 --- a/mongodb/pom.xml +++ b/mongodb/pom.xml @@ -17,9 +17,10 @@ 2011-2014 + aggregation example - aggregation text-search + util diff --git a/mongodb/text-search/pom.xml b/mongodb/text-search/pom.xml index ed8a1ce9..0b04942e 100644 --- a/mongodb/text-search/pom.xml +++ b/mongodb/text-search/pom.xml @@ -14,13 +14,14 @@ - org.springframework.boot - spring-boot-starter-web + com.fasterxml.jackson.core + jackson-databind - com.rometools - rome - 1.5.0 + ${project.groupId} + spring-data-mongodb-utils + ${project.version} + test diff --git a/mongodb/text-search/src/main/java/example/springdata/mongodb/textsearch/BlogPost.java b/mongodb/text-search/src/main/java/example/springdata/mongodb/textsearch/BlogPost.java index f50b7945..02de2c42 100644 --- a/mongodb/text-search/src/main/java/example/springdata/mongodb/textsearch/BlogPost.java +++ b/mongodb/text-search/src/main/java/example/springdata/mongodb/textsearch/BlogPost.java @@ -39,4 +39,9 @@ public class BlogPost { private @TextIndexed(weight = 2) String content; private @TextIndexed List categories; private @TextScore Float score; + + @Override + public String toString() { + return "BlogPost [id=" + id + ", score=" + score + ", title=" + title + ", categories=" + categories + "]"; + } } diff --git a/mongodb/text-search/src/test/java/example/springdata/mongodb/textsearch/MongoTestConfiguration.java b/mongodb/text-search/src/test/java/example/springdata/mongodb/textsearch/MongoTestConfiguration.java index 5218cf6f..1c0d4442 100644 --- a/mongodb/text-search/src/test/java/example/springdata/mongodb/textsearch/MongoTestConfiguration.java +++ b/mongodb/text-search/src/test/java/example/springdata/mongodb/textsearch/MongoTestConfiguration.java @@ -15,15 +15,16 @@ */ package example.springdata.mongodb.textsearch; -import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; import org.springframework.data.mongodb.core.MongoOperations; - -import example.springdata.mongodb.util.BlogPostInitializer; +import org.springframework.data.repository.init.Jackson2RepositoryPopulatorFactoryBean; /** * @author Christoph Strobl @@ -35,15 +36,12 @@ public class MongoTestConfiguration { @Autowired MongoOperations operations; - /** - * Initializes the repository with a predefined set of entities. - * - * @return - * @throws Exception - */ - @PostConstruct - void initialize() throws Exception { - BlogPostInitializer.INSTANCE.initialize(operations); + @Bean + public Jackson2RepositoryPopulatorFactoryBean repositoryPopulator() { + + Jackson2RepositoryPopulatorFactoryBean factoryBean = new Jackson2RepositoryPopulatorFactoryBean(); + factoryBean.setResources(new Resource[] { new ClassPathResource("spring-blog.atom.json") }); + return factoryBean; } /** diff --git a/mongodb/text-search/src/test/java/example/springdata/mongodb/textsearch/TextSearchRepositoryTests.java b/mongodb/text-search/src/test/java/example/springdata/mongodb/textsearch/TextSearchRepositoryTests.java index 981f6e57..f1cba0e3 100644 --- a/mongodb/text-search/src/test/java/example/springdata/mongodb/textsearch/TextSearchRepositoryTests.java +++ b/mongodb/text-search/src/test/java/example/springdata/mongodb/textsearch/TextSearchRepositoryTests.java @@ -15,7 +15,7 @@ */ package example.springdata.mongodb.textsearch; -import static example.springdata.mongodb.util.ConsoleResultPrinter.printResult; +import static example.springdata.mongodb.util.ConsoleResultPrinter.*; import java.util.List; @@ -29,7 +29,7 @@ import org.springframework.data.util.Version; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import example.springdata.mongodb.util.MongoVersionRule; +import example.springdata.mongodb.util.RequiresMongoDB; /** * Integration tests showing the text search functionality using repositories. @@ -44,7 +44,7 @@ public class TextSearchRepositoryTests { @Autowired BlogPostRepository repo; - @ClassRule public static MongoVersionRule versionRule = MongoVersionRule.atLeast(new Version(2, 6)); + @ClassRule public static RequiresMongoDB mongodbAvailable = RequiresMongoDB.atLeast(new Version(2, 6)); /** * Show how to do simple matching.
diff --git a/mongodb/text-search/src/test/java/example/springdata/mongodb/textsearch/TextSearchTemplateTests.java b/mongodb/text-search/src/test/java/example/springdata/mongodb/textsearch/TextSearchTemplateTests.java index 8a25993f..f67a3c03 100644 --- a/mongodb/text-search/src/test/java/example/springdata/mongodb/textsearch/TextSearchTemplateTests.java +++ b/mongodb/text-search/src/test/java/example/springdata/mongodb/textsearch/TextSearchTemplateTests.java @@ -15,8 +15,8 @@ */ package example.springdata.mongodb.textsearch; -import static example.springdata.mongodb.util.ConsoleResultPrinter.printResult; -import static org.springframework.data.mongodb.core.query.Query.query; +import static example.springdata.mongodb.util.ConsoleResultPrinter.*; +import static org.springframework.data.mongodb.core.query.Query.*; import java.util.List; @@ -33,7 +33,7 @@ import org.springframework.data.mongodb.core.query.TextQuery; import org.springframework.data.util.Version; import example.springdata.mongodb.util.BlogPostInitializer; -import example.springdata.mongodb.util.MongoVersionRule; +import example.springdata.mongodb.util.RequiresMongoDB; /** * @author Christoph Strobl @@ -43,7 +43,7 @@ public class TextSearchTemplateTests { MongoOperations operations; - @ClassRule public static MongoVersionRule versionRule = MongoVersionRule.atLeast(new Version(2, 6)); + @ClassRule public static RequiresMongoDB mongodbAvailable = RequiresMongoDB.atLeast(new Version(2, 6)); @Before public void setUp() throws Exception { diff --git a/mongodb/text-search/src/test/java/example/springdata/mongodb/util/BlogPostInitializer.java b/mongodb/text-search/src/test/java/example/springdata/mongodb/util/BlogPostInitializer.java index c7d12bea..84fc0b56 100644 --- a/mongodb/text-search/src/test/java/example/springdata/mongodb/util/BlogPostInitializer.java +++ b/mongodb/text-search/src/test/java/example/springdata/mongodb/util/BlogPostInitializer.java @@ -15,21 +15,12 @@ */ package example.springdata.mongodb.util; -import java.util.ArrayList; -import java.util.List; - import lombok.extern.slf4j.Slf4j; -import org.springframework.core.convert.converter.Converter; +import org.springframework.core.io.ClassPathResource; import org.springframework.data.mongodb.core.MongoOperations; -import org.springframework.http.ResponseEntity; +import org.springframework.data.repository.init.Jackson2ResourceReader; import org.springframework.util.Assert; -import org.springframework.web.client.RestTemplate; - -import com.rometools.rome.feed.atom.Category; -import com.rometools.rome.feed.atom.Content; -import com.rometools.rome.feed.atom.Entry; -import com.rometools.rome.feed.atom.Feed; import example.springdata.mongodb.textsearch.BlogPost; @@ -44,73 +35,31 @@ public enum BlogPostInitializer { INSTANCE; - private final RestTemplate restTemplate = new RestTemplate(); - private final Converter converter = EntryConverter.INSTANCE; - private final String url = "https://spring.io/blog.atom"; - /** * Initializes the given {@link MongoOperations} with {@link BlogPost}s from the Spring Blog. * * @param operations must not be {@literal null}. + * @throws Exception */ - public void initialize(MongoOperations operations) { + public void initialize(MongoOperations operations) throws Exception { Assert.notNull(operations, "MongoOperations must not be null!"); - - ResponseEntity feed = restTemplate.getForEntity(url, Feed.class); - int count = 0; - - if (feed.hasBody()) { - for (Object entry : feed.getBody().getEntries()) { - if (entry instanceof Entry) { - operations.save(converter.convert((Entry) entry)); - count++; - } - } - } - - log.info("Imported {} blog posts from spring.io!", count); + loadFromClasspathSource(operations); } - /** - * {@link Converter} implementation capable of converting atom feed {@link Entry} into {@link BlogPost}. - * - * @author Christoph Strobl - * @author Oliver Gierke - */ - private enum EntryConverter implements Converter { + @SuppressWarnings({ "unchecked", "rawtypes" }) + private void loadFromClasspathSource(MongoOperations operations) throws Exception { - INSTANCE; + Jackson2ResourceReader reader = new Jackson2ResourceReader(); - /* - * (non-Javadoc) - * @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object) - */ - @Override - public BlogPost convert(Entry source) { + Object source = reader.readFrom(new ClassPathResource("spring-blog.atom.json"), this.getClass().getClassLoader()); - BlogPost post = new BlogPost(); - - post.setId(source.getId()); - post.setTitle(source.getTitle()); - - for (Object content : source.getContents()) { - if (content instanceof Content) { - post.setContent(((Content) content).getValue()); - } - } - - List categories = new ArrayList(); - - for (Object category : source.getCategories()) { - if (category instanceof Category) { - categories.add(((Category) category).getLabel()); - } - } - - post.setCategories(categories); - - return post; + if (source instanceof Iterable) { + ((Iterable) source).forEach(element -> operations.save(element)); + } else { + operations.save(source); } + + log.info("Imported blog posts from classpath!"); } } diff --git a/mongodb/text-search/src/test/java/example/springdata/mongodb/util/ConsoleResultPrinter.java b/mongodb/text-search/src/test/java/example/springdata/mongodb/util/ConsoleResultPrinter.java index 5c4ae508..caca4521 100644 --- a/mongodb/text-search/src/test/java/example/springdata/mongodb/util/ConsoleResultPrinter.java +++ b/mongodb/text-search/src/test/java/example/springdata/mongodb/util/ConsoleResultPrinter.java @@ -17,7 +17,7 @@ package example.springdata.mongodb.util; import java.util.Collection; -import org.springframework.data.mongodb.core.query.TextCriteria; +import org.springframework.data.mongodb.core.query.CriteriaDefinition; import example.springdata.mongodb.textsearch.BlogPost; @@ -28,7 +28,7 @@ import example.springdata.mongodb.textsearch.BlogPost; */ public class ConsoleResultPrinter { - public static void printResult(Collection blogPosts, TextCriteria criteria) { + public static void printResult(Collection blogPosts, CriteriaDefinition criteria) { System.out.println(String.format("XXXXXXXXXXXX -- Found %s blogPosts matching '%s' --XXXXXXXXXXXX", blogPosts.size(), criteria != null ? criteria.getCriteriaObject() : "")); diff --git a/mongodb/text-search/src/test/resources/spring-blog.atom.json b/mongodb/text-search/src/test/resources/spring-blog.atom.json new file mode 100644 index 00000000..6c4c2674 --- /dev/null +++ b/mongodb/text-search/src/test/resources/spring-blog.atom.json @@ -0,0 +1,201 @@ +[ +{ + "_id" : "tag:spring.io,2014-09-01:1745", + "_class" : "example.springdata.mongodb.textsearch.BlogPost", + "title" : "Spring Security OAuth 2.0.3 Available Now", + "content" : "

Spring Security OAuth 2.0.3 is available now in all the usual Maven repositories. It's a bug fix release, nothing major, so upgrading from 2.0.x should be painless (and is recommended). Some people were having issues getting JWT tokens to work properly, and those should be fixed. The only noteworthy functional change is that Resource Servers (if configured with @Configuration) will now check the validity of the client and scopes before allowing access to protected resources. This means that client privileges can be revoked quickly, but may also lead to a performance penalty (so caching the ClientDetailsService results would be recommended).

", + "categories" : [ + "Releases" + ] +}, + +{ + "_id" : "tag:spring.io,2014-08-28:1744", + "_class" : "example.springdata.mongodb.textsearch.BlogPost", + "title" : "Spring Tool Suite and Groovy/Grails Tool Suite 3.6.1 released", + "content" : "

Dear Spring Community,

\n\n

I am happy to announce the new release of our Eclipse-based tooling today:\nThe Spring Tool Suite (STS) 3.6.1 and the Groovy/Grails Tool Suite (GGTS) 3.6.1.

\n\n

Highlights from this release include:

\n\n
    \n
  • updated to tc Server 3.0.0
  • \n
  • performance improvements for building Spring projects
  • \n
  • AspectJ/AJDT now support annotation processors
  • \n

To download the distributions, please go visit:

\n\n

Detailed new and noteworthy notes can be found here: STS/GGTS 3.6.1 New & Noteworthy.

\n\n

NOTE:\nBoth tool suites ship on top of the latest Eclipse Luna 4.4 release as 64bit and 32bit based zip files only.\nThere will be no native installers for STS/GGTS anymore.

\n\n

With the 3.6.0 release we shifted towards a slightly changed release schedule, shipping minor releases more frequently. Therefore 3.6.2 is scheduled to ship already in October, shortly after the Eclipse Luna SR1 release, followed by 3.6.3 in early Dezember and 3.6.4 in early March 2015, shortly after the Eclipse Luna SR2 release.

\n\n

Enjoy!

", + "categories" : [ + "Releases" + ] +}, + +{ + "_id" : "tag:spring.io,2014-08-19:1740", + "_class" : "example.springdata.mongodb.textsearch.BlogPost", + "title" : "This Week in Spring-19th August 2014", + "content" : "

Welcome to another installment of This Week in Spring! It's a few weeks before SpringOne2GX 2014, already! Time sure flies when you're having fun! The beginning of 2015 will mark the 4th year of This Week in Spring, and it's more exciting every week! I'm hoping to see as many of you as possible at SpringOne2GX 2014. This is sure to be an amazing event.

\n\n

Anyway, with that out of the way, let's get on to this week's roundup!

\n\n
    \n
  1. Spring Security lead Rob Winch just announced Spring Security 4.0.0.M2, which
    \nprovides a lot of great features, including improved Security-aware testing support, Spring Data integration, support for websocket security, and ties into the nascent Spring Session projet that was derived from the work for this release. Check it out! Rob also announced Spring Security 3.2.5 and 3.1.7 which is a fix that closes a few potential security holes. This is good stuff, all around!
  2. \n
  3. \nSpring framework 4.1.RC2 just dropped. Spring 4.1 is very near completion, so be sure to check out the latest and greatest bits in this release!
  4. \n
  5. Christoph Strobl just announced the first RC for the Spring Data Evans release train. The new release includes a lot of features, including text search integration for Spring Data MongoDB, improved multistore support, configuration options for Redis sentinels, and much more.
  6. \n
  7. Our friends at Codecentric have just announced a new cut of their custom Spring Boot autoconfiguration for Spring Batch. This implementation is different than the auto-configuration provided out of the box with Spring Boot, and includes support for JSR 352.
    \n
  8. \n
  9. Netflix Developer Dan Woods recently gave a nice talk looking at what they hope to get out of the Spring Boot-based Grails 3, and the slide deck is definitely worth a look.
  10. \n
  11. The Being Java Guys blog has a nice post on how to build a REST service with Spring 4 and Hibernate 4. The example uses web.xml and Spring XML configuration. It's a working recipe, but I hope readers will remember that you can get the same done with Spring Boot in much less time and code.
  12. \n
  13. \nOracle has particular support for Spring-based applications in WebLogic 12.1.3 which, I confess, I didn't know about. This is a pretty interesting read if you're on WebLogic.
  14. \n
  15. Tirthal's Java cafe blog takes a look at the recently announced Spring IO.
  16. \n
  17. This Vietnamese-language post on building a simple Spring-based web application was pretty straightforward, and worth a read.
  18. \n
  19. This post introduces how to integrate Spring Security 3.0.4 and GWT\n
  20. \n
", + "categories" : [ + "Engineering" + ] +}, + +{ + "_id" : "tag:spring.io,2014-08-27:1743", + "_class" : "example.springdata.mongodb.textsearch.BlogPost", + "title" : "Spring Data Dijkstra SR4 released", + "content" : "

On behalf of the Spring Data team I am pleased to announce the availability of the fourth service release of the Dijkstra release train. It includes 36 fixes overall for the following modules:

\n\n

The release is a recommended upgrade for all Dijkstra users as it contains a few important bug fixes. The next release coming will be the final release of the upcoming release train Evans.

\n\n

If you want to learn more about Spring Data, be sure to attend this year's SpringOne conference. The schedule contains a lot of data-related talks to introduce you to the latest features we're going to ship with Evans.

", + "categories" : [ + "Releases" + ] +}, + +{ + "_id" : "tag:spring.io,2014-08-26:1742", + "_class" : "example.springdata.mongodb.textsearch.BlogPost", + "title" : "This Week in Spring - August 26th, 2014", + "content" : "

Holy cats! Can you believe how close we are to SpringOne2GX? Last year we made a huge splash with the announcements of Spring Boot and Spring XD, both of which have recently hit 1.0 releases. I happen to know the next level looks like, and you're going to want to see it. Register now if you haven't already!

\n\n

I am personally super excited to see Greg, Rob, the rest of the Spring team, and of course all of you, at SpringOne2GX! Register now if you haven't!

", + "categories" : [ + "Engineering" + ] +}, + +{ + "_id" : "tag:spring.io,2014-08-20:1741", + "_class" : "example.springdata.mongodb.textsearch.BlogPost", + "title" : "Building a RESTful quotation service with Spring", + "content" : "

I was recently made aware that a public API we were using for one of our guides contained objectionable material. After confirming this, I immediately responded that we would pick another source. Wishing to avoid such an issue in the future, I decided the best solution was to build our own RESTful quote service. So I decided to use the best tools to do so, the Spring stack, and was able to migrate the very next day.

\n\n

\nPicking your tools

\n\n

To kick things off, I made a check list of what I knew would be the right tools for the job of creating a RESTful web service.

\n\n
    \n
  • \nSpring Data JPA - quickly pre-load, fetch, and potentially update content
  • \n
  • \nSpring MVC - solid REST support since Spring 3
  • \n
  • \nSpring Boot - create all the needed components with little to no effort
  • \n
  • \nhttp://start.spring.io - assemble a project by simply checking the desired items on a form
  • \n

I quickly set aside the desire to add, delete, manage, or view the data through a web page. Instead, my focus was to serve up a fixed set of content with the exact same structure that the guide expected to consume.

\n\n

\nPicking your content

\n\n

The original content for the guide was a series of \"Chunk Norris\" jokes. I like a good laugh. But when I revisited the public API, I saw that several of the jokes were a bit rancid. After a brief discussion with colleagues, the idea came up to cite historical quotes. I took that idea and bent it a little. I had recently collected quotes from various developers about Spring Boot for personal reasons, so I decided to use that as the curated content.

\n\n

\nTime to code!

\n\n

To kick things off, I visited http://start.spring.io. This Spring Boot app lets you enter the details of your new project, pick the Java level, and select the Spring Boot starters you need. I used my checklist up above and created a new gradle-based project.

\n\n

\nDefining your domain

\n\n

With the project unpacked and imported into my IDE, the first thing I did was copy the domain objects shown in the Reactor guide. This way, I could ensure that the data sent out by my REST service was correct. Since the POJOs in my Quoters Incorporated app are almost identical, I won't post them here.

\n\n

Then I created a Spring Data repository.

\n\n
public interface QuoteRepository extends CrudRepository<Quote, Long> {}\n
\n\n

This empty interface definition handles Quote objects with an internal primary key of type Long. By extending the Spring Data Commons CrudRepository, it inherits a fistful of database operations we'll use later on.

\n\n

Next step? Initialize some data. I created a DatabaseLoader like this:

\n\n
@Service\npublic class DatabaseLoader {\n\n    private final QuoteRepository repository;\n\n    @Autowired\n    public DatabaseLoader(QuoteRepository repository) {\n        this.repository = repository;\n    }\n\n    @PostConstruct\n    void init() {\n        repository.save(new Quote(\"Working with Spring Boot is like pair-programming with the Spring developers.\"));\n        // more quotes...\n    }\n\n}\n
\n\n
    \n
  • It's marked as a @Service so it will be automatically picked up by @ComponentScan when the app starts.
  • \n
  • It uses constructor injection with auto-wiring to ensure a copy of the QuoteRepository is made available.
  • \n
  • \n@PostConstruct tells Spring MVC to run the data loading method after all beans have been created.
  • \n
  • Finally, the init() method uses Spring Data JPA to create a whole slew of quotations.
  • \n

Because I have H2 as my database of choice (com.h2database:h2) in build.gradle, there is no database set up at all (thanks to Spring Boot).

\n\n

\nCreating a controller

\n\n

After I built this database layer, I went on to create the APIs. With Spring MVC, it wasn't hard at all.

\n\n
@RestController\npublic class QuoteController {\n\n    private final QuoteRepository repository;\n\n    private final static Quote NONE = new Quote(\"None\");\n\n    private final static Random RANDOMIZER = new Random();\n\n    @Autowired\n    public QuoteController(QuoteRepository repository) {\n        this.repository = repository;\n    }\n\n    @RequestMapping(value = \"/api\", method = RequestMethod.GET)\n    public List<QuoteResource> getAll() {\n        return StreamSupport.stream(repository.findAll().spliterator(), false)\n            .map(q -> new QuoteResource(q, \"success\"))\n            .collect(Collectors.toList());\n    }\n\n    @RequestMapping(value = \"/api/{id}\", method = RequestMethod.GET)\n    public QuoteResource getOne(@PathVariable Long id) {\n        if (repository.exists(id)) {\n            return new QuoteResource(repository.findOne(id), \"success\");\n        } else {\n            return new QuoteResource(NONE, \"Quote \" + id + \" does not exist\");\n        }\n    }\n\n    @RequestMapping(value = \"/api/random\", method = RequestMethod.GET)\n    public QuoteResource getRandomOne() {\n        return getOne(nextLong(1, repository.count() + 1));\n    }\n\n    private long nextLong(long lowerRange, long upperRange) {\n        return (long)(RANDOMIZER.nextDouble() * (upperRange - lowerRange)) + lowerRange;\n    }\n\n}\n
\n\n

Let's break it down:

\n\n
    \n
  • The whole class is flagged as a @RestController. This means all routes return objects not views.
  • \n
  • I have some static objects, particular a NONE quote and a Java 8 Random for randomly picking quotes.
  • \n
  • It uses constructor injection to get a hold of QuoteRepository.
  • \n
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
APIDescription
/apiFetch ALL quotes
/api/{id}Fetch quote id\n
/api/randomFetch a random quote

To fetch ALL quotes, I use a Java 8 stream to wrap the Spring data's findAll() and in turn, wrap each one into a QuoteResource. The results are turned into a List.

\n\n

To fetch a single quote, it first tests if a given id exists. If not, return NONE. Otherwise, return a wrapped quote.

\n\n

Finally, to fetch a random quote, I use Java 8's Random utility inside the nextLong() utility method to fetch a Long with the lowerRange and upperRange, inclusively.

\n\n
\n

QUESTION: Why am I using QuoteResource? Quote is the core domain object returned by the QuoteRepository. To match the previous public API, I wrap each instance in a QuoteResource which includes a status code.

\n
\n\n

\nTesting the results

\n\n

With this in place, the default Application class created by http://start.spring.io was ready to run.

\n\n
$ curl localhost:8080/api/random\n{\n    type: \"success\",\n    value: {\n        id: 1,\n        quote: \"Working with Spring Boot is like pair-programming with the Spring developers.\"\n    }\n}\n
\n\n

Ta dah!

\n\n

To wrap things up, I built the JAR file and pushed it up to Pivotal Web Services. You can view the site yourself at http://gturnquist-quoters.cfapps.io/api/random.

\n\n

Suffice it to say, I was able to tweak the Reactor guide by altering ONE LINE OF CODE. With that in place, I did some other clean up of the content and was done!

\n\n

To see the code, please visit https://github.com/gregturn/quoters.

\n\n

\nOutstanding issues

\n\n
    \n
  • This RESTful service satisfies Level 2 - HTTP Verbs of the Richardson Maturity Model. While good, it's best to shoot for Level 3 - Hypermedia. With Spring HATEOAS, it's easier than ever to add hypermedia links. Stay tuned.
  • \n
  • There is no friendly web page. This would be nice, but it isn't required.
  • \n
  • Content is fixed and defined inside the app. To make content flexible, we would need to open the door to POSTs and PUTs. This would introduce the desire to also secure things properly.
  • \n

These are some outstanding things that didn't fit inside the time budget and weren't required to solve the original problem involving the Reactor guide. But they are good exercises you can explore! You can clone the project in github and take a shot at it yourself!

\n\n

\nSpringOne 2GX 2014

\n\n

Book your place at SpringOne in Dallas, TX for Sept 8-11 soon. It's simply the best opportunity to find out first hand all that's going on and to provide direct feedback. You can see myself and Roy Clarkson talk about Spring Data REST - Data Meets Hypermedia to see how to merge Spring Data and RESTful services.

", + "categories" : [ + "Engineering" + ] +}, + +{ + "_id" : "tag:spring.io,2014-08-18:1732", + "_class" : "example.springdata.mongodb.textsearch.BlogPost", + "title" : "Spring Security 4.0.0.M2 Released", + "content" : "

I'm pleased to announce the release of Spring Security 4.0.0.M2 available in the Spring Milestone repository.

\n\n

\n
SpringOne 2GX 2014 is around the corner
\nBook your place at SpringOne in Dallas, TX for Sept 8-11 soon. It's simply the best opportunity to find out first hand all that's going on and to provide direct feedback. From 0 to Spring Security 4.0 session will contain detailed information on how to get started with Spring Security and provide a deep dive into the new features found in Spring Security 4. Of course there plenty of other exciting Spring related talks!\n

\n\n

\nChangelog

\n\n

You can find details about this release in the release notes. Highlights of the release include:

\n\n
    \n
  • Support for WebSocket Security using Spring's messaging abstraction
  • \n
  • Spring Data integration
  • \n
  • \nSpring Session was produced out of the work necessary for this release. In an application server independent way you can easily use a custom backend (i.e. Redis) as the HttpSession implementation. See the project page for additional features of this exciting new project.
  • \n
  • Enhancements and fixes to the testing support\n\n
      \n
    • Easier integration with MockMvc through SecurityMockMvcConfigurers\n
    • \n
    • You no longer need to specify WithSecurityContextTestExecutionListener on your tests
    • \n
    • \n@WithSecurityContext works even with custom SecurityContextRepository implementations
    • \n
    • Support for digest and certificate based authentication testing
    • \n
    \n
  • \n
  • Support nested static groups in LDAP Authentication
  • \n
  • Lots of integration tests added to the sample applications
  • \n
  • Updated minimum version of Spring 4.1 RC2. This was necessary for enough of the features, that it made sense to do across the board
  • \n

Stay tuned to the spring.io blog for a blog series introducing these exciting new features.

\n\n

Reference | Javadoc | Guides

", + "categories" : [ + "Releases" + ] +}, + +{ + "_id" : "tag:spring.io,2014-08-15:1730", + "_class" : "example.springdata.mongodb.textsearch.BlogPost", + "title" : "CVE-2014-3527 Fixed in Spring Security 3.2.5 and 3.1.7", + "content" : "

Spring Security 3.2.5 (change log) and 3.1.7 (change log) have been released and are available in Maven Central. Important highlights of this release are:

\n\n
    \n
  • This release contains a fix for CVE-2014-3527 which resolves an issue where a malicious CAS Service can impersonate another CAS Service when using proxy tickets.
  • \n
  • This release updates the transitive dependencies of the cas module to cas-client-core which has a fix for CVE-2014-4172. This issue was not in Spring Security itself, but the library in which it depends on.
  • \n

A special thanks to Scott Battaglia & the rest of the CAS team for relaying CVE-2014-3527 to the Spring Security team and coordinating with the Spring Security team on the CAS release to resolve CVE-2014-4172.

\n\n

SpringOne 2GX 2014 is around the corner

\n\n

Book your place at SpringOne in Dallas, TX for Sept 8-11 soon. It's simply the best opportunity to find out first hand all that's going on and to provide direct feedback. There will be deep dive sessions on the latest updates to Spring, Groovy, and Grails!

", + "categories" : [ + "Releases" + ] +}, + +{ + "_id" : "tag:spring.io,2014-08-15:1729", + "_class" : "example.springdata.mongodb.textsearch.BlogPost", + "title" : "Spring Framework 4.1 RC2 Released", + "content" : "

On behalf of the team I am pleased to announce the second release candidate of Spring Framework 4.1 is now available from our milestone repository. This release includes over 70 fixes and improvements.

\n\n

Spring 4.1 is really coming up soon: please try it out and let us know if you run into any issue. We're looking forward to getting in touch via Twitter, StackOverflow or JIRA.

\n\n

SpringOne 2GX 2014 is around the corner

\n\n

Book your place at SpringOne in Dallas, TX for Sept 8-11 soon. It's simply the best opportunity to find out first hand all that's going on and to provide direct feedback. There will be deep dive sessions on Spring XD along with general Big Data talks to provide an introduction to the landscape and challenges in developing Big Data applications.

", + "categories" : [ + "Releases" + ] +}, + +{ + "_id" : "tag:spring.io,2014-08-13:1725", + "_class" : "example.springdata.mongodb.textsearch.BlogPost", + "title" : "First Release Candidate of Spring Data Release Train Evans Available", + "content" : "

We are happy to announce the first release candidate of the Spring Data release train Evans. We ship the following modules:

\n\n

Some of the highlights that happened since the first milestone are:

\n\n

Overall 95 tickets have be processed so make sure you've booked your place for SpringOne in Dallas to find out firsthand what's new in Spring Data. Meanwhile watch out for upcoming blog posts on selected features of this release. The release train wiki page might be a good start to find out about relevant new stuff as well.

\n\n

Got questions? Have feedback? Found a bug? Don't hesitate to contact us! We're looking forward to getting in touch via Twitter, StackOverflow or JIRA.

", + "categories" : [ + "Releases" + ] +}, + +{ + "_id" : "tag:spring.io,2014-08-13:1724", + "_class" : "example.springdata.mongodb.textsearch.BlogPost", + "title" : "This Week in Spring - August 12th, 2014", + "content" : "

Welcome to another installment of This Week in Spring. We've got a lot of cool stuff happening and, as you might imagine, the entire team is abuzz in preparation for SpringOne2GX 2014, coming in just a few short weeks! If you haven't registered, now's the time to do so!

\n\n
    \n
  1. Spring Security lead and all-around sleepless ninja Rob Winch has just announced that Spring MVC Test HtmlUnit 1.0.0.M2 has been released. This is an awesome release if you're trying to unit test real pages with Spring MVC\n
  2. \n
  3. \nSpring Boot 1.1.5 has just been released. The new release mainly addresses a few issues and is a recommended upgrade for all users.
  4. \n
  5. I really enjoyed this blog, ¿Qué es Spring Framework?, which tries to explain what the fundamental value of Spring is. Largely, the (Spanish language) article explains that Spring handles the lifecycle for objects in a consistent way. It's easy to plug in various frameworks, software, around the edges when the fundamental life-cycle is handled. I would point out that this post uses Spring 3.0 and XML configuration, which is a bit outdated, though certainly still works.
  6. \n
  7. The RebelLabs folks are back at it with an interesting look at web framework usage. Check out this latest report which has Spring MVC leading the charge (by a lot).
  8. \n
  9. This is a nice post looking at how to use Spring MVC (as part of Spring framework 4.x) to handle file uploads\n
  10. \n
  11. The Mr. Haki * blog has a nice post on analyzing dependencies using Gradle, with an example based on Spring Boot. Spring Boot, of course, is easy to get started with, can be used with Maven *or Gradle, and has numerous benefits, not the least of which being that it makes it dead simple to use Spring libraries in your project without worrying about version mismatches.
  12. \n
  13. Stuck on JAX-RS and JSF? Still want to use Spring Security? This post - from the JSF Usefullness post - has the code snippets that (sort of) demonstrate a path forward. Granted, you'll have an easier time of doing this using straight Spring. No need to add all that extra Java EE weight..
  14. \n
  15. This is a sort of oldie-but-a-goodie: a post on how to implement a JQuery-powered autosave example in Spring MVC\n
  16. \n
  17. This is a (particularly tortured) example of how to write a Spring application that uses Primefaces and runs on the Wildfly application server. I don't see why you'd need all this indirection when Spring has good JSF support out of the box. Additionally, there's no reason to recreate the JdbcTemplate or inject an ApplicationContext into a bean. Maybe it'll help somebody as a first-cut, though.
  18. \n

So, did I mention SpringOne2GX 2014? It's right around the corner! I'll be there, and so will everyone from the Spring team, so don't miss out. This is going to be an amazing year. I happen to know what some of the keynotes are going to be about. Do not miss out. Register today!

", + "categories" : [ + "Engineering" + ] +}, + +{ + "_id" : "tag:spring.io,2014-08-07:1722", + "_class" : "example.springdata.mongodb.textsearch.BlogPost", + "title" : "Spring Boot 1.1.5 released", + "content" : "

We are pleased to announce that Spring Boot 1.1.5 has been released and is available from repo.spring.io and Maven Central.

\n\n

This release addresses a number of issues and is a recommended upgrade for all Spring Boot users. For a complete list of changes please refer to the issue tracker.

\n\n

Project Page | GitHub | Issues | Documentation

", + "categories" : [ + "Releases" + ] +}, + +{ + "_id" : "tag:spring.io,2014-08-06:1721", + "_class" : "example.springdata.mongodb.textsearch.BlogPost", + "title" : "Spring MVC Test HtmlUnit 1.0.0.M2 Released", + "content" : "

I'm pleased to announce the second milestone release of Spring MVC Test HtmlUnit.

\n\n

The project’s aim is to provide integration between Spring MVC Test and HtmlUnit. This simplifies performing end to end testing when using HTML based views.

\n\n

Changelog

\n\n

You can view the complete changelog on github. Below are the highlights of the release:

\n\n
    \n
  • The release contains Reference Documentation and Publishes the API Docs\n
  • \n
  • The artifact name has changed from spring-test-mvc-htmlunit to spring-test-htmlunit See the Updating Dependencies to see how to add Spring MVC Test HtmlUnit as either a Maven or Gradle dependency
  • \n
  • The project name has been changed to Spring MVC Test HtmlUnit in order to better align with Spring MVC Test's name
  • \n
  • Context root of \"\" is now supported
  • \n
  • \nSupport for external resources has been added. See the javadoc of DelegatingWebConnection for additional details.
  • \n
  • Bug fixes
  • \n

\n
SpringOne 2GX 2014 is around the corner
\nBook your place at SpringOne in Dallas, TX for Sept 8-11 soon. It's simply the best opportunity to find out first hand all that's going on and to provide direct feedback. The Quest for the Holy Integration Test session will contain detailed information on how to test your Spring web applications including detailed information about Spring MVC Test HtmlUnit. Of course there plenty of other exciting Spring related talks!\n

", + "categories" : [ + "Releases" + ] +}, + +{ + "_id" : "tag:spring.io,2014-08-06:1720", + "_class" : "example.springdata.mongodb.textsearch.BlogPost", + "title" : "This Week in Spring - August 5th, 2014", + "content" : "

Welcome to another installment of This Week in Spring! As usual, we've got a lot to cover so let's get to it.

\n\n
    \n
  1. Spring Cloud lead Ramnivas Laddad has written up a nice post that looks at how to extend Spring Cloud to consume other services in a consistent manner.
  2. \n
  3. I liked Samer Abdelkafi's blog introducing how to use Java configuration with Spring. It's always a good time to review..
  4. \n
  5. The Pragmatists blog has a detailed look at the sort of (tortured) steps involved in using Spring with the Play! web framework
  6. \n
  7. Biju Kunjummen put together a great post that looks at how to deploy a Spring Cloud enabled application to Cloud Foundry
  8. \n
  9. Thys Michels is back at it again, this time with a post on building a ToDo application with Spring MVC and Angular.js
  10. \n
  11. I am really happy that this link is in this week's roundup, the author -Priyadarshini - did an amazing job! Check out this really thoughtful introduction to using Spring Boot to build a CRUD-capable Spring Boot-based application.
  12. \n
  13. The /dev/Kico blog has a nice Portguese-language post on what's new in Spring 4\n
  14. \n
  15. Ahmed Essam El-din Ahmed's roundup of the integrations for security among the various web frameworks - including Spring MVC - is fantastic.
    \n
  16. \n
  17. Did you know that Spring provides a StoredProcedure object that can be used to wrap and adapt the painful setup involved in invoking a stored procedure from JDBC.
    \n
  18. \n
  19. Theodora Fragkouli put together a nice post on how to handle Spring MVC form handling
  20. \n
  21. The ITEssays blog has a code recipe demonstrating how to use Spring Data MongoDB with XML configuration.
  22. \n

SpringOne 2GX 2014 is around the corner

\n\n

Book your place at SpringOne in Dallas, TX for Sept 8-11 soon. It's simply the best opportunity to find out first hand all that's going on and to provide direct feedback. There will be deep dive sessions on Spring XD along with general Big Data talks to provide an introduction to the landscape and challenges in developing Big Data applications.

", + "categories" : [ + "Engineering" + ] +}, + +{ + "_id" : "tag:spring.io,2014-07-24:1697", + "_class" : "example.springdata.mongodb.textsearch.BlogPost", + "title" : "Extending Spring Cloud", + "content" : "

One of the most interesting capabilities of Spring Cloud is its extensibility. You can extend it to support additional clouds, enhance already supported clouds, support new services, new service connectors--all without modifying the Spring Cloud code itself. In this blog, we explore this capability. If you haven’t done so already, please read the first and second blog in this series to acquire sufficient background.

\n\n

\nThe three axes of extensibility

\n\n

Spring Cloud provides extensibility along three orthogonal directions. You may extend it in one of these directions and orthogonality ensures that you continue to benefit from the others.

\n\n
    \n
  1. Cloud Platforms: While Spring Cloud supports Cloud Foundry, Heroku, and a Local Config cloud (to test locally in a cloud-like environment), you aren’t limited by these choices. You can add your own cloud platform and take advantage of the rest of Spring Cloud capability such as Spring Java Config.

  2. \n
  3. Cloud Services: Cloud platforms offer a variety of services ranging from relational databases to messaging. Services offered by each cloud platform vary a lot, even for multiple installations of the same platform. This is especially true for PaaS offerings such as Cloud Foundry, where private instances of Cloud Foundry tend to have services specific to each installation. Spring Cloud offers an easy way to extend to services beyond its core offering. Just like cloud platform extensibility, you don’t have to change Spring Cloud code to extend it to new services and you continue to take advantage of the other parts.

  4. \n
  5. Frameworks: Spring Cloud currently supports Spring frameworks through the spring-service-connector module. However, except for that module, nothing in Spring Cloud depends on Spring. As such, you should be able to either use other parts from any JVM-based framework or extend it for a framework by adding a new module.

  6. \n

In the previous blog, we looked at how you would use CloudFactory and Cloud to programmatically use Spring Cloud. When it comes to extensibility, you will not be working with either of these; instead you will implement other types in the core module. Let’s take a look at them.

\n\n

\nCloud Platform Extensibility

\n\n

The main type you will need to be familiar with to extend Spring Cloud to a new cloud platform is CloudConnector, which is a simple three-method interface:

\n\n
public interface CloudConnector {\n    boolean isInMatchingCloud();\n    ApplicationInstanceInfo getApplicationInstanceInfo();\n    List<ServiceInfo> getServiceInfos();\n}\n
\n\n

The isInMatchingCloud() method should examine its environment to decide if it is operating in the right environment. For example, the Cloud Foundry connector checks the existence of the VCAP_APPLICATION environment variable, whereas the Heroku connector looks for the existence of the DYNO environment variable. The getApplicationInstanceInfo() method returns information about the current application instance (app name, host, port, and application properties). The most interesting method getServiceInfos() returns a list with each element containing enough information so that applications know how to connect to each service. Exact information contained in each ServiceInfo object is left up to each implementation (the ServiceInfo as such defines only one method: getId()).

\n\n

Once you create an implementation of CloudConnector, you need to make Spring Cloud aware of it. For all extension points, Spring Cloud uses a uniform mechanism based on ServiceLoader. As applied to Spring Cloud for platform extensibility, it boils down to including a file named /META-INF/services/org.springframework.cloud.CloudConnector with an entry with the fully-qualified name of the implementation class. Typically, you will bundle this file along with your implementation and supporting classes. Then all an app has to do is include this jar on the classpath.

\n\n

\nService Extensibility

\n\n

The ServiceInfoCreator interface provides an extension point to work with a new service.

\n\n
public interface ServiceInfoCreator<SI extends ServiceInfo, SD> {\n    public boolean accept(SD serviceData);\n    public SI createServiceInfo(SD serviceData);\n}\n
\n\n

The generic parameter SI defines the kind of ServiceInfo it will create, whereas the SD parameter defines the raw service data type it can work with. The raw service data type depends on the cloud platform. For example, in Cloud Found, it will be a Map based on the VCAP_SERVICES environment variable, whereas in Heroku, it will be a pair containing the service-specific environment variables and its value. Since the raw data type depends on the platform, so does implementations of ServiceInfoCreator. The accept() method examines the service data and determines if it can deal with it. For example, it can look at the URL scheme and determine if it can consume that service data. If it can, the createServiceInfo() must return a ServiceInfo object. If it is a completely new service, you may also have to implement ServiceInfo for that, else you can use one of the existing ones.

\n\n

Once you have implemented a ServiceInfoCreator, you will have to let Spring Cloud know about it. This follows the same idea as discussed earlier for cloud platform extensibility. In this case, the file name you use is CloudConnector dependent. For Cloud Foundry, it is /META-INF/services/org.springframework.cloud.cloudfoundry.CloudFoundryServiceInfoCreator (theoretically, a CloudConnector implementation may decide to use another extension mechanism, but Spring Cloud doesn’t recommend that).

\n\n

As discussed in the previous blog, a cloud app developer may decide to work directly with a ServiceInfo object. As such, if you just implement a ServiceInfoCreator, you would have provided some benefit already. However, working with a raw ServiceInfo object may not be appreciated by many developers focused on developing apps, so you will implement the next extension as well.

\n\n

\nFramework Extensibility

\n\n

The last extensibility point is ServiceConnectorCreator. Its job is to transform ServiceInfo into a service connector that is suitable for consumption in the framework the app is using. For example, it could transform MysqlServiceInfo into a DataSource object. Out of the box, Spring Cloud supports connectors for DataSource and a few Spring Data and Spring AMQP types. If you wish to extend Spring Cloud to other frameworks or if you wanted to support other Spring Data types (such as Neo4J, Elasticsearch, Cassandra) or Spring-compatible types (such as S3) not yet supported directly by Spring Cloud, this is the extension point you need.

\n\n
public interface ServiceConnectorCreator<SC, SI extends ServiceInfo> {\n    SC create(SI serviceInfo, ServiceConnectorConfig serviceConnectorConfig);\n    ...\n}\n
\n\n

There are a couple more methods; however, you will normally extend the AbstractServiceConnectorCreator that takes care of implementing those.

\n\n

The SC generic parameter to ServiceConnectorCreator is bound to the type of connector it will create, such as DataSource, whereas the SI parameter signifies the type of ServiceInfo it can work with.

\n\n

The create() method is supplied with a ServiceInfo object and a configuration object, that carries service-specific info such as pooling parameters. It needs to use these parameters to create an appropriate connector.

\n\n

Once the implementation is ready, just put it in a file named /META-INF/services/org.springframework.cloud.service.ServiceConnectorCreator. Spring Cloud will use the Service Loader mechanism described earlier.

\n\n

\nSummary

\n\n

As you can see Spring Cloud offers substantial extensibility along cloud platform, services, and framework axis. Next time, you come across a new kind of these, you should be able to extend Spring Cloud to work with them. If you open-source your extensions, let us know, so that we can showcase it for others to benefit. If it is a common enough extension, consider making a pull request.

", + "categories" : [ + "Engineering" + ] +}, + +{ + "_id" : "tag:spring.io,2014-07-30:1715", + "_class" : "example.springdata.mongodb.textsearch.BlogPost", + "title" : "Spring XD 1.0 GA Released", + "content" : "

On behalf of the Spring XD team, I am very pleased to announce the general availability of Spring XD 1.0! You can download the zip distribution. You can also install on OSX using homebrew and on RHEL/CentOs using yum.

\n\n

Spring XD's goal is to be your one stop shop for developing and deploying Big Data Applications. Such applications require a wide range of technologies to address different use-cases while interoperating as a cohesive process. The steps in this process include:

\n\n
    \n
  • Data collection
  • \n
  • Real-time streaming and analytics
  • \n
  • Data cleansing
  • \n
  • Batch processing (both on and off Hadoop)
  • \n
  • Machine learning and exploratory data analysis
  • \n
  • Visualization and Reporting
  • \n
  • Closed loop analytics between real-time and batch processing
  • \n

Spring XD brings together many of these steps into a single unified runtime platform so you can address as many use-cases as possible. You don't have to piece together a large number of individual projects, each with its own configuration and programming model. Instead, with Spring XD, you can quickly get started developing an end-to-end solution with a simple but powerful DSL and scale it out.

\n\n

Spring XD provides:

\n\n

There are several resources available to help you get started using Spring XD.

\n\n

There are many samples available in our samples repository Here are a few that show the range of functionality available

\n\n

This was a great team effort, with over a dozen active contributors spread around the world working for 68 weeks, divided into 32 sprints, resolving 1,650 issues in 2000 commits, 1,000 tests, and 270 pages of documentation. The 51,000 HipChat messages helped keep the team in constant contact and searching for new emoticons and fun images

\n\n

Thanks for all the feedback from early adopters. Feedback is very important, so please get in touch with questions and comments via

\n\n

SpringOne 2GX 2014 is around the corner

\n\n

Book your place at SpringOne in Dallas, TX for Sept 8-11 soon. It's simply the best opportunity to find out first hand all that's going on and to provide direct feedback. There will be deep dive sessions on Spring XD along with general Big Data talks to provide an introduction to the landscape and challenges in developing Big Data applications.

", + "categories" : [ + "Releases" + ] +}, + +{ + "_id" : "tag:spring.io,2014-07-30:1718", + "_class" : "example.springdata.mongodb.textsearch.BlogPost", + "title" : "This Week in Spring (Spring XD Edition) - July 29th, 2014", + "content" : "

Welcome to another installment of This Week in Spring! This week saw the release of the amazing Spring XD 1.0.0.RELEASE. The release announcement is a good place to start your big-data journey. There, you'll find links to other great posts, learning content, etc. This is a great opportunity to evaluate what you hope to get out of your data, and whether you're getting it. Spring XD is your big-data Swiss-army knife: it can support live, streaming workloads; batch-centric offline workloads; and general data integration solutions. If you digest but one post from this week's roundup, let it be the Spring XD release! (Then, write the data-integration solution to read and organize the rest of them using Spring XD!)

\n\n

Of course, there's a lot more to say on the matter, and on all matters Spring and things, so be sure to book your place at SpringOne2GX 2014 in Dallas, TX for Sept 8-11 soon. It's simply the best opportunity to find out first hand all that's going on and to provide direct feedback. There will be deep dive sessions on Spring XD along with general Big Data talks to provide an introduction to the landscape and challenges in developing Big Data applications.

\n\n

With that out of the way, let's get on to this week's roundup...

\n\n
    \n
  1. starting with... Spring XD 1.0.GA! I know, I know. We just did this. But, there are some great posts about Spring XD that you might take a moment to read, starting with this great introduction to Spring XD on InfoQ.
  2. \n
  3. Spring framework 4.1 RC1 dropped last week and this week we have some nice posts on Spring 4.1 features, including MVC improvements like JSONP, Google Protocol Buffers support, and Java 8 java.util.Optional support where appropriate...
  4. \n
  5. ... and a post on Spring MVC 4.1's very sensible approach to static web resource handling. Read the comments, too! There's some great feedback there, too.
  6. \n
  7. I'll be giving a webinar that looks at microservices with Spring Boot on September 16th and I hope you'll join me with questions, comments and more.
  8. \n
  9. Activiti project member Joram Barrez and I will be giving a webinar introducing how to use Spring and Activiti to deliver a one-two punch for process-centric applications - join us!
  10. \n
  11. \nSpring Data SR2 has just been released. This ia service release, and users are encouraged to upgrade at their earliest convenience.
  12. \n
  13. I was lucky enough to present at the Toronto Pivotal Open Source Hub meetup on Spring Boot. The recording's now available online, though I caution you the audio can be a bit choppy at times.
  14. \n
  15. Spring Cloud lead Ramnivas Laddad put up a nice post on how to use Spring Cloud programatically (as opposed to via XML, or even Spring's Java configuration). Spring Cloud is a client for PaaS-bound services like your databases, message brokers, caches, etc. It works on Heroku and Cloud Foundry. Besides working on Spring Cloud, Ramnivas is one of the original contributors to AspectJ and Spring's AOP support, and one of the early, lead architects behind Cloud Foundry. Ramnivas lives at the intersection between Spring and the cloud, and Spring Cloud is exactly what the doctor ordered!
  16. \n
  17. Spring Batch lead Michael Minella just announced that Spring Batch Admin 1.3.0 is now available. The latest release raises compatibility to the latest-and-greatest third party libraries and also represents the last cut to include the Spring Batch Integration module that now ships as part of Spring Batch 3.0.
  18. \n
  19. Did you see Michael Plöd's webinar on why he recommends Spring framework to his customers? The slidedeck's online and, I think, offers a suitably pragmatic look at the reasons for (and sometimes against) using Spring in your next project.
    \n
  20. \n
  21. The ZeroTurnaround team has put together a nice look at XRebel, an interactive profile designed to shine a light on performance issues in a running application. They disect the classic Petclinic sample application's use of sessions and see how they can optimize it. Interesting read!
    \n
  22. \n
  23. Idriss Mrabti has put together a nice post explaining how to load JSR 303 validation messages from internationalized (\"i18n\") MessageSources managed by Spring - handy!
  24. \n
  25. Shazin Sadakath has revisited one of his previous posts introductions to registering and using Spring-managed Filters with Spring MVC, this time doing so in Java configuration\n
  26. \n
  27. James Watters, director of product on the Cloud Foundry team, has put together an almost-too-abbreviated look at Cloud Foundry's features in 2 slides. I.. tried... but couldn't find anything wrong with this. If you understand those two slides, then you have enough to make the case for Cloud Foundry. Obviously, these aren't implementation instructions so much as a darned good first step at making the business case. Why Cloud Foundry for you and me? Because it's a perfect platform to run Spring-based workloads. There. That probably wouldn't even have needed a whole slide. :)
  28. \n
", + "categories" : [ + "Engineering" + ] +}, + +{ + "_id" : "tag:spring.io,2014-07-30:1717", + "_class" : "example.springdata.mongodb.textsearch.BlogPost", + "title" : "Webinar: Process Driven Spring Applications with Activiti - Sept 23rd", + "content" : "

Speakers: Josh Long and Joram Barrez, Activiti

\n\n

Today's applications are complex, distributed systems that - taken together - produce results. Tracking the flow of work through that system, however, becomes increasingly more painful as automated- and human-driven tasks are integrated into business processes. Business can't react to what it can't see. Business can't measure what it can't see. \"Workflow\" describes the sequence of processes through which a piece of work passes from initiation to completion. Workflow systems, like Activiti, describe and then execute these processes. Activiti is an open-source, Apache 2-licensed workflow engine that works with Spring and Spring Boot. In this webinar, join Spring Developer Advocate Josh Long and Activiti-ninja Joram Barrez for a look at how to distill, describe and reuse complex business processes using Spring (and Spring Boot) and Activiti.

\n\n

Tuesday, Sept 23rd, 2014 3:00PM BST (London UTC+01:00) Register

\n\n

Tuesday, Sept 23rd, 2014 10:00 am Pacific Daylight Time (San Francisco, UTC-07:00) Register

", + "categories" : [ + "News and Events" + ] +}, + +{ + "_id" : "tag:spring.io,2014-07-30:1716", + "_class" : "example.springdata.mongodb.textsearch.BlogPost", + "title" : "Webinar: Microservices with Spring Boot - Sept 16th", + "content" : "

Speaker: Josh Long, Pivotal

\n\n

Microservices? A thing? Or hype? What does it mean in practice? The answer, like so many Facebook statuses, is complicated. In broad strokes, Microservices offer a refreshed approach to application architecture. Microservices are a new way to describe many of the patterns that have fallen out of large-scale applications in practice over the recent years. There is no doubt that the approach works. The question is: how does one build a microservice architecture? Join Josh Long for this webinar introducing Spring's support for building microservice architectures.

\n\n

Tuesday, Sept 16th, 2014 3:00PM BST (London UTC+01:00) Register

\n\n

Tuesday, Sept 16th, 2014 10:00 am Pacific Daylight Time (San Francisco, UTC-07:00) Register

", + "categories" : [ + "News and Events" + ] +}, + +{ + "_id" : "tag:spring.io,2014-07-15:1690", + "_class" : "example.springdata.mongodb.textsearch.BlogPost", + "title" : "Using Spring Cloud programmatically", + "content" : "

In the last blog, I showed you how to use Spring Cloud's Java configuration option to obtain service connectors declaratively (there is also XML namespace support, if you need it). In this blog, we will take a closer look at how you would use Spring Cloud programmatically. This will help in the situations where you cannot use Java or XML configuration. It will also demystify how Spring Cloud works and prepare for the next blog in this series, where we discuss extending Spring Cloud.

\n\n

To work with Spring Cloud we need to access an object of the Cloud class. However, you can’t create a Cloud object directly (its constructor is not public). Instead, you will obtain it through CloudFactory.

\n\n
CloudFactory cloudFactory = new CloudFactory();\nCloud cloud = cloudFactory.getCloud();\n
\n\n

The cloud object created in this matter is suitable for the environment in which the app is operating. For example, if the app is running in Cloud Foundry it is configured to understand how it exposes services to the app. Note that creating a CloudFactory instance is somewhat expensive, therefore you should try to avoid creating multiple instances. If you use a dependency injection framework such as Spring, it will take care of avoiding multiple instances; otherwise, just manage it yourself.

\n\n

Once we have the cloud object, we can get application instance information, service information objects using various criteria, and service connectors using the specified criteria. Let's say, you want to get ServiceInfo objects for all services bound to the app and print the JDBC URL for relational services, you could use the following snippet:

\n\n
List<ServiceInfo> serviceInfos = cloud.getServiceInfos();\nfor (ServiceInfo serviceInfo : serviceInfos) {\n    if (serviceInfo instanceof RelationalServiceInfo) {\n        System.out.println(((RelationalServiceInfo) serviceInfo).getJdbcUrl());\n    }\n}\n
\n\n

This will produce output such as this:

\n\n
jdbc:postgresql://babar.elephantsql.com:5432/tbsonrjm?user=***&password=***\n
\n\n

Objects obtained using getServiceInfos() and its variations contain enough information such as URL and credentials to create a service connector. In some cases, obtaining a ServiceInfo object may be all you need, since you can always create suitable connectors (such as a DataSource) based on it. But in most cases, you would let Spring Cloud create a suitable service connector for a service. For example, if you would like to get a DataSource for the \"inventory-db\" service directly, you could use the following snippet:

\n\n
DataSource inventoryDataSource = \n    cloud.getServiceConnector(\"inventory-db\", DataSource.class, null);\n
\n\n

There is a variation of this method: getSingletonServiceConnector(), which you can use as follows:

\n\n
DataSource inventoryDataSource = cloud.getSingletonServiceConnector(DataSource.class, null);\n
\n\n

Here, it will return a DataSource for the unique relational database service bound to the app; if there is no such service or there is more than one service, it will throw an exception. We passed null as the last argument to both methods to use the default configuration for the created connector. However, you can pass a configuration you desire to override. For example, here we specify pool config as well as connection config for the datasource to be created.

\n\n
PoolConfig poolConfig = new PoolConfig(20, 200);\nConnectionConfig connectionConfig = new ConnectionConfig(\"characterEncoding=UTF-8\");\nDataSourceConfig serviceConfig = new DataSourceConfig(poolConfig, connectionConfig);\nDataSource invetoryDataSource = cloud.getSingletonServiceConnector(DataSource.class, serviceConfig);\n
\n\n

Last, there is a method to obtain application info that contains application id (cloud dependent, but typically the application name), application instance id, and loosely defined application properties. Let’s print all this information:

\n\n
ApplicationInstanceInfo appInstanceInfo = cloud.getApplicationInstanceInfo();\nSystem.out.println(\"Application id: \" + appInstanceInfo.getAppId());\nSystem.out.println(\"Application instance id: \" + appInstanceInfo.getInstanceId());\nfor (Map.Entry<String, Object> entry: appInstanceInfo.getProperties().entrySet()) {\n    System.out.println(\"Application property: \" + entry.getKey() + \"=\" + entry.getValue());\n}\n
\n\n

When you execute this code in an app running in Cloud Foundry, you get output similar to the following (abbreviated here). If the same app is running in Heroku, it will produce a similar output, however, with a different set of keys:

\n\n
\nApplication id: hello-spring-cloud\nApplication instance id: 8b523252a9d3478b92750ef27ad4e5b0\nApplication property: limits={mem=800, disk=1024, fds=16384}\nApplication property: application_version=b1257c57-2a5c-47aa-8ca7-5e8b6d9a7b9c\nApplication property: application_name=hello-spring-cloud\nApplication property: application_uris=[hello-spring-cloud.cfapps.io]\nApplication property: version=b1257c57-2a5c-47aa-8ca7-5e8b6d9a7b9c\nApplication property: name=hello-spring-cloud\nApplication property: space_name=development\nApplication property: space_id=5f629937-1821-4f48-9eb4-8c67c70c0df0\nApplication property: application_id=a345f90f-e075-4005-b003-f4ab86ad716a\nApplication property: instance_id=8b523252a9d3478b92750ef27ad4e5b0\nApplication property: instance_index=0\nApplication property: host=0.0.0.0\nApplication property: port=61023\nApplication property: start=2014-07-15 21:27:34 +0000\nApplication property: state_timestamp=1405459654\n
\n\n

That is pretty much all you need to know to use Spring Cloud programmatically. In the next blog, we will shift our focus on the extensibility aspect of Spring Cloud. Stay tuned.

", + "categories" : [ + "Engineering" + ] +} +] \ No newline at end of file diff --git a/mongodb/util/pom.xml b/mongodb/util/pom.xml new file mode 100644 index 00000000..786680e1 --- /dev/null +++ b/mongodb/util/pom.xml @@ -0,0 +1,21 @@ + + 4.0.0 + + spring-data-mongodb-utils + + Spring Data MongoDB - Example utilities + + + org.springframework.data.examples + spring-data-mongodb-examples + 1.0.0.BUILD-SNAPSHOT + + + + + junit + junit + + + diff --git a/mongodb/text-search/src/test/java/example/springdata/mongodb/util/MongoVersionRule.java b/mongodb/util/src/main/java/example/springdata/mongodb/util/RequiresMongoDB.java similarity index 78% rename from mongodb/text-search/src/test/java/example/springdata/mongodb/util/MongoVersionRule.java rename to mongodb/util/src/main/java/example/springdata/mongodb/util/RequiresMongoDB.java index 10947cf4..539ecd93 100644 --- a/mongodb/text-search/src/test/java/example/springdata/mongodb/util/MongoVersionRule.java +++ b/mongodb/util/src/main/java/example/springdata/mongodb/util/RequiresMongoDB.java @@ -15,6 +15,8 @@ */ package example.springdata.mongodb.util; +import java.net.UnknownHostException; + import org.junit.ClassRule; import org.junit.Rule; import org.junit.internal.AssumptionViolatedException; @@ -37,7 +39,7 @@ import com.mongodb.MongoClient; * @author Christoph Strobl * @since 1.6 */ -public class MongoVersionRule implements TestRule { +public class RequiresMongoDB implements TestRule { private String host = "localhost"; private int port = 27017; @@ -47,24 +49,24 @@ public class MongoVersionRule implements TestRule { private Version currentVersion; - public MongoVersionRule(Version min, Version max) { + public RequiresMongoDB(Version min, Version max) { this.minVersion = min; this.maxVersion = max; } - public static MongoVersionRule any() { - return new MongoVersionRule(new Version(0, 0, 0), new Version(9999, 9999, 9999)); + public static RequiresMongoDB anyVersion() { + return new RequiresMongoDB(new Version(0, 0, 0), new Version(9999, 9999, 9999)); } - public static MongoVersionRule atLeast(Version minVersion) { - return new MongoVersionRule(minVersion, new Version(9999, 9999, 9999)); + public static RequiresMongoDB atLeast(Version minVersion) { + return new RequiresMongoDB(minVersion, new Version(9999, 9999, 9999)); } - public static MongoVersionRule atMost(Version maxVersion) { - return new MongoVersionRule(new Version(0, 0, 0), maxVersion); + public static RequiresMongoDB atMost(Version maxVersion) { + return new RequiresMongoDB(new Version(0, 0, 0), maxVersion); } - public MongoVersionRule withServerRunningAt(String host, int port) { + public RequiresMongoDB serverRunningAt(String host, int port) { this.host = host; this.port = port; @@ -99,8 +101,8 @@ public class MongoVersionRule implements TestRule { DB db = client.getDB("test"); CommandResult result = db.command(new BasicDBObjectBuilder().add("buildInfo", 1).get()); this.currentVersion = Version.parse(result.get("version").toString()); - } catch (Exception e) { - e.printStackTrace(); + } catch (com.mongodb.MongoTimeoutException | UnknownHostException e) { + throw new AssumptionViolatedException("Seems as mongodb server is not running.", e); } }