I read a properties-file at the webapplication startup phase (contextInitialized()) and I started to think about how to make these settings 'visible' to the servlets. Do I need to loop through the keys and add each and every one to the context, like this
Iterator i = settings.keySet().iterator();
while (i.hasNext()) {
key = (String) i.next();
value = (String) settings.get(key);
context.setAttribute(key, value);
}
or are there better methods?
Thank you!
/Adam
why not store the entire contents in your servlet context?
context.setAttribute("mySettings", settings);
setAttribute's signature is:
public void setAttribute(String name, Object object)
Have you considered the possibility of defining the settings in web.xml?
Also, if that's not possible, use generics if possible:
String key = null;
Iterator<String> i = settings.keySet().iterator();
while (i.hasNext())
context.setAttribute(key = i.next(), settings.get(key));
I've been toying with an idea:
In the context initialized method, I've planned to create just one global object for the settings. Much like toolkit proposed. But instead of setting context attributes for each key/attribute/setting, would it be a terrible idea to add a settings container/wrapper object? I'm thinking this class would be responsible for holding (static?) classes of module settings. This way I can get typed references like so
//ExampleServlet.java
Settings settings = (Settings)context.getAttribute("application.settings");
String color = settings.getModule1().getColor();
String font = settings.getModule1().getFont();
int blogs = settings.getModule2().getActiveBlogCount();
Throughout the code I'll have to remember only one attribute key, the one for the entire settings container. Less risk of typos which could cause rumtime exceptions!
It will also make it easy to rename attributes.
What do you think?
/Adam
What about using the JNDI context. JNDI is a more common way to pass properties to a webapp.
Any Properties may be specified in the META-INF/context.xml for tomcat or any application specific setup.
It's something that I have contemplated, setting the entire properties object as a context attribute.
If I do not go this route, are there any guidelines for how to name these attributes or do you feel that "application.settings" or "myBlog.settings"? How do you group keys? Would this be okay:
application.module1.color=black
application.module1.font=arial
I feel, in a way, that it could become a burden to maintain such an application where the property keys are spread throughout the code? Should another developer rename a property in the properties file, we'll know only when running the application (if/when/what referenced the old key). Right?
I'll have to lookup JNDI.
Related
I am working on a project where every model has this line:
#Model(adaptables = { SlingHttpServletRequest.class,Resource.class },
defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
In my understanding:
If Resource or SlingHTTPRequest is not to be used, this dependency injection must be removed from the model
SlingHTTPRequest can help obtain resource with the use of .getResource method anyway, so using SlingHTTPServeltRequest class alone, with required dependencyInjectionStrategy should be sufficient, and Resource class as an adaptable is never needed?
Please share your thoughts. Thanks in advance!
Question 1)
A SlingModel MUST be either created/adapted from SlingHttpServletRequest or a Resource. It cannot be created from nothing.
The the adaptables-property specifies, from which object it can be created.
If the SlingModel can be created from both, the scripting-environment (e.g. HTL scripts) will use the Resource. But SlingModels can be used elsewhere too, so the source will be random.
Hint 1: Do not use both adaptables. So either decide for SlingHttpServletRequest or Resource. Because both will work, but the injecting will be different - and can cause weird bugs (at least it is thin ice, and hard to test). The example with #Self is simple, but some other injectors are even more complicated, as the implicitly the #Via changes.
#Model(adaptables = { SlingHttpServletRequest.class, Resource.class },
defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class MySlingModel {
#Self
// will be null, if adapted from Resource!!!
private SlingHttpServletRequest request;
#Self
// will be null, if adapted from SlingHttpServletRequest!!!
private Resource resource;
Question 2
Components (and so SlingModels) should be context-free, and be represented by a Resource (= JCR node and evtl. some sub-nodes).
So a SlingModel should normally adapted from a Resource. It is also easier to use elsewhere (in other services or sling-models).
Only, if you need something from the request, then switch to the SlingHttpServletRequest. Unfortunately this is often needed for URL mapping. But limit yourself to access RequestAttributes. Even something like WcmMode should not be used in a SlingModel. It is better to see SlingModels as a Wrapper around a Resource, a small Java-Layer to access data.
Hint 2: Not everything is a SlingModel! You can create Services, Servlets, AdapterFactories, Filters, Rewriter, ...
yes its not mandatory. but if your data is in a nested structure (think of slides inside a carousel), and you need to adapt a nested resource (slide) to model, you need resource as adaptable. request.getResource will get you the component resource,
additionally, you might have to work with resources without a request object, say in a workflowprocessstep or a sling job processor. capability to just do resource.adaptTo saves you a bit of time.
My Java application loads a properties file at startup, which contains key-value pairs. I can set and retrieve the expected properties successfully.
However, as it stands the properties file can contain any property name I care to put in there. I'd like to be able to restrict the properties to a specific set, some of which are mandatory and others optional.
I can manually check each loaded property against a valid set but I was wondering if there was a more elegant way to do this. E.g. perhaps some way to declare the expected mandatory/optional properties, so that when the properties file is loaded, an exception is thrown if an invalid or missing property is detected. Similar to the kind of thing boost::program_options offers in C++.
Since Properties is already a simple iterable structure, I would just perform your validation against that object. Below is a simple validation of required vs optional.
public static void testProps(Properties props, Set<String> required, Set<String> optional) {
int requiredCount=0;
Enumeration keys = props.keys();
while (keys.hasMoreElements()) {
String key=(String) keys.nextElement();
if (required.contains(key)) {
requiredCount++;
} else if (!optional.contains(key)) {
throw new IllegalStateException("Unauthorized key : " + key);
}
}
if (requiredCount<required.size()) {
for (String requiredKey : required) {
if (!props.containsKey(requiredKey)) {
throw new IllegalStateException("Missing required key : " + requiredKey);
}
}
}
}
I can manually check each loaded property against a valid set but I
was wondering if there was a more elegant way to do this. E.g. perhaps
some way to declare the expected mandatory/optional properties, so
that when the properties file is loaded, an exception is thrown if an
invalid or missing property is detected.
The built-in API of the JDK (java.util.Properties) do not offer this kind of validation.
However, it should not be difficult to implment your own ConfigLoader class which does this. Your class could wrap java.util.Properties, and validate the data after loading. You could for example maintain a list of mandatory and optional keys (hardcoded, or loaded externally), and then check the list of loaded keys against these lists.
It's possible you could find some implementation which does this, but as the validation itself will be specific to your needs anyway, and the rest is fairly simple, I don't think it's worth hunting for an existing solution.
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.
PUsing Spring 3.2.0.release and JDK 1.6. I've a standalone Java program (NOT running inside tomcat etal) and I'm loading properties from a database.
I've used this excellent article as a base and it works perfectly. Using the PropertiesPrinter bean (defined there) as a base and adding getters I can do stuff like getFileLocation(), getPetDogsName() but then I need to have/create setter/getters for every property.
What I would like to have is a Spring Bean or normal Java class called DatabaseProperties with a method like getProperty("filelocation"); which I can use in my application (main)and so I can retrieve/get the value of the property filelocation which is somewhere inside the information collected by PropertyPlaceholderConfigurer.
I've done a lot of digging but can't seem to find the information I need or at least I'm not able to combine the gathered info into a working program as I'm not fluent with Spring....
Any hint/pointers/urls/code is higly appreciated. It's probably relative easy but it is still out of reach for me atm.
One solution for reading values set by the PropertyPlaceholderConfigurer, is to use the #Value annotation rather than a method for setting class member variables:
class MyClass {
#Value("${file.location}")
private String fileLocation;
...
}
I have to access some application through an mbean so that I can change its application properties. Now i think this can be done in two ways:
First, either I ask the developer of that application to register all the application properties in an arraylist which my mbean will access.
Secondly, if there is any other way, such that the developer will only need to register editable properties and still my mbean can access both readable/editable(r/w) application properties.
Now since I don't know where these application properties are stored in the JVM, is there a way to implement my second point so that the mbean will just need to access that object and it will get all application properties?
Seems like you have some contradicting requirements here.
You want to change minimal code in the application.
You want to be cause to expose all properties for read and/or write.
You may or may not be talking about System.getProperty(...). If not then I guess you are talking about just fields in various objects.
There are (at least) two ways of doing this. Without knowing how you are exporting the mbeans from the source code right now, I can't tailor my answer to your specific config. My answer will instead show how you might use my SimpleJMX package to expose your properties.
If you are talking about System.getProperty(...) then you could write a JMX mbean that could query any property and return the value:
#JmxOperation(description = "Query for property")
public String queryForProperty(String name) {
return System.getProperty(name);
}
If, instead, you need to export of fields from some list of objects then you are going to either have to add annotations to each fields you are exporting or you are going to have to write beans that export the fields through delegation. I see no easy way and I know of no package that will easily export a series of objects for you without some sort of information about what is to be exported and how.
Using SimpleJMX, you can export a field by annotating either the field or the get method:
#JmxAttributeField(description = "Number of hits in the cache")
private int hitCount;
...
// this can also be specified as #JmxAttributeMethod on the getter/setter methods
#JmxAttributeMethod(description = "Number of misses in the cache")
private int getMissCount() {
return missCount;
}
The #JmxAttributeField supports a isWritable = true to allow the value to be set by JMX. You can also annotation the setter with #JmxAttributeMethod to make it writable.
If you don't want to add annotations to each of your classes, then you are going to have to write some sort of JMX container class that exports the values through delegation:
public class JmxPublisher {
private Class1 object1;
private Class2 object2;
...
public JmxPublisher(Class1 object1, Class2 object2) {
this.object1 = object1;
this.object2 = object2;
...
}
#JmxAttributeMethod(description = "Number of hits in the cache")
public int getClass1HitCount() {
return object1.getHitCount();
}
#JmxAttributeMethod(description = "Shutdown the background thread")
public void setClass2Shutdown(boolean shutdown) {
return object2.setShutdown(shutdown);
}
...
}
I also think you should express yourself more clearly.
From what I understood - why not providing a way to query the remote application, and get information on all properties and if they are Read-only, Write-only or RW?
This way the list of properties will not be mentioned at the source code of the client application - maybe you should let the user of the client application see the list of properties, and let him edit the properties he can edit, and prevent him from editing the properties he can't.