Does Aries managed-service-factory also manage properties? - java

I'm using Apache Aries 0.2 in Servicemix 4.3.1 and creating a cm:managed-service-factory. Creation of the services with .cfg files works fine (except for #ARIES-584), but the properties from the .cfg file do not get injected into the service object. They do get set properly in ConfigAdmin, just my bean setter methods never get called for the values in my config file.
I was thinking I should maybe use a cm:managed-properties or something like that nested inside my managed-service-factory, but that would require a separate pid, so doesn't seem right.
If I don't put the property tag in, then no value ever gets set. With the property tag, then just the default value gets set, but never the actual config file value.
I can't find any documentation for usage of the Aries CM subproject, except for blueprint-sample.xml, which doesn't show managed properties inside a managed service factory. I've really been trying to use Servicemix, but around every corner there is missing documentation, broken or missing features, or bugs that affect core functionality.
Both the spring and gemini documentation indicate that their managed-service-factory implementations should also function as managed-properties.
foo.xml:
<blueprint>
<cm:managed-service-factory id="myfoo-msf" factory-pid="my.msf" interface="my.IFoo">
<cm:managed-component class="my.Foo">
<property name="name" value="default />
</cm:managed-component>
</cm:managed-service-factory>
</blueprint>
IFoo.java
package my;
public interface IFoo {
public String getName();
public void setName(String name);
}
Foo.java
package my;
public class Foo implements IFoo {
private String name;
public void setName(String name) {
this.name = name;
System.out.println("name set to: " + name);
}
public String getName() {
return name;
}
}
my.msf-1.cfg
name=name1
my.msf-2.cfg
name=name2
System.out
name set to default
name set to default
config:proplist
service.pid = my.msf.xxxxxxx-xx-xx-xxxxxxxxxxxxxxx
name = name1
service.factoryPid = my.msf
service.pid = my.msf.yyyyyyy-yy-yy-yyyyyyyyyyyyyyy
name = name2
service.factoryPid = my.msf

I believe you have to add one extra line within your managed-component element.
<blueprint>
<cm:managed-service-factory id="myfoo-msf" factory-pid="my.msf" interface="my.IFoo">
<cm:managed-component class="my.Foo">
<cm:managed-properties persistent-id="" update-strategy="container-managed"/>
<property name="name" value="default />
</cm:managed-component>
</cm:managed-service-factory>
</blueprint>
The default value will indeed be overwritten whatever is in your cfg file. If it matters,the default property value setter will be invoked, followed by the same property setter with the value from the cfg.
In this case I have used container-managed for update strategy. But you could use component managed.
This seems kind of redundant to me and in poor taste. Why do I need to set another managed-properties within my bean with a blank persistent id when I have already done so above? Maybe there is a better way but this seems to work.
Also, there is no obvious way to affect the Service Properties that are advertised. For example, we might want to have a convention that any cfg properties that start with service:xxx would be passed through to the Service properties.
Update: The Apache Aries tests are pretty helpful. They can be found here http://aries.apache.org/downloads/currentrelease.html. In particular take a look at the one for configuration management, org.apache.aries.blueprint.cm . In the test folder it has some examples. It shows that in addition to the cm:managed-properties child element within the cm:managed-component shown above, there is also an option to have a cm:cm-properties element within the service-properties.
<service-properties>
<entry key="key" value="foo3" />
<cm:cm-properties persistent-id="" update="true"/>
</service-properties>

Related

Spring Boot application.properties lifecyle

I have a large Spring web application, dating back several years. I need to update it to Spring Boot (corporate requirement). I'm well on my way - it starts (!), although there are some issues with properties being injected, which causes the app to fail.
Specifically, there are three huge config files per profile, eg qa_config.properties, qa_ehcache.xml, qa_monitoring.properties. At present I only care about qa_config.properties, which I have renamed to Spring Boot's preferred name, application-qa.properties, and application-qa_monitoring.properties
The application has a number of classes annotated with #Named (from the javax.ws.rs-api ) which are loaded early - so early that I need to inject properties in the constuctor:
package com.domain.app;
import org.springframework.beans.factory.annotation.Value;
import javax.inject.Named;
#Named
public class Foo {
// Cant use #Value here, it is not yet in the context
protected String bar; // lives in application-qa.properties
protected String qux; // lives in application-qa_monitoring.properties
public Foo(#Value("${application.property.named.bar}") String bar,
#Value("${monitoring.property.named.qux}") String qux) {
this.bar = bar;
this.qux = qux;
doSomeWork();
}
}
Properties files:
#application-qa.properties
application.property.named.bar=something
and
#application-qa_monitoring.properties
monitoring.property.named.qux=another_thing
My problem: I want to have both application-qa.properties and application-qa_monitoring.properties in context as soon as possible, and before the #Named classes are loaded.
To achieve this, I am running the application with an active profile of qa, which successfully adds that set of properties into the context.
I added this line to the application.properties file, to ensure that the other properties are loaded:
spring.profiles.include=${spring.profiles.active}_monitoring.properties
When I run the Spring Boot app, the output tells me
The following profiles are active: qa_monitoring.properties,qa
When debugging the Foo class, the value of bar is correct
But, the value of qux is null.
Am I missing something about the order in which properties files are loaded? I would have thought that the include line in application.properties would be sufficient to "flatten" the two files very early on, if one is in context, so both should be available?
What I could do instead is just throw all the vars in the two properties files into one, the application-qa.properties but I'd like, if possible, to keep them seperate and as close to the original structure as possible.
Thanks to pvpkiran and Andy Brown.
My application.properties file should have read
spring.profiles.include=${spring.profiles.active}_monitoring
ie, just adding another profile, in this case qa_monitoring - Spring automagically adds the application- prefix and the .properties suffix
The issue you are having is because you use a literal value instead of a lookup key in the #Value annotation of your qux value.
Replace
public Foo(#Value("${application.property.named.bar}") String bar,
#Value("monitoring.property.named.qux") String qux) {
With
public Foo(#Value("${application.property.named.bar}") String bar,
#Value("${monitoring.property.named.qux}") String qux) {
And it should work.

How to get rid of OSGi bundle's properties that are not exist in their corresponding configuration ("service.pid", etc.)?

I have the class similar to the following:
#Component(configurationPid = "foo.bar", configurationPolicy = ConfigurationPolicy.REQUIRE)
public class MyClass {
#Activate
public void activate(Map<String, Object> properties) throws Exception {
for (String property : properties.keySet()) {
if (!isValidProperty(property)) {
throw new IllegalArgumentException("Unknown property: " + property);
}
...
}
}
}
The properties map must contain the properties from the corresponding configuration source (e.g. a file provided by an user). And it is, but it also contains some properties that are not really exist (service.pid, felix.fileinstall.dir, etc.), so my program is broken. I want to get rid of them somehow.
I tried to use ConfigurationAdmin.getConfiguration.getProperties and also blueprint cm-properties but this gives the same effect.
I can't hardcode the names of the properties to exclude, because I don't know what they are.
Is there any means to tell the OSGi runtime not to put them at all in my map?
I'm doing this using ServiceMix's OSGi support (which is essentially Karaf, Felix, and Aries).
Just ignore the properties you don't like/understand. The system is designed so that the party doing the configuration can add any property and that property will be passed to your component and thus be a service property on your component's service. Removing the properties you, the component developer, don't understand is overly restrictive. You would remove the ability of someone in the deployment process from decorating your service in a way meaningful to someone else.
Currently there is no way to exclude these artificial properties but I agree this is pretty bad.
You can open an issue and the Apache felix project jira.

Append type level validation error message to specific field

I've got a simple class which get's validated using the boolean isValid() method, which works and of course the error message is at class/type level.
Here's my simple class:
public class NewPasswordDTO {
#NotNull
public String password;
#NotNull
public String confirmation;
#AssertTrue(message="Passwords must match.")
protected boolean isValid() {
return password.equals(confirmation);
}
}
But what I really want is something like that:
public class NewPasswordDTO {
#NotNull
#Equals("confirmation", message="...")
public String password;
#NotNull
public String confirmation;
}
So the error message would be set at field level and not at class/type level.
Is this possible somehow? Maybe using a custom Validator for that class?
Thanks in advance!
SOLUTION:
Thanks to Gunnar! I've just came up with a nice, universal solution :-). I simply used (means copy & paste) the code from Hibernates #ScriptAssert and ScriptAssertValidator and modified it slightly:
#ScriptAssert:
Add new String field(). (this is where the error message gets appended)
ScriptAssertValidator:
Inside the initialize method, make sure to also save the fieldName and message properties, because we need to access them in the next step
Add this snippet at the bottom of isValid method:
context.buildConstraintViolationWithTemplate(errorMessage)
.addPropertyNode(fieldName).addConstraintViolation();
Also add context.disableDefaultConstraintViolation(); somewhere inside the isValid method to not generate the default error message which else would get appended at class level.
And that's it. Now I can use it like that:
#FieldScriptAssert(lang="javascript", script="_this.password.equals(_this.confirmation)", field="password", message="...")
public class NewPasswordDTO { ... }
You either could use the #ScriptAssert constraint on the class (note that a constraint should always be side-effect free, so it's not a good idea to alter the state of the validated bean; instead you should just check whether the two fieldss match) or you implement a custom class-level constraint.
The latter also allows to point to a custom property path for the constraint violation, which it allows to mark the "confirmation" property as erroneous instead of the complete class.
Simple answer : It is not (unless you implement it) :http://docs.oracle.com/javaee/6/api/javax/validation/constraints/package-summary.html shows all annotation constraints.
Of course you could inject your string as a resource in your class by #producer and so on (which recently is discussed to be removed in jdk8), but you could not use this value for your assert. In reply to the comment:
This was asuming that the nature is a constant string which you would like to use as a string resource.And then of course it is possible to write your own class based on java.lang.string with a #Producer which is then #Inject - able. Though it is certainly not the way I personally would deal with constant strings.
If you’re using the Spring Framework, then as an alternative to the #ScriptAssert using a JSR 223 scripting, you can use the #SpELAssert that uses the Spring Expression Language (SpEL). The advantage is that it doesn’t need any JSR 223 compliant scripting engine which may not be available on some environments. See this answer for more information.

how to refer to the property of bean used in BeanEditForm (tapestry5) in Java?

I've got in my .tml file something like this:
<t:beaneditform t:id="adForm" object="editableAd"
reorder="actiontype,shops,movies,streams,widgets" ....
My question is how to access (refer) actionType, which is an Enum (and in fact SELECT) in .java file? I just need to handle event when user changes the value of this select (dropdown), obviously before submitting the form itself.
If something like this would work for me...
#OnEvent(component = "adForm.actionType", value=EventConstants.VALUE_CHANGED)
public void actionTypeValueChanged(String value) {
log.info("value is: " + value);
}
To be updated with the changed value in a Select html component on the client side, have a tapestry select component in your template file with a t:zone attribute (i.e. in your case it could point to any dummy zone, this is only needed to be set correctly if you need to update a zone when a value is changed)
Also set the t:value attribute to your enum variable in your page\component java file, usually this variable will be annotated with tapestry's #Property.
Example:
<t:select t:id="myEnumVariable" t:zone="dummyZone" t:value="myEnumVariable"/>
myEnumVariable is used to refer to your class's variable AND to act as an ID (i.e. the actual string myEnumVariable is used as an id), this is not necessary, but it's more readable and maintainable that way)
public class MyClass{
#Property
private MyEnum myEnumVariable;
#OnEvent(component = "myEnumVariable", value=EventConstants.VALUE_CHANGED)
public void actionTypeValueChanged(**MyEnum** newValue) {
this.myEnumVariable = newValue; // <<<<<<
log.info("value is: " + myEnumVariable );
}
}
If you don't mind using the ChenilleKit framework for tapestry you could try using the
framework's OnEvent mixin.
You 'll find the example on the link I share but basically you add two attributes the select tag:
<t:select t:id="myselect" ... t:mixins="ck/OnEvent" t:event="change" />
then you add the event handler on your java class:
#OnEvent(component="myselect", value='change')
public void onChangeDoSomething(String value) {
hope that helps, by the way I think Muhammad's answer is equally correct (and doesn't requires the use of an extra framework).

Referencing Spring Singletons created in a parent context from a child context

Hard to think of a title for this one! I have a bean that is initialized in a spring container. It loads classes that also create objects from files using Spring classloaders. Some of these objects may have dependencies on expensive objects and I would like those objects to be initialized in the parent. Okay I can't explain in words so on to a simplified example:
public class MainLoader {
public static void main(String[] args) {
XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("top-context.xml"));
ChildLoader childLoader = (ChildLoader)beanFactory.getBean("childLoader");
childLoader.loadChildAndDoSomething("message1.xml");
childLoader.loadChildAndDoSomething("message2.xml");
}
}
public class ChildLoader {
public void loadChildAndDoSomething(String childContextfile){
XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource(childContextfile));
ClassThatDoesStuff classThatDoesStuff = (ClassThatDoesStuff)beanFactory.getBean("classThatDoesStuff");
classThatDoesStuff.saySomething();
}
}
public class ClassThatDoesStuff {
private ReallyExpensiveService reallyExpensiveService;
private String messageStart;
public void saySomething(){
System.out.println(messageStart + reallyExpensiveService.getName());
}
// .. field setters removed for brevity
}
public class ReallyExpensiveService {
public String getName(){
return "Joe";
}
}
These have the following beans in the files:
top-context.xml:
<bean id="childLoader" class="com.mark.test.ChildLoader" />
message1.xml (message2.xml is similar):
<bean id="classThatDoesStuff" class="com.mark.test.ClassThatDoesStuff">
<property name="messageStart" value = "Hello! " />
<property name ="reallyExpensiveService" ref="theExpensiveserviceReference" />
</bean>
<bean id="theExpensiveserviceReference" class="com.mark.test.ReallyExpensiveService" />
When these are run you get the expected:
Hello! Joe
Goodbye! Joe
The only problem here is that the "ReallyExpensiveService" is getting created and cached by Spring on each occasion. This is verified by the log. Better to load up any services that might be needed by the "ClassThatDoesStuff" classes (imagine it's an interface) when the MainLoader is initialzed. I.e. (conceptually) change the spring context files to:
top-context.xml:
<bean id="childLoader" class="com.mark.test.ChildLoader" />
<bean id="theExpensiveserviceReference" class="com.mark.test.ReallyExpensiveService" />
message1/2.xml
<bean id="classThatDoesStuff" class="com.mark.test.ClassThatDoesStuff"
autoWired="byType">
<property name="messageStart" value = "Hello! " />
</bean>
I realise that the way out of this would be to have the ClassThatDoeStuff have a setter for the service and set the value from the Child container which itself had it injected via the main context. But imagine that there are arbitrary services and each of the ClassThatDoesStuff implementers used different ones.. Is there any way for this to work in Spring..?
It seems like the best you can hope for is to instantiate each ReallyExpensiveService one time. (You mention in there that you're not sure which ClassThatDoesStuff may use a different one.) I would probably try to define all of my ReallyExpensiveService beans in the top level context and then hand them out to the classes that use them wherever it's appropriate, either through the XML configuration files that you're using or through some kind of factory that you inject into the ClassThatDoesStuff beans.
You might also try to look for a way to defer the expensive operations of starting up ReallyExpensiveService until you're sure they're going to be used. Of course this depends on what "expensive" means. Is it that the services use too much memory and you don't want them around if they're not in use or that they take too long to instantiate?
In any case, the key here is to have as few instances of expensive things floating around as possible, so you'll want to configure them at the top level so that the references to the single instances can be passed around anywhere.
I fiddled around a lot with this and learnt a lot about spring in the process. I don't think it's possible to get the parent spring context to apply these properties dynamically. I got around the problem by implementing caching in the mainloader object so that expensive types aren't created multiple times frmo the spring definition.
The other possiblity I investigated was making the ChildLoader context aware and allowing the ClassThatDoesStuff to use the parent context to get handles on beans, but this was bedding in spring to the app too much for my liking.

Categories

Resources