Introduction to using JavaFX with afterburner.fx

I wanted to try out afterburner.fx, a JavaFX framework which describes itself as:

a minimalistic (3 classes) JavaFX MVP framework based on Convention over Configuration and Dependency Injection.

For this purpose I created a simple note taking application which looks like this when finished:

Screen Shot 2015-03-24 at 19.38.24

First off, the domain class that represents a Note:

public class Note
{
	private long id;
	private String title;
	private String content;

// Getter and setters ommitted

I also made a NoteService to retrieve the current notes and update an existing note:

public interface NoteService
{
	SortedSet<Note> getNotes();

	void updateNode( Note note );
}

I have made an in memory implementation for testing purpose:

public class InMemoryNoteService implements NoteService
{
	private Map<Long,Note> notes = new HashMap<>();

	public InMemoryNoteService()
	{
		notes.put( 1L, new Note( 1, "note title 1", "some more info on the note" ) );
		notes.put( 2L, new Note( 2, "note title 2", "some more info on the other note" ) );
	}

	@Override
	public SortedSet<Note> getNotes()
	{
		TreeSet<Note> treeSet = new TreeSet<>( new NoteComparator() );
		treeSet.addAll( notes.values() );
		return treeSet;
	}

	@Override
	public void updateNode( Note note )
	{
		notes.put( note.getId(), note );
	}

}

Now, off to the actual JavaFX stuff. We start with creating our FXML code that defines the components in our application:

<SplitPane dividerPositions="0.3" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity"
           minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1"
           xmlns="http://javafx.com/javafx/8.0.40" fx:controller="org.deblauwe.afterburnernote.view.MainPresenter">
    <items>
        <BorderPane minHeight="0.0" minWidth="100.0" prefHeight="398.0" prefWidth="176.0"
                    styleClass="defaultBorderSpacing">
            <center>
                <ListView fx:id="listView"/>
            </center>
        </BorderPane>
        <GridPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0" styleClass="defaultBorderSpacing">
            <rowConstraints>
                <RowConstraints vgrow="NEVER" valignment="TOP"/>
                <RowConstraints vgrow="ALWAYS" valignment="TOP"/>
                <RowConstraints vgrow="NEVER"/>
            </rowConstraints>
            <columnConstraints>
                <ColumnConstraints hgrow="NEVER"/>
                <ColumnConstraints hgrow="ALWAYS"/>
            </columnConstraints>
            <Label text="Title" GridPane.rowIndex="0" GridPane.columnIndex="0"/>
            <TextField fx:id="titleField" prefWidth="308.0" GridPane.rowIndex="0" GridPane.columnIndex="1"/>
            <Label layoutX="14.0" text="Todo" GridPane.rowIndex="1" GridPane.columnIndex="0"/>
            <TextArea fx:id="contentField" prefWidth="308.0" GridPane.rowIndex="1" GridPane.columnIndex="1"/>
            <Button fx:id="saveButton" text="Save" GridPane.rowIndex="2" GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.halignment="RIGHT"/>
        </GridPane>
    </items>
</SplitPane>

What is important is the use of the fx:controller attribute which needs to point a controller that defines the behaviour. I named my FXML main.fxml and I followed the convention to name the controller nameofviewPresenter.
Before I show the presenter, you also need a View, which I called MainView. It does not contain any actual code, it just extends from FXMLView (which is a class from the afterburner.fx framework):

public class MainView extends FXMLView
{
}

The MainPresenter contains the bulk of the code:

public class MainPresenter implements Initializable
{
// ------------------------------ FIELDS ------------------------------

	@FXML
	public TextArea contentField;
	@FXML
	public Button saveButton;
	@FXML
	private ListView<Note> listView;

	@FXML
	private TextField titleField;

	@Inject
	private NoteService noteService;

// ------------------------ INTERFACE METHODS ------------------------

// --------------------- Interface Initializable ---------------------

	@Override
	public void initialize( URL location, ResourceBundle resources )
	{
		listView.setCellFactory( param -> new NoteListCell() );
		listView.setItems( FXCollections.observableArrayList( noteService.getNotes() ) );
		listView.getSelectionModel().selectedItemProperty().addListener( new NoteListViewSelectionChangeListener() );

		selectFirstItemIfPossible();

		saveButton.setOnAction( event -> {
			// Save the updated note with the service
			Note selectedItem = listView.getSelectionModel().getSelectedItem();
			selectedItem.setTitle( titleField.getText() );
			selectedItem.setContent( contentField.getText() );
			noteService.updateNode( selectedItem );

			listView.getItems().set( listView.getSelectionModel().getSelectedIndex(), selectedItem );
			listView.getItems().sort( new NoteComparator() );
		} );
	}

// -------------------------- PRIVATE METHODS --------------------------

	private void selectFirstItemIfPossible()
	{
		if (listView.getItems().size() > 0)
		{
			listView.getSelectionModel().select( 0 );
		}
	}

// -------------------------- INNER CLASSES --------------------------

	private static class NoteListCell extends ListCell<Note>
	{
		@Override
		protected void updateItem( Note item, boolean empty )
		{
			super.updateItem( item, empty );
			if (item != null)
			{
				setText( item.getTitle() );
			}
		}
	}

	private class NoteListViewSelectionChangeListener implements ChangeListener<Note>
	{
		@Override
		public void changed( ObservableValue<? extends Note> observable, Note oldValue, Note newValue )
		{
			if( newValue != null )
			{
				titleField.setText( newValue.getTitle() );
				contentField.setText( newValue.getContent() );
			}
		}
	}
}

Let us break this down a bit. First we can reference any component that is declared in the FXML file by using the @FXML annotation on a private field.

For example:

@FXML
public Button saveButton;

Note that the name of the field should match with the fx:id in the FXML file for this to work:

<Button fx:id="saveButton" text="Save" GridPane.rowIndex="2" GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.halignment="RIGHT"/>

@Inject allows to inject arbitrary values or services. Here, I used it to get a reference to the NoteService:

@Inject
private NoteService noteService;

To have this working, you need to setup the injection in your main class. This is what I have:

public class Main extends Application
{

	@Override
	public void start( Stage primaryStage ) throws Exception
	{
		Map<Object, Object> context = new HashMap<>();
		context.put( "noteService", new InMemoryNoteService() );

		Injector.setConfigurationSource( context::get );

		MainView mainView = new MainView();
		Scene scene = new Scene( mainView.getView() );
		primaryStage.setTitle( "AfterburnerNoteFX" );
		primaryStage.setScene( scene );
		primaryStage.show();
	}
}

The Injector has a static method which needs a Function. So anything that returns an Object, given another Object is ok. A Java 8 method reference to the get method of a Map is probably the easiest.
Notice that the key in the Map has to match with the field name of the @Inject annotation in the controller.

To make it good looking, we add a CSS file which has the same name as the FXML file (So main.css in my example):

.defaultBorderSpacing {
    -fx-border-width: 10;
    -fx-border-color: transparent;
}

GridPane {
    -fx-hgap: 10;
    -fx-vgap: 10;
}

This the full file tree for the application:

File Tree AfterburnerNote

This concludes my introduction. Please take a look at the website for some more info and links to other example projects. I really like what afterburner.fx provides. It would be even better if this could be combined with the Spring Framework to have a more feature rich dependency injection, but I can understand that this would totally clash with the minimalistic goal of the framework.

Posted in Programming | Tagged | Leave a comment

Using Font Awesome in JavaFX with fontawesomefx

Icons are a great way to spice up any UI. You can easily use the Font Awesome icons in JavaFX, by using the fontawesomefx library.

I will show a small example on how to use the icons in JavaFX code and how to apply some styling.

First import the library. I am using Maven, so I just add this dependency:

<dependency>
  <groupId>de.jensd</groupId>
  <artifactId>fontawesomefx</artifactId>
  <version>8.2</version>
</dependency>

We will start with a simple app that uses a BorderPane to put some content at the center and have a kind of header at the top:

public class FontAwesomeTest extends Application
{
  @Override
  public void start( Stage stage ) throws Exception
  {
    StackPane root = new StackPane();

    BorderPane borderPane = new BorderPane();
    HBox headerBox = new HBox();
    headerBox.getStyleClass().add( &quot;header-component&quot; );
    borderPane.setTop( headerBox );
    Label centerComponent = new Label( &quot;CENTER COMPONENT&quot; );
    centerComponent.setPrefSize( Double.MAX_VALUE, Double.MAX_VALUE );
    centerComponent.getStyleClass().add( &quot;center-component&quot; );
    borderPane.setCenter( centerComponent );
    root.getChildren().add( borderPane );

    Scene scene = new Scene( root );
    scene.getStylesheets().add( &quot;font-awesome-test.css&quot; );

    stage.setScene( scene );
    stage.setWidth( 300 );
    stage.setHeight( 400 );
    stage.setTitle( &quot;JavaFX 8 app&quot; );
    stage.show();
  }
}

The CSS file used:

.center-component {
    -fx-background-color: coral;
    -fx-alignment: center;
}

The app looks like this initially:

Screen Shot 2015-03-13 at 17.59.59

We will now add an icon in the header:

HBox headerBox = new HBox();
headerBox.getStyleClass().add( &quot;header-component&quot; );
headerBox.getChildren()
         .addAll( GlyphsDude.createIcon( FontAwesomeIcons.BARS, 
                                         &quot;40px&quot; ) );

Notice how we use the static factory method createIcon to build us a Node with the icon from the constants in the enum FontAwesomeIcons. As a 2nd argument, we can specify the size of the icon.

We get the following result:

Screen Shot 2015-03-13 at 18.03.49

We can add some CSS to add a border so the icon does not stick to the side:

.header-component {
    -fx-border-width: 7px;
    -fx-border-color: transparent;
}

NOTE: Do not forget to set the -fx-border-color style as well as the -fx-border-width. Only setting the width will not do anything!

Screen Shot 2015-03-13 at 18.10.06

If we want to add some text next to the icon, we can use the static factory method createIconLabel:

HBox headerBox = new HBox();
headerBox.getStyleClass().add( &quot;header-component&quot; );
Label iconLabel = GlyphsDude.createIconLabel( FontAwesomeIcons.BARS, 
                                              &quot;Menu&quot;, 
                                              &quot;40px&quot;, 
                                              &quot;40px&quot;, 
                                              ContentDisplay.LEFT );
iconLabel.getStyleClass().add( &quot;header-label&quot; );
headerBox.getChildren().addAll( iconLabel );

Which shows as:

Screen Shot 2015-03-13 at 18.13.33

Finally, we can color the icon and the text by applying this CSS:

.header-label &gt; .text {
    -fx-fill: #8A0808;
}

.header-label &gt; .glyph-icon {
    -fx-fill: #8A0808;
}

Final result:

Screen Shot 2015-03-13 at 18.15.09

Posted in Programming | Tagged , | 3 Comments

Spring Boot application with “exploded” directory structure

Spring Boot is really amazing for getting started quickly with a new Spring application. By default, your application is contained in a single jar when packaging it. This has some advantages, but what if you want a “classic” layout with a config folder (for your application.properties or logback.xml files) and a lib folder?

Getting Started

This blog post will show you a way of doing this using Maven and the Maven Assembly Plugin.

First, we create a simple project using the Spring Initializr. I opted for Java 8 and selected the “Web” dependency. The current Spring Boot version is 1.1.8.

This gave me a zip file with the following structure:

pom.xml
src/main/java/.../Application.java
src/main/resources/application.properties
src/test/java/...

For some fun, I added a simple rest controller:

package org.deblauwe.example.boot.exploded;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/test")
public class TestController
{
	@Value( "${hello.value:World}" )
	private String helloValue;

	@RequestMapping("/")
	public String sayHello()
	{
		return "Hello " + helloValue;
	}
}

Running this application and pointing to http://localhost:8080/test/ returns “Hello World” in the browser.

We can now inject a different value into ‘helloValue’ by adding the following line to application.properties:

hello.value=Maven

If you now refresh the browser, it shows: Hello Maven

Creating the assembly

We now want to build a zip file out of this simple application with the following layout:

start.sh
config/application.properties
lib/spring-boot-exploded-example-0.0.1-SNAPSHOT.jar

For this, we add the Maven Assembly Plugin to our pom.xml:

<build>
  <plugins>
    ...
    <plugin>
      <artifactId>maven-assembly-plugin</artifactId>
        <configuration>
          <descriptors>
            <descriptor>src/main/assembly/descriptor.xml</descriptor>
          </descriptors>
        </configuration>
        <executions>
          <execution>
            <id>make-assembly</id> <!-- this is used for inheritance merges -->
            <phase>package</phase> <!-- bind to the packaging phase -->
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
      </plugin>

We also create the descriptor.xml file in the src/main/assembly folder:

<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
    <id>application</id>
    <formats>
        <format>zip</format>
    </formats>
    <fileSets>
        <fileSet>
            <directory>${project.basedir}/src/main/resources</directory>
            <outputDirectory>/config</outputDirectory>
            <includes>
                <include>application.properties</include>
            </includes>
        </fileSet>
        <fileSet>
            <directory>${project.basedir}/src/main/assembly</directory>
            <outputDirectory>/</outputDirectory>
            <filtered>true</filtered>
            <fileMode>0755</fileMode>
            <includes>
                <include>*.sh</include>
            </includes>
        </fileSet>
        <fileSet>
            <directory>${project.build.directory}</directory>
            <outputDirectory>/lib</outputDirectory>
            <includes>
                <include>*.jar</include>
            </includes>
        </fileSet>
    </fileSets>
</assembly>

The final piece is the start.sh file. Place this one also in the src/main/assembly folder:

#!/bin/sh

DIR=`dirname $0`
cd $DIR
java -jar lib/${project.artifactId}-${project.version}.jar --spring.profiles.active=prod $*

The assembly plugin will replace project.artifactId and project.version during the build. The --spring.profiles.active=prod is not needed for this sample application, but it shows how you can force a certain Spring profile in the startup script.

Now run: mvn package

This will create a zip file in the target folder with exactly the layout like we wanted:
Screen Shot 2014-11-04 at 21.24.31

So now it becomes very easy to change something in application.properties if needed.

Assembly with all jar files separately

We can now take this one step further. Maybe you want to have all the jar files separately in the lib folder, just in case you need to patch one of your dependencies, or you just want to test something quickly? For this, we need to remove the spring-boot-maven-plugin in the pom.xml. After this, update the assembly descriptor:

<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
    <id>application</id>
    <formats>
        <format>zip</format>
    </formats>
    <dependencySets>
        <dependencySet>
            <outputDirectory>lib</outputDirectory>
            <unpack>false</unpack>
        </dependencySet>
    </dependencySets>
    <fileSets>
        <fileSet>
            <directory>${project.basedir}/src/main/resources</directory>
            <outputDirectory>/config</outputDirectory>
            <includes>
                <include>application.properties</include>
            </includes>
        </fileSet>
        <fileSet>
            <directory>${project.basedir}/src/main/assembly</directory>
            <outputDirectory>/</outputDirectory>
            <filtered>true</filtered>
            <fileMode>0755</fileMode>
            <includes>
                <include>*.sh</include>
            </includes>
        </fileSet>
    </fileSets>
</assembly>

Notice the dependencySets that has been added and the fileSet for the jar has been removed.

You also need to edit the start.sh startup script to load all jar files from the lib directory:

#!/bin/sh

DIR=`dirname $0`
cd $DIR
java -cp .:./config:./lib/* ${start-class} --spring.profiles.active=prod $*

After running mvn clean package, you end up with a zip file with this structure:
Screen Shot 2014-11-04 at 21.46.02

 

Conclusion

I showed how can you easily use the Maven assembly plugin to output your project in a zip file so you can edit properties without having to unjar the jar file like in the standard Spring Boot setup. I find this extremely useful for things like changing the log level settings for example.

Posted in Programming | Tagged , , | 1 Comment

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 , , | 2 Comments

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 , , , | 6 Comments