ADF/JSF Configuration Data in App Scoped Managed Bean - jsf

I'm fairly new to ADF/JSF and I've inherited an application that uses a properties file to store application configuration data (as key = value pairs). I tried something like the following example:
public class AppScopeManagedBean {
private static final String property1;
public AppScopeManagedBean() { }
static {
// Load the properties file and initialize fields
}
public static final String getProperty1() {
return property1;
}
}
The problem is that I need to be able to reference these properties in EL bindings as well and ADF (and I presume JSF as well) does not allow me to do this.
What are some recommendations for storing configuration data in an application scoped managed bean?

Once you are setting your managed bean in application scope, there is no reason to have static properties. You can place the static initializer in bean's constructor.
Just use a normal bean so you can reference it from EL.

Related

How to use the strategy pattern with managed objects

I process messages from a queue. I use data from the incoming message to determine which class to use to process the message; for example origin and type. I would use the combination of origin and type to look up a FQCN and use reflection to instantiate an object to process the message. At the moment these processing objects are all simple POJOs that implement a common interface. Hence I am using a strategy pattern.
The problem I am having is that all my external resources (mostly databases accessed via JPA) are injected (#Inject) and when I create the processing object as described above all these injected objects are null. The only way I know to populate these injected resources is to make each implementation of the interface a managed bean by adding #stateless. This alone does not solve the problem because the injected members are only populated if the class implementing the interface is itself injected (i.e. container managed) as opposed to being created by me.
Here is a made up example (sensitive details changed)
public interface MessageProcessor
{
public void processMessage(String xml);
}
#Stateless
public VisaCreateClient implements MessageProcessor
{
#Inject private DAL db;
…
}
public MasterCardCreateClient implements MessageProcessor…
In the database there is an entry "visa.createclient" = "fqcn.VisaCreateClient", so if the message origin is "Visa" and the type is "Create Client" I can look up the appropriate processing class. If I use reflection to create VisaCreateClient the db variable is always null. Even if I add the #Stateless and use reflection the db variable remains null. It's only when I inject VisaCreateClient will the db variable get populated. Like so:
#Stateless
public QueueReader
{
#Inject VisaCreateClient visaCreateClient;
#Inject MasterCardCreateClient masterCardCreateClient;
#Inject … many more times
private Map<String, MessageProcessor> processors...
private void init()
{
processors.put("visa.createclient", visaCreateClient);
processors.put("mastercard.createclient", masterCardCreateClient);
… many more times
}
}
Now I have dozens of message processors and if I have to inject each implementation then register it in the map I'll end up with dozens of injections. Also, should I add more processors I have to modify the QueueReader class to add the new injections and restart the server; with my old code I merely had to add an entry into the database and deploy the new processor on the class path - didn't even have to restart the server!
I have thought of two ways to resolve this:
Add an init(DAL db, OtherResource or, ...) method to the interface that gets called right after the message processor is created with reflection and pass the required resource. The resource itself was injected into the QueueReader.
Add an argument to the processMessage(String xml, Context context) where Context is just a map of resources that were injected into the QueueReader.
But does this approach mean that I will be using the same instance of the DAL object for every message processor? I believe it would and as long as there is no state involved I believe it is OK - any and all transactions will be started outside of the DAL class.
So my question is will my approach work? What are the risks of doing it that way? Is there a better way to use a strategy pattern to dynamically select an implementation where the implementation needs access to container managed resources?
Thanks for your time.
In a similar problem statement I used an extension to the processor interface to decide which type of data object it can handle. Then you can inject all variants of the handler via instance and simply use a loop:
public interface MessageProcessor
{
public boolean canHandle(String xml);
public void processMessage(String xml);
}
And in your queueReader:
#Inject
private Instance<MessageProcessor> allProcessors;
public void handleMessage(String xml) {
MessageProcessor processor = StreamSupport.stream(allProcessors.spliterator(), false)
.filter(proc -> proc.canHandle(xml))
.findFirst()
.orElseThrow(...);
processor.processMessage(xml);
}
This does not work on a running server, but to add a new processor simply implement and deploy.

Seed value in Weld CDI custom scope

Coming from a Guice background, I know that it is possible to seed an object value from a scope using.
scope.seed(Key.get(SomeObject.class), someObject);
I suppose one could do this by registering a Bean that gets a value from an AbstractBoundContext, but examples just seeding one value from a Custom Scope seem hard to find. How do I create a custom scope that seeds a value that can be injected elsewhere?
Edit:
I am currently using the following workaround, that can be injected in an interceptor to set the Configuration when entering the scope, and can then be injected through its thread local provider. I am still looking for options that feel less hacky / are more integrated with the scope/scope context system in Weld though.
#Singleton
public class ConfigurationProducer {
private final InheritableThreadLocal<Configuration> threadLocalConfiguration =
new InheritableThreadLocal<>();
#Produces
#ActiveDataSet
public ConfigurationConfiguration() {
return threadLocalConfiguration.get()
}
public void setConfiguration(Configuration configuration) {
threadLocalConfiguration.set(configuration);
}
}
The answer is to register a custom bean with the AfterBeanDiscovery event, like so:
event.addBean()
.createWith(ctx -> commandContext.getCurrentCommandExecution())
.addType(CommandExecution.class)
.addQualifier(Default.Literal.INSTANCE)
.scope(CommandScoped.class)
.beanClass(CommandExtension.class);
There is a quite sophisticated example available at https://github.com/weld/command-context-example

How to set up a managed bean to work with Notes document

I would like to set up a managed bean that manages a Notes document in Notes view where I store application preferences in (e.g. path on server to store attachments, application title, which logo to display etc)
Has anyone an example for such a bean and how I should use it?
Current I load a SSJS library an place everything in application scope or session scope variables.
Here is a simple example for such a managed bean.
First create a Java class. I called it "Config". It reads the first document in view "Config" and puts at instantiation time (=first call) the items in java fields. Doing this you can recycle the domino objects after reading all items and have the values in memory then.
package de.leonso;
import java.io.Serializable;
import lotus.domino.Database;
import lotus.domino.Document;
import lotus.domino.View;
import com.ibm.xsp.extlib.util.ExtLibUtil;
public class Config implements Serializable {
private static final long serialVersionUID = 1L;
private String applicationTitle;
// ... other private fields
public Config() throws NotesException {
Database db = ExtLibUtil.getCurrentSession().getCurrentDatabase();
View view = db.getView("Config");
Document doc = view.getFirstDocument();
applicationTitle = doc.getItemValueString("ApplicationTitle");
// ... read all other items and store them in private fields
doc.recycle();
view.recycle();
db.recycle();
}
public String getApplicationTitle() {
return applicationTitle;
}
// ... getters for other private fields
}
Next define this Java class as a managed bean in faces-config.xml file:
<faces-config>
<managed-bean>
<managed-bean-name>config</managed-bean-name>
<managed-bean-class>de.leonso.Config</managed-bean-class>
<managed-bean-scope>application</managed-bean-scope>
</managed-bean>
</faces-config>
You can use as scope "application" (instance per server) or "session" (instance per user).
Then you can use the config bean in JavaScript:
#{javascript:var titel = config.applicationTitle; ...}
or Expression Language:
#{config.applicationTitle}
That should give you a good starting point to develop an advanced version of a config bean.
The application-scoped bean is definitely a good way to go for this. Once you get more comfortable with Java, you might want to consider using a VariableResolver instead or even an OSGi plugin if some of those options are server-wide. I've also posted an XSnippet for retrieving values from xsp.properties, which may also be appropriate for some settings http://openntf.org/s/retrieve-property-from-xsp.properties-in-nsf-server-or-notes.ini

CDI: How to put an existing object into application scope (without writing CDI extension)?

I have an object which I initialized manually (legacy code).
I'd like to put this object to the application context to make it available through CDI.
How do I do that without writing a CDI extension?
Using a producer. Make a bean that #Produces instances of your class.
Do you need something like that?
#ApplicationScoped
public class ApplicationScopedClass {
#Produces
public static ApplicationScopedClass makeAnInstance() {
return new ApplicationScopedClass();
}
}

Monotouch - global variables

How can I store/access global variables within a monotouch application? I am retrieving the GPS Location (using Monotouch.CoreLocation.CLLocationManager) during the FinishedLaunching method of the AppDelegate. How do I then access that information from a property on that appdelegate (from a view, for example)? Or is there another preferred method for global data?
UPDATE:
I just want to grab the location once, at startup, then have access to that location from all my views. Here's my AppDelegate - I'd like to access the locationManager field from a view. I can certainly add a property to do so, but I guess my question is "How do I access that property from a view (or can I even, considering it's a delegate)"?
// The name AppDelegate is referenced in the MainWindow.xib file.
public partial class AppDelegate : UIApplicationDelegate
{
private CLLocationManager locationManager = new CLLocationManager();
// This method is invoked when the application has loaded its UI and its ready to run
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
locationManager.Delegate = new GpsLocationManagerDelegate();
locationManager.StartUpdatingLocation();
window.AddSubview (navController.View);
window.MakeKeyAndVisible ();
return true;
}
// This method is required in iPhoneOS 3.0
public override void OnActivated (UIApplication application)
{
}
}
Generally, most people will tell you to avoid global variables and instead pass what you need into the delegate. (I would agree with that sentiment).
However, you can use a singleton class, a service locator, or a static class with static fields/properties to get global variable-like behavior in C# (or any other Dotnet/Mono compatible language).
In your case, I presume you wrote the class GpsLocationManagerDelegate yourself. If so, you can change the constructor to take parameters for the necessary information (the view, a reference to the app delegate, and/or a reference to the location manager) and store it in your GpsLocationManagerDelegate instance. If you didn't write GpsLocationManagerDelegate yourself and it's not declared sealed, subclass it and create an appropriate constructor.
This example seems close to what you're after: http://www.conceptdevelopment.net/iPhone/MapKit01/Main.cs.htm
You should make locationManager a public property, then you can access it from most places in the app like so:
CLLocationManager LocationManager {get;set;}
AppDelegate delegateReference =
(AppDelegate)UIApplication.SharedApplication.Delegate;
then access the locationmanager anywhere in code via:
delegateReference.LocationManager
Generally, you should setup such things as singletons, setup within the AppDelegate.

Resources