Monotouch - global variables - xamarin.ios

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.

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.

How to override protected methods of a class of MVCResourceCommand in liferay?

I want to override a protected method in the class ExportArticleMVCResourceCommand which extends theBaseMVCResourceCommand class.
I want to convert journal article's to pdf in liferay 7 . I have written this functionality in its own method and wish to call that method in the doServeResource(...) method. But as doServeResource() is protected, I am not able to call it on a button submit. Therefore, I want to ask how to override this doServeResource() method in liferay 7.
Dissecting the problem
Liferay 7 is an open source Java platform an as such the best way to troubleshoot (absent any documentation) is to first at the code. You will notice that theExportArticleMVCResourceCommand class extends BaseMVCResourceCommand. In the ExportArticleMVCResourceCommand class you can see that the doServeResource method overrides it's parent's doServeResource method. In BaseMVCResourceCommand there are several things to note.
It is an abstract class
There is protected abstract void doServeResource method with no implementation.
The serveResource method simply calls the doServeResource
Piecing it together
So you want to override the doServeResource method in the ExportArticleMVCResourceCommandclass because that method does not work when the "targeted extension" is of type PDF (purportedly). You cannot override the doServeResource by extending or implementing any *MVCResourceCommand class or interface because it's either protected (and your OSGi component override is bundled separately) or in the case of MVCResourceCommand interface it doesn't exist.
Solution
Remember the doServeResource method is simply called by the serveResource method in ExportArticleMVCResourceCommand, and the serveResource method is public in both the MVCResourceCommand interface and BaseMVCResourceCommand class. Therefore to override the doServeResource method you simply need to create your own OSGi component with that appropriate annotations, have it override the serveResource method, and do not the referened serveResource method at the end of your own.
#Component(
property = {
"javax.portlet.name=" + JournalPortletKeys.JOURNAL,
"mvc.command.name=exportArticle"
},
service = MVCResourceCommand.class
public class CustomExportArticleMVCResourceCommand implements MVCResourceCommand {
#Override
public boolean serveResource
(ResourceRequest resourceRequest, ResourceResponse resourceResponse) {
// Call your custom method here
// ExportArticleUtil.sendFile("pdf", resourceRequest, resourceResponse);
}
#Reference(target = "(component.name=com.liferay.journal.web.internal.portlet.action.ExportArticleMVCResourceCommand)")
protected MVCResourceCommand mvcResourceCommand;
}

constructor parameters on controller actions

I am trying to create a custom manager which is passed in the controller when it is being called and I am having troubles understanding the current implementation of new MVC5 project in c#.
Here is the default implementation:
public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager )
{
UserManager = userManager;
SignInManager = signInManager;
}
above all of that are declarations for them:
public ApplicationSignInManager SignInManager
{
get
{
return _signInManager ?? HttpContext.GetOwinContext().Get<ApplicationSignInManager>();
}
private set
{
_signInManager = value;
}
}
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
Now from my understanding the SignInManager and UserManager get created when application gets created for the first time in Startup.Auth.cs which looks like this:
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
So now whenever I call UserManager I will get that first instance that was created when project ran for the first time.
I have 2 questions. Question 1 is is anything I said above wrong and Do I have a wrong understanding of how MVC5 works?
Question2: How is UserManager and SignInManager generated and passed in the controller? Where is the code that creates that first instance of the manager and passes it in the controller? I am assuming it is app.CreatePerOwnContext that does it. If so, can I then just create my own Manager and then register it with Owin in the same fashion and reuse throughout the project? Will my code get the latest data from the database if I do this and not cache it?
The code you're showing is coming from the IMO very ugly MVC5 template, which works out of the box but does some ugly things.
This constructor:
public AccountController(ApplicationUserManager userManager,
ApplicationSignInManager signInManager)
makes you think OWIN automagically injects the managers for you. But in fact this is not the case. That is why the template comes with the ugly properties you supplied in the questions. When you do not change anything to the template, the default constructor is called (also present in the template). To try it, just delete, or comment, the default constructor and you'll see the AccountController can't be created anymore.
So what is actually happening there is that both managers are located using the Service Locator anti pattern in the getters of the supplied properties.
So now whenever I call UserManager I will get that first instance that was created when project ran for the first time?
No this is not the case. What this line:
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
does, is creating a delegate to the Create method of both managers. The managers are cached within an Owin Request. The next request the delegates are called again and you get a fresh ApplicationUserManager etc.
To be a little bit more verbose this line could be rewritten as:
Func<ApplicationUserManager> userManagerFactory = () => ApplicationUserMangager.Create();
app.CreatePerOwinContext<ApplicationUserManager>(userManagerFactory);
So if you would a breakpoint here:
public ApplicationUserManager UserManager
{
get
{
// place breakpoint here
return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
// ....
You would see that while stepping through the code, you will hit the line where you created the UserManagerFactory which in his turn will call the Create() method of the ApplicationUserManager.
How is UserManager and SignInManager generated and passed in the controller
It isn't! You would need to use dependency injection for that.
If so, can I then just create my own Manager and then register it with Owin in the same fashion and reuse throughout the project
Yes you can. You can completely refactor the ApplicationUserManager you also got 'for free' in the template. As long as you supply a factory method to the 'CreatePerOwinContext' extension method.
Will my code get the latest data from the database if I do this and not cache it?
The instances are cached on per request base. So each request you will get a new one, with a new DbContext etc.
I'm unsure how familiar you are with dependency injection but MVC5 is a pretty easy framework to start with it, IMO.
I once wrote a blogpost how to configure my DI container of choice (Simple Injector) to use with the MVC5 template.
I also wrote several answers here on SO regarding this template: specifically this one, should interest you. This one is interesting also!

ADF/JSF Configuration Data in App Scoped Managed Bean

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.

JavaFX IllegalAccessException during FXML load()

I have a dialog window that is invoked by the following code (DialogController is a helper class for using modal dialog windows; it mainly bundles together a controller reference with its window):
void handleServicesEdit(ActionEvent event) throws IOException {
DCServRecEditor sre = DialogController.<DCServRecEditor>loadFXML(
CensusAssistant.RES_FXML_DIALOG_SERVEDIT,
CensusAssistant.RES_STRING_SERVEDIT,
this.getDialog());
sre.setDialogMode(DB.DBEDIT_MODE_EDIT,
tbvService.getItems(),
tbvService.getSelectionModel().getSelectedIndex(),
m_encCal);
sre.showAndWait();
sre.release();
this.updateGUI();
}
I have confirmed that I get an exception during the FXMLLoader.load() method. I have also determined that the error occurs before any code in my initialize() method has a chance to run. Some of the stack trace that I get from load() is here:
java.lang.IllegalAccessException: Class sun.reflect.misc.ReflectUtil
can not access a member of class org.kls.md.censusassistant.DCServRecEditor
with modifiers ""
file:/D:/Documents/NetBeansProjects/CensusAssistant/dist/run1284250063/CensusAssistant.jar!/org/kls/md/censusassistant/fxml/GUIServRecEditor.fxml:13
at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:738)
at javafx.fxml.FXMLLoader$InstanceDeclarationElement.processAttribute(FXMLLoader.java:775)
at javafx.fxml.FXMLLoader$Element.processStartElement(FXMLLoader.java:180)
at javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:563)
at javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2314)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2131)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2028)
at org.kls.md.censusassistant.DialogController.loadFXML(DialogController.java:63)
at org.kls.md.censusassistant.DCMainEditor.handleServicesEdit(DCMainEditor.java:330)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
...
Caused by: java.lang.IllegalAccessException: Class sun.reflect.misc.ReflectUtil
can not access a member of class org.kls.md.censusassistant.DCServRecEditor
with modifiers ""
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:95)
at java.lang.Class.newInstance0(Class.java:368)
at java.lang.Class.newInstance(Class.java:327)
at sun.reflect.misc.ReflectUtil.newInstance(ReflectUtil.java:46)
at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:731)
... 66 more
My class DCServRecEditor is a subclass of DialogController. It is a pretty normal looking FXML controller class:
class DCServRecEditor extends DialogController {
private int m_dialogMode = DB.DBEDIT_MODE_ADD;
private int m_selServ = -1;
private GregorianCalendar m_cal = null;
#FXML // ResourceBundle that was given to the FXMLLoader
private ResourceBundle resources;
#FXML // URL location of the FXML file that was given to the FXMLLoader
private URL location;
#FXML // fx:id="ancMatchSelector"
private AnchorPane ancMatchSelector; // Value injected by FXMLLoader
#FXML // fx:id="ancServEditor"
private AnchorPane ancServEditor; // Value injected by FXMLLoader
#FXML // fx:id="ancServRecEditor"
private AnchorPane ancServRecEditor; // Value injected by FXMLLoader
...
}
I have double and triple checked to make sure that there wasn't a named control in the FXML that didn't also have an instance field in the controller class.
All the instance fields are tagged with #FXML.
The name of the controller class in the FXML is the same as my java file and is properly qualified.
The error occurs before initialize() is called, so I don't think it's anything with initialize(), although I have checked to make sure it is also tagged with #FXML.
The skeleton for my controller class was copied and pasted from Scene Builder ... I've gone back and repasted blocks of stuff from Scene Builder to be sure that there wasn't a control I was missing in my java file.
The error message gives me no specifics about the member it is having its problem with, other than to say it has modifiers "".
I went back to my controller class and made all the members with default access public, and I still get the error.
I don't even know where in my class the problem is coming from.
Anyone have any ideas about what is going wrong here?
Yet another embarrassingly simple problem.
I'm surprised someone didn't jump on this by now.
The problem was in my class DCServRecEditor. Note that the class was declared with default access permission.
JavaFX requires that controller classes be made public.
To be fair to myself, Java's error reporting in this situation is abominable and misleading. The stack trace clearly shows that Java is complaining about being unable to access a member of my class, hence my focus on my instance fields and methods. Java really should have complained that it was the class itself that it could not access and not its members.
Had the same issue. In my case controller was at folder that named with uppercase letter. cast to lowercase solve the problem.
I prefer to declare every method and filed public.

Resources