Skip to content

Commit f728901

Browse files
authored
docs(sample): Add sample for native image support in Datastore (#640)
* docs(sample): add native image sample for Datastore
1 parent b793e7d commit f728901

File tree

5 files changed

+456
-0
lines changed

5 files changed

+456
-0
lines changed
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# Datastore Sample Application with Native Image
2+
3+
This application uses the [Google Cloud Datastore client library](https://cloud.google.com/datastore/docs/reference/libraries) and is compatible with Native Image compilation.
4+
5+
This sample runs through some basic operations of creating/deleting entities, running queries, and running transaction code.
6+
7+
## Setup Instructions
8+
9+
You will need to follow these prerequisite steps in order to run the samples:
10+
11+
1. If you have not already, [create a Google Cloud Platform Project](https://cloud.google.com/resource-manager/docs/creating-managing-projects#creating_a_project).
12+
13+
2. Install the [Google Cloud SDK](https://cloud.google.com/sdk/) which will allow you to run the sample with your project's credentials.
14+
15+
Once installed, log in with Application Default Credentials using the following command:
16+
17+
```
18+
gcloud auth application-default login
19+
```
20+
21+
**Note:** Authenticating with Application Default Credentials is convenient to use during development, but we recommend [alternate methods of authentication](https://cloud.google.com/docs/authentication/production) during production use.
22+
23+
3. Install the GraalVM compiler.
24+
25+
You can follow the [official installation instructions](https://www.graalvm.org/docs/getting-started/#install-graalvm) from the GraalVM website.
26+
After following the instructions, ensure that you install the native image extension installed by running:
27+
28+
```
29+
gu install native-image
30+
```
31+
32+
Once you finish following the instructions, verify that the default version of Java is set to the GraalVM version by running `java -version` in a terminal.
33+
34+
You will see something similar to the below output:
35+
36+
```
37+
$ java -version
38+
39+
openjdk version "11.0.7" 2020-04-14
40+
OpenJDK Runtime Environment GraalVM CE 20.1.0 (build 11.0.7+10-jvmci-20.1-b02)
41+
OpenJDK 64-Bit Server VM GraalVM CE 20.1.0 (build 11.0.7+10-jvmci-20.1-b02, mixed mode, sharing)
42+
```
43+
## Sample
44+
1. **(Optional)** If you wish to run the application against the [Datastore emulator](https://cloud.google.com/sdk/gcloud/reference/beta/emulators/datastore), ensure that you have the [Google Cloud SDK](https://cloud.google.com/sdk) installed.
45+
46+
In a new terminal window, start the emulator via `gcloud`:
47+
48+
```
49+
gcloud beta emulators datastore start --host-port=localhost:9010
50+
```
51+
52+
Leave the emulator running in this terminal for now.
53+
In the next section, we will run the sample application against the Datastore emulator instance.
54+
55+
2. Navigate to this directory and compile the application with the native image compiler.
56+
57+
```
58+
mvn package -P native -DskipTests
59+
```
60+
61+
3. **(Optional)** If you're using the emulator, export the `DATASTORE_EMULATOR_HOST` as an environment variable in your terminal.
62+
63+
```
64+
export DATASTORE_EMULATOR_HOST=localhost:9010
65+
```
66+
67+
The Datastore Client Libraries will detect this environment variable and automatically connect to the emulator instance if this variable is set.
68+
69+
4. Run the application.
70+
71+
```
72+
./target/native-image-sample
73+
```
74+
75+
5. The application will run through some basic Datastore operations and log some output statements.
76+
77+
```
78+
Successfully added entity.
79+
Reading entity: 1cf34cc1-2b8a-4945-9fc4-058f03dcd08e
80+
Successfully deleted entity: 1cf34cc1-2b8a-4945-9fc4-058f03dcd08e
81+
Run fake transaction code.
82+
Found entity:
83+
name=de4f36f4-3936-4252-98d3-e0d56d485254
84+
kind=test-kind
85+
namespace=nativeimage-test-namespace
86+
properties={description=StringValue{valueType=STRING, excludeFromIndexes=false, meaning=0, value=hello world}}
87+
Ran transaction callable.
88+
```
89+
90+
### Sample Integration test with Native Image Support
91+
92+
In order to run the sample integration test as a native image, call the following command:
93+
94+
```
95+
mvn test -Pnative
96+
```
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
<?xml version='1.0' encoding='UTF-8'?>
2+
<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">
3+
<modelVersion>4.0.0</modelVersion>
4+
<groupId>com.example.datastore</groupId>
5+
<artifactId>native-image-sample</artifactId>
6+
<name>Native Image Sample</name>
7+
<url>https://github.com/googleapis/java-datastore</url>
8+
9+
<!--
10+
The parent pom defines common style checks and testing strategies for our samples.
11+
Removing or replacing it should not affect the execution of the samples in anyway.
12+
-->
13+
<parent>
14+
<groupId>com.google.cloud.samples</groupId>
15+
<artifactId>shared-configuration</artifactId>
16+
<version>1.2.0</version>
17+
</parent>
18+
19+
<properties>
20+
<maven.compiler.target>11</maven.compiler.target>
21+
<maven.compiler.source>11</maven.compiler.source>
22+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
23+
</properties>
24+
25+
<dependencyManagement>
26+
<dependencies>
27+
<dependency>
28+
<groupId>com.google.cloud</groupId>
29+
<artifactId>libraries-bom</artifactId>
30+
<version>24.2.0</version>
31+
<type>pom</type>
32+
<scope>import</scope>
33+
</dependency>
34+
</dependencies>
35+
</dependencyManagement>
36+
37+
<dependencies>
38+
<dependency>
39+
<groupId>com.google.cloud</groupId>
40+
<artifactId>google-cloud-datastore</artifactId>
41+
</dependency>
42+
43+
<dependency>
44+
<groupId>junit</groupId>
45+
<artifactId>junit</artifactId>
46+
<version>4.13.2</version>
47+
<scope>test</scope>
48+
</dependency>
49+
<dependency>
50+
<groupId>com.google.truth</groupId>
51+
<artifactId>truth</artifactId>
52+
<version>1.1.3</version>
53+
<scope>test</scope>
54+
</dependency>
55+
</dependencies>
56+
57+
<build>
58+
<plugins>
59+
<plugin>
60+
<groupId>org.apache.maven.plugins</groupId>
61+
<artifactId>maven-jar-plugin</artifactId>
62+
<configuration>
63+
<archive>
64+
<manifest>
65+
<mainClass>com.example.datastore.NativeImageDatastoreSample
66+
</mainClass>
67+
</manifest>
68+
</archive>
69+
</configuration>
70+
</plugin>
71+
</plugins>
72+
</build>
73+
74+
<!-- Native Profile-->
75+
<profiles>
76+
<profile>
77+
<id>native</id>
78+
79+
<dependencies>
80+
<dependency>
81+
<groupId>com.google.cloud</groupId>
82+
<artifactId>native-image-support</artifactId>
83+
<version>0.12.4</version>
84+
</dependency>
85+
<dependency>
86+
<groupId>org.junit.vintage</groupId>
87+
<artifactId>junit-vintage-engine</artifactId>
88+
<version>5.8.2</version>
89+
<scope>test</scope>
90+
</dependency>
91+
<dependency>
92+
<groupId>org.graalvm.buildtools</groupId>
93+
<artifactId>junit-platform-native</artifactId>
94+
<version>0.9.9</version>
95+
<scope>test</scope>
96+
</dependency>
97+
</dependencies>
98+
99+
<build>
100+
<plugins>
101+
<plugin>
102+
<groupId>org.apache.maven.plugins</groupId>
103+
<artifactId>maven-surefire-plugin
104+
</artifactId> <!-- Must use older version of surefire plugin for native-image testing. -->
105+
<version>2.22.2</version>
106+
<configuration>
107+
<includes>
108+
<include>**/IT*</include>
109+
</includes>
110+
</configuration>
111+
</plugin>
112+
<plugin>
113+
<groupId>org.graalvm.buildtools</groupId>
114+
<artifactId>native-maven-plugin</artifactId>
115+
<version>0.9.9</version>
116+
<extensions>true</extensions>
117+
<configuration>
118+
<mainClass>com.example.datastore.NativeImageDatastoreSample
119+
</mainClass>
120+
<buildArgs>
121+
<buildArg>--no-fallback</buildArg>
122+
<buildArg>--no-server</buildArg>
123+
</buildArgs>
124+
</configuration>
125+
<executions>
126+
<execution>
127+
<id>build-native</id>
128+
<goals>
129+
<goal>build</goal>
130+
<goal>test</goal>
131+
</goals>
132+
<phase>package</phase>
133+
</execution>
134+
<execution>
135+
<id>test-native</id>
136+
<goals>
137+
<goal>test</goal>
138+
</goals>
139+
<phase>test</phase>
140+
</execution>
141+
</executions>
142+
</plugin>
143+
</plugins>
144+
</build>
145+
</profile>
146+
</profiles>
147+
</project>
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/*
2+
* Copyright 2020-2021 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.datastore;
18+
19+
import com.google.cloud.datastore.Datastore;
20+
import com.google.cloud.datastore.DatastoreOptions;
21+
import com.google.cloud.datastore.Entity;
22+
import com.google.cloud.datastore.Key;
23+
import com.google.cloud.datastore.Query;
24+
import com.google.cloud.datastore.QueryResults;
25+
import com.google.cloud.datastore.StructuredQuery;
26+
import com.google.cloud.datastore.Transaction;
27+
import java.time.Duration;
28+
import java.time.Instant;
29+
import java.util.UUID;
30+
31+
/**
32+
* Sample Datastore Application.
33+
*/
34+
public class NativeImageDatastoreSample {
35+
36+
/* Datastore namespace where entities will be created. */
37+
private static final String TEST_NAMESPACE = "nativeimage-test-namespace";
38+
39+
/* Datastore kind used. */
40+
private static final String TEST_KIND = "test-kind";
41+
42+
/**
43+
* Entrypoint to the Datastore sample application.
44+
*/
45+
public static void main(String[] args) {
46+
Instant startTime = Instant.now();
47+
Datastore datastore = DatastoreOptions.getDefaultInstance().getService();
48+
49+
String testId = UUID.randomUUID().toString();
50+
51+
addEntity(datastore, testId);
52+
getEntity(datastore, testId);
53+
deleteEntity(datastore, testId);
54+
55+
runTransaction(datastore);
56+
57+
String id = UUID.randomUUID().toString();
58+
Key key = createKey(datastore, id);
59+
runTransactionCallable(datastore, key);
60+
Instant endTime = Instant.now();
61+
Duration duration = Duration.between(startTime, endTime);
62+
System.out.println("Duration: " + duration.toString());
63+
}
64+
65+
static void addEntity(Datastore datastore, String id) {
66+
Key key = createKey(datastore, id);
67+
Entity entity = Entity.newBuilder(key)
68+
.set("description", "hello world")
69+
.build();
70+
datastore.add(entity);
71+
System.out.println("Successfully added entity.");
72+
}
73+
74+
static void getEntity(Datastore datastore, String id) {
75+
Key key = createKey(datastore, id);
76+
Entity entity = datastore.get(key);
77+
System.out.println("Reading entity: " + entity.getKey().getName());
78+
}
79+
80+
static void deleteEntity(Datastore datastore, String id) {
81+
Key key = createKey(datastore, id);
82+
datastore.delete(key);
83+
84+
Entity entity = datastore.get(key);
85+
if (entity == null) {
86+
System.out.println("Successfully deleted entity: " + id);
87+
} else {
88+
throw new RuntimeException("Failed to delete entity: " + id);
89+
}
90+
}
91+
92+
static void runTransactionCallable(Datastore datastore, Key entityKey) {
93+
datastore.runInTransaction(client -> {
94+
Entity entity = Entity.newBuilder(entityKey)
95+
.set("description", "hello world")
96+
.build();
97+
datastore.add(entity);
98+
99+
StructuredQuery query =
100+
Query.newEntityQueryBuilder()
101+
.setNamespace(TEST_NAMESPACE)
102+
.setKind(TEST_KIND)
103+
.build();
104+
105+
QueryResults<Entity> results = datastore.run(query);
106+
while (results.hasNext()) {
107+
Entity result = results.next();
108+
String name = result.getKey().getName();
109+
String kind = result.getKey().getKind();
110+
String namespace = result.getKey().getNamespace();
111+
System.out.println(
112+
"Found entity:" + "\n\t\tname=" + name + "\n\t\tkind=" + kind + "\n\t\tnamespace="
113+
+ namespace + "\n\t\tproperties=" + result.getProperties().toString());
114+
}
115+
116+
datastore.delete(entityKey);
117+
return null;
118+
});
119+
120+
System.out.println("Ran transaction callable.");
121+
}
122+
123+
private static void runTransaction(Datastore datastore) {
124+
Transaction transaction = datastore.newTransaction();
125+
transaction.commit();
126+
transaction = datastore.newTransaction();
127+
transaction.rollback();
128+
System.out.println("Run fake transaction code.");
129+
}
130+
131+
static Key createKey(Datastore datastore, String id) {
132+
return datastore.newKeyFactory()
133+
.setNamespace(TEST_NAMESPACE)
134+
.setKind(TEST_KIND)
135+
.newKey(id);
136+
}
137+
}

0 commit comments

Comments
 (0)