Spring Boot using multiple datasources

Java, programming, Spring Boot

I cannot believe how little info there is on using multiple Datasources in Spring Boot. Out of the box, Spring Boot makes it very easy to configure the default Datasource: tweak a few properties for spring.datasource.* and I’m done.

However, if I want to use multiple datasources, very little documentation/instruction is available. The pieces are all there, but there is just no documentation. Even Manning’s Spring Boot in Action doesn’t have anything on the topic.

Well. After some searching and experimenting, I finally figured it out. Here are my findings: http://www.therealvan.com/multidsdemo.html

 

Spring Boot Command Line program

programming, Spring Boot

Command line program w/ Spring Boot

To write a command line program (e.g. launched w/ static void main(String args[])), have the main application class implements org.springframework.boot.CommandLineRunner and implement the function:

public void run(String... args) throws Exception
Running the program can be done with:
java -jar myjar.jar args... 
or with:
 mvn spring-boot:run -Drun.arguments="args..."
See Link to stackoverflow.
One oddity is that, when looking at the logs, the actual running of the program looks like it all happens within the initialization phase of the program:
  .   ____          _            __ _ _
 /\ / ___'_ __ _ _(_)_ __  __ _    
( ( )___ | '_ | '_| | '_ / _` |    
 \/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |___, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.2.4.RELEASE)

2015-08-19 16:11:20 INFO  MyApplication:47 - Starting MyApplication on ...2015-08-19 16:11:20 DEBUG MyApplication:50 - Running with Spring Boot v1.2.4.RELEASE, Spring v4.1.6.RELEASE
2015-08-19 16:11:20 INFO  AnnotationConfigApplicationContext:510 - Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@6fa107f2: startup date [Wed Aug 19 16:11:20 PDT 2015]; root of context hierarchy
2015-08-19 16:11:20 INFO  ProfilesConfigFileLoader:185 - Skip unsupported property name region in profile [default].

... program runs here ...

2015-08-19 16:11:23 INFO  MyApplication:56 - Started MyApplication in 3.484 seconds (JVM running for 7.704)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

EC2: “chmod ugo+rw ~” breaks SSH

AWS, ec2, programming, ssh

“chmod go+rw ~” breaks SSH

Quick note: running

chmod go+rw /home/ec2-user

could break subsequent attempts to SSH into the EC2 instance.

When all the usual suspects regarding SSH identity files, keypairs, etc., are ruled out, one not-well documented cause for the dreaded

Permission denied (publickey).

error could be that the default permissions on /home/ec2-user was modified.

The permissions can be modified temporarily in order to perform some tasks. However, before exiting that SSH session, be sure to restore the original ACL (0700) on that home dir lest all subsequent SSH attempts will fail.

 

Spring boot w/ Thymeleaf, jQuery & jQuery UI, and Bootstrap

programming, Spring Boot, Uncategorized

A more typical/modern setup would be to replace JSP with one of the template engines and JS and styling libraries:

Add Thymeleaf to Dependency

Add this to the project POM:

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>

Installing files

jQuery

Copy into src/main/resources/static/js/ the downloaded jquery-a.b.c.js (or jquery-a.b.c.min.js)

jQuery UI

  • Copy into src/main/resources/static/js/ the downloaded jquery-ui.js (or jquery-ui.min.js)
  • Copy into src/main/resources/static/css/ the downloaded jquery-ui*.css
  • Copy into src/main/resources/static/css/ the images subdirectory itself (i.e. as src/main/resources/static/css/images)

Bootstrap

Copy into src/main/resources/static/ the three subdirectories from the Bootstrap distribution:

  • css
  • fonts
  • js

Include the files into templates

This can be done per-template, but probably easier to have a fragment that templates can call.

Start with a fragment file

Create fragment template such as src/main/resources/templates/fragments/js.html

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<body>
<div th:fragment="bootstrap">
    <link rel="stylesheet" href="/css/bootstrap.min.css"/>
    <script src="/js/bootstrap.min.js"></script>
</div>
<div th:fragment="jquerys">
    <link rel="stylesheet" href="/css/jquery-ui.css"/>
    <script src="/js/jquery-1.11.2.min.js"></script>
    <script src="/js/jquery-ui.min.js"></script>
</div>
</body>
</html>

NOTE the two jquery libraries are combined into one fragment “jquerys”. They can be broken up as needed.

Reference various fragments in templates as needed

E.g. from src/main/resources/templates/index.html:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
...
<div th:include="fragments/js :: jquerys"></div>
<div th:include="fragments/js :: bootstrap"></div>
....

Spring Boot w/ JSP

Java, maven, programming, Spring Boot

Project Setup

From the CLI or http://start.spring.io/, initialize a project with “web” capability.  What ends up happening is addition of the dependency:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>

Start with this directory structure. Be sure the controller (and any other Spring beans) are located under where the Application class (JspDemoApplication in this example) is.

...
  src/
    main/
      java/
        org/
          van/
            jspdemo/
              JspDemoApplication.java
              controller/
                DemoController.java
      resources/
        application.properties
      webapp/
        WEB-INF/
          jsp/
            demoindex.jsp

Controller and View

Add a controller file DemoController.java (see tree above for location):

...

@Controller
@RequestMapping("/jspdemo")
class DemoController { 
  @RequestMapping("/index")
  public String index(@RequestParam("name") String name, Model model) {
    model.addAttribute(name.toUpperCase());
    return "demoindex";  // view/JSP name
  }
}

Then the view file demoindex.jsp (see tree above for location). NOTE that the webapp/WEB-INF/jsp subdirectory needs to be created.

<html>
  <div>
    Hello, ${name}.
  </div>
</html>

Add support for JSP

Add these dependencies:

<dependency>
  <groupId>org.apache.tomcat.embed</groupId>
  <artifactId>tomcat-embed-jasper</artifactId>
  <scope>provided</scope>
</dependency>
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>jstl</artifactId>
  <scope>provided</scope>
</dependency>

Add these to application.properties:

spring.view.prefix: /WEB-INF/jsp/
spring.view.suffix: .jsp

SimpleDB w/ AWS JDK

programming

Problem to solve

A flow on the App server triggers an event that needs to be handled by several listeners that then need to each run for a couple of seconds (or more).  Obviously the Web request has to return relatively fast, so doing all that synchronously is out of the question.

One solution is to use a thread pool with N worker threads to do these queued up tasks.  But that approach also takes processing power away from the App server.  Works some times and not others, depending on the load and cost of these tasks.

Another solution, if timing is not that important, is to push up a request into a persistent message queue and have worker processes pull requests off of that queue and process each.  Nice separation of concerns.  Decoupling. Etc.  All the nice things that message queue vendors say.

Each message has to be processed in sequence relative to others.  In other words, FIFO.

Why SimpleDB?

There are full-blown message queue solutions (ZeroMQ & ActiveMQ come to mind). But then I’d have to get the “DevOps” people to stand one up and manage it which is kinda like pulling teeth.

Then there’s the good ‘ol stand-by: Postgresql.  Others have used a dedicated table for queuing purposes, with a “status” column and values like “Pending,” “Processing,” “Success,” and “Fail.”  It’s persistent, and the synthetic row ID can be used for sequencing to get the FIFO iteration. But I have hated the idea of using a table to implement a queue.  Mostly because all the hassle of checking in a migration script to create the damn table and a lot of boiler-plate process to go through.  And the schema is inflexible if I ever need to tweak the message structure.  So I either need to worry about schema changes or break the 1st normal form.

Then there are SaaS offerings.  We use EC2 and various other services from the AWS stack, so it makes sense to see what can work.

SQS — not FIFO

Initially I had gone with SQS for a work queue. It worked well for some other things I’ve done in the past.  BUT in this case I actually need strict ordering which SQS is not providing. I tried to get around that using a timestamp in the message, but unless I read all the packets (or a sufficient number of them), I can’t tell if the first message I get is the right one.  Then I have to either cache the message locally to sort them and then work through them locally and/or re-queue the rest.  That makes them further back in the queue when they should probably be at the head, and the sequencing just got worse.  Yuck.

Comes SimpleDB

So then comes SimpleDB. It’s persistent, almost like a RDBMS without the strict schema and DDL BS (those are good things for domain data, to be sure–just not for my message queue).

So each “row” will have the attribute “timestamp” which currently is just that Unix time (System.currentTimeInMillis())–a convenient long that is easy to sort by to get the FIFO behavior. And the rest of the attributes are basically whatever I need for my message.

AWS Console: no SimpleDB here

I had to check my glasses because I cannot find a page/console for SimpleDB. Almost all of the services in the AWS suite each at least has a page for management of instances of the service.  DynamoDB has one, for instance.  (Incidentally, I didn’t go with DynamoDB since it just felt like overkill at the time.)

Anyway.  No management page.  So it’s a bit frustrating to get thing up to test and figuring out what went wrong when things don’t work.  There IS a tool: SimpleDB Scratchpad  (https://aws.amazon.com/code/JavaScript/1137), but that needs to be downloaded and “installed.” The installation process is more than just un-packaging the files:

  1. Change the various endpoints to point to the correct one for the region I want (i.e. change “sdb.amazonaws.com” to “sdb.us-west-2.amazonaws.com” for the US-WEST-2 region).
  2. Pre-fill the key and secret in the navbar since it’s tedious to type that in all the time.

Once that’s all done, simply bringing up the webapp/index.html as a file in a browser pretty much works–except not for Chrome because it thinks it’s more clever than you about security of Javascript.  Fine.  Firefox, it is.

Weird SELECT syntax

The SELECT query syntax is deceptively similar to SQL but not really it.  Obviously joins are out of the question, but even simple queries have nuances:

  • If your table (“domain”) has anything other than alphanumeric and _ OR if it starts with a digit, you need to quote it with back-tick (`).  E.g. SELECT * FROM `my-domain` …
  • To sort on (aka ORDER BY) something, that thing has to be in the WHERE clause (huh ?!) E.g. SELECT … WHERE timestamp > ‘0’ ORDER BY timestamp
  • Why the quote on 0? All literals seem to be of type text, even things like the timestamp.

 

Aptana w/ Rails for Windows 7

ide, programming, rails

See http://www.therealvan.com/pn/?p=186 for installing: Rails 3.0.3 & MySQL on Windows 7.

After installing those, and once work begins, chances are an IDE w/ line-debugging capabilities are needed.

Aptana Studio 3 seems to be the best (free) IDE right now:

http://www.aptana.com/products/studio3/download.html

But to get that working fully for debugging, a gem needs to be installed:

gem install ruby-debug-ide

Otherwise, the “Debug Server” option will frustratingly do nothing in the IDE.