I'm attempting to put together a multi-project application, wherein one of the sub-projects has multiple views for a single presenter. I am using Gin to inject views into my presenters.
The sub-project contains the presenter and the 2 different views. I have 2 separate gin modules, each binding one of the views to the view interface.
As per Thomas Broyer's suggestion on the answer to this post, my Ginjectors are wrapped in a "holder" class that calls the GWT.create on the particular ginjector. The appropriate holder is configured in the gwt.xml file using a replace-with statement.
When I run my project in Dev Mode, I see the alternate view appear as I expect it to. However, when I compile the project, I still only get the default view. Also, only 6 permutations (I would expect more on account of the replace-with logic), and I do not get the view I expect in the different scenarios.
Here is some code to illustrate.
Subproject.gwt.xml contains this:
<replace-with class="com.example.GinjectorDesktopHolder">
<when-type-is class="com.example.GinjectorHolder" />
</replace-with>
<replace-with class="com.example.GinjectorTabletHolder">
<when-type-is class="com.example.GinjectorHolder" />
<when-property-is name="formfactor" value="tablet" />
</replace-with>
The "formfactor" variable is defined in a gwt.xml copied verbatim from GWT's mobilewebapp sample project.
The Holder classes look like this:
public abstract class GinjectorHolder {
public abstract Ginjector getGinjector();
}
public class GinjectorTabletHolder extends GinjectorHolder {
#Override
public Ginjector getGinjector() {
return GWT.create(GinjectorTablet.class);
}
}
public class GinjectorDesktopHolder extends GinjectorHolder {
#Override
public Ginjector getGinjector() {
return GWT.create(GinjectorDesktop.class);
}
}
My Ginjectors look like this:
public interface MyGinjector {
MyView getView();
EventBus getEventBus();
}
#GinModules({ModuleDesktop.class})
public interface GinjectorDesktop extends Ginjector, MyGinjector {}
#GinModules({ModuleTablet.class})
public interface GinjectorTablet extends Ginjector, MyGinjector {}
My modules look like this:
public class ModuleDesktop extends AbstractGinModule {
#Override
protected void configure() {
bind(MyPresenter.View.class).to(DesktopView.class);
}
}
public class ModuleTablet extends AbstractGinModule {
#Override
protected void configure() {
bind(MyPresenter.View.class).to(TabletView.class);
}
}
And finally, in my presenter proxy, basically the entry point into this particular sub-project, I have this line:
GinjectorHolder holder = GWT.create(GinjectorHolder.class);
MyGinjector ginjector = holder.getGinjector();
As mentioned earlier, when I run in Dev Mode and put in breakpoints, I can see the appropriate GinjectorHolder is created. The FormFactor.gwt.xml (linked above) provides a switch for using a URL param to switch to the context you'd like to see. So I can do formfactor=tablet in the URL and the Tablet Ginjector Holder is created.
As mentioned in the comments, removing the line
<collapse-property name="formfactor" values="*"/>
leads to the expected increase in the number of permutations.
Still, it's mysterious, why this is necessary, because usually it should be possible to collapse any properties you like - it just means, that each browser has to download more code, but should still get everything it needs. Could be a bug.
First of all instead of mapping view to viewimpl you can bind it to viewprovider, and then based on user-agent values you can return the appropriate instance to bind to.
Related
I am migrating from org.apache.felix.scr annotations to org.osgi.service.component annotations. I have a set of Components that inherit from a common abstract class. In the felix case, I can use a #Component annotation with the option componentAbstract=true on the super class, and then use #Reference annotation in the super class. I cannot find how to migrate this to osgi annotations.
Is it possible to use Component annotations in a super class of a Component? And if so, what is then the appropriate way to handle the properties and metatype generation?
So, what I am looking for, is something like this
/* No component definition should be generated for the parent, as it is
abstract and cannot be instantiated */
#Component(property="parent.property=parentValue")
public abstract class Parent {
#Reference
protected Service aService;
protected activate(Map<String,Object> props) {
System.out.println("I have my parent property: "+props.get("parent.property"));
#Override
public abstract void doSomething();
}
/* For this class, the proper Component definition should be generated, also
including the information coming from the annotations in the parent */
#Component(property="child.property=childValue")
public class Child extends Parent {
#Activate
public activate(Map<String,Object> props) {
super.activate(props);
System.out.println("I have my child property: "+props.get("child.property"));
}
public void doSomething() {
aService.doSomething();
}
}
By default BND will not process DS annotations in parent classes. You can change that with -dsannotations-options: inherit but please see http://enroute.osgi.org/faq/ds-inheritance.html why you shouldn't!
2021-02-23 UPDATE: It seems like the page mentioned above is no longer available. I don't know if it was moved elsewhere or simply removed but its content (in Markdown format) is still available on GitHub: https://github.com/osgi/osgi.enroute.site/blob/pre-R7/_faq/ds-inheritance.md
I come from the guice world and am looking for a way to do something similar to the Modules.override provided by Guice. I have a pattern where I create a base Module/AbstractBinder for my production and then in test I override the bindings that need to be changed.
In an ideal world I would like to simply either extends the Parent AbstractBinder and then implement the bindings to override the parent binder. Or the other alternative is to simply install the parent Binder and then override the bindings that I want for testing purposes.
public class IOCRestModule extends AbstractBinder {
#Override
protected void configure() {
// Max timeout for rest calls is 20 seconds, this will come from properties later on.
bind(20000).to(Integer.class).named("MAX_REST_REQUEST_TIMEOUT");
bind("tcp://localhost").to(String.class).named("jms.url");
}
}
public class IOCMockRestModule extends AbstractBinder {
public static final Logger logger = Logger.getLogger(IOCMockRestModule.class.getName());
#Override
protected void configure() {
install(new IOCRestModule());
bind(200).to(Integer.class).named("MAX_REST_REQUEST_TIMEOUT");
bind("vm://localhost").to(String.class).named("jms.url");
}
Is this possible to do, and is it recommended? I noticed when I did this that the bindings for the IOCRestModule were not overridden by the IOCMockRestModule. I am assuming I could add the install at the end and this may work but not sure if this will cause any issues later on.
In hk2 you can have multiple bindings for the same thing. By default the oldest will take precedence, but you can change this by using rank. So I think the following code would change the ordering around:
#Override
protected void configure() {
install(new IOCRestModule());
bind(200).to(Integer.class).named("MAX_REST_REQUEST_TIMEOUT").ranked(10);
bind("vm://localhost").to(String.class).named("jms.url").ranked(10);
}
This essentially gives this binding a higher rank than the one from the IOCRestModule, and that will then be used in Injection points first. You should note that if anyone looks for a list of Integer with name MAX_REST_REQUEST_TIMEOUT they will get two of them
Throughout my GWT app there are many different async calls to the server, using many different services. In order to do better error handling I want to wrap all my callbacks so that I can handle exceptions like InvocationExceptions in one place. A super class implementing AsyncCallback isn't really an option because that would mean that I would have to modify every async call.
RpcServiceProxy#doCreateRequestCallback() looks like the method to override. Simple enough. I just can't see how to make GWT use my new class.
Another way to state the question would be
How do I make GWT use my own subclass of RpcServiceProxy?
In order to wrap every AsynCallback<T> that is passed to any RemoteService you need to override RemoteServiceProxy#doCreateRequestCallback() because every AsynCallback<T> is handed in here before an RPC call happens.
Here are the steps to do so:
As #ChrisLercher alluded, you need to define your own Proxy Generator to step in every time a RemoteService proxy gets generated. Start by extending ServiceInterfaceProxyGenerator and overriding #createProxyCreator().
/**
* This Generator extends the default GWT {#link ServiceInterfaceProxyGenerator} and replaces it in the
* co.company.MyModule GWT module for all types that are assignable to
* {#link com.google.gwt.user.client.rpc.RemoteService}. Instead of the default GWT {#link ProxyCreator} it provides the
* {#link MyProxyCreator}.
*/
public class MyServiceInterfaceProxyGenerator extends ServiceInterfaceProxyGenerator {
#Override
protected ProxyCreator createProxyCreator(JClassType remoteService) {
return new MyProxyCreator(remoteService);
}
}
In your MyModule.gwt.xml make use of deferred binding to instruct GWT to compile using your Proxy Generator whenever it generates something of the type RemoteService:
<generate-with
class="com.company.ourapp.rebind.rpc.MyServiceInterfaceProxyGenerator">
<when-type-assignable class="com.google.gwt.user.client.rpc.RemoteService"/>
</generate-with>
Extend ProxyCreator and override #getProxySupertype(). Use it in MyServiceInterfaceProxyGenerator#createProxyCreator() so that you can define the base class for all the generated RemoteServiceProxies.
/**
* This proxy creator extends the default GWT {#link ProxyCreator} and replaces {#link RemoteServiceProxy} as base class
* of proxies with {#link MyRemoteServiceProxy}.
*/
public class MyProxyCreator extends ProxyCreator {
public MyProxyCreator(JClassType serviceIntf) {
super(serviceIntf);
}
#Override
protected Class<? extends RemoteServiceProxy> getProxySupertype() {
return MyRemoteServiceProxy.class;
}
}
Make sure both your MyProxyCreator and your MyServiceInterfaceProxyGenerator are located in a package that will not get cross-compiled by GWT into javascript. Otherwise you will see an error like this:
[ERROR] Line XX: No source code is available for type com.google.gwt.user.rebind.rpc.ProxyCreator; did you forget to inherit a required module?
You are now ready to extend RemoteServiceProxy and override #doCreateRequestCallback()! Here you can do anything you like and apply it to every callback that goes to your server. Make sure that you add this class, and any other class you use here, in my case AsyncCallbackProxy, to your client package to be cross-compiled.
/**
* The remote service proxy extends default GWT {#link RemoteServiceProxy} and proxies the {#link AsyncCallback} with
* the {#link AsyncCallbackProxy}.
*/
public class MyRemoteServiceProxy extends RemoteServiceProxy {
public MyRemoteServiceProxy(String moduleBaseURL, String remoteServiceRelativePath, String serializationPolicyName,
Serializer serializer) {
super(moduleBaseURL, remoteServiceRelativePath, serializationPolicyName, serializer);
}
#Override
protected <T> RequestCallback doCreateRequestCallback(RequestCallbackAdapter.ResponseReader responseReader,
String methodName, RpcStatsContext statsContext,
AsyncCallback<T> callback) {
return super.doCreateRequestCallback(responseReader, methodName, statsContext, new AsyncCallbackProxy<T>(callback));
}
}
References:
DevGuideCodingBasicsDeferred.html
An example applied to performance tracking
The type you're looking for is probably RemoteServiceProxy (not RpcServiceProxy), and I assume, that you should start with overriding the default binding in /com/google/gwt/user/RemoteService.gwt.xml (just copy the lines to your own .gwt.xml file and adjust):
<generate-with
class="com.google.gwt.user.rebind.rpc.ServiceInterfaceProxyGenerator">
<when-type-assignable class="com.google.gwt.user.client.rpc.RemoteService"/>
</generate-with>
There you'll find protected Class<? extends RemoteServiceProxy> getProxySupertype(), which you can override to return your own RemoteServiceProxyclass.
Haven't tried it yet, so this may need a few additional steps...
Normally the way in GWT to handle exceptions happening in async processes is via UncaughtExceptionHandlers.
I would use my own handler to manage those exceptions:
GWT.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
public void onUncaughtException(Throwable e) {
if (e instanceof WhateverException) {
// handle the exception here
}
}
});
Using this you dont need to subclass anything.
If by "one place" you mean "I want to handle all errors in one method", then I would suggest either catching and throwing stuff until they're in one place OR creating an EventBus that you basically just send every error to. Then you can just have a single handler attached to this bus that can handle everything.
I want to make custom internationalization for my gwt app. What does this means? Imagine that my app must be internationalized for men and women. (id=men, id=women).
is it possible to make two different .properties files like
MyAppMessages_men_en.properties
MyAppMessages_women_en.properties
MyAppMessages_men_fr.properties
MyAppMessages_men_fr.properties
etc...
and my app host page will be accessed like this for example http://blabla/MyAppHostPage.html?locale=en&id=men
and this must load english version for men.
Thanks.
How about using fictional locale identifiers such as en_US_Men and en_US_Women and so forth for other locales?
(note that you should include a country whenever you include a variant of a locale)
Otherwise, I'd suggest using an abstract factory for your Messages and switch the concrete implementation using deferred binding on a distinct property (men vs. women):
interface MyAppMessagesFactory { MyAppMessages create(); }
class MyAppMessagesFactory_Men implements MyAppMessagesFactory {
#Override
public MyAppMessages create() { return GWT.create(MyAppMessages_Men.class); }
}
class MyAppMessagesFactory_Women implements MyAppMessagesFactory {
#Override
public MyAppMessages create() { return GWT.create(MyAppMessages_Women.class); }
}
You'd then have your MyAppMessages_Men_en.properties and MyAppMessages_Women_en.properties.
I'm confuse about IAdaptable and related classes. Which class is the adapter, the adaptee, the adaptable type?
[Context]
I have a context menu for entries of a table/tree viewer. Certain actions in the context menu must not be visible depending on the state of the respective object in the viewer (i.e. attribute value of a row in the table viewer).
I can achieve this with a config like this in plugin.xml:
<extension
point="org.eclipse.ui.popupMenus">
<objectContribution
adaptable="false"
id="<some_id>"
objectClass="<object_class_of_viewer_entry>">
<visibility>
<objectState name="buildable" value="true"/>
</visibility>
<action
class="<my_action_class>"
However, this only works if the object class implements org.eclipse.ui.IActionFilter.
[Problem]
My object class can't implement IActionFilter, I don't want to change its interface. Hence, I need to work around that using the IAdaptable mechanism.
Reading the Eclipse documentation left me all puzzled with terms (adapter, the adaptee, adaptable type) and I'm still confused about how to go about my problem.
The object class (referred to by in the above config) must remain untouched.
My approach was the following.
<extension
point="org.eclipse.core.runtime.adapters">
<factory
adaptableType="<object_class_of_viewer_entry>"
class="MyFactory">
<adapter
type="org.eclipse.ui.IActionFilter">
</adapter>
</factory>
</extension>
MyFactory is like this:
public class MyFactory implements IAdapterFactory {
private static final Class[] types = {
<object_class_of_viewer_entry>.class,
};
#Override
public Object getAdapter(Object adaptableObject, Class adapterType) {
return new <class_that_implements_IActionFilter>((<object_class_of_viewer_entry>) adaptableObject);
}
#Override
public Class[] getAdapterList() {
return types;
}
}
What's wrong about this? Where did I miss something?
Turns out everything, well, almost everything, was correct. I had simply mixed up interface and implementation of object_class_of_viewer_entry in the plugin.xml.
Two articles that helped: http://www.eclipsezone.com/articles/what-is-iadaptable/ and http://wiki.eclipse.org/FAQ_How_do_I_use_IAdaptable_and_IAdapterFactory%3F