Skip to content
This repository was archived by the owner on Oct 24, 2025. It is now read-only.

Commit 683838a

Browse files
committed
examples showinghow to use the new Java API
1 parent 7e74bc9 commit 683838a

File tree

3 files changed

+354
-0
lines changed

3 files changed

+354
-0
lines changed
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
package com.softwaremill.example;
2+
3+
import akka.NotUsed;
4+
import akka.actor.ActorSystem;
5+
import akka.dispatch.MessageDispatcher;
6+
import akka.http.javadsl.ConnectHttp;
7+
import akka.http.javadsl.Http;
8+
import akka.http.javadsl.ServerBinding;
9+
import akka.http.javadsl.model.HttpRequest;
10+
import akka.http.javadsl.model.HttpResponse;
11+
import akka.http.javadsl.model.StatusCodes;
12+
import akka.http.javadsl.model.Uri;
13+
import akka.http.javadsl.server.Route;
14+
import akka.http.javadsl.unmarshalling.Unmarshaller;
15+
import akka.stream.ActorMaterializer;
16+
import akka.stream.javadsl.Flow;
17+
import com.softwaremill.session.BasicSessionEncoder;
18+
import com.softwaremill.session.CheckHeader;
19+
import com.softwaremill.session.CookieST$;
20+
import com.softwaremill.session.InMemoryRefreshTokenStorageWrapper;
21+
import com.softwaremill.session.RefreshTokenStorage;
22+
import com.softwaremill.session.Refreshable;
23+
import com.softwaremill.session.SessionConfig;
24+
import com.softwaremill.session.SessionEncoder;
25+
import com.softwaremill.session.SessionManager;
26+
import com.softwaremill.session.javadsl.HttpSessionAwareDirectives;
27+
import org.slf4j.Logger;
28+
import org.slf4j.LoggerFactory;
29+
30+
import java.io.IOException;
31+
import java.util.concurrent.CompletionStage;
32+
33+
34+
public class JavaExample extends HttpSessionAwareDirectives<MySession> {
35+
36+
private static final Logger logger = LoggerFactory.getLogger(JavaExample.class);
37+
private static final String SECRET = "c05ll3lesrinf39t7mc5h6un6r0c69lgfno69dsak3vabeqamouq4328cuaekros401ajdpkh60rrtpd8ro24rbuqmgtnd1ebag6ljnb65i8a55d482ok7o0nch0bfbe";
38+
private static final SessionEncoder<MySession> BASIC_ENCODER = new BasicSessionEncoder<>(MySession.getSerializer());
39+
40+
// in-memory refresh token storage
41+
private static final RefreshTokenStorage<MySession> REFRESH_TOKEN_STORAGE = new InMemoryRefreshTokenStorageWrapper<MySession>() {
42+
@Override
43+
public void log(String msg) {
44+
logger.info(msg);
45+
}
46+
};
47+
48+
private Refreshable<MySession> refreshable;
49+
private CookieST$ sessionTransport;
50+
51+
public JavaExample(MessageDispatcher dispatcher) {
52+
super(new SessionManager<>(
53+
SessionConfig.defaultConfig(SECRET),
54+
BASIC_ENCODER
55+
)
56+
);
57+
58+
// use Refreshable for sessions, which needs to be refreshed or OneOff otherwise
59+
// using Refreshable, a refresh token is set in form of a cookie or a custom header
60+
refreshable = new Refreshable<>(getSessionManager(), REFRESH_TOKEN_STORAGE, dispatcher);
61+
62+
// set the session transport - based on Cookies (or Headers)
63+
sessionTransport = CookieST$.MODULE$;
64+
}
65+
66+
public static void main(String[] args) throws IOException {
67+
68+
// ** akka-http boiler plate **
69+
ActorSystem system = ActorSystem.create("example");
70+
final ActorMaterializer materializer = ActorMaterializer.create(system);
71+
final Http http = Http.get(system);
72+
73+
// ** akka-http-session setup **
74+
MessageDispatcher dispatcher = system.dispatchers().lookup("akka.actor.default-dispatcher");
75+
final JavaExample app = new JavaExample(dispatcher);
76+
77+
// ** akka-http boiler plate continued **
78+
final Flow<HttpRequest, HttpResponse, NotUsed> routes = app.createRoutes().flow(system, materializer);
79+
final CompletionStage<ServerBinding> binding = http.bindAndHandle(routes, ConnectHttp.toHost("localhost", 8080), materializer);
80+
81+
System.out.println("Server started, press enter to stop");
82+
System.in.read();
83+
84+
binding
85+
.thenCompose(ServerBinding::unbind)
86+
.thenAccept(unbound -> system.terminate());
87+
}
88+
89+
private Route createRoutes() {
90+
CheckHeader<MySession> checkHeader = new CheckHeader<>(getSessionManager());
91+
return
92+
route(
93+
pathSingleSlash(() ->
94+
redirect(Uri.create("/site/index.html"), StatusCodes.FOUND)
95+
),
96+
randomTokenCsrfProtection(checkHeader, () ->
97+
pathPrefix("api", () ->
98+
route(
99+
path("do_login", () ->
100+
post(() ->
101+
entity(Unmarshaller.entityToString(), body -> {
102+
logger.info("Logging in {}", body);
103+
return setSession(refreshable, sessionTransport, new MySession(body), () ->
104+
setNewCsrfToken(checkHeader, () ->
105+
extractRequestContext(ctx ->
106+
onSuccess(() -> ctx.completeWith(HttpResponse.create()), routeResult ->
107+
complete("ok")
108+
)
109+
)
110+
)
111+
);
112+
}
113+
)
114+
)
115+
),
116+
117+
// This should be protected and accessible only when logged in
118+
path("do_logout", () ->
119+
post(() ->
120+
requiredSession(refreshable, sessionTransport, session ->
121+
invalidateSession(refreshable, sessionTransport, () ->
122+
extractRequestContext(ctx -> {
123+
logger.info("Logging out {}", session.getUsername());
124+
return onSuccess(() -> ctx.completeWith(HttpResponse.create()), routeResult ->
125+
complete("ok")
126+
);
127+
}
128+
)
129+
)
130+
)
131+
)
132+
),
133+
134+
// This should be protected and accessible only when logged in
135+
path("current_login", () ->
136+
get(() ->
137+
requiredSession(refreshable, sessionTransport, session ->
138+
extractRequestContext(ctx -> {
139+
logger.info("Current session: " + session);
140+
return onSuccess(() -> ctx.completeWith(HttpResponse.create()), routeResult ->
141+
complete(session.getUsername())
142+
);
143+
}
144+
)
145+
)
146+
)
147+
)
148+
)
149+
)
150+
),
151+
pathPrefix("site", () ->
152+
getFromResourceDirectory(""))
153+
);
154+
}
155+
}
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
package com.softwaremill.example;
2+
3+
import akka.NotUsed;
4+
import akka.actor.ActorSystem;
5+
import akka.dispatch.MessageDispatcher;
6+
import akka.http.javadsl.ConnectHttp;
7+
import akka.http.javadsl.Http;
8+
import akka.http.javadsl.ServerBinding;
9+
import akka.http.javadsl.model.HttpRequest;
10+
import akka.http.javadsl.model.HttpResponse;
11+
import akka.http.javadsl.model.StatusCodes;
12+
import akka.http.javadsl.model.Uri;
13+
import akka.http.javadsl.server.Route;
14+
import akka.http.javadsl.unmarshalling.Unmarshaller;
15+
import akka.stream.ActorMaterializer;
16+
import akka.stream.javadsl.Flow;
17+
import com.softwaremill.session.CheckHeader;
18+
import com.softwaremill.session.CookieST$;
19+
import com.softwaremill.session.InMemoryRefreshTokenStorageWrapper;
20+
import com.softwaremill.session.JValueSessionSerializer$;
21+
import com.softwaremill.session.JwtSessionEncoder;
22+
import com.softwaremill.session.RefreshTokenStorage;
23+
import com.softwaremill.session.Refreshable;
24+
import com.softwaremill.session.SessionConfig;
25+
import com.softwaremill.session.SessionEncoder;
26+
import com.softwaremill.session.SessionManager;
27+
import com.softwaremill.session.javadsl.HttpSessionAwareDirectives;
28+
import org.json4s.DefaultFormats$;
29+
import org.slf4j.Logger;
30+
import org.slf4j.LoggerFactory;
31+
32+
import java.io.IOException;
33+
import java.util.concurrent.CompletionStage;
34+
35+
36+
public class JavaJwtExample extends HttpSessionAwareDirectives<String> {
37+
38+
private static final Logger logger = LoggerFactory.getLogger(JavaJwtExample.class);
39+
private static final String SECRET = "c05ll3lesrinf39t7mc5h6un6r0c69lgfno69dsak3vabeqamouq4328cuaekros401ajdpkh60rrtpd8ro24rbuqmgtnd1ebag6ljnb65i8a55d482ok7o0nch0bfbe";
40+
private static final SessionEncoder<String> JWT_ENCODER = new JwtSessionEncoder<>(JValueSessionSerializer$.MODULE$.stringToJValueSessionSerializer(), DefaultFormats$.MODULE$);
41+
42+
// in-memory refresh token storage
43+
private static final RefreshTokenStorage<String> REFRESH_TOKEN_STORAGE = new InMemoryRefreshTokenStorageWrapper<String>() {
44+
@Override
45+
public void log(String msg) {
46+
logger.info(msg);
47+
}
48+
};
49+
50+
private Refreshable<String> refreshable;
51+
private CookieST$ sessionTransport;
52+
53+
public JavaJwtExample(MessageDispatcher dispatcher) {
54+
super(new SessionManager<>(
55+
SessionConfig.defaultConfig(SECRET),
56+
JWT_ENCODER
57+
)
58+
);
59+
60+
// use Refreshable for sessions, which needs to be refreshed or OneOff otherwise
61+
// using Refreshable, a refresh token is set in form of a cookie or a custom header
62+
refreshable = new Refreshable<>(getSessionManager(), REFRESH_TOKEN_STORAGE, dispatcher);
63+
64+
// set the session transport - based on Cookies (or Headers)
65+
sessionTransport = CookieST$.MODULE$;
66+
}
67+
68+
public static void main(String[] args) throws IOException {
69+
70+
// ** akka-http boiler plate **
71+
ActorSystem system = ActorSystem.create("example");
72+
final ActorMaterializer materializer = ActorMaterializer.create(system);
73+
final Http http = Http.get(system);
74+
75+
// ** akka-http-session setup **
76+
MessageDispatcher dispatcher = system.dispatchers().lookup("akka.actor.default-dispatcher");
77+
final JavaJwtExample app = new JavaJwtExample(dispatcher);
78+
79+
// ** akka-http boiler plate continued **
80+
final Flow<HttpRequest, HttpResponse, NotUsed> routes = app.createRoutes().flow(system, materializer);
81+
final CompletionStage<ServerBinding> binding = http.bindAndHandle(routes, ConnectHttp.toHost("localhost", 8080), materializer);
82+
83+
System.out.println("Server started, press enter to stop");
84+
System.in.read();
85+
86+
binding
87+
.thenCompose(ServerBinding::unbind)
88+
.thenAccept(unbound -> system.terminate());
89+
}
90+
91+
private Route createRoutes() {
92+
CheckHeader<String> checkHeader = new CheckHeader<>(getSessionManager());
93+
return
94+
route(
95+
pathSingleSlash(() ->
96+
redirect(Uri.create("/site/index.html"), StatusCodes.FOUND)
97+
),
98+
randomTokenCsrfProtection(checkHeader, () ->
99+
pathPrefix("api", () ->
100+
route(
101+
path("do_login", () ->
102+
post(() ->
103+
entity(Unmarshaller.entityToString(), body -> {
104+
logger.info("Logging in {}", body);
105+
//return setSession(refreshable, sessionTransport, new MySession(body), () ->
106+
return setSession(refreshable, sessionTransport, body, () ->
107+
setNewCsrfToken(checkHeader, () ->
108+
extractRequestContext(ctx ->
109+
onSuccess(() -> ctx.completeWith(HttpResponse.create()), routeResult ->
110+
complete("ok")
111+
)
112+
)
113+
)
114+
);
115+
}
116+
)
117+
)
118+
),
119+
120+
// This should be protected and accessible only when logged in
121+
path("do_logout", () ->
122+
post(() ->
123+
requiredSession(refreshable, sessionTransport, session ->
124+
invalidateSession(refreshable, sessionTransport, () ->
125+
extractRequestContext(ctx -> {
126+
//logger.info("Logging out {}", session.getUsername());
127+
logger.info("Logging out {}", session);
128+
return onSuccess(() -> ctx.completeWith(HttpResponse.create()), routeResult ->
129+
complete("ok")
130+
);
131+
}
132+
)
133+
)
134+
)
135+
)
136+
),
137+
138+
// This should be protected and accessible only when logged in
139+
path("current_login", () ->
140+
get(() ->
141+
requiredSession(refreshable, sessionTransport, session ->
142+
extractRequestContext(ctx -> {
143+
logger.info("Current session: " + session);
144+
return onSuccess(() -> ctx.completeWith(HttpResponse.create()), routeResult ->
145+
//complete(session.getUsername())
146+
complete(session)
147+
);
148+
}
149+
)
150+
)
151+
)
152+
)
153+
)
154+
)
155+
),
156+
pathPrefix("site", () ->
157+
getFromResourceDirectory(""))
158+
);
159+
}
160+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.softwaremill.example;
2+
3+
import com.softwaremill.session.SessionSerializer;
4+
import com.softwaremill.session.SessionSerializer$;
5+
import com.softwaremill.session.SingleValueSessionSerializer;
6+
import scala.compat.java8.JFunction0;
7+
import scala.compat.java8.JFunction1;
8+
import scala.util.Try;
9+
10+
public class MySession {
11+
12+
/**
13+
* This session serializer converts a session type into a value (always a String type). The first two arguments are just conversion functions.
14+
* The third argument is a serializer responsible for preparing the data to be sent/received over the wire. There are some ready-to-use serializers available
15+
* in the com.softwaremill.session.SessionSerializer companion object, like stringToString and mapToString, just to name a few.
16+
*/
17+
private static final SessionSerializer<MySession, String> serializer = new SingleValueSessionSerializer<>(
18+
(JFunction1<MySession, String>) (session) -> (session.getUsername())
19+
,
20+
(JFunction1<String, Try<MySession>>) (login) -> Try.apply((JFunction0<MySession>) (() -> new MySession(login)))
21+
,
22+
SessionSerializer$.MODULE$.stringToStringSessionSerializer()
23+
);
24+
25+
private final String username;
26+
27+
public MySession(String username) {
28+
this.username = username;
29+
}
30+
31+
public static SessionSerializer<MySession, String> getSerializer() {
32+
return serializer;
33+
}
34+
35+
public String getUsername() {
36+
return username;
37+
}
38+
39+
}

0 commit comments

Comments
 (0)