Skip to content

Commit 8a29412

Browse files
Merge pull request #157 from SNT01/release-8.0.0
Upgrade Play Framework 3.0.5 + Apache Pekko 1.0.2 + Scala 2.13.12
2 parents 1fd3be9 + ff67134 commit 8a29412

35 files changed

+432
-184
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ jobs:
7171
- name: Build and push Docker image to GHCR
7272
uses: docker/build-push-action@v4
7373
with:
74-
context: ./service/target
74+
context: .
7575
file: ./Dockerfile
7676
push: true
7777
tags: ${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }}

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,8 @@ RUNNING_PID
8282
/.target/
8383
/bin/
8484
/logs
85-
*.zip
85+
*.zip
86+
87+
# Maven build artifacts
88+
dependency-reduced-pom.xml
89+
**/dependency-reduced-pom.xml

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ RUN apk update \
44
&& apk add curl \
55
&& adduser -u 1001 -h /home/sunbird/ -D sunbird \
66
&& mkdir -p /home/sunbird/
7-
ADD ./notification-service-1.0.0-dist.zip /home/sunbird/
7+
ADD ./service/target/notification-service-1.0.0-dist.zip /home/sunbird/
88
RUN unzip /home/sunbird/notification-service-1.0.0-dist.zip -d /home/sunbird/
99
RUN chown -R sunbird:sunbird /home/sunbird
1010
USER sunbird

UPGRADE_README.md

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# Play Framework and Apache Pekko Upgrade
2+
3+
## Overview
4+
5+
This repository has been upgraded from Play Framework 2.7.2 with Akka 2.5.22 to Play Framework 3.0.5 with Apache Pekko 1.0.3.
6+
7+
## Why This Upgrade
8+
9+
**License Compliance**: Akka changed from Apache 2.0 to Business Source License 1.1, requiring commercial licenses for production use. Apache Pekko maintains Apache 2.0 license.
10+
11+
**Security**: Play 2.7.2 and Akka 2.5.22 no longer receive security updates.
12+
13+
**Modernization**: Access to latest features and performance improvements.
14+
15+
## Technology Stack Changes
16+
17+
- Play Framework: 2.7.2 to 3.0.5
18+
- Actor Framework: Akka 2.5.22 to Apache Pekko 1.0.2
19+
- Scala: 2.12.11 to 2.13.12
20+
- Guice: 3.0 to 5.1.0
21+
- SLF4J: 1.6.1 to 2.0.13
22+
- Logback: 1.2.3 to 1.4.14
23+
- Jackson: 2.13.5 to 2.14.3
24+
- Netty: 4.1.77.Final to 4.1.112.Final
25+
26+
## Key Changes
27+
28+
### Dependencies
29+
30+
All Maven POM files updated with new versions. Play Framework groupId changed from com.typesafe.play to org.playframework. Scala library exclusions added to prevent version conflicts between Scala 2.12 and 2.13.
31+
32+
### Source Code
33+
34+
Akka imports migrated to Pekko across all Java files:
35+
- akka.actor.* to org.apache.pekko.actor.*
36+
- akka.pattern.* to org.apache.pekko.pattern.*
37+
- akka.routing.* to org.apache.pekko.routing.*
38+
- akka.util.* to org.apache.pekko.util.*
39+
- akka.testkit.* to org.apache.pekko.testkit.*
40+
41+
Updated FutureConverters for Scala 2.13:
42+
- scala.compat.java8.FutureConverters to scala.jdk.javaapi.FutureConverters
43+
- toJava() to asJava()
44+
45+
### Configuration
46+
47+
application.conf files updated with Pekko namespaces:
48+
- akka {} to pekko {}
49+
- Actor system configurations migrated
50+
- Serialization bindings updated
51+
- Dispatcher references changed
52+
53+
54+
### Play 3.0 API Updates
55+
56+
Play 3.0 removed the request() method and Http.Context. All controller methods now inject Http.Request as a parameter.
57+
58+
Controller updates:
59+
- HealthController
60+
- NotificationController
61+
- NotificationTemplateController
62+
- LogController
63+
- BaseController helper methods
64+
65+
Routes file updated with request injection for all endpoints.
66+
67+
### Test Framework
68+
69+
Test files updated:
70+
- Replaced JavaTestKit.duration() with java.time.Duration.ofSeconds()
71+
- Resolved Duration class ambiguity between java.time and scala.concurrent
72+
- Fixed import conflicts
73+
74+
### Scala Version Conflicts
75+
76+
Added exclusions to prevent Scala 2.12 transitive dependencies:
77+
- Excluded scala-library and scala-reflect from dependencies where needed
78+
- Explicitly declared scala-library 2.13.12 dependency
79+
80+
## Build Instructions
81+
82+
Build all modules:
83+
```
84+
mvn clean install -Dmaven.test.skip=true
85+
```
86+
87+
Build with test compilation:
88+
```
89+
mvn clean install -DskipTests
90+
```
91+
92+
Create distribution package:
93+
```
94+
cd service
95+
mvn play2:dist
96+
```
97+
98+
## Migration Impact
99+
100+
**Business Logic**: No changes to business logic or functionality
101+
102+
**API Compatibility**: Maintained, as Pekko is API-compatible with Akka 2.6
103+
104+
**Code Changes**: Primarily package name updates from akka to pekko
105+
106+
**License**: Now compliant with Apache 2.0 throughout the stack
107+
108+
## Known Issues
109+
110+
**Scala 2.12/2.13 Conflict**: If you encounter NoClassDefFoundError for scala.collection.GenMap, verify dependency tree to ensure no Scala 2.12 artifacts are present. Run mvn dependency:tree and add exclusions for any scala-library or scala-reflect with version 2.12.
111+
112+
**PowerMock Tests**: PowerMock is incompatible with Java 9+ module system. Tests using PowerMock will need to be updated or JVM arguments added.
113+
114+
## Verification Steps
115+
116+
1. Clean compilation successful
117+
2. All modules build without errors
118+
3. Dependency tree verified for no Scala 2.12 conflicts
119+
4. Configuration files validated
120+
5. Routes file compiled successfully

all-actors/pom.xml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,9 @@
7979
<version>${junit.version}</version>
8080
</dependency>
8181
<dependency>
82-
<groupId>com.typesafe.akka</groupId>
83-
<artifactId>akka-testkit_${scala.major.version}</artifactId>
84-
<version>${typesafe.akka.version}</version>
82+
<groupId>org.apache.pekko</groupId>
83+
<artifactId>pekko-testkit_${scala.major.version}</artifactId>
84+
<version>${pekko.version}</version>
8585
<scope>test</scope>
8686
</dependency>
8787
<dependency>
@@ -126,6 +126,9 @@
126126
<exclude>META-INF/*.SF</exclude>
127127
<exclude>META-INF/*.DSA</exclude>
128128
<exclude>META-INF/*.RSA</exclude>
129+
<exclude>org/slf4j/**</exclude>
130+
<exclude>ch/qos/logback/**</exclude>
131+
<exclude>META-INF/services/org.slf4j.spi.SLF4JServiceProvider</exclude>
129132
</excludes>
130133
</filter>
131134
</filters>

all-actors/src/main/java/org/sunbird/Application.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package org.sunbird;
22

3-
import akka.actor.ActorRef;
3+
import org.apache.pekko.actor.ActorRef;
44
import org.sunbird.actor.core.ActorCache;
55
import org.sunbird.actor.core.ActorService;
66

all-actors/src/main/java/org/sunbird/BaseActor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package org.sunbird;
22

3-
import akka.actor.UntypedAbstractActor;
3+
import org.apache.pekko.actor.UntypedAbstractActor;
44
import org.sunbird.common.exception.ActorServiceException;
55
import org.sunbird.common.exception.BaseException;
66
import org.sunbird.common.message.IResponseMessage;

all-actors/src/main/java/org/sunbird/NotificationValidator.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,10 @@ private static void validatePresence(String key, Object value, Class<?> type, St
130130
}
131131

132132
public static boolean isInstanceOf(Class objClass, Class targetClass) {
133+
// Handle Scala collections - Scala Seq should be treated as List
134+
if (targetClass == List.class && scala.collection.Seq.class.isAssignableFrom(objClass)) {
135+
return true;
136+
}
133137
return targetClass.isAssignableFrom(objClass);
134138
}
135139

all-actors/src/main/java/org/sunbird/notification/actor/CreateNotificationActor.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.sunbird.request.LoggerUtil;
2020
import org.sunbird.telemetry.TelemetryEnvKey;
2121
import org.sunbird.telemetry.util.TelemetryUtil;
22+
import scala.collection.JavaConverters;
2223

2324
import java.text.MessageFormat;
2425
import java.util.ArrayList;
@@ -43,8 +44,14 @@ public void onReceive(Request request) throws Throwable {
4344
try {
4445
Response response = new Response();
4546
ObjectMapper mapper = new ObjectMapper();
46-
List<Map<String, Object>> notifications =
47-
(List<Map<String, Object>>) request.getRequest().get(JsonKey.NOTIFICATIONS);
47+
// Convert Scala collection to Java List to avoid ClassCastException
48+
Object notificationsObject = request.getRequest().get(JsonKey.NOTIFICATIONS);
49+
List<Map<String, Object>> notifications;
50+
if (notificationsObject instanceof scala.collection.Seq) {
51+
notifications = new ArrayList<>(JavaConverters.asJavaCollectionConverter((scala.collection.Seq<Map<String, Object>>) notificationsObject).asJavaCollection());
52+
} else {
53+
notifications = (List<Map<String, Object>>) notificationsObject;
54+
}
4855

4956
String deliveryMode = request.getManagerName();
5057
if (StringUtils.isNotBlank(deliveryMode) && "sync".equalsIgnoreCase(deliveryMode)) {

all-actors/src/main/java/org/sunbird/notification/actor/DeleteNotificationActor.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
1515
import org.sunbird.service.NotificationServiceImpl;
1616
import org.sunbird.util.RequestHandler;
1717
import org.sunbird.utils.PropertiesCache;
18+
import scala.collection.JavaConverters;
1819

1920
import java.text.MessageFormat;
21+
import java.util.ArrayList;
2022
import java.util.Collections;
2123
import java.util.List;
2224
import java.util.Map;
@@ -63,7 +65,14 @@ private void deleteV1Feed(Request request) {
6365

6466
private void deleteFeed(Request request, String requestedBy){
6567
String userId = (String) request.getRequest().get(JsonKey.USER_ID);
66-
List<String> feedIds = (List<String>)request.getRequest().get(JsonKey.IDS);
68+
// Convert Scala collection to Java List to avoid ClassCastException
69+
Object idsObject = request.getRequest().get(JsonKey.IDS);
70+
List<String> feedIds;
71+
if (idsObject instanceof scala.collection.Seq) {
72+
feedIds = new ArrayList<>(JavaConverters.asJavaCollectionConverter((scala.collection.Seq<String>) idsObject).asJavaCollection());
73+
} else {
74+
feedIds = (List<String>) idsObject;
75+
}
6776
try {
6877
if (StringUtils.isEmpty(userId)) {
6978
throw new BaseException(IResponseMessage.Key.MANDATORY_PARAMETER_MISSING,
@@ -77,7 +86,7 @@ private void deleteFeed(Request request, String requestedBy){
7786
NotificationService notificationService = NotificationServiceImpl.getInstance();
7887
boolean isSupportEnabled = Boolean.parseBoolean(PropertiesCache.getInstance().getProperty(JsonKey.VERSION_SUPPORT_CONFIG_ENABLE));
7988
if(isSupportEnabled) {
80-
List<Map<String, Object>> mappedFeedIdLists = notificationService.getFeedMap((List<String>) request.getRequest().get(JsonKey.IDS), request.getContext());
89+
List<Map<String, Object>> mappedFeedIdLists = notificationService.getFeedMap(feedIds, request.getContext());
8190
getOtherVersionUpdatedFeedList(mappedFeedIdLists,feedIds);
8291
}
8392
Response response = notificationService.deleteNotificationFeed(Collections.singletonMap(requestedBy,feedIds), request.getContext());

0 commit comments

Comments
 (0)