How to configure a SessionHandler with a SessionContext in Jetty? - kotlin

jetty-9.4.11.v20180605
I have one project where I'm very happily using Jetty by configuring it programatically (in Kotlin/Java code, not in .xml or .ini files). I'm adding Jetty to an older project and it's working well, except for configuring the SessionHandler. It looks like it never gets the SessionContext 'cause it blows up with a NPE here:
java.lang.NullPointerException
at org.eclipse.jetty.server.session.AbstractSessionDataStore.newSessionData(AbstractSessionDataStore.java:142)
at org.eclipse.jetty.server.session.AbstractSessionCache.newSession(AbstractSessionCache.java:798)
at org.eclipse.jetty.server.session.SessionHandler.newHttpSession(SessionHandler.java:794)
at org.eclipse.jetty.server.Request.getSession(Request.java:1559)
at org.eclipse.jetty.server.Request.getSession(Request.java:1532)
The insufficient config code (in Kotlin) looks like this:
val sessionIdManager = DefaultSessionIdManager(server, SecureRandom())
server.sessionIdManager = sessionIdManager
val sessionHandler = SessionHandler()
sessionHandler.sessionIdManager = sessionIdManager
sessionHandler.sessionCache =
DefaultSessionCacheFactory().getSessionCache(sessionHandler)
val dataStoreFactory = FileSessionDataStoreFactory()
dataStoreFactory.storeDir = File(someDir)
val dataStore = dataStoreFactory.getSessionDataStore(sessionHandler)
sessionHandler.sessionCache.sessionDataStore = dataStore
server.handler = sessionHandler
I think maybe I'm missing a SessionContext in AbstractSessionDataStore which is called from SessionHandler.newHttpSession(), but I don't know how to set that. It looks like SessionContex is associated with SessionHandler by calling sessionHandler.doStart() which is protected in SessionHandler. If this isn't possible, I think I could get by with a WeakHashMap instead of a true Session, but I'm assuming it's better to try to use the existing Session.

Related

Replacing Type with var for all 'Class class = new Class()' usages in Java project

I recently switched to Java 11 for a rather big project, and would like to switch to using var class = new Class() instead of Class class = new CLass().
I tried using Intellij Structural Search (and replace) for this, but its turning out to be more complex than expected.
My first attempt was $Type$ $Inst$ = new $Constructor$($Argument$);, which also matches global variables (which don't allow var).
My second attempt is:
class $Class$ {
$ReturnType$ $Method$ ($ParameterType$ $Parameter$) throws $ExceptionType$ {
$Statements$;
final $Type$ $Inst$ = new $Constructor$($Argument$);
$Statements2$;
}
}
Which misses all calls inside e.g. try blocks (since they get matched by the expressions)
Any help would be greatly appreciated!
Use your first template
$Type$ $Inst$ = new $Constructor$($Argument$);
But add a Script modifier on the $Inst$ variable with the following text:
Inst instanceof com.intellij.psi.PsiLocalVariable
Alternatively you may want to try the Local variable type can be omitted inspection that is available in IntelliJ IDEA.

kotest change environment variables

I am writing tests for Ktor app using Kotests, but stumbled into the problem how can I change env variables for tests preferably globally. I have tried adding withEnvironment but it throw quite strange error into me
Unable to make field private final java.util.Map java.util.Collections$UnmodifiableMap.m accessible: module java.base does not "opens java.util" to unnamed module #3daa422a
java.lang.reflect.InaccessibleObjectException: Unable to make field private final java.util.Map java.util.Collections$UnmodifiableMap.m accessible: module java.base does not "opens java.util" to unnamed module #3daa422a
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
my test file looks like this
class VisitorSpec : FreeSpec({
val ds = createDataSourceTest()
val visitor = RegisterVisitorDTO(
email = TestConstants.VISITOR_EMAIL,
username = TestConstants.VISITOR_USERNAME,
password = TestConstants.PASSWORD,
firstName = TestConstants.VISITOR_FIRST_NAME,
lastName = TestConstants.VISITOR_LAST_NAME,
gender = TestConstants.VISITOR_GENDER,
birthday = TestConstants.VISITOR_BIRTHDAY,
)
"check visitor routes" - {
val loginData = LoginDTO(TestConstants.VISITOR_EMAIL + 0, TestConstants.PASSWORD)
"can get list of visitors with correct query" {
withEnvironment(
mapOf(
"POSTGRES_URL" to "jdbc:postgresql://localhost:5432/test",
"POSTGRES_USERNAME" to "test_user",
"POSTGRES_PASSWORD" to "test_pass"
)
) {
testApplication {
val client = getClient(ds)
repeat(6) {
registerConfirmedUser(
client, visitor.copy(
email = "${TestConstants.VISITOR_EMAIL}$it",
username = "${TestConstants.VISITOR_USERNAME}$it",
)
)
}
val accessToken = loginUser(client, loginData).run { this.body<LoginResponseDTO>().accessToken }
client.get("/api/v1/visitors?page=1&count=5") {
header("Authorization", "Bearer $accessToken")
}.apply {
val response = this.body<VisitorPaginatedResponseDTO>()
response.data.size.shouldBe(5)
response.totalCount.shouldBe(6)
response.currentPage.shouldBe(1)
}
}
}
}
...
if I remove
withEnvironment(
mapOf(
"POSTGRES_URL" to "jdbc:postgresql://localhost:5432/test",
"POSTGRES_USERNAME" to "test_user",
"POSTGRES_PASSWORD" to "test_pass"
)
)
it will just work but with default db, any advice on this?
In some places, it was advised to use
override fun listeners() = listOf(
SystemEnvironmentTestListener("fooKeyEnv", "barValueEnv"),
SystemPropertyTestListener("fooKeyProp", "barValueProp")
)
but ide tells me that this method is deprecated.
Thanks in advance for any advice.
Recent Java versions prohibit modifying the environment variables with the default access settings (JEP 403: Strongly Encapsulate JDK Internals). Kotest and some other testing frameworks that manipulate the environment variables got affected by this, you can find the related issues:
https://github.com/kotest/kotest/issues/2849
https://github.com/stefanbirkner/system-lambda/issues/23
https://github.com/junit-pioneer/junit-pioneer/issues/509
One solution would be to add the arguments to the JVM running the tests that would make the Java Platform Module System allow the access to the API used by the test framework. Here's an answer that explains the arguments: How to set environment variable in Java without 'illegal reflective access'? How to use add-opens?
The simplest form of the argument, if you are not using Java modules in your code, would be:
--add-opens java.base/java.util=ALL-UNNAMED
If you are running the tests using Gradle, then you can pass this argument to the jvmArgs of the test task:
tasks.withType<Test>().named("jvmTest") {
jvmArgs("--add-opens", "java.base/java.util=ALL-UNNAMED")
}
Note: modifying the module access in this way could make the tests pass even if some of your code needs illegal access to the JDK internals. Make sure that your code doesn't do that or that you have other tests that check for this without modifying module access rights.
It seems that some other libraries, like system-stubs, provide a way to modify the environment variables in tests without illegal reflective access to the JDK internals.

Micronaut declarative client with base url per environment

I'd like to be able to use Micronaut's declarative client to hit an a different endpoint based on whether I'm in a local development environment vs a production environment.
I'm setting my client's base uri in application.dev.yml:
myserviceclient:
baseUri: http://localhost:1080/endpoint
Reading the docs from Micronaut, they have the developer jumping through quite a few hoops to get a dynamic value piped into the actual client. They're actually quite confusing. So I've created a configuration like this:
#ConfigurationProperties(PREFIX)
class MyServiceClientConfig {
companion object {
const val PREFIX = "myserviceclient"
const val BASE_URL = "http://localhost:1080/endpoint"
}
var baseUri: String? = null
fun toMap(): MutableMap<String, Any> {
val m = HashMap<String, Any>()
if (baseUri != null) {
m["baseUri"] = baseUri!!
}
return m
}
}
But as you can see, that's not actually reading any values from application.yml, it's simply setting a const value as a static on the class. I'd like that BASE_URL value to be dynamic based on which environment I'm in.
To use this class, I've created a declarative client like this:
#Client(MyServiceClientConfig.BASE_URL)
interface MyServiceClient {
#Post("/user/kfc")
#Produces("application/json")
fun sendUserKfc(transactionDto: TransactionDto)
}
The docs show an example where they're interpolating values from the config map that's built like this:
#Get("/api/\${bintray.apiversion}/repos/\${bintray.organization}/\${bintray.repository}/packages")
But how would I make this work in the #Client() annotation?
Nowhere in that example do they show how bintray is getting defined/injected/etc. This appears to be the same syntax that's used with the #Value() annotation. I've tried using that as well, but every value I try to use ends up being null.
This is very frustrating, but I'm sure I'm missing a key piece that will make this all work.
I'm setting my client's base uri in application.dev.yml
You probably want application-dev.yml.
But how would I make this work in the #Client() annotation?
You can put a config key in the #Client value using something like #Client("${myserviceclient.baseUri}").
If you want the url somewhere in your code use this:
#Value("${micronaut.http.services.occupancy.urls}")
private String occupancyUrl;

Is it possible to programmatically add a new Mule Flow after the context has been initialized?

I would like to programmatically add new RSS Connector flows while Mule is running (after the context has been initialized). When I try to do this, I get a Lifecycle Exception saying that the context is already initialized.
Is there a way to do this without restarting the whole context?
I figured out a solution on my own. It turned out that creating a new Mule context, adding my flow, and then starting the context worked just fine. In fact, this ended up being simpler, faster, and cleaner than the other path I was going down.
Creating a default Mule context worked just fine for me. You might need to add a ConfigurationBuilder to yours if you have special needs.
MuleContext newMuleContext = new DefaultMuleContextFactory().createMuleContext();
MuleRegistry registry = newMuleContext.getRegistry();
Flow flow = createFlow();
registry.registerFlowConstruct(flow);
newMuleContext.start();
Edit. Here's the createFlow method. Your specifics will be different based on the needs of your app.
protected Flow createFlow(MuleContext context, RssBean feed) throws Exception {
MuleRegistry registry = context.getRegistry();
String feedName = feed.getName();
HttpPollingConnector connector = getHttpPollingConnector(context, registry, feedName);
EndpointURIEndpointBuilder endpointBuilder = getEndpointBuilder(context, feed, registry, shortName, connector);
registry.registerEndpointBuilder(feedName + ".in", endpointBuilder);
MessagePropertiesTransformer transformer = getTransformer(context, feedName);
MessageProcessor mp = getOutboundFlowRef(context);
Flow flow = getFlow(context, shortName, endpointBuilder, transformer, mp);
registry.registerFlowConstruct(flow);
return flow;
}

What options do I have for automating bindings with NInject

Rather than manually having to bind every class, what methods and patterns, if any, are recommended for automatically setting up bindings?
For example, the vast majority of bindings simply look like this:
Bind<ICustomerRepository>.To<CustomerRepository>();
Once modules get large, you can end up with 100s of bindings that all look exactly the same. Can this be automated?
check out the conventions extension:
https://github.com/ninject/ninject.extensions.conventions
using (IKernel kernel = new StandardKernel())
{
var scanner = new AssemblyScanner();
scanner.From(Assembly.GetExecutingAssembly());
scanner.BindWith<DefaultBindingGenerator>();
kernel.Scan(scanner);
var instance = kernel.Get<IDefaultConvention>();
instance.ShouldNotBeNull();
instance.ShouldBeInstanceOf<DefaultConvention>();
}