I am currently experimenting with quarkus and cannot find a way to change some openapi information at runtime (here, I want the authorization url to change depending on the environment).
It should be possible by using OASFilter and feeding information from environment variables but OASFilter seems to be initialized at build time. I added a log in the filterSecurityScheme method and the log is displayed at build (by quarkus-maven-plugin) and then never displayed at runtime.
The code is pretty simple :
public class OASSecurityConfiguration implements OASFilter {
#Override
public SecurityScheme filterSecurityScheme(final SecurityScheme securityScheme) {
securityScheme.getFlows().
getImplicit().
setAuthorizationUrl(ConfigProvider.getConfig().getValue("quarkus.oidc.auth-server-url", String.class)+"/protocol/openid-connect/auth");
return securityScheme;
}
}
Is there any other way to change openapi specs at runtime from environment variables or to prevent the OASFilter to be initialized at build time ?
Thanks.
Since Quarkus v2 there is now a config option quarkus.smallrye-openapi.always-run-filter (docs) that enables you to run the OASfilter everytime the openapi document is served.
Related
I started using Azure App Configuration service and Feature Flags functionality in my project. I followed this documentation and was able to create a Spring boot project. I also created a FeatureFlagService class and autowired the FeatureManager class in it as shown below :
#Service
public class FeatureFlagService {
private FeatureManager featureManager;
public FeatureFlagService(FeatureManager featureManager) {
this.featureManager = featureManager;
}
public boolean isFeatureEnabled() {
return featureManager.isEnabledAsync("scopeid/MyFeature").block();
}
}
With this I get the value of the feature flag 'MyFeature' but with no label.
I have the same feature defined with different labels in Azure App Configuration as shown below.
I need to fetch the feature flag with specific label. How can I achieve it at runtime?
I don't see a way to do it using the FeatureManager class.
They only way to load from a label is by using spring.cloud.azure.appconfiguration.stores[0].feature-flags.label-filter, the Feature Management Library itself has no concept of a label.
I would like to set bootstrap.yaml property aws.paramstore.prefix programmatically.
According to the documentation the only way to configure it is via bootstrap.yaml file. And it works fine if I define aws.paramstore.prefix in the bootstrap.yaml file. However, I would like to do that programmatically.
There is also a possibility to customize bootstrap property sources, however this does not solve the problem. Custom Bootstrap seem to be loaded later than aws.paramstore properties.
As far as I can see the aws.paramstore properties are loaded very early on using spring.factories that are defined in spring-cloud-starter-aws-parameter-store-config dependency:
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
org.springframework.cloud.aws.autoconfigure.paramstore.AwsParamStoreBootstrapConfiguration
And in AwsParamStoreBootstrapConfiguration constructor AwsParamStoreProperties is passed as an argument, which is instantiated via #ConfigurationProperties. That is aws.paramstore are loaded very early on.
You can try to look into PostProcessors that executed on the very first stages of Spring Context initialization. For example, EnvironmentPostProcessor. It executes quite early and probably can help you to manage some properties/modify files before they will be loaded to context.
Note: if you want to use this code in some library that will be a part of another project, you should add such PostProcessor to spring.factories file. In other case it won't be added to configuration stage of another Spring.
A hacky workaround is to set the aws.paramstore.prefix property before calling SpringApplication#run method.
Say we want to set aws.paramstore.prefix to the value of a Spring profile that is being passed to the application. Then one can do something like:
public static void main(String[] args) {
// or System.getenv("SPRING_PROFILES_ACTIVE")
// or some additional logic that filters a profile that is being passed to the application
// note that application can also have multiple profiles
String activeProfile = System.getProperty("spring.profiles.active");
System.setProperty("aws.paramstore.prefix", activeProfile);
SpringApplication.run(MyApplication.class, args);
}
In this way we "guarantee" that aws.paramstore.prefix is available before ane bootstraps from spring.factories kicks in.
I am building an app that mostly provide REST services, nothing fancy. since my data consumed by the app can have multiple languages I thought about using the bundle files.
I created 3 files, one with the default file name and another two with specific languages. The files created using intellij IDE I am using.
I followed this guide https://www.baeldung.com/java-resourcebundle however on each run I am getting:
MissingResourceException: Can't find bundle for base name tp_app_strings, locale en_US
I tried numerous articles but none of them seems to resolve the issue.
One fun fact is that if I am using the #Value("classpath:tp_app_strings.properties") on a 'Resource' field I am able to get a reference to that file, so it spring is able to find it.
Additional thing that I tried was to create a WEB-INF directory and place the files there (read it in some article) but still no positive affect
The project structure is quite straight forward:
Spring boot version 2.2 running tomcat.
Any suggeestions would be highly appriciated
You can load the .properties file to the application context using #PropertySource annotation instead using #Value to load the .properties file to a org.springframework.core.io.Resource instance.
The usage;
#Configuration
#PropertySource("classpath:tp_app_strings.properties")
public class DefaultProperties {
#Value("${property1.name}") // Access properties in the above file here using SpringEL.
private String prop1;
#Value("${property2.name}")
private String prop2;
}
You wouldn't need java.util.ResourceBundle access properties this way. Use different or same class to load other .properties files as well.
Update 1:
In order to have the functionality of java.util.ResourceBundle, you can't just use org.springframework.core.io.Resource class. This class or non of it sub-classes don't provide functions to access properties by its name java.util.ResourceBundle whatsoever.
However, if you want a functionality like java.util.ResourceBundle, you could implement something custom like this using org.springframework.core.io.Resource;
#Configuration
public class PropertyConfig {
#Value("classpath:tp_app_strings.properties")
private Resource defaultProperties;
#Bean("default-lang")
public java.util.Properties getDefaultProperties() throws IOException {
Properties props = new Properties();
props.load(defaultProperties.getInputStream());
return props;
}
}
Make sure to follow correct naming convention when define the property file as java.util.Properties#load(InputStream) expect that.
Now you can #Autowire and use this java.util.Properties bean wherever you want just like with java.util.ResourceBundle using java.util.Properties#getProperty(String) or its overloaded counterpart.
I think it's problem of you properties file naming convention. use underline "_" for specifying locale of file like
filename_[languageCode]_[regionCode]
[languageCode] and [regionCode] are two letters standard code that [regionCode] section is optional
about code abbrivation standard take a look on this question
in your case change file name to tp_app_strings_en_US.properties
I'm trying to inject "management.endpoints.web.base-path" into my class's field that I need to know. I did a few hours of search for it, but all the answer is "how to customize your endpoint" by setting management.endpoints.web.base-path in the application.xml(or yaml), not "how to get a default of management.endpoints.web.base-path".
Simple code as below was expecting to grab whatever variable loaded when Spring Boot app is starting up, but nothing was retrieved in the variable.
#Autowired
private Environment environment;
public void myMethod(){
final String actuatorBase = environment.getProperty("management.endpoints.web.base-path");
}
If I define it in the application.properties I should be able to load it for sure, but I'd like to know why the default("/actuator") can't be retrieved here. However when I run the application, I had no problem to access all the actuator related functionality endpoint through /actuator.
Since it doesn't work, injecting the variable with #Value annotation also doesn't work either.
When I checked the environment variable in the debugger, I was able to see application.yaml is loaded and all the overrides variables are there, too, but not all the default "management" stuff was there.
Any idea? This app has some custom configuration, not using all the AutoConfigurer stuff, so wondering if there is specific autoconfig I need to use to make it happen.
I'm using Spring Boot 2.1.0.RELEASE.
Self answering here.
WebEndpointProperties is the one that loads all the management.endpoints.web prefix properties, so simply
#Autowired
private WebEndpointProperties webEndpointProperties;
in the class and then
String actuatorWebBasePath = this.webEndpointProperties.getBasePath();
in my method gave me a base path(/actuator).
I have develop a new Connector. This connector requires to be configured with two parameters, lets say:
default_trip_timeout_milis
default_trip_threshold
Challenge is, I want read ${myValue_a} and ${myValue_a} from an API, using an HTTP call, not from a file or inline values.
Since this is a connector, I need to make this API call somewhere before connectors are initialized.
FlowVars aren't an option, since they are initialized with the Flows, and this is happening before in the Mule app life Cycle.
My idea is to create an Spring Bean implementing Initialisable, so it will be called before Connectors are init, and here, using any java based libs (Spring RestTemplate?) , call API, get values, and store them somewhere (context? objectStore?) , so the connector can access them.
Make sense? Any other ideas?
Thanks!
mmm you could make a class that will create the properties in the startup and in this class obtain the API properties via http request. Example below:
public class PropertyInit implements InitializingBean,FactoryBean {
private Properties props = new Properties();
#Override
public Object getObject() throws Exception {
return props;
}
#Override
public Class getObjectType() {
return Properties.class;
}
}
Now you should be able to load this property class with:
<context:property-placeholder properties-ref="propertyInit"/>
Hope you like this idea. I used this approach in a previous project.
I want to give you first a strong warning on doing this. If you go down this path then you risk breaking your application in very strange ways because if any other components depend on this component you are having dynamic components on startup, you will break them, and you should think if there are other ways to achieve this behaviour instead of using properties.
That said the way to do this would be to use a proxy pattern, which is a proxy for the component you recreate whenever its properties are changed. So you will need to create a class which extends Circuit Breaker, which encapsulates and instance of Circuit Breaker which is recreated whenever its properties change. These properties must not be used outside of the proxy class as other components may read these properties at startup and then not refresh, you must keep this in mind that anything which might directly or indirectly access these properties cannot do so in their initialisation phase or your application will break.
It's worth taking a look at SpringCloudConfig which allows for you to have a properties server and then all your applications can hot-reload those properties at runtime when they change. Not sure if you can take that path in Mule if SpringCloud is supported yet but it's a nice thing to know exists.