Reading sling:OsgiConfig into #ObjectClassDefinition - osgi

We have a OSGI Service (using R7 DS annotation). We are using OCD as innerclass within the service.
Also, we would like the component to read properties from the predefined sling:osgiconfig nodes in JCR.
Configuration policy is defined as required.
When the component/service load it goes into a "no config" state.
Need help to read these configs from sling:osgiCongig nodes.

The sling:OsgiConfig configurations should be defined with the Service implementation class name that's supposed to consume the OCD configurations, and not with the OCD name.
OCDs are basically interfaces that can have multiple implementations. Hence the sling:OsgiConfig nodes have to be defined with the service implementation class name. For example let's say you have a SampleServiceImpl.class defining a SampleOCDConfig.class as below:
#Component(service = SampleService.class)
#Designate(ocd = SampleServiceImpl.Config.class)
public class SampleServiceImpl implements SampleService {
public static final String DEFAULT_CUSTOM_CONFIG = "default configuration value";
#ObjectClassDefinition(name = "Sample OCD Configuration")
#interface Config {
#AttributeDefinition(name = "The custom config", defaultValue = DEFAULT_CUSTOM_CONFIG)
String custom_config() default DEFAULT_CUSTOM_CONFIG;
}
...
Now when you define the configurations for above setup, you must define it like below:
/apps/your_project/config/your.sample.service.package.path.SampleServiceImpl.xml
with following content:
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
jcr:primaryType="sling:OsgiConfig"
custom.config="default configuration value" />

Related

How to define a conditional property with a variable sub property name

I have a configuration property class that contains a map. The map is filled with values from a yml file. the structure looks like this.
config:
variable_sub_key_a:
key_a: 1234
key_b: 1234
variable_sub_key_b:
...
The configuration class looks like:
#Configuration
public class Configuration{
private Map<String, KEY> config= new HashMap<>();
}
I would like that the configuration class is only initialized by spring when the config element exists in the yml file. My problem is that a part of the property name can vary. So i can't use #ConditionalOnProperty. I tried it with different contidional-annotations but haven't found out how i could define a conditional that checks only that the property starts with config.* . Any hints how i can do this?

How to create a bean from a fully-qualified class name specified in external configuration? (Spring)

I'm using Spring Boot and have an external configuration file called application.yml.
In this file, suppose I have a property foo that takes a fully-qualified class name as value.
Using Java configuration, what is the typical way to create a bean of the type specified by the foo property?
I suppose that foo is implementing some known interface. Otherwise, it is kind of pointless to create a bean of an unknown Type.
Something like:
#Configuration
public class FooConfiguration {
#Value("foo.class-name") // ref to the key used in you application.yml
private String fooClassName;
#Bean
public FooInterface fooBean(){
FooInterface fooImpl = Class.forName(fooClassName).newInstance(); // concreet implemetation
return fooImpl;
}
}

Load custom properties file in Spring Boot MVC Main

I have created a myApp.properties in resources folder location and mentioned the server.port in this file.
myApp.properties
myApp.server.port=8020
Now I want to read load this property into my application. But I have to read this before I actually a server.
Here I am trying to do like this
#SpringBootApplication
#ComponentScan(basePackages = {"com.myorg.myapp" })
#EnableConfigurationProperties
#PropertySource("classpath:myApp.properties")
#Component
public class MyAppApplication {
#Value("${myApp.server.port}")
private static String serverPort;
public static void main(String[] args) throws Exception{
try {
SpringApplication appCtxt = new SpringApplication(MyAppApplication.class);
appCtxt.setDefaultProperties(Collections
.singletonMap("server.port", serverPort));
appCtxt.run(args);
} catch (Exception e) {
e.printStackTrace();
}
}
But serverPort is coming as null.
I also tried to create a separate Config file like this but it can't be accessed in static main
#Configuration
#PropertySource("myApp.properties")
#ConfigurationProperties
public class MyAppConfig {
#Value("${myApp.server.port}")
private String serverPort;
/**
* #return the serverPort
*/
public String getServerPort() {
return serverPort;
}
}
Any suggestion would be helpful.
Spring boot injects properties during the initialization of the application context.
This happens (gets triggered) in the line:
appCtxt.run(args);
But you try to access the property before this line - that why it doesn't work.
So bottom line, using "#Value" in the main method doesn't work and it shouldn't.
Now from the code snippet, it looks like you could merely follow the "standards" of spring boot and create the file application.properties with:
server.port=1234
The process of starting the embedded web server in spring boot honors this property and bottom line it will have the same effect and Tomcat will be started on port 1234
Update 1
Based on OP's comment:
So, how can I have multiple application.properties.
In the Spring Boot's documentation it is written that application.properties are resolved from the classpath. So you can try the following assuming you have different modules A,B,C and web app D:
Create src/main/resources/application.properties inside each of 4 modules and pack everything together. The configuration values will be merged (hopefully they won't clash)
If you insist on naming properties A.properties, B.properties and C.properties for each of non-web modules, you can do the following (I'll show for module A, but B and C can do the same).
#Configuration
#PropertySource("classpath:A.properties")
public class AConfiguration {
}
Create in Module A: src/main/resources/A.properties
If you need to load the AConfiguration automatically - make the module A starter (using autoconfig feature of spring-boot):
Create src/resources/META-INF/spring.factories file with the following content:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
<package_of_AConfiguration>.AConfiguration
Also this has been the requirement to separate C from entire bundle where it might run as bundle for some and as a separate for some others
Although I haven't totally understood the requirement, but you can use #ConditionalOnProperty for configuration CConfiguration (that will be created just like AConfiguration.java in my previous example) but this times for module C.
If the conditional is met, configuration will run and load some beans / load its own properties or whatever. All in all conditionals (and in particular Profiles in spring) can help to reach the desired flexibility.
By default, the application.properties file can be used to store property pairs, though you can also define any number of additional property files.
If you save myApp.server.port=8020 in application.properties, it will work fine.
To register a custome property file, you can annotate a #Configuration class with the additional #PropertySource annotation:
#Configuration
#PropertySource("classpath:custom.properties")
#PropertySource("classpath:another.properties")
public class ConfigClass {
// Configuration
}
make sure, your class path is correct.

Spring #Value not getting set

I'm sure this has been asked 1000 times, because i've seen them, however I'm missing something.
Context:
<beans profile="localDev">
<util:properties id="propertiesLocalDev"location="classpath:/localDev.properties"/>
</beans>
<beans profile="test">
<util:properties id="properties-test" location="classpath:/test.properties"/>
</beans>
Init:
System.setProperty("spring.profiles.active", "localDev");
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:applicationContext.xml");
ctx.refresh();
Config:
#Configuration
public class AppConfig {
#Value("${test.value}")
private String testValue;
...
Logs:
INFO: Loading properties file from class path resource [localDev.properties]
Properties:
test.value=ugh
So it seems the properties are getting read, however the the value in AppConfig.testValue is not getting set. I have tried pure java java/xml etc... Some configs break some work, tried using #PropertySource, but the constant is testValue never gets set, so I'm fundamentally doing something wrong.
The overall goal is to load different properties files depending on different profiles.
Can anyone see what I'm doing wrong?
Thanks
You will also a need a PropertySourcesPlaceholderConfigurer which can resolve the property for you. This is configured using:
<context:property-placeholder location="..."
local-override="true" properties-ref="propertiesLocalDev" />
With this your property value should resolve cleanly.
This also should work - using Spring-EL:
#Value("#{#propertiesLocalDev['test.value']}")
private String testValue;
Try
public class AppConfig {
#Autowired
private String testValue;
}
If the variable is properly autowired you can use
String sUgh = testValue.getProperty("test.value"); // = "ugh"
I alsou would use plain
<util:properties id="propertiesLocalDev"location="classpath:/localDev.properties"/>
instead of using the
<beans profile>
tag.
You have to use something like, in XML only use following
<util:properties id="test" location="classpath:fn-test-configuration.properties" />
Now, following way you can use the property values in class
#Value("#{test.test.value}")
private String testValue;
I have used the same way and it is working fine.

How do #value annotations work in Spring?

I've never worked with Spring before, and I've run into a configuration object that looks somewhat like this
public class Config {
#Value("${app.module.config1}")
private String config1;
#Value("${app.module.config2}")
private String config2
...
public String getConfig1() {
return config1;
}
...
Can anyone explain what is happening here? I'm assuming this is some type of code injection, but I can't find where these values are coming from!
They allow you to direct inject a Value from a properties file (system or declared property) in the variable. Using the util:properties tag you can add something like this in your applicationContext.xml
<util:properties id="message" location="classpath:com/your/program/resources/message.properties" />
Pointing for a properties file named "message.properties" with some content:
application.hello.message = Hello World!
And then, in your java source file, inject a direct value from this properties file using the #Value annotation:
#Value("#{message['application.hello.message']}")
private String helloWorldMessage;
#Value("${app.module.config1}")
This is part of the spring expression language where the spring framework would look for app.module.config1 JVM property from System.getProperties() and injects the value of that property into config1 attribute in that class. Please see this reference for more details in Spring 3.0.x and this reference for the current docs.

Resources