Skip to content

Commit 38c3105

Browse files
committed
Q Code Transform update
1 parent 08a5ca7 commit 38c3105

File tree

17 files changed

+584
-39
lines changed

17 files changed

+584
-39
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#folders#
22
.idea
3+
.vscode
34
/target
45
.classpath
56
.project

README.md

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,101 @@
11
# AWS AppConfig Java Sample
22

3+
## **V2-2024**
4+
5+
## **Overview**
6+
7+
This project is a demo of Amazon Q Developer agent for Code Transformation. This is a Java 1.8 based microservice application which displays free list of movies for the month based on configuration stored in AWS AppConfig service using AWS SDK. This application was first open sourced in 2020 and uses legacy versions of libraries such as Spring Boot 2.x, Log4j 2.13.x, Mockito 1.x, Javax and Junit 4.
8+
9+
The Amazon Q Developer Agent for Code Transformation can upgrade the code language version of your files in place. You can transform a module in JetBrains and a project or entire workspace in Visual Studio Code. Amazon Q first builds your code in the source language version and verifies that it has the information necessary to transform your code. After Amazon Q successfully transforms your code, you verify and accept the changes in your integrated development environment (IDE). For more information, see How the Amazon Q Developer Agent for Code Transformation works.Currently, Amazon Q can upgrade Java 8 and Java 11 code to Java 17 code.
10+
11+
Refer to Getting Started guide and 3 ways how Amazon Q Developer agent for code transformation accelerates your java upgrades.
12+
13+
14+
## **Installation Instructions**
15+
16+
## **Local**
17+
18+
1. Compile the application in Local IDE
19+
2. Open a new terminal and type `java -jar .\target\movie-service-0.1.0.jar`
20+
3. Follow the STEP 1 in AWS section below to set up AppConfig Configuration in your default AWS account profile
21+
4. Open a browser and go to http://localhost:8080/movies/getMovies
22+
5. You should be able to see list of paid movies
23+
24+
## **AWS**
25+
26+
### **STEP 1: Create application, environments and configuration profile in AWS AppConfig**
27+
28+
1. Open the AWS Systems Manager console.
29+
2. In the left navigation pane, choose AWS AppConfig and click Get Started
30+
3. If the AWS AppConfig welcome page appears, click Create application on the left navigation.
31+
4. For Name, enter a name for the application. (*MyContainerApplication*) You can add an optional description and apply tags to the application. Choose Create application.
32+
5. After the application is created, you are directed to a page with Environments and Configuration Profiles Choose Create environment, and then enter a name (*MyContainerApplicationProductionEnvironment*) and optional description for the environment. You can also optionally add tags and configure Amazon CloudWatch alarms for this environment.
33+
6. In the top navigation, choose the application name, and on the Configuration Profiles and Feature flags tab, choose Create configuration profile and Freeform configuration.
34+
7. Enter a name (*MyContainerApplicationConfigurationProfile*) and optional description for the configuration profile.
35+
8. Under Configuration source, choose AWS AppConfig hosted configuration.Under Content, choose JSON, paste the following content, and then choose Next.
36+
37+
```
38+
{
39+
"movies": [
40+
{
41+
"id": 1,
42+
"movieName": "The Shawshank Redemption"
43+
},
44+
{
45+
"id": 2,
46+
"movieName": "City of God"
47+
},
48+
{
49+
"id": 3,
50+
"movieName": "Memento"
51+
},
52+
{
53+
"id": 4,
54+
"movieName": "The Intouchables"
55+
},
56+
{
57+
"id": 5,
58+
"movieName": "Stardust"
59+
},
60+
{
61+
"id": 6,
62+
"movieName": "Apocalypto"
63+
},
64+
{
65+
"id": 7,
66+
"movieName": "Taxi Driver"
67+
},
68+
{
69+
"id": 8,
70+
"movieName": "No Country for Old Men"
71+
},
72+
{
73+
"id": 9,
74+
"movieName": "Planet 51"
75+
},
76+
{
77+
"id": 10,
78+
"movieName": "The Beach"
79+
}
80+
]
81+
}
82+
83+
```
84+
85+
9. (Optional) You can add validators to validate the configuration. For information, check [about validators](https://docs.aws.amazon.com/appconfig/latest/userguide/appconfig-creating-configuration-and-profile-validators.html) in the AWS AppConfig documentation.
86+
10. Choose Create configuration profile.
87+
11. Choose Start deployment.
88+
12. Choose the environment, hosted configuration version, deployment strategy, and an optional description to start the deployment process.
89+
13. To create a custom deployment strategy, choose Create Deployment Strategy. Or choose one of the predefined deployment strategies provided by AWS AppConfig. For more information, check [creating a deployment strategy](https://docs.aws.amazon.com/appconfig/latest/userguide/appconfig-creating-deployment-strategy.html) in the AWS AppConfig documentation. For the purposes of this post, we chose the *AppConfig.Linear50PercentEvery30Seconds* deployment strategy.
90+
91+
Note: Depending on the deployment strategy you selected, this operation might take few minutes to complete. The configuration is available to the application as soon as the deployment state is Complete.
92+
93+
94+
95+
## **V1 - 2020 **
96+
97+
Note: Use this version only if you want to try out AppConnfig related features.
98+
399
## **Overview**
4100

5101
This is a demo of the [AWS AppConfig](https://docs.aws.amazon.com/appconfig/latest/userguide/what-is-appconfig.html) Java application as explained in the blog post [Application configuration deployment to container workloads using AWS AppConfig](https://aws.amazon.com/blogs/mt/application-configuration-deployment-to-container-workloads-using-aws-appconfig). This demo shows how to integrate a Java Microservices application with AWS AppConfig service along with implementing an in-memory cache to efficiently manage the application configuration.
@@ -20,6 +116,16 @@ This application has a Caching layer built in to cache the responses from AWS Ap
20116

21117
## **Installation Instructions**
22118

119+
## **Local**
120+
121+
1. Compile the application in Local IDE
122+
2. Open a new terminal and type `java -jar .\target\movie-service-0.1.0.jar`
123+
3. Follow the STEP 1 in AWS section below to set up AppConfig Configuration in your default AWS account profile
124+
4. Open a browser and go to http://localhost:8080/movies/getMovies
125+
5. You should be able to see list of 5 Paid movies
126+
127+
## **AWS**
128+
23129
### **STEP 1: Create application, environments and configuration profile in AWS AppConfig**
24130

25131
1. Open the AWS Systems Manager console.

pom.xml

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,43 @@
4040
<artifactId>json</artifactId>
4141
<version>20200518</version>
4242
</dependency>
43+
<dependency>
44+
<groupId>org.springframework.boot</groupId>
45+
<artifactId>spring-boot-starter-test</artifactId>
46+
<scope>test</scope>
47+
</dependency>
48+
<!-- Maven -->
49+
<dependency>
50+
<groupId>org.apache.logging.log4j</groupId>
51+
<artifactId>log4j-api</artifactId>
52+
<version>2.13.3</version>
53+
</dependency>
54+
<!-- https://mvnrepository.com/artifact/junit/junit -->
55+
<dependency>
56+
<groupId>junit</groupId>
57+
<artifactId>junit</artifactId>
58+
<version>4.13.1</version>
59+
<scope>test</scope>
60+
</dependency>
61+
<dependency>
62+
<groupId>org.apache.logging.log4j</groupId>
63+
<artifactId>log4j-core</artifactId>
64+
<version>2.13.3</version>
65+
</dependency>
66+
<dependency>
67+
<groupId>org.mockito</groupId>
68+
<artifactId>mockito-all</artifactId>
69+
<version>1.10.19</version>
70+
<scope>test</scope>
71+
</dependency>
72+
<!-- https://mvnrepository.com/artifact/javax.persistence/javax.persistence-api -->
73+
<!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
74+
<dependency>
75+
<groupId>javax.validation</groupId>
76+
<artifactId>validation-api</artifactId>
77+
<version>2.0.1.Final</version>
78+
</dependency>
79+
4380
</dependencies>
4481

4582
<properties>
@@ -55,7 +92,7 @@
5592
<plugin>
5693
<groupId>org.apache.maven.plugins</groupId>
5794
<artifactId>maven-compiler-plugin</artifactId>
58-
<version>3.1</version>
95+
<version>3.8.1</version>
5996
<configuration>
6097
<source>${java.version}</source>
6198
<target>${java.version}</target>

src/main/java/com/amazonaws/samples/appconfig/movies/Movie.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22

33
public class Movie {
44

5-
private final long id;
5+
private long id;
66
private final String movieName;
77

88

9+
910
public Movie(Long id, String movieName) {
1011
this.id = id;
1112
this.movieName = movieName;
@@ -15,6 +16,9 @@ public long getId() {
1516
return this.id;
1617
}
1718

19+
public long setId(int movieId){
20+
return this.id = movieId;
21+
}
1822
public String getMovieName() {
1923
return this.movieName;
2024
}

src/main/java/com/amazonaws/samples/appconfig/movies/MoviesApplication.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import org.springframework.boot.SpringApplication;
44
import org.springframework.boot.autoconfigure.SpringBootApplication;
55

6+
67
@SpringBootApplication
78
public class MoviesApplication {
89

src/main/java/com/amazonaws/samples/appconfig/movies/MoviesController.java

Lines changed: 93 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,91 +4,150 @@
44
import java.util.Optional;
55
import java.util.UUID;
66
import java.util.function.Supplier;
7-
8-
import com.amazonaws.samples.appconfig.AppConfigUtility;
7+
import java.util.List;
8+
import java.util.ArrayList;
9+
import com.amazonaws.samples.appconfig.utils.AppConfigUtility;
910
import com.amazonaws.samples.appconfig.cache.ConfigurationCache;
1011
import com.amazonaws.samples.appconfig.model.ConfigurationKey;
12+
import com.amazonaws.samples.appconfig.utils.HTMLBuilder;
13+
import org.json.JSONArray;
1114
import org.json.JSONObject;
1215
import org.springframework.beans.factory.annotation.Autowired;
1316
import org.springframework.core.env.Environment;
17+
import org.springframework.validation.BindingResult;
1418
import org.springframework.web.bind.annotation.GetMapping;
19+
import org.springframework.web.bind.annotation.PathVariable;
20+
import org.springframework.web.bind.annotation.RequestMapping;
1521
import org.springframework.web.bind.annotation.RestController;
1622
import software.amazon.awssdk.services.appconfig.AppConfigClient;
1723
import software.amazon.awssdk.services.appconfig.model.GetConfigurationResponse;
24+
import org.apache.logging.log4j.LogManager;
25+
import org.apache.logging.log4j.Logger;
26+
import javax.validation.Valid;
1827

19-
28+
import static org.springframework.web.bind.annotation.RequestMethod.POST;
2029

2130
@RestController
2231
public class MoviesController {
32+
private static final Logger logger = LogManager.getLogger(MoviesController.class);
2333

2434
/**
2535
* Static Movie Array containing all the list of Movies.
2636
*/
27-
private static final Movie[] PAIDMOVIES = {
28-
new Movie(1L, "Paid Movie 1"),
29-
new Movie(2L, "Paid Movie 2"),
30-
new Movie(3L, "Paid Movie 3"),
31-
new Movie(4L, "Paid Movie 4"),
32-
new Movie(5L, "Paid Movie 5"),
33-
new Movie(6L, "Paid Movie 6"),
34-
new Movie(7L, "Paid Movie 7"),
35-
new Movie(8L, "Paid Movie 8"),
36-
new Movie(9L, "Paid Movie 9"),
37-
new Movie(10L, "Paid Movie 10")
37+
static final Movie[] PAIDMOVIES = {
38+
new Movie(1L, "Static Movie 1"),
39+
new Movie(2L, "Static Movie 2"),
40+
new Movie(3L, "Static Movie 3"),
41+
new Movie(4L, "Static Movie 4"),
42+
new Movie(5L, "Static Movie 5"),
43+
new Movie(6L, "Static Movie 6"),
44+
new Movie(7L, "Static Movie 7"),
45+
new Movie(8L, "Static Movie 8"),
46+
new Movie(9L, "Static Movie 9"),
47+
new Movie(10L, "Static Movie 10")
3848
};
3949
public Duration cacheItemTtl = Duration.ofSeconds(30);
4050
private Boolean boolEnableFeature;
4151
private int intItemLimit;
42-
private AppConfigClient client;
43-
private String clientId;
44-
private ConfigurationCache cache;
52+
AppConfigClient client;
53+
String clientId;
54+
ConfigurationCache cache;
4555

4656
@Autowired
47-
private Environment env;
57+
Environment env;
4858

4959
/**
5060
* REST API method to get all the Movies based on AWS App Config parameter.
5161
*
5262
* @return List of Movies
5363
*/
5464
@GetMapping("/movies/getMovies")
55-
public Movie[] movie() {
65+
public String movie() {
66+
logger.info("Fetching movies from AWS App Config");
67+
try {
68+
5669

57-
final String application = env.getProperty("appconfig.application");
58-
final String environment = env.getProperty("appconfig.environment");
59-
final String config = env.getProperty("appconfig.config");
6070
cacheItemTtl = Duration.ofSeconds(Long.parseLong(env.getProperty("appconfig.cacheTtlInSeconds")));
6171

6272
final AppConfigUtility appConfigUtility = new AppConfigUtility(getOrDefault(this::getClient, this::getDefaultClient),
6373
getOrDefault(this::getConfigurationCache, ConfigurationCache::new),
6474
getOrDefault(this::getCacheItemTtl, () -> cacheItemTtl),
6575
getOrDefault(this::getClientId, this::getDefaultClientId));
6676

77+
final String application = env.getProperty("appconfig.application");
78+
final String environment = env.getProperty("appconfig.environment");
79+
final String config = env.getProperty("appconfig.config");
6780
final GetConfigurationResponse response = appConfigUtility.getConfiguration(new ConfigurationKey(application, environment, config));
6881
final String appConfigResponse = response.content().asUtf8String();
6982

7083
final JSONObject jsonResponseObject = new JSONObject(appConfigResponse);
71-
boolEnableFeature = jsonResponseObject.getBoolean("boolEnableFeature");
72-
intItemLimit = jsonResponseObject.getInt("intItemLimit");
73-
final Movie[] limitedMovies = new Movie[intItemLimit];
74-
75-
for (int i = 0; i < intItemLimit; i++) {
76-
limitedMovies[i] = PAIDMOVIES[i];
84+
System.out.println("json is "+jsonResponseObject);
85+
86+
JSONArray moviesArray = jsonResponseObject.getJSONArray("movies");
87+
System.out.println("movies array is "+moviesArray);
88+
List<Movie> movieList = new ArrayList<>();
89+
for (int i = 0; i < moviesArray.length(); i++) {
90+
JSONObject movieObj = moviesArray.getJSONObject(i);
91+
long id = movieObj.getLong("id");
92+
String movieName = movieObj.getString("movieName");
93+
// Extract other fields as needed
94+
Movie movie = new Movie(id, movieName);
95+
movieList.add(movie);
7796
}
78-
79-
if (boolEnableFeature) {
80-
return limitedMovies;
81-
} else {
82-
return PAIDMOVIES;
97+
Movie[] movies = movieList.toArray(new Movie[movieList.size()]);
98+
HTMLBuilder htmlBuilder = new HTMLBuilder();
99+
String moviesHtml = htmlBuilder.getMoviesHtml(movies);
100+
101+
return moviesHtml;
102+
} catch (Exception e) {
103+
logger.error("Error fetching movies from AWS App Config", e);
104+
HTMLBuilder htmlBuilder = new HTMLBuilder();
105+
String moviesHtml = htmlBuilder.getMoviesHtml(PAIDMOVIES);
106+
return moviesHtml;
83107
}
84108
}
85109

110+
@RequestMapping(value = "/movies/{movie}/edit", method = POST)
111+
public String processUpdateMovie(@Valid Movie movie, BindingResult result, @PathVariable("movieId") int movieId) {
112+
final AppConfigUtility appConfigUtility = new AppConfigUtility(getOrDefault(this::getClient, this::getDefaultClient),
113+
getOrDefault(this::getConfigurationCache, ConfigurationCache::new),
114+
getOrDefault(this::getCacheItemTtl, () -> cacheItemTtl),
115+
getOrDefault(this::getClientId, this::getDefaultClientId));
116+
117+
118+
final String application = env.getProperty("appconfig.application");
119+
final String environment = env.getProperty("appconfig.environment");
120+
final String config = env.getProperty("appconfig.config");
121+
122+
final GetConfigurationResponse response = appConfigUtility.updateConfiguration(new ConfigurationKey(application, environment, config),movie.toString());
123+
final String appConfigResponse = response.content().asUtf8String();
124+
125+
final JSONObject jsonResponseObject = new JSONObject(appConfigResponse);
126+
System.out.println("json is "+jsonResponseObject);
127+
128+
JSONArray moviesArray = jsonResponseObject.getJSONArray("movies");
129+
System.out.println("movies array is "+moviesArray);
130+
List<Movie> movieList = new ArrayList<>();
131+
for (int i = 0; i < moviesArray.length(); i++) {
132+
JSONObject movieObj = moviesArray.getJSONObject(i);
133+
long id = movieObj.getLong("id");
134+
String movieName = movieObj.getString("movieName");
135+
// Extract other fields as needed
136+
movieList.add(movie);
137+
}
138+
Movie[] movies = movieList.toArray(new Movie[movieList.size()]);
139+
HTMLBuilder htmlBuilder = new HTMLBuilder();
140+
String moviesHtml = htmlBuilder.getMoviesHtml(movies);
141+
142+
return moviesHtml;
143+
144+
}
86145

87146
private <T> T getOrDefault(final Supplier<T> optionalGetter, final Supplier<T> defaultGetter) {
88147
return Optional.ofNullable(optionalGetter.get()).orElseGet(defaultGetter);
89148
}
90149

91-
private String getDefaultClientId() {
150+
String getDefaultClientId() {
92151
return UUID.randomUUID().toString();
93152
}
94153

0 commit comments

Comments
 (0)