Javafx pass login token from LoginController to CalendarController - javafx

I am using Angela's framework for screens management and I am trying to write a very simple Calendar-application. While writing the UI and the controllers and using the aforementioned framework, all screens initialize immediately on program start. This means I have no idea when the user is actually looking at a certain view.
I need the login-token from the server (assigned in the LoginController) to fire a changed value event of some kind in the CalendarController that is currently running in the background (I presume). At the moment I don't know when the Calendar.fxml is visible and/if the user is logged in, and hence I don't know how to structure my logic to make a function start in CalendarController ONLY after the login-token has been set.
Been stuck a few days here, any help would be greatly appreciated. I have tried using an ObservableList and Listlistener-interface to no avail. Here is the respective part of my LoginController. TokenFactory is a class of static fields and methods (mostly trying to debug).
#FXML
public boolean login() throws JSONException, UnirestException {
if(validateUsernameField() && validatePasswordField()) {
HttpResponse<JsonNode> jsonResponse = Unirest.post(TokenFactory.getSERVER_ADR())
.field("username", usernameField.getText())
.field("password", passwordField.getText())
.asJson();
if ( ((String) jsonResponse.getBody().getObject().get("message")).equalsIgnoreCase("OK")) {
String token = ((String) jsonResponse.getBody().getObject().get("token"));
//Ignore JSON to debug
TokenFactory.setToken("fakeToken123");
responseLabel.setText("Logging in...");
myController.setScreen(ScreensFramework.CalendarID);
return true;
} else {
responseLabel.setText("Wrong username or password.");
passwordField.clear();
}
} return false;
}
//Screen management
ScreensController myController;

You have a bunch of options here:
First option: instead of loading all the screens at startup, just load the calendar screen when the login is successful. Then your CalendarController's initialize() method can basically assume the user is logged in.
Second option: modify the framework so that it either returns a reference to the controllers when it loads them, or gives you access to the controllers once loaded. The first version of this would look like:
public <T extends ControlledScreen> T loadScreen(String name, String resource) {
try {
FXMLLoader myLoader = new FXMLLoader(getClass().getResource(resource));
Parent loadScreen = (Parent) myLoader.load();
T myScreenControler = myLoader.getController();
myScreenControler.setScreenParent(this);
addScreen(name, loadScreen);
return myScreenControler ;
} catch (Exception e) {
System.out.println(e.getMessage());
return null;
}
}
Now when you first load the calendar screen, you can get a reference to its controller:
CalendarController calendarController = screensController.loadScreen(...);
so now when you are successfully logged in, you can invoke a method on the calendarController. Note the return type of loadScreen(...) has changed, so you may need to modify other code accordingly.
Alternatively, you could introduce a new map in ScreensController:
public class ScreensController extends StackPane {
private Map<String, Node> screens = new HashMap<>();
private Map<String, ControlledScreen> controllers = new HashMap<>();
// ...
public boolean loadScreen(String name, String resource) {
try {
FXMLLoader myLoader = new FXMLLoader(getClass().getResource(resource));
Parent loadScreen = (Parent) myLoader.load();
ControlledScreen myScreenControler = ((ControlledScreen) myLoader.getController());
myScreenControler.setScreenParent(this);
addScreen(name, loadScreen);
// also save the controller:
controllers.put(name, myScreenControler);
return true;
} catch (Exception e) {
System.out.println(e.getMessage());
return false;
}
}
// ...
// new method to retrieve controller:
public ControlledScreen getController(String name) {
return controllers.get(name);
}
// modify the remove method to clean up the controller as well:
public boolean unloadScreen(String name) {
if (screens.remove(name) == null) {
System.out.println("Screen didn't exist");
return false;
} else {
controllers.remove(name);
return true;
}
}
}
Now when the user logs in, you can do
CalendarController calendarController =
(CalendarController) myController.getController(ScreensFramework.CalendarID);
and invoke whatever method you need on calendarController.
Third option: create a BooleanProperty loggedIn = new SimpleBooleanProperty(); and just set it to true when the user is logged in. Then arrange for your CalendarController to be able to observe it and react when it changes. I like this option less, because arranging for the CalendarController to see the loggedIn property will almost certainly involve some kind of additional coupling between that controller and another class, but it is possible.

Related

Using Unity Dependency Injection in Multi-User Web Application: Second User to Log In Causes First User To See Second User's Data

I'm trying to implement a web application using ASP.NET MVC and the Microsoft Unity DI framework. The application needs to support multiple user sessions at the same time, each of them with their own connection to a separate database (but all users using the same DbContext; the database schemas are identical, it's just the data that is different).
Upon a user's log-in, I register the necessary type mappings to the application's Unity container, using a session-based lifetime manager that I found in another question here.
My container is initialized like this:
// Global.asax.cs
public static UnityContainer CurrentUnityContainer { get; set; }
protected void Application_Start()
{
// ...other code...
CurrentUnityContainer = UnityConfig.Initialize();
// misc services - nothing data access related, apart from the fact that they all depend on IRepository<ClientContext>
UnityConfig.RegisterComponents(CurrentUnityContainer);
}
// UnityConfig.cs
public static UnityContainer Initialize()
{
UnityContainer container = new UnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
return container;
}
This is the code that's called upon logging in:
// UserController.cs
UnityConfig.RegisterUserDataAccess(MvcApplication.CurrentUnityContainer, UserData.Get(model.AzureUID).CurrentDatabase);
// UnityConfig.cs
public static void RegisterUserDataAccess(IUnityContainer container, string databaseName)
{
container.AddExtension(new DataAccessDependencies(databaseName));
}
// DataAccessDependencies.cs
public class DataAccessDependencies : UnityContainerExtension
{
private readonly string _databaseName;
public DataAccessDependencies(string databaseName)
{
_databaseName = databaseName;
}
protected override void Initialize()
{
IConfigurationBuilder configurationBuilder = Container.Resolve<IConfigurationBuilder>();
Container.RegisterType<ClientContext>(new SessionLifetimeManager(), new InjectionConstructor(configurationBuilder.GetConnectionString(_databaseName)));
Container.RegisterType<IRepository<ClientContext>, RepositoryService<ClientContext>>(new SessionLifetimeManager());
}
}
// SessionLifetimeManager.cs
public class SessionLifetimeManager : LifetimeManager
{
private readonly string _key = Guid.NewGuid().ToString();
public override void RemoveValue(ILifetimeContainer container = null)
{
HttpContext.Current.Session.Remove(_key);
}
public override void SetValue(object newValue, ILifetimeContainer container = null)
{
HttpContext.Current.Session[_key] = newValue;
}
public override object GetValue(ILifetimeContainer container = null)
{
return HttpContext.Current.Session[_key];
}
protected override LifetimeManager OnCreateLifetimeManager()
{
return new SessionLifetimeManager();
}
}
This works fine as long as only one user is logged in at a time. The data is fetched properly, the dashboards work as expected, and everything's just peachy keen.
Then, as soon as a second user logs in, disaster strikes.
The last user to have prompted a call to RegisterUserDataAccess seems to always have "priority"; their data is displayed on the dashboard, and nothing else. Whether this is initiated by a log-in, or through a database access selection in my web application that calls the same method to re-route the user's connection to another database they have permission to access, the last one to draw always imposes their data on all other users of the web application. If I understand correctly, this is a problem the SessionLifetimeManager was supposed to solve - unfortunately, I really can't seem to get it to work.
I sincerely doubt that a simple and common use-case like this - multiple users logged into an MVC application who each are supposed to access their own, separate data - is beyond the abilities of Unity, so obviously, I must be doing something very wrong here. Having spent most of my day searching through depths of the internet I wasn't even sure truly existed, I must, unfortunately, now realize that I am at a total and utter loss here.
Has anyone dealt with this issue before? Has anyone dealt with this use-case before, and if yes, can anyone tell me how to change my approach to make this a little less headache-inducing? I am utterly desperate at this point and am considering rewriting my entire data access methodology just to make it work - not the healthiest mindset for clean and maintainable code.
Many thanks.
the issue seems to originate from your registration call, when registering the same type multiple times with unity, the last registration call wins, in this case, that will be data access object for whoever user logs-in last. Unity will take that as the default registration, and will create instances that have the connection to that user's database.
The SessionLifetimeManager is there to make sure you get only one instance of the objects you resolve under one session.
One option to solve this is to use named registration syntax to register the data-access types under a key that maps to the logged-in user (could be the database name), and on the resolve side, retrieve this user key, and use it resolve the corresponding data access implementation for the user
Thank you, Mohammed. Your answer has put me on the right track - I ended up finally solving this using a RepositoryFactory which is instantiated in an InjectionFactory during registration and returns a repository that always wraps around a ClientContext pointing to the currently logged on user's currently selected database.
// DataAccessDependencies.cs
protected override void Initialize()
{
IConfigurationBuilder configurationBuilder = Container.Resolve<IConfigurationBuilder>();
Container.RegisterType<IRepository<ClientContext>>(new InjectionFactory(c => {
ClientRepositoryFactory repositoryFactory = new ClientRepositoryFactory(configurationBuilder);
return repositoryFactory.GetRepository();
}));
}
// ClientRepositoryFactory.cs
public class ClientRepositoryFactory : IRepositoryFactory<RepositoryService<ClientContext>>
{
private readonly IConfigurationBuilder _configurationBuilder;
public ClientRepositoryFactory(IConfigurationBuilder configurationBuilder)
{
_configurationBuilder = configurationBuilder;
}
public RepositoryService<ClientContext> GetRepository()
{
var connectionString = _configurationBuilder.GetConnectionString(UserData.Current.CurrentPermission);
ClientContext ctx = new ClientContext(connectionString);
RepositoryService<ClientContext> repository = new RepositoryService<ClientContext>(ctx);
return repository;
}
}
// UserData.cs (multiton-singleton-hybrid)
public static UserData Current
{
get
{
var currentAADUID = (string)(HttpContext.Current.Session["currentAADUID"]);
return Get(currentAADUID);
}
}
public static UserData Get(string AADUID)
{
UserData instance;
lock(_instances)
{
if(!_instances.TryGetValue(AADUID, out instance))
{
throw new UserDataNotInitializedException();
}
}
return instance;
}
public static UserData Current
{
get
{
var currentAADUID = (string)(HttpContext.Current.Session["currentAADUID"]);
return Get(currentAADUID);
}
}
public static UserData Get(string AADUID)
{
UserData instance;
lock(_instances)
{
if(!_instances.TryGetValue(AADUID, out instance))
{
throw new UserDataNotInitializedException();
}
}
return instance;
}

WF 4 OnUnhandledException not hit

I've created a custom activity which contains as a Body another Activity.
[Browsable(false)]
public Activity Body { get; set; }
protected override void Execute(NativeActivityContext context)
{
ActivityInstance res = context.ScheduleActivity(Body, new CompletionCallback(OnExecuteComplete), OnFaulted);
}
private void OnFaulted(NativeActivityFaultContext faultContext, Exception propagatedException, ActivityInstance propagatedFrom)
{
throw new Exception(propagatedException.Message);
}
When an exception is thrown during the execution of the Body, ma handler for the OnFaulted is hit.
My execution starts with a call to static method Run of the WorkflowApplication class. My WorkflowApplication instance has a handler associated for the OnUnhandledException event.
instance.OnUnhandledException +=
delegate(WorkflowApplicationUnhandledExceptionEventArgs args)
{
Console.WriteLine(args.ExceptionSource);
waitEvent.Set();
return UnhandledExceptionAction.Cancel;
};
But regardless of what happens when the Activity hosted in the Body is executed, i never reach the handler defined above. I thought that if i throw an exception from the OnFaulted, i will be able to redirect the flow to the OnUnhandledException but i was wrong. Any ideas ?
I need this in order to centralize my errors, check them and display messages accordingly. Also i need a way to stop the execution and so on and i don't want to define handlers all over the application. Is there any way to accomplish this ?
As Will suggested, i will post what i did to handle my scenario.
Basically, in my custom activity i have hosted an Assign :
[Browsable(false)]
public Activity Body { get; set; }
Activity System.Activities.Presentation.IActivityTemplateFactory.Create(System.Windows.DependencyObject target)
{
return new Assignment()
{
Body = new Assign() { DisplayName = "" }
};
}
I've added this code to my Execute method :
ActivityInstance res = context.ScheduleActivity(Body, new CompletionCallback(OnExecuteComplete), OnFaulted);
I was trying to run this Assignment by giving an array a negative value as index and and an exception was thrown. This, somehow ended my execution but no handler for the events of my WorkflowApplication instance were hit.
Here is the method given as a callback when executing the body ( in our case the Assign activity ) :
private void OnFaulted(NativeActivityFaultContext faultContext, Exception propagatedException, ActivityInstance propagatedFrom)
{
faultContext.HandleFault();
CommunicationExtension ce = faultContext.GetExtension<CommunicationExtension>();
ITextExpression toTextExpression = (propagatedFrom.Activity as Assign).To.Expression as ITextExpression;
string valueTextExpression = string.Empty;
if ((propagatedFrom.Activity as Assign).Value != null)
{
if ((propagatedFrom.Activity as Assign).Value.Expression != null)
valueTextExpression = (propagatedFrom.Activity as Assign).Value.Expression.ToString();
}
if (ce != null)
{
ce.AddData(string.Format("{0} found on Assignment definition [{1} = {2}]", propagatedException.Message, toTextExpression.ExpressionText, valueTextExpression));
}
}
The trick was to call :
faultContext.HandleFault();
and use CommunicationExtension to allow me to to display the erros in the GUI.
The code for this class is trivial :
public class CommunicationExtension
{
public List<string> Messages { get; set; }
public CommunicationExtension()
{
Messages = new List<string>();
}
public void AddData(string message)
{
if (string.IsNullOrEmpty(message))
return;
Messages.Add(message);
}
}
Use this to add the extension:
CommunicationExtension ce = new CommunicationExtension();
instance.Extensions.Add(ce);
where instance is my WorkflowApplication instance.
I understood that for each instance of the workflow application we have one instance of its extension class. So i can send messages like this from all my custom activities in order to display their status.
I hope this scenario can help other people too.

How do I centralize code shared by multiple Web API controllers?

I have close to 10 controllers that currently share the same code. The code is pretty simple, it just checks if a set of data is null and checks if the current user has permission to access the data.
If there is an issue, I throw an HttpResponseException.
The code works when it is sitting in each controller. I have also managed to centralize the code but I think the way I have done it is wrong. I've created a new class which inherits ApiController and then I have the controllers inheriting my new class. This is the only way I could get the HttpResponseExceptions working. Code is as follows:
//New centralized class:
public class AuthorizationClass : ApiController
{
private DataModel db = new DataModel();
public async Task checkUserisValid(int user_id)
{
user_list user_list = await db.user_list.FindAsync(user_id);
if (user_list == null)
{
throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest,"This user does not exist"));
}
int businessID = user_list.business_id;
var result = checkAccess(User.Identity.Name, businessID);
if (result.Count <= 0)
{
throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "You do not have access to modify this business"));
}
}
public static List<user_details> checkAccess(string userName, int id)
{
//code which checks if the user is in the right tables
return checkAccess.ToList();
}
}
Then in the controller class, I have:
public class MyController : AuthorizationClass
{
public async Task<IHttpActionResult> Postnew_table(int id, new_table new_table)
{
await checkUserisValid(id);
//rest of controller
}
}
I tried to do it in different ways but this is the only way I could get it working with HttpResponseException. Is there a better way to do this without inheriting classes or is this the only way to do what I am after?
Thanks.
You could just move these 2 methods to some static helper class in a common assembly, you mention that Request is an instance variable on the controller, just pass it to the method.
public static class SomeHelper
{
public static async Task checkUserisValid(int user_id, DataModel db, Request request, User user)
{
user_list user_list = await db.user_list.FindAsync(user_id);
if (user_list == null)
{
throw new HttpResponseException(request.CreateErrorResponse(HttpStatusCode.BadRequest,"This user does not exist"));
}
int businessID = user_list.business_id;
var result = checkAccess(user.Identity.Name, businessID);
if (result.Count <= 0)
{
throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "You do not have access to modify this business"));
}
}
public static List<user_details> checkAccess(string userName, int id)
{
//code which checks if the user is in the right tables
return checkAccess.ToList();
}
}

Synchronous responses to `Gdx.net.sendHttpRequest` in LibGDX

I'm making a small game in LibGDX. I'm saving the player's username locally as well as on a server. The problem is that the application is not waiting for the result of the call so the online database's ID is not saved locally. Here's the overall flow of the code:
//Create a new user object
User user = new User(name);
//Store the user in the online database
NetworkService networkService = new NetworkService();
String id = networkService.saveUser(user);
//Set the newly generated dbase ID on the local object
user.setId(id);
//Store the user locally
game.getUserService().persist(user);
in this code, the id variable is not getting set because the saveUser function is returning immediately. How can I make the application wait for the result of the network request so I can work with results from the server communication?
This is the code for saveUser:
public String saveUser(User user) {
Map<String, String> parameters = new HashMap<String, String>();
parameters.put("action", "save_user");
parameters.put("json", user.toJSON());
HttpRequest httpGet = new HttpRequest(HttpMethods.POST);
httpGet.setUrl("http://localhost:8080/provisioner");
httpGet.setContent(HttpParametersUtils.convertHttpParameters(parameters));
WerewolfsResponseListener responseListener = new WerewolfsResponseListener();
Gdx.net.sendHttpRequest (httpGet, responseListener);
return responseListener.getLastResponse();
}
This is the WerewolfsResponseListener class:
class WerewolfsResponseListener implements HttpResponseListener {
private String lastResponse = "";
public void handleHttpResponse(HttpResponse httpResponse) {
System.out.println(httpResponse.getResultAsString());
this.lastResponse = httpResponse.getResultAsString();
}
public void failed(Throwable t) {
System.out.println("Saving user failed: "+t.getMessage());
this.lastResponse = null;
}
public String getLastResponse() {
return lastResponse;
}
}
The asynchrony you are seeing is from Gdx.net.sendHttpRequest. The methods on the second parameter (your WerewolfsResponseListener) will be invoked whenever the request comes back. The success/failure methods will not be invoked "inline".
There are two basic approaches for dealing with callbacks structured like this: "polling" or "events".
With polling, your main game loop could "check" the responseListener to see if its succeeded or failed. (You would need to modify your current listener a bit to disambiguate the success case and the empty string.) Once you see a valid response, you can then do the user.setId() and such.
With "events" then you can just put the user.setId() call inside the responseListener callback, so it will be executed whenever the network responds. This is a bit more of a natural fit to the Libgdx net API. (It does mean your response listener will need a reference to the user object.)
It is not possible to "wait" inline for the network call to return. The Libgdx network API (correctly) assumes you do not want to block indefinitely in your render thread, so its not structured for that (the listener will be queued up as a Runnable, so the earliest it can run is on the next render call).
I would not recommend this to any human being, but if you need to test something in a quick and dirty fashion and absolutely must block, this will work. There's no timeout, so again, be prepared for absolute filth:
long wait = 10;
while(!listener.isDone())
{
Gdx.app.log("Net", "Waiting for response");
try
{
Thread.sleep(wait *= 2);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
public static class BlockingResponseListener implements HttpResponseListener
{
private String data;
private boolean done = false;
private boolean succeeded = false;
#Override
public void handleHttpResponse(HttpResponse httpResponse)
{
Gdx.app.log("Net", "response code was "+httpResponse.getStatus().getStatusCode());
data = httpResponse.getResultAsString();
succeeded = true;
done = true;
}
#Override
public void failed(Throwable t)
{
done = true;
succeeded = false;
Gdx.app.log("Net", "Failed due to exception ["+t.getMessage()+"]");
}
public boolean succeeded()
{
return succeeded;
}
public boolean isDone()
{
return done;
}
public String getData()
{
return data;
}
}

How to automatically call a method when Session["something"] throws a NullReferenceException?

I am going to be using Session["firmaid"] quite alot in my application. This value is set when someone logs in to my system.
If something happens, and this value is lost from the Session, i would like to somehow have a global method that will get it, if it throws a NullReferenceException.
How can i do this?
Currently, my solution is to try and catch every time i use Session["firmaid"], then execute the method that will put firmaid in the Session, if it throws an Exception.
Is there an easier way to do this?
Instead of try/catching everytime you could wrap the access to the session in a strongly typed class and then access the session through this wrapper.
Or even write an extension method:
public static class SessionExtensions
{
public static string GetFirmaId(this HttpSessionStateBase session)
{
var firmaid = session["firmaid"] as string;
if (string.IsNullOrEmpty(firmaid))
{
// TODO: call some method, take respective actions
}
return firmaid;
}
}
and then in your code instead of:
try
{
var firmaid = Session["firmaid"];
// TODO: do something with the result
}
catch (Exception ex)
{
// TODO: call some method, take respective actions
}
use:
var firmaid = Session.GetFirmaId();
// TODO: do something with the result
Why not simply write a static wrapper around this? Much more robust and more DRY:
public static int GetFirmaid() {
if (HttpContext.Current.Session["firmaid"] == null) {
//do something to fall back
}
return HttpContext.Current.Session["firmaid"]
}
You obviously would have to put this in a Class you can easily access and then call it through:
Class.GetFirmaid()
You can create an action filter which will ensure that Session["firmaid"] has a value:
public class SetFirmaIdAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
try
{
var firmaId = Session["firmaid"];
}
catch (Exception ex)
{
// pass filterContext if you need access to Request, Session etc.
Session["firmaid"] = SetFirmaId(filterContext);
}
}
private int SetFirmaId(ActionExecutingContext filterContext)
{
// TODO: implement some logic
}
}
OnActionExecuting will be called before action executes so you will already have Session["firmaid"] set when the action gets executed.
Once you implement this attribute you can put it on an action, controller or set it as global.

Resources