Opening multiple SSH sessions with iTerm automatically

iTerm is great, but if you are working with a cluster of servers, it quickly becomes tedious to open an SSH session to each server and to configure splits so you can talk to all servers at once. Based upon the scripts here (but does not use splits) and here (but does not work with 7 servers which I needed in my case), I came up with the following AppleScript that works for me.

-- Launch iTerm and log into multiple servers using SSH
launch application "iTerm"
tell application "iTerm"
	activate
	-- Read serverlist from file path below
	set Servers to paragraphs of (do shell script "/bin/cat $HOME/serverlist")
	set num_hosts to count of Servers
	set current_host to 1
	repeat with nextLine in Servers
		-- If line in file is not empty (blank line) do the rest
		if length of nextLine is greater than 0 then
			set server to "nextLine"
			set term to (current terminal)
			-- Open a new tab
			tell term
				
				
				if current_host ≥ num_hosts / 2 then
					tell i term application "System Events" to keystroke "]" using command down
					tell i term application "System Events" to keystroke "D" using {command down, shift down}
				else
					tell i term application "System Events" to keystroke "d" using command down
				end if
				delay 1
				-- launch session "Default Session"
				tell the current session
					write text "ssh root@" & nextLine
					-- sleep to prevent errors if we spawn too fast
					do shell script "/bin/sleep 0.01"
				end tell
			end tell
		end if
		set current_host to current_host + 1
	end repeat
	-- Close the first tab since we do not need it
	terminate the first session of the current terminal
end tell

The script will launch iTerm and open as many split panes as is needed. The server ip addresses are read from ~/serverlist which you have to populate with the ip addresses of the servers you want to connect to (each on a separate line)

Mobaxterm solves this better I think (but is not available on Mac OS X, only on Windows). They have a single button that allows you to turn the tabs to each server into a split view and back. Would be great if iTerm would also implement this.

Posted in Uncategorized | Tagged , , | Leave a comment

Using Cassandra-unit with TestNG

I just started some tests with Cassandra and Spring Data Cassandra. I want to write some unit tests for this using TestNG. The Cassandra Unit project uses JUnit by default, but can be used with TestNG as well with some tweaking.

To start, add the following dependencies in your Maven pom:

<dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-cassandra</artifactId>
            <version>1.0.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cassandra</groupId>
            <artifactId>cassandra-all</artifactId>
            <version>2.0.5</version>
        </dependency>
        <dependency>
            <groupId>org.cassandraunit</groupId>
            <artifactId>cassandra-unit</artifactId>
            <version>2.0.2.1</version>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <artifactId>cassandra-all</artifactId>
                    <groupId>org.apache.cassandra</groupId>
                </exclusion>
                <exclusion>
                    <groupId>com.datastax.cassandra</groupId>
                    <artifactId>cassandra-driver-core</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.cassandraunit</groupId>
            <artifactId>cassandra-unit-spring</artifactId>
            <version>2.0.2.1</version>
            <scope>test</scope>
        </dependency>

Now we can setup Spring context loading with TestNG (using Java Config):

@Test
@ContextConfiguration
public class CassandraMessageRepositoryTest extends AbstractTestNGSpringContextTests
{

  public void testStoreMessage()
  {

  }

  @Configuration
  static class ContextConfiguration
  {
      // Add your @Bean's here
  }
}

After this, we need to start an embedded Cassandra before the Spring context loads, since the spring context needs to connect to the Cassandra server. For this, I have found no better way than overriding the @TestExecutionListeners. First create a new class:

import org.apache.cassandra.exceptions.ConfigurationException;
import org.apache.thrift.transport.TTransportException;
import org.cassandraunit.utils.EmbeddedCassandraServerHelper;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.test.context.TestContext;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;

import java.io.IOException;

public class PreContextLoadingTestExecutionListener extends DependencyInjectionTestExecutionListener
{
	protected void injectDependencies( final TestContext testContext ) throws Exception
	{
		doInitBeforeContextIsLoaded();

		Object bean = testContext.getTestInstance();
		AutowireCapableBeanFactory beanFactory = testContext.getApplicationContext().getAutowireCapableBeanFactory();
		beanFactory.autowireBeanProperties( bean, AutowireCapableBeanFactory.AUTOWIRE_NO, false );
		beanFactory.initializeBean( bean, testContext.getTestClass().getName() );
		testContext.removeAttribute( REINJECT_DEPENDENCIES_ATTRIBUTE );
	}

	private void doInitBeforeContextIsLoaded() throws InterruptedException, TTransportException, ConfigurationException, IOException
	{
		EmbeddedCassandraServerHelper.startEmbeddedCassandra();
	}
}

And register this listener in the test:

@Test
@ContextConfiguration
@TestExecutionListeners(inheritListeners = false, value = {DirtiesContextTestExecutionListener.class,
		PreContextLoadingTestExecutionListener.class})
public class CassandraMessageRepositoryTest extends AbstractTestNGSpringContextTests
{

}

The inner class ContextConfiguration looks like this in my example:

@Bean
		public MessageSourceService messageSourceService()
		{
			return mock( MessageSourceService.class );
		}

		@Bean
		public MessageRepository messageRepository() throws Exception
		{
			return new CassandraMessageRepository( cassandraTemplate(), messageSourceService(), objectMapper() );
		}

		@Bean
		public CassandraClusterFactoryBean cluster()
		{
			CassandraClusterFactoryBean cluster = new CassandraClusterFactoryBean();
			cluster.setContactPoints( "127.0.0.1" );
			cluster.setPort( 9142 );
			return cluster;
		}

		@Bean
		public CassandraSessionFactoryBean session() throws Exception
		{
			CassandraSessionFactoryBean session = new CassandraSessionFactoryBean();
			session.setCluster( cluster().getObject() );
			session.setConverter( converter() );
			session.setSchemaAction( SchemaAction.NONE );
			return session;
		}

		@Bean
		public CassandraOperations cassandraTemplate() throws Exception
		{
			return new CassandraTemplate( session().getObject() );
		}

		@Bean
		public CassandraMappingContext mappingContext()
		{
			return new BasicCassandraMappingContext();
		}

		@Bean
		public CassandraConverter converter()
		{
			return new MappingCassandraConverter( mappingContext() );
		}

		@Bean
		public ObjectMapper objectMapper()
		{
			ObjectMapper objectMapper = new ObjectMapper();
			objectMapper.registerModule( new MyCustomJacksonModule() );
			return objectMapper;
		}

A few points to note:
* CassandraMessageRepository is the class I want to test here
* The port of the embedded server is 9142, while the default port in a Cassandra installation is 9042.
* mock() is a Mockito static method to mock a collaborator to my class under test
* CassandraSessionFactoryBean should not declare the keyspace to use. A keyspace is created by cassandra-unit automatically.

With this in place, I can autowire what I need in my test:

	@Autowired
	private CassandraMessageRepository m_messageRepository;

	@Autowired
	private CassandraOperations m_cassandraOperations;

	@Autowired
	private Session m_session;

And then finally, the actual test:

	public void testStoreMessage()
	{
		ClassPathCQLDataSet dataSet = new ClassPathCQLDataSet( "com/mycompany/myapp/infrastructure/message/cassandra/create-event_message-table.cql" );
		CQLDataLoader loader = new CQLDataLoader( m_session );
		loader.load( dataSet );

		assertThat( m_cassandraOperations.queryForObject( "select count(*) from event_message", Long.class ) ).isEqualTo( 0 );

		m_messageRepository.storeMessage( Messages.createEventMessage() );

		assertThat( m_cassandraOperations.queryForObject( "select count(*) from event_message", Long.class ) ).isEqualTo( 1 );
	}

There are basically 4 steps in this method:
* First we load the CQL script from the classpath. For this we need the autowired Session
* We assert that the event_message table is empty (Using AssertJ statements)
* We store a message through our repository
* We check that there is 1 record in our table

If you have more then 1 test, you need to clean your database in between:

	@AfterMethod
	public void cleanCassandra() throws InterruptedException, TTransportException, ConfigurationException, IOException
	{
		EmbeddedCassandraServerHelper.cleanEmbeddedCassandra();
	}

It took me some time to figure all this out, so in case someone wants to use Cassandra Unit with TestNG, above is how to do it.

Posted in Programming | Tagged , , , , | Leave a comment

Release JIRA Database Values plugin 3.3

Just a quick note that I released version 3.3 of my JIRA database values plugin. It has only 1 bugfix: https://bitbucket.org/wimdeblauwe/jdvp/issue/14/ajax-style-field-dont-run-in-popup-screen but an important one given the 5 votes it got. Note that I cannot take any credit for the fix, user Mirek Hankus provide it. Thanks for it!

Posted in Programming | Tagged , | Leave a comment

Switching easily between Java JDKs on Mac OS X

I just came upon a neat little trick to easily switch what JDK you are using on the command line on Mac OS X (10.9.2 is the version I am using), courtesy of this AskDifferent answer.

First, add the following aliases in ~/.profile file:

alias setJdk6='export JAVA_HOME=$(/usr/libexec/java_home -v 1.6)'
alias setJdk7='export JAVA_HOME=$(/usr/libexec/java_home -v 1.7)'
alias setJdk8='export JAVA_HOME=$(/usr/libexec/java_home -v 1.8)'

Open a new terminal window or use source ~/.profile to load the aliases.

Now you can easily switch between the installed JDKs:

> setJdk6

We can verify that Maven picks this up correctly:

> mvn --version
Apache Maven 3.0.4 (r1232337; 2012-01-17 09:44:56+0100)
Maven home: /Applications/maven/apache-maven-3.0.4
Java version: 1.6.0_65, vendor: Apple Inc.
Java home: /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
Default locale: en_US, platform encoding: MacRoman
OS name: "mac os x", version: "10.9.2", arch: "x86_64", family: "mac"

To go to JDK 7:

> setJdk7

And Maven shows:

> mvn --version
Apache Maven 3.0.4 (r1232337; 2012-01-17 09:44:56+0100)
Maven home: /Applications/maven/apache-maven-3.0.4
Java version: 1.7.0_45, vendor: Oracle Corporation
Java home: /Library/Java/JavaVirtualMachines/jdk1.7.0_45.jdk/Contents/Home/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "mac os x", version: "10.9.2", arch: "x86_64", family: "mac"

This works just as well to switch to the just released JDK 8:

> setJdk8

Maven output:

> mvn --version
Apache Maven 3.0.4 (r1232337; 2012-01-17 09:44:56+0100)
Maven home: /Applications/maven/apache-maven-3.0.4
Java version: 1.8.0, vendor: Oracle Corporation
Java home: /Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "mac os x", version: "10.9.2", arch: "x86_64", family: "mac"

Voila, simpel and effective!

 

 

Posted in Programming | Tagged , , , | 4 Comments

Synchronizing LiquidPlanner with Exchange calendars

Quite some time ago I wrote Groovy code to synchronize Atlassian JIRA with LiquidPlanner. You can find my 2 part blog post on that here and here. In case you don’t know LiquidPlanner, be sure to check it out, it is the best project management/scheduling tool I know.

One thing that was missing is the integration of the holidays into LiquidPlanner. Since the holidays are already in everybody’s Outlook Calendar, I could get the needed information from there.
At first, I was afraid that it would be difficult to do from Groovy/Java, but it turns out if your Microsoft Exchange version is fairly recent, there is a very nice Java library from Microsoft itself you can use. It is called the EWS Java API which stands for Exchange Web Services Java API. Basically, it is a Java library that uses the Web Services API from Exchange, a perfect fit for what I needed to do.

Step 1. Connect to Exchange and get appointments

To connect to exchange we just need the credentials of a domain user. The auto discovery mechanism will automatically find the Exchange server:

private static ExchangeService createExchangeService( LiquidPlannerToolsConfiguration configuration )
{
	logger.info( "Connecting to Exchange..." )
	ExchangeService service = new ExchangeService( ExchangeVersion.Exchange2010_SP2 )
	ExchangeCredentials credentials = new WebCredentials( configuration.exchangeUser, 
								configuration.exchangePassword, 
								configuration.exchangeDomain )
	service.setCredentials( credentials )
	service.autodiscoverUrl( configuration.exchangeAutodiscoverEmail )
	return service
}

The LiquidPlannerToolsConfiguration class is a simple POJO that contains the configuration parameters for the script. Now that we are connected, we can query Exchange for the calendar of a user:

private static def getAppointments( ExchangeService service, String emailAddress )
{
	def Mailbox mailbox = new Mailbox( emailAddress )
	def folderId = new FolderId( WellKnownFolderName.Calendar, mailbox )

	def startDate = DateTime.now().toDate()
	def endDate = DateTime.now().plusMonths( 6 ).toDate()

	def allAppointments = service.findAppointments( folderId, new CalendarView( startDate, endDate ) )
	def relevantAppointments = allAppointments.findAll { Appointment appointment -> appointment.duration.hours >= 4 }
	logger.debug "Found ${allAppointments.items.size()} appointments of which ${relevantAppointments.size()} are relevant"
	return relevantAppointments
}

With the ExchangeService and the email address of a user, we ask for all the appointments in the coming 6 months. Using Groovy’s findAll() method, I filter out appointments that are shorter than 4 hours. I only want to put half days and days that people are not in the office into LiquidPlanner.

Step 2. Create appointments in LiquidPlanner

Now that I have all the relevant appointments, I need to create an entry for each of those in LiquidPlanner:

private static def createAppointmentInLP( LiquidPlannerService liquidPlannerService,
					Appointment appointment,
					LiquidPlannerUserVacationPackage userVacationPackage )
{
	liquidPlannerService.createAppointment( userVacationPackage,
						getAppointmentIdForExternalReference( appointment ),
						appointment.subject,
						new DateTime( appointment.start, getTimeZone( appointment.startTimeZone ) ),
						new DateTime( appointment.end, getTimeZone( appointment.endTimeZone ) ) )
}

private static String getAppointmentIdForExternalReference( Appointment appointment )
{
	// LiquidPlanner has trouble matching the id afterwards if there is a '+' in there, so we replace it with something else to work around it.
	return appointment.id.uniqueId.replace( '+', "_" )
}

Everything in LiquidPlanner has a field ‘External Reference’ which is great if you have to integrate with external systems. Here, I use this field to put in the unique id that exchange associates with each calendar entry (You would be amazed that there are enough unique id’s in the world for all the meetings). I can use this id later to know if an appointment is already created in LiquidPlanner or not.

Note: I had issues with putting in the unique id from Exchange in the External Reference field of LiquidPlanner. I could not get back entries if the reference contained a plus (+) sign, so I replace it with an underscore just to avoid that problem.

The LiquidPlannerService hides all the HTTP/JSON stuff to interact with the LiquidPlanner API. This is the createAppoinment method:

public void createAppointment( LiquidPlannerUserVacationPackage userVacationPackage, String exchangeAppointmentId, String subject, DateTime startDateTime, DateTime endDateTime )
	{
		String requestPath = 'workspaces/' + LP_WORKSPACE_ID + '/events/';
		liquidPlanner.request( Method.POST, ContentType.JSON ) { req ->
			uri.path = requestPath;

			def startTime = LP_DATE_FORMATTER.print( startDateTime )
			def endTime = LP_DATE_FORMATTER.print( endDateTime )
			logger.debug "$startTime - $endTime : ${subject}"
			body = [event: [
					name: subject,
					owner_id: userVacationPackage.ownerId,
					parent_id: userVacationPackage.id,
					external_reference: exchangeAppointmentId,
					start_date: startTime,
					finish_date: endTime]]

			response.success = { resp, json ->
				logger.debug "Succesfully created appointment in LP"
			}
			response.failure = { resp ->
				throw new RuntimeException( "Unable to create appointment in LP: ${resp.status} - ${requestPath}" )
			}
		}

		Thread.sleep( m_sleepBetweenLPRequests );
		// Sleep a bit to avoid hitting the liquidplanner server too fast (See http://www.liquidplanner.com/api-guide/technical-reference/request-throttling.html)

	}

The liquidPlanner is a Groovy HTTP Builder object. The LiquidPlannerUserVacationPackage represents a vacation in the bounded context of LiquidPlanner (I had just finished reading Implementing Domain-Driven Design when I implemented this, and incorporating some of the ideas really made my code a lot better):

import net.sf.json.JSONObject

class LiquidPlannerUserVacationPackage
{
	String id
	String ownerId
	String name
	String emailAddress

	public static LiquidPlannerUserVacationPackage fromJSON( JSONObject jsonObject )
	{
		return new LiquidPlannerUserVacationPackage(
				id: jsonObject.id,
				ownerId: jsonObject.owner_id,
				name: jsonObject.name,
				emailAddress: jsonObject.external_reference )
	}
}

Step 3. Prepare LiquidPlanner so the script has enough information

To make all of this work, there is some preparation in LiquidPlanner needed.
First, you need to create a top-level package that will have all the vacations. Below that, I create a package per user that is in LiquidPlanner. There are a lot more users in Exchange than there are people using LiquidPlanner, so it makes no sense to try to autogenerate this from Exchange in our case.
Each ‘user’ package will have the email address of the person set as ‘External Reference’. The script will use that to connect to Exchange to get the appointments of each user.
Note that all the users will need to have shared their calendar with the user you use to connect to Exchange initially, otherwise, it cannot work!

This is the code that retrieves all the LiquidPlanner packages (1 per user):

public Set<LiquidPlannerUserVacationPackage> getVacationPackages()
{
	def JSONObject outlookCalendarFolder = liquidPlanner.get( path: 'workspaces/' + LP_WORKSPACE_ID + '/packages', query: ['filter[]': ['name="Vacations"']] );
	logger.debug "Outlook calendars package found under id " + outlookCalendarFolder.id

	def JSONArray userFolders = liquidPlanner.get( path: 'workspaces/' + LP_WORKSPACE_ID + "/treeitems/" + outlookCalendarFolder.id, query: ['depth': '1'] ).children
	return userFolders.findAll {
		!(it.external_reference instanceof JSONNull) && isNotBlank( it.external_reference )
	}.collect {
		LiquidPlannerUserVacationPackage.fromJSON( it )
	}
}

What this does is first searching for a package called ‘Vacations’. Then it takes all the children at the first depth level, which are our user packages. The returned JSON is then converted into LiquidPlannerUserVacationPackage so that the rest of the script does not need to know that we are using a JSON REST API to talk to LiquidPlanner.

To check if an appointment already exists in LiquidPlanner, we need this piece of code:

public boolean doesAppointmentExist( String exchangeAppointmentId )
{
	def queryFilter = 'external_reference="' + exchangeAppointmentId + '"'
	JSONArray appointmentInLP = liquidPlanner.get( path: 'workspaces/' + LP_WORKSPACE_ID + '/events', query: ['filter[]': [queryFilter]] );

	def result = appointmentInLP.size() > 0
	if (!result)
	{
		logger.debug "Could not find appointment with id ${exchangeAppointmentId} in LP"
	}
	return result;
}

Notice how we can directly get the event in LiquidPlanner with the matching external reference. I use this to avoid creating new entries in LiquidPlanner for appointments that already exist.

This is it. This post has showed you the most important bits and pieces to synchronize LiquidPlanner with calendars in Microsoft Exchange.

Posted in Programming | Tagged , , | Leave a comment

Creating a REST web application in 4 classes

After visiting Spring Exchange in London, I wanted to try Spring Boot and Spring Data. I managed to it this weekend and was quite impressed.

First, I needed an entity class:

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class SensorEndpoint
{
	@Id
	@GeneratedValue()
	private long id;
	private String name;
	private String endpointUrl;

	// for hibernate
	public SensorEndpoint()
	{
	}

	public SensorEndpoint( String name, String endpointUrl )
	{
		this.name = name;
		this.endpointUrl = endpointUrl;
	}

        // Getters and Setters omitted
}

My entity just has an id which will be used as primary key in the database, a descriptive name and an other String (purpose of this one is not important now).

Now I want a Repository to store and retrieve these objects in the database. Spring Data makes this super easy. I only have to create an interface, implementation is done automatically by Spring Data:

import org.springframework.data.repository.CrudRepository;

import java.util.List;

public interface SensorEndpointRepository extends CrudRepository<SensorEndpoint,Long>
{
	List<SensorEndpoint> findByName(String name);
}

This is all that needs to be done. The ‘findByName’ method is optional. The CrudRepository already allows the most important operations like getting all, getting one by primary key, saving one, …

Now we need to expose this over HTTP REST API. For this we create a Controller:

import com.google.common.collect.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@RestController
public class HelloController
{
	@Autowired
	private SensorEndpointRepository m_repository;

	@RequestMapping("/")
	public String index()
	{
		return "Greetings from Spring Boot!";
	}

	@RequestMapping(value="/endpoints", method = RequestMethod.GET)
	public List<SensorEndpoint> getAllEndpoints()
	{
		Iterable<SensorEndpoint> all = m_repository.findAll();
		return Lists.newArrayList( all );
	}

	@RequestMapping(value="/endpoints/{id}", method = RequestMethod.GET)
	public SensorEndpoint getEndpoint( @PathVariable("id") long id )
	{
		return m_repository.findOne( id );
	}

	@RequestMapping(value="/endpoints/add", method=RequestMethod.POST)
	public SensorEndpoint addEndpoint( @RequestParam("name") String name,
									   @RequestParam("url") String endpointUrl )
	{
		return m_repository.save( new SensorEndpoint( name, endpointUrl ) );
	}
}

The controller is annotated with @RestController to tell Spring that this class is a web controller for REST. Using the @RequestMapping, @PathVariable and @RequestParam annoations makes it great to define the URLs in a very simple way. With this controller the following URLs can be hit:

* http://localhost:8080/endpoints -> Will return all the objects in the repository in JSON
* http://localhost:8080/endpoints/1 -> Will return the object with primary key 1 in JSON
* http://localhost:8080/endpoints/add -> if you do a POST with a ‘name’ and ‘url’ request parameters, it will be added to the database.

Note how I can just return the object or a list of objects and it gets marshalled into JSON automatically.

The last class we need is to start the application:

package hello;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jmx.export.annotation.AnnotationMBeanExporter;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;
import java.util.Arrays;

import static org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType.H2;

@Configuration
@EnableAutoConfiguration
@ComponentScan
@EnableJpaRepositories
public class Application
{
	@Bean
	public DataSource dataSource()
	{
		return new EmbeddedDatabaseBuilder().setType( H2 ).build();
	}

	@Bean
	public LocalContainerEntityManagerFactoryBean entityManagerFactory( DataSource dataSource, JpaVendorAdapter jpaVendorAdapter )
	{
		LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
		lef.setDataSource( dataSource );
		lef.setJpaVendorAdapter( jpaVendorAdapter );
		lef.setPackagesToScan( "hello" );
		return lef;
	}

	@Bean
	public JpaVendorAdapter jpaVendorAdapter()
	{
		HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
		hibernateJpaVendorAdapter.setShowSql( false );
		hibernateJpaVendorAdapter.setGenerateDdl( true );
		hibernateJpaVendorAdapter.setDatabase( Database.H2 );
		return hibernateJpaVendorAdapter;
	}

	@Bean
	public PlatformTransactionManager transactionManager()
	{
		return new JpaTransactionManager();
	}

	public static void main( String[] args )
	{
		ApplicationContext ctx = SpringApplication.run( Application.class, args );

                // Put in some test data
		SensorEndpointRepository bean = ctx.getBean( SensorEndpointRepository.class );
		bean.save( new SensorEndpoint( "Kortrijk", "http://www.kortrijk.be/api") );
		bean.save( new SensorEndpoint( "Gent", "http://www.gent.be/api") );
	}

}

This uses Spring Boot and Spring java configuration to bootstrap the application. The final piece of the puzzel is the Maven pom.xml with the dependencies (Note that Gradle can also be used, but I am more familiar with Maven):

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.springframework</groupId>
    <artifactId>gs-spring-boot</artifactId>
    <version>0.1.0</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>0.5.0.M6</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jpa</artifactId>
            <version>1.4.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>4.0.0.RC1</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>4.2.1.Final</version>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.3.172</version>
        </dependency>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>12.0</version>
        </dependency>

    </dependencies>

    <properties>
        <start-class>hello.Application</start-class>
    </properties>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-snapshots</id>
            <url>http://repo.spring.io/libs-snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>spring-snapshots</id>
            <url>http://repo.spring.io/libs-snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>
</project>

We depend on 2 Spring Boot starter projects: spring-boot-starter-web and spring-boot-starter-actuator. Next to that we need Spring Data, so we pull in ‘spring-data-jpa’, ‘spring-orm’ and ‘hibernate-entitymanager’. As a database, I use an embedded H2 database. If you want to run this example with MySQL, just import the MySQL driver instead.

To run the project, import the Maven pom in IntelliJ IDEA and run the ‘Application’ class. After that go to one of the URLs I mentioned and you should see the JSON in your browser. The HTTP POST can easily be done from the built-in REST client in IntelliJ.

Posted in Programming | Tagged , | 4 Comments

JIRA Database Values 3.1 released

I have just released the version 3.1 of the JIRA Database values plugin. It fixes the issue that sometimes the AJAX style input did not work in the create issue screen. The plugin is compatible with Atlassian JIRA 6.x.

See https://marketplace.atlassian.com/plugins/org.deblauwe.jira.plugin.database-values-plugin for more info and download.

Posted in Programming | Tagged | Leave a comment