Android: Create new instance of bundle and pass to intent in dagger in mvp - dagger-2

I would like to use MVP with dagger in my project.
In view I have this method and into this method I will pass some object to the presenter:
#Override
public void onLogin(User user, Cookie cookie, UUID sessionId, List<Permission> permissions) {
super.onLogin(user, cookie, sessionId, permissions);
presenter.onLogin(user, cookie, sessionId, permissions);
}
Here is my presenter:
public class Presenter implements ILogin.LoginPresenter{
private Context context;
#Inject
public Presenter(Context context) {
this.context = context;
}
#Override
public void onLogin(User user, Cookie cookie, UUID sessionId, List<Permission> permissions) {
Intent intent = new Intent(context,MainActivity.class);///?
Bundle bundle = new Bundle();///?
bundle.putString("USER", user.getUserName());
intent.putExtras(bundle);
context.startActivity(intent);
}
I have nothing in module :
#Module
public class LoginModule {
}
My questions:
Is it true that I am creating new object (Intent and Bundle) in the presenter when I am using dagger?
How could I use dagger to my scenario? That's mean create new instance of intent and bundle in module class?

The point of MVP pattern is to separate business logic from its view. It's a common good practice not to have any android framework related code in your presenter (here your presenter depends on Context, Intent and Bundle from the android framework).
In your case, you should not create your Intent and Bundle in your presenter since it belongs to your view (MainActivity).
Your onLogin function could look like this:
#Override
public void onLogin(User user, Cookie cookie, UUID sessionId, List<Permission> permissions) {
// whatever is your business logic
view.showMainActivity(user);
}
where view is an interface implemented by your MainActivity and injected in your presenter.

Related

Is there any way to register tenant specific controller in asp.net core using autofac?

I am working on an application built on asp.net core 3.1 + Autofac as DI. Now i want to implement multi tenant feature. I am able to register tenant specific services and it is working as expected.
What i want to achieve is to register tenant specific controller to override default controller registered in main/application level container.
I have registered custom IApplicationFeatureProvider to register only main controllers.
here is the code.
//Startup.cs
public class StartUp
{
void ConfigureServices(IServiceCollection services)
{
services.AddControllers().ConfigureApplicationPartManager(apm =>
{
apm.FeatureProviders.RemoveAt(0); //remove default controller feature provider
apm.FeatureProviders.Add(new MyControllerFeatureProvider()); //register custom provider
}).AddControllersAsServices();
services.AddAutofacMultitenantRequestServices();
//rest of the configuration
}
public void ConfigureContainer(ContainerBuilder builder)
{
//registration of global or main services
builder.RegisterType<MyTenantIdentificationStrategy>()
.As<ITenantIdentificationStrategy>().SingleInstance(); //Get Tenant from request header
builder.Register(container =>
{
ITenantIdentificationStrategy strategy =
container.Resolve<ITenantIdentificationStrategy>();
// tenant resolution code
return new Tenant();
}).InstancePerLifetimeScope();
}
public static MultitenantContainer ConfigureMultitenantContainer(IContainer container)
{
var strategy <-- resolved from container
MultitenantContainer mtc = new MultitenantContainer(strategy, container);
mtc.ConfigureTenant(1, cb => {
cb.RegisterType<IP.Controllers.Extended.HomeController>).InstancePerLifetimeScope();
});
return mtc;
}
}
//HomeController.cs
namespace IP.Controllers
{
[Route("[controller]")]
public class HomeController : ControllerBase
{
}
[Route("Get")
public IActionResult Get()
{
return new JsonResult(new {Main = true});
}
}
//HomeController1.cs
namespace IP.Controllers.Extended <-- different namespace
{
[Route("[controller]")]
public class HomeController : ControllerBase
{
}
[Route("Get")
public IActionResult Get()
{
return new JsonResult(new {Main = false});
}
}
//program.cs
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new AutofacMultitenantServiceProviderFactory(Startup.ConfigureMultitenantContainer))
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
http://localhost:8082/Home/Get [Without tenantid in header]
http://localhost:8082/Home/Get [Without tenantid=1 in header]
In both case main home controller is resolved not tenant specific..
Any help well be appreciated.
Answer to my own question,
Routing and controller selection is handled Asp.Net Core not by Autofac.
I am registering tenant specific controllers in ConfigureTenant method. Asp.Net Core Framework is not aware about these controllers. So for given route framework always selects registered controller not extended one registered in ConfigureTenant method.
So first i have removed custom application feature provider. Now all controllers in current assembly are registered. Then removed separate registration of controllers from ConfigureTenant method. Now framework throws ambiguity exception because there are two controllers with same route.
From stack trace, i found that EndPointResolver implementation is throwing ambiguity exception. Since we can provide our own implementation for EndPointResolver, i create custom EndPointResolver and register it.
Now during route selection, if there is ambiguity while selecting controller, i just retrieve tenant information from request header and based on Tanent i am handling ambiguity exception.
I am not sure if it is the correct approach but now i am able to register controller with same name [same Route] in different namespace/assembly.

How to initialize several UserProviders in Keycloak

I'm having big difficulties when trying to make Keycloak to use default JPA provider that is implemented in Keycloak (package: org.keycloak.models.jpa.JpaUserProviderFactory)
alongside with my custom UserProvider.
My user provider is implemented like this:
public class MyCustomUserProviderFactory extends JpaUserProviderFactory {
#Override
public String getId() {
return "demo";
}
#Override
public UserProvider create(KeycloakSession session) {
EntityManager em = session.getProvider(JpaConnectionProvider.class).getEntityManager();
return new MyCustomUserProvider(session, em);
}
}
and MyCustomUserProvider
public class MyCustomUserProvider extends JpaUserProvider {
private final KeycloakSession session;
public MyCustomUserProvider(KeycloakSession session, EntityManager em) {
super(session, em);
this.session = session;
}
}
startup.cli
/subsystem=keycloak-server/spi=user:add(default-provider=demo)
/subsystem=keycloak-server/spi=user/provider=jpa:add(enabled=true)
/subsystem=keycloak-server/spi=user/provider=demo:add(enabled=true)
also in META-INF/service i have
org.keycloak.models.UserProviderFactory
with com.demo.keycloak.providers.user.MyCustomUserProviderFactory
So with this implementation and settings, keycloak is started successfully but when I need to access both demo and jpa UserProvider I only get default provider that is in this case demo.
I access UserProvider with:
UserProvider demoProvider = session.getProvider(UserProvider.class, "demo");
but if I execute
UserProvider jpaProvider = session.getProvider(UserProvider.class, "jpa");
I only get null.
If I change the default provider in the startup.cli (default-provider=demo) I would then get the jpa but not the demo provider.
Can somebody explan to me how could I have several UserProvider implementation and how can I access to both of them?
Sorry for not answering on my question after quite a long time.
Unfortunately there is no way of having multiple JPAUserProvider at the same time.
The only way to add custom implementation in JpaUserProvider methods is to override them add the additional call and in the configuration itself add the custom version as a default one
/subsystem=keycloak-server/spi=user:add(default-provider=demo).

Dagger 2 Activity context/ApplicationContext modules

I'm struggling with dagger 2 in order to understand how i can pass a context or another according to my needs.
- First I have an ApplicationModule annotated #Singleton since it provides hi level objects like the webservice object, the model ..., generally those objects are passed the ApplicationContext (since the y need to live during the whole Application lifetime)
#Singleton
#dagger.Component(modules = {
AppModule.class
})
public interface AppComponent {
void inject(MyApp application);
Model model();
Context context();<--- should provide the application Context for the Object above (model)
...
the implementation looks like that
#dagger.Module
public class AppModule {
private final Application app;
public ApplModule(Application app) {
this.app = app;
}
#Provides
#Singleton
Model provideModel(Bus bus) {
return new Model(bus);
}
#Provides
#Singleton
Context provideApplicationContext() {
return app.getApplicationContext();
}
...
secondly I have an Activity Scope componenet in with I provide the current activity and different views which need a Context.
#ActivityScope
#Component(
dependencies = AppComponent.class
, modules = {ActivityModule.class}
)
public interface ActivityComponent {
void inject(MyActivity activity);
Context context(); <---should provide the activity's context
MyView homeView(); <----takes a Context as a contructor parameter
#Module
public class ActivityModule {
private final Activity activity;
public ActivityModule(Activity activity) {
this.activity = activity;
}
#Provides
#ActivityScope
public Activity activity() {
return activity;
}
#Provides
#ActivityScope
#Named("viewcontext") <----- if I removed this I get an error from Dagger
public Context context() {
return activity;
}
#Provides
#ActivityScope
MyView provideZeView(Bus bus, Model model) { <---- previously receiving the ApplicationContext as a parameter
MyView v = new MyView(activity, bus, model); <---- must pass the activity otherwise passing the Context reveived is the ApplicationContext
return v;
}
so Here are my questions:
I used scopes in order to have a better "granularity" over what is passed and i still get the applicationContext
If I remove the #Named qulifier i get an error
previously the Views where produced by another module with a dependence to the ActivityModule but still getting the ApplicationContext
Well the point is I am certainly missing something...but I can't figure what, maybe I misundestood the use of Scopes
you can use qualifiers like this. in two separate files define the following:
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
public #interface ActivityContext {
}
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
public #interface ApplicationContext {
}
then in your ActivityModule do this:
#Provides
#ActivityScope
#ActivityContext
public Context context() {
return activity;
}
and likewise in your appmodule do this:
#Provides
#Singleton
#ApplicationContext
Context provideApplicationContext() {
return app.getApplicationContext();
}
now we have a way to ask for whatever type of context we need based on the qualifier #ApplicationContext and #ActivityContext.
so for example in your activity you could do this:
#Inject #ApplicationContext
Context c;
which would inject an application context.
and in a module you could do this for example:
#Provides
#ActivityScope
LoginPresenter provideLoginPresenter(#ActivityContext Context context) {
return new LoginPresenter(context);
}
to provide an activity context. this is just an example.
#Named is a requirement if you want to provide multiple objects of the same type from your module.
As far as your second question, in regards to passing the correct Activity context, you need to have this in your ActivityComponent:
Activity activity();

OSGI - two objects of a bundle service

I have a bundle that provides a service.
My bundle implementation looks like this:
class ServiceImpl implements Service
{
Object value;
#Override
public void setValue(Object value)
{
this.value = value;
}
#Override
public Object getValue()
{
return value;
}
}
In my java application, I load this bundle to OSGI framework, and create TWO references to the service, in an attempt to have two objects with different values for "value".
Unfortunately, this does not seem to work. The service always returns the last value set by either objects. How can I overcome this issue?
Here's an example for the problem:
Service object1 = context.getService(reference1);
Service object2 = context.getService(reference2);
Integer one= 1;
Integer two =2;
object1.setValue(1);
object2.setValue(2);
System.out.println(object1.getValue() ); //returns 2 !!!!!!!!!!!!!!!!!!
System.out.println(object2.getValue() ); //returns 2
I used ServiceFactory but it seems not useful for my case. What should I do? Thanks.
Both BJ and Balazs offer valuable information, but no solution that works with current versions of the OSGi specification.
What you can do is register your service with a second "Factory" interface. This factory then allows you to create instances of the service. Because you probably don't want to do that manually, you can hide this logic in a ServiceTracker.
There are a few "downsides" to this approach. First of all, you need to register the service and have the instance implement both Factory and Service. Secondly, you always have to use this custom ServiceTracker to access it. If you use a dependency manager that allows you to extend its dependencies (such as Apache Felix Dependency Manager) you can easily hide all of this in a custom ServiceDependency.
Anyway, to show you that this actually works, here is a simple example:
public class Activator implements BundleActivator {
#Override
public void start(final BundleContext context) throws Exception {
context.registerService(Service.class.getName(), new FactoryImpl(), null);
ServiceTrackerCustomizer customizer = new ServiceTrackerCustomizer() {
#Override
public Object addingService(ServiceReference reference) {
Object service = context.getService(reference);
if (service instanceof Factory) {
return ((Factory) service).createInstance();
}
return service;
}
#Override
public void modifiedService(ServiceReference reference,
Object service) {
// TODO Auto-generated method stub
}
#Override
public void removedService(ServiceReference reference,
Object service) {
// TODO Auto-generated method stub
}
};
ServiceTracker st1 = new ServiceTracker(context, Service.class.getName(), customizer);
ServiceTracker st2 = new ServiceTracker(context, Service.class.getName(), customizer);
st1.open();
st2.open();
Service s1 = (Service) st1.getService();
Service s2 = (Service) st2.getService();
s1.setValue("test1");
s2.setValue("test2");
System.out.println(s1.getValue());
System.out.println(s2.getValue());
}
#Override
public void stop(BundleContext context) throws Exception {
}
static interface Factory {
public Object createInstance();
}
static class FactoryImpl extends ServiceImpl implements Factory, Service {
#Override
public Object createInstance() {
return new ServiceImpl();
}
}
static interface Service {
public void setValue(Object value);
public Object getValue();
}
static class ServiceImpl implements Service {
private Object m_value;
#Override
public void setValue(Object value) {
m_value = value;
}
#Override
public Object getValue() {
return m_value;
}
}
}
You need to wait for R6. Pre-R6, each bundle can be exposed to at most one instance of a service. Even registering a ServiceFactory will not change that since the framework will cache the service object from the ServiceFactory to return to the bundle on subsequent calls to getService.
In R6, we introduce service scopes which allows a service implementation to return multiple service objects to a bundle. Using this requires both the service provider and the service consumer to use new API added in R6.
You can play with this now as it is implemented in Eclipse Equinox Luna.
Even if you use ServiceFactory, for the same bundle the same service object will be returned.
There might be a PrototypeServiceFactory in the future as there is an RFP about it: https://github.com/osgi/design/tree/master/rfcs/rfc0195
That would fit to your needs.
Although there might be a PrototypeServiceFactory in the future, I think it is better to solve this use-case programmatically by yourself. E.g.:
Instead of creating a mutuable OSGi service (I do not think creating mutuable services is a good idea) create a factory.
On the client side you would use:
BusinessLogicFactory factory = context.getService(reference);
BusinessLogic object1 = factory.createInstance();
BusinessLogic object2 = factory.createInstance();
...

Server side session management in GWTP

Hello I am using GWTP for my application development. In the application I am in need to server side session instance to put some data in that session instance. I saw some examples of GWT where there is Action class which extends ActionSupport class.
There are some method in the examples through which we can have the server side session instance.Like below :
public HttpServletRequest getRequest() {
return ServletActionContext.getRequest();
}
public HttpServletResponse getResponse() {
return ServletActionContext.getResponse();
}
public HttpSession getSession() {
HttpSession session = getRequest().getSession();
return session;
}
But I am not getting the similar thing in GWTP. Please help me out. Thanks in Advance.
Finally I got some thing which is helping me.I am sharing this here.
private Provider<HttpServletRequest> requestProvider;
private ServletContext servletContext;
#Inject
public LoginCallerActionHandler(
Provider<HttpServletRequest> requestProvider,
ServletContext servletContext) {
super();
this.requestProvider = requestProvider;
this.servletContext = servletContext;
}
Here is my action handler class.In which i can use session.
servletContext.setAttribute(SessionKeys.LOGGEDIN_USER.toString(), returnObject.getLoggedInUser());
If you are using Spring or Guice on your server side you can get Request/Response injected into your Action. For example, if your are using GWTP's DispatchServletModule, you can use features of Guice's ServletModule as:
DispatchServletModule extends Guice ServletModule and maps request
URLs to handler classes.
Here's an example from Guice wiki:
#RequestScoped
class SomeNonServletPojo {
#Inject
SomeNonServletPojo(HttpServletRequest request, HttpServletResponse response, HttpSession session) {
...
}
}
I am not sure if GWTP binds the handlers in Singleton scope or not. If it does bind it in singleton you should inject a Provider instead.