Example Project
Overview
Here is an example project that shows how XAP Scala can be used in a real project and how Scala and Java code might be integrated.
OpenSpaces Maven plugin project
The project is based on a template project of basic
type from the XAP Maven plugin
. A few changes were introduced:
Common
module, which implements Space classes, written in Scala and takes advantage of constructor based properties.- A new module -
verifier
was introduced. It uses a class with constructor based properties and predicate based queries to obtain objects from Space. - Build process of
common
andverifier
modules was modified to handle Scala and mixed Java/Scala modules, respectively.
Build & run
Requirements
- JDK in version at least 1.6 is required to build the project.
- The project uses
maven
build tool. - To run the project, Scala libraries have to be a accessible for XAP.
Please note that Scala is not required to build the project, since requried libraries will be downloaded by maven
.
Build and run steps
- Download xap-scala and unzip it.
- From the project’s main directory
$XAP_SCALA
run commandmvn clean install
- From the project’s main directory
$XAP_SCALA/example/gs-openspaces-scala-example
run commandmvn clean package
- necessary JAR files to deploy on a grid will be created. - Start XAP Grid Service by running command:
$GS_HOME/bin/gs-agent.sh/bat
- Run this command:
$GS_HOME/tools/maven/installmavenrep.sh/bat
- Deploy the project on the grid (from
$XAP_SCALA/example/gs-openspaces-scala-example
):mvn os:deploy -Dgroups=$LOOKUPGROUPS
.
XAP Scala features
Constructor based properties
Common
module defines Space classes used by other modules. Please note, that the classes are written in Scala and are used in other Scala and Java modules as well. All of these classes are translated to bytecode
and therefore can be used interchangeably.
Sometimes, having immutable state is a desired feature. This requirement is covered in XAP Scala by classes that use constructor based properties, in case of the common
module it is the Verification
class. It is written only once to the Space
and never changed (instances can be removed).
case class Verification @SpaceClassConstructor() (
@BeanProperty
@SpaceId
id: String,
@BeanProperty
dataId: String) extends scala.Serializable {
override def toString: String = s"id[$id] dataId[$dataId]"
}
The other class (Data
) has been rewritten in Scala. However, its behavior has not been modified (apart from adding a new field needed by the verifier
module):
case class Data (
@BeanProperty @SpaceId(autoGenerate = true) var id: String = null,
@BeanProperty @SpaceRouting @SpaceProperty(nullValue = "-1") var `type`: Long = -1,
@BeanProperty var rawData: String = null,
@BeanProperty var data: String = null,
@BooleanBeanProperty var processed: Boolean = false,
@BooleanBeanProperty var verified: Boolean = false) {
def this(`type`: Long, rawData: String) = this(null, `type`, rawData, null, false, false)
def this() = this(-1, null)
override def toString: String = s"id[${id}] type[${`type`}] rawData[${rawData}] data[${data}] processed[${processed}] verified[${verified}]"
}
Predicate based queries
The verifier
module extends the pipeline presented in the baseline project (the one created by the OpenSpaces Maven plugin
). The Verifier
picks up processed Data
instances and tries to verify them. The objects that pass the verification process are then modified (verified
set to true
) and saved along with a new, immutable Verification
object. The objects that failed during verification process are removed from the Space. The verifier
uses the new feature - predicate based queries - to access the Space in a more readable and natural way (especially for functional languages such as Scala):
@GigaSpaceContext private var gigaSpace: GigaSpace = _ // injected
// ...
// data instances to process further are obtained in the following way
val unverifiedData = gigaSpace.predicate.readMultiple { data: Data => data.processed == true && data.verified == false }
Pu.xml contains a standard description of gigaSpace:
...
<os-core:giga-space-context/>
<os-core:space-proxy id="space" name="mySpace"/>
<os-core:giga-space id="gigaSpace" space="space"/>
...
Please note that gigaSpace
from the code above is an instance of ScalaEnhancedGigaSpaceWrapper - a wrapper around GigaSpace introduced in XAP Scala.
Building Scala and mixed Java/Scala modules
The build configuration in Scala or Java/Scala modules is almost as simple in case of pure Java modules.
Scala module
The common
module is a pure Scala module. The maven-compiler-plugin
has been replaced by scala-maven-plugin
. The build configuration from the pom.xml
for the common
has the following form:
<build>
<sourceDirectory>src/main/scala</sourceDirectory>
<plugins>
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
<configuration>
<scalaCompatVersion>${scalaBinaryVersion}</scalaCompatVersion>
</configuration>
</plugin>
</plugins>
<finalName>gs-openspaces-scala-example-common</finalName>
</build>
where scalaBinaryVersion
is a property defined in a parent pom file (in this case it is 2.11
).
Java-Scala module
The verifier
module is a mixed Java-Scala module, where Scala classes call Java classes. This configuration can be used when a separate task is implemented in Java and it only needs to be called from other parts of application. In case of this project, Java module is simulated by VerifierEngine
class and, for ease of use, it is executed by Scala verifier
.
In such a configuration, the Scala compiler has to ‘somehow’ reach Java compiled classes. This is where a build-helper-maven-plugin
is used - it adds Java classes to the source, then they are compiled and finally the Scala compiler uses them during Scala code compilation. The build configuration of the verifier
module is as follows:
<build>
<sourceDirectory>src/main/scala</sourceDirectory>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<id>add-java-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${basedir}/src/main/java</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
<configuration>
<scalaCompatVersion>${scalaBinaryVersion}</scalaCompatVersion>
</configuration>
</plugin>
</plugins>
</build>