I'm trying to parse the following swagger file with openapi4j:
{
"openapi" : "3.0.0",
"info" : {
"title" : "My Service",
"version" : "1.0.0"
},
"paths" : {
"/endpoint" : { "$ref" : "swagger2.json#/paths/get_endpoint" },
}
}
You can see it has a simple ref to another file within the same folder.
I parse the Swagger file with the following:
URL url = Thread.currentThread().getContextClassLoader().getResource(filePath);
openAPI = new OpenApi3Parser().parse(url, false);
Locally in my IDE, this works great. The ref is loaded and I am able to validate requests against it with no issues. However, when I jar up the project, it is able to load the initial swagger file fine, but none of the refs. I get the following error:
StackTrace: org.openapi4j.core.exception.ResolutionException: Failed to load document from 'swagger2.json'
at org.openapi4j.core.model.reference.AbstractReferenceResolver.registerDocument(AbstractReferenceResolver.java:118)
at org.openapi4j.core.model.reference.AbstractReferenceResolver.findReferences(AbstractReferenceResolver.java:92)
at org.openapi4j.core.model.reference.AbstractReferenceResolver.resolve(AbstractReferenceResolver.java:53)
at org.openapi4j.core.model.v3.OAI3Context.resolveReferences(OAI3Context.java:103)
at org.openapi4j.core.model.v3.OAI3Context.<init>(OAI3Context.java:73)
at org.openapi4j.core.model.v3.OAI3Context.<init>(OAI3Context.java:47)
at org.openapi4j.parser.OpenApi3Parser.parse(OpenApi3Parser.java:34)
at org.openapi4j.parser.OpenApi3Parser.parse(OpenApi3Parser.java:18)
at org.openapi4j.parser.OpenApiParser.parse(OpenApiParser.java:53)
I'm not sure if this is possible. I assume I may have to copy my project resources out at runtime to the filesystem somewhere to be accessed more easily. I would like to avoid that route if possible.
Turns out this was a bug in openapi4j, which was resolving refs with URI instead of URL. This has been fixed in 0.9
Related
I've been trying to figure out if there is a way to use Chromium browser as the UI for a Java application. I found this IntelliJ page: https://jetbrains.org/intellij/sdk/docs/reference_guide/jcef.html The thing I can't figure out is how I actually use this in my project. My IntelliJ version is 2020.3 and it says that in 2020.2 JCEF was enabled by default. I however cannot figure out how I use JCEF in my project. I can't seem to find any clear documentation. When I try to import, for example, com.intellij it can't find the package.
Are there any tutorials or guides to integrate JCEF in my IntelliJ project?
You can run jetty server or use resource provider.
Example of resource provider:
https://medium.com/virtuslab/creating-intellij-plugin-with-webview-3b27c3f87aea
Also this example of abstract WebDialog explain how to pass data to fe:
https://github.com/sergeysenja1992/xm-online-idea-plugin/blob/master/src/main/kotlin/com/icthh/xm/actions/WebDialog.kt
All magic in class BrowserPipe (WebDialog.kt file) on backend side, and same class in frontend class
https://github.com/sergeysenja1992/xm-online-idea-plugin/blob/master/src/main/webapp/src/index.html
Next js file it's one more part of magic
<script src="http://registercallback/events.js"></script>
This js file does not exists, but be listen this request and return generated js code.
CefApp.getInstance().registerSchemeHandlerFactory("http", "registercallback", InjectJsHandlerFactory(inject()))
For more details pls look to this line of code in (WebDialog.kt file)
After all manipulation as result i have ability to write components in simple way:
FE: https://github.com/sergeysenja1992/xm-online-idea-plugin/blob/master/src/main/webapp/src/app/settings/settings.component.ts
constructor(private zone: NgZone) {
let w: any = window;
w.messagePipe.subscribe('initData', (res) => {
console.info('initData', res);
zone.run(() => {
this.updateData(res);
});
});
w.messagePipe.post('componentReady', 'SettingsComponent ready')
}
BE: https://github.com/sergeysenja1992/xm-online-idea-plugin/blob/master/src/main/kotlin/com/icthh/xm/actions/settings/SettingsDialog.kt
override fun callbacks(): List<BrowserCallback> {
val data = ArrayList(project.getSettings().envs.map { it.copy() })
this.data = data;
return listOf(
BrowserCallback("componentReady") {body, pipe ->
logger.info("Update ${body}")
pipe.post("initData", mapper.writeValueAsString(mapOf(
"updateModes" to updateModes,
"branches" to project.getRepository().getLocalBranches(),
"envs" to data,
)))
},
BrowserCallback("envsUpdated") {body, pipe ->
logger.info("envsUpdated ${body}")
val envs = mapper.readValue<List<EnvironmentSettings>>(body)
this.data = ArrayList(envs);
}
)
}
Under http://[JENKINS_NAME]/job/[JOB_NAME]/[BUILD_NUMBER]/
I can see Started by user [USER_NAME].
I want to get that username from my java application.
Any help is much appreciated.
You can make a http call to get all these details. URL to get those details is:
http://<Jenkins URL>/job/<job name>/<build number>/api/json
After the rest call, you will be getting this json.
{
"_class": "hudson.model.FreeStyleBuild",
"actions": [
{
"_class": "hudson.model.CauseAction",
"causes": [
{
"_class": "hudson.model.Cause$UserIdCause",
"shortDescription": "Started by user XXXXXX",
"userId": "xxx#yyy.com",
"userName": "ZZZZZZZZ"
}
]
},
{},
{
"_class": "jenkins.metrics.impl.TimeInQueueAction"
},
{},
{}
],
...
}
So All you have do is parse this json and get the value under javavar['actions'][0]['causes'][0]['userName']. Definitely it will be like that only. I maynot be sure about the indexes. You just try and figure out. Hope this helps.
Mostly for every page in the jenkins instance, you will be having REST API link. Please click on it to see the rest api url and its output for that url.
You could get the build user from Jenkins environment (i.e as an env var). If you use Jenkins 2 pipeline, For example:
pipeline {
//rest of the pipeline
stages {
stage('Build Info') {
steps {
wrap([$class: 'BuildUser']) {
sh 'java -jar <your_java_app>.jar'
}
}
}
}
In your java app you should be able to get the environment variable using System.getenv("BUILD_USER") or else you could pass it as a JVM arg. Ex: sh 'java -jar -DbuildUser=$BUILD_USER <your_java_app>.jar' and get the buildUser system property in the application.
On older version of Jenkins, you may use Build User Vars Plugin or Env Inject plugin. As in the answers on this question. how to get the BUILD_USER in Jenkins when job triggered by timer
I've got question about resolving environment variables in shared files of config server.
My current setup is pretty minimal :
src/main/resources/shared/application.yml :
application:
version: 0.0.1-early
test: ${JAVA_HOME}
src/main/resources/application.properties :
spring.profiles.active=native
spring.cloud.config.server.native.searchLocations=classpath:/shared
Using gradle with :
spring-boot-gradle-plugin:2.0.0.RELEASE
spring-cloud-dependencies:Camden.SR7
And then of course compile 'org.springframework.cloud:spring-cloud-config-server' in deps
Problem :
GET http://localhost:8888/apptest/application gives me :
{
"name": "apptest",
"profiles": [
"application"
],
"label": null,
"version": null,
"state": null,
"propertySources": [
{
"name": "classpath:/shared/application.yml",
"source": {
"application.version": "0.0.1-early",
"application.test": "${JAVA_HOME}"
}
}
]
}
So env variable is not resolved. Same thing is with :
http://localhost:8888/apptest/application?resolvePlaceholders=true
http://localhost:8888/lab/apptest-application.properties?resolvePlaceholders=true
http://localhost:8888/lab/apptest-application.properties?resolvePlaceholders=false
http://localhost:8888/apptest-application.properties?resolvePlaceholders=true
I've looked at Spring cloud config server. Environment variables in properties but solution didn't help me + there where few new versions since then. So I'm opening new question.
Actually it's not a bug and everything is fine. I did not understood how Config server works.
http://localhost:8888/apptest/application - returns yet not resolved value of ${JAVA_HOME}
When we get ei. into container "C" that pings Config Service for configuration and do curl http://config:8888/apptest/application we get the same - unresolved ${JAVA_HOME}
But when we look into Spring application ei. in container "C" and try to inject #Value("${application.test}") somewhere, we get proper value or info that env variable was not set.
It means that environment variables are resolved on client side.
Thanks to that I've understood how NOT production ready env_variables approach is.
Well the changes happened here https://github.com/spring-cloud/spring-cloud-config/commit/f8fc4e19375d3b4c0c2562a71bc49ba288197100 that removes the support of replacing the environment variables.
You can always add a new controller and override the behaviour of the EnvironmentPropertySource#prepareEnvironment
I'm writing an intelij plugin and would like to download the platform specific artefact at runtime.
I've loaded the platform specific jar into a class loader but the ChromiumExtractor cannot access the nested resources when prefixed with "/". So I can access the resource as "chromium-mac.zip" but the library cannot.
I've tried to unzip the nested zipped chromium artefact into the correct directory but this does not leading to a working solution. So now I've been trying to piece together the way the library extracts the artefact but it's rather tedious as the code is obfuscated.
Does the jxbrowser plugin have some support for retrieving the artefact at runtime. Could such support be added (jxbtrowser devs use SO for support questions etc, this is a message to them :D ) ?
Approach taken :
// inside intelij plugin . The plugin has the jxbrowser-6.6.jar
// and license.jar loaded into the classloader. the platform specific
// artefact will be retrieved manual).
val cl = URLClassLoader(arrayOf(URL("file://.../jxbrowser-mac-6.6.jar")), Browser::class.java.classLoader)
val backup = Thread.currentThread().contextClassLoader
try {
Thread.currentThread().contextClassLoader = cl
// can access like this
Thread.currentThread().contextClassLoader.getResource("chromium-mac.zip")
val ce = ChromiumExtractor.create()
// cannot access as resource is retrieved "/chromium-mac.zip" ?
ce.extract(BrowserPreferences.getChromiumDir())
browser = Browser()
} finally {
Thread.currentThread().contextClassLoader = backup
}
The following does the trick, The resource jar had to be in the same class loader as the client jar (as well as the license). It would be nice if JxBrowser added a helper for this that is capable of performing the download and initialising chromium, perhaps taking just a path for a persistent storage directory.
private fun initializeJxBrowser(): Browser {
if(ChromiumExtractor.create().shouldExtract(BrowserPreferences.getChromiumDir())) {
val cl = URLClassLoader(arrayOf(
URL("file:.../license.jar"),
URL("file:.../jxbrowser-mac-6.6.jar"),
URL("file:../jxbrowser-6.6.jar")
))
cl.loadClass("com.teamdev.jxbrowser.chromium.BrowserContext")
.getMethod("defaultContext")
.invoke(null)
}
return Browser()
}
I have a simple Gradle build script to compile and package (similar to the application plugin) my Java application. The only thing I do not accomplish is to replace the current version number in a simple .properties file.
I have created a file 'src/main/resources/app-info.properties' with a single line 'application.version = #version#'. No I want to replace this version string whenever the file is copied to the build folder (think this happens during the build task).
I already tried a simple solution with ants ReplaceTokens. This one replaced the version but also broke my .png files in the resources..
So is there a simple solution to just replace tokens in one single file during the build task (or whatever task handles the copy to the build folder)?
Thank you for any help!
Ben
====== Edit based on the comment from Opal =====
Based on the hint I have added the following:
import org.apache.tools.ant.filters.ReplaceTokens
// ...
build {
from('src/main/resources') {
include '*.properties'
filter(ReplaceTokens, tokens: [version : project.version])
}
}
Which throws this error:
Could not find method from() for arguments [src/main/resources, build_vbjud9ah7v3pj5e7c5bkm490b$_run_closure6_closure12#43ead1a8] on root project
Seems like I am on the wrong task?
====== Edit for completeness adding the solution based on Opals suggest =====
Thanks man, the following is the working solution!
processResources {
from('src/main/resources') {
include '*.properties'
filter(ReplaceTokens, tokens: [version : project.version])
}
}
Books and blogs alike, including the answer from Opal all recommend using a vivid mixture of exclude/include, from() and filter(). And of course, so did I on my first attempt to replace the text {{app javascript library}} in a index.html file to the path of a JavaScript library which depended on a simple project property setting.
The problem that hit me was that my 'war' task produced duplicated index.html files in the war archive and getting rid of the problem, using the pattern described previously, resulted in one huge unreadable hack.
Then I found a really straight forward solution. The following example is from my own build script and you have to customize it a bit to suite your needs:
war {
eachFile { copyDetails ->
if (copyDetails.path == 'index.html') {
filter { line ->
line.replace('{{app javascript library}}', "lib/someLib.js")
}
}
}
}
Paste sample code. What You need to do is to include file for replacement and exclude other files from replacement. Here is sample usage. Search for ReplaceTokens and You'll see what am I talking about.
You need to add filtering to processResources task. Sample code:
processResources {
def profile = project.properties['profile']
def replace_tokens = profile ? filter_tokens[profile] : filter_tokens['default']
exclude '**/log4j-test.xml'
from('src/main/resources') {
exclude '**/*.ttf'
filter(ReplaceTokens, tokens: replace_tokens)
}
from('src/main/resources') {
include '**/*.ttf'
}
}
Above ttf (binary) files are excluded from filtering but copied. replace_tokens is a filter taken from map defined in other part of the script.