Not able to inject CommandService to execute the command manually - eclipse

I have handler (to create new parts) assigned to particular command, which is defined as below and working fine,
Handler class :
..
#Execute
public void execute(EPartService partService,MApplication application,EModelService modelService) {
MPart part = MBasicFactory.INSTANCE.createPart();
part.setLabel("New Part");
part.setContributionURI("platform:/plugin/com.my.First.app/src/com/my/first/Parts/EditorPart/EmptyPart");
List<MPartStack> stacks = modelService.findElements(application, null, MPartStack.class, null);
stacks.get(2).getChildren().add(part);
partService.showPart(part, PartState.ACTIVATE);
}
#Execute
public void execute() {
//This Hello is getting printed.
System.out.println("Hello ");
}
I have one controller class to control the Fxml Objects (the click event on treeView). I want to execute that command manually from event handler treeview.
Controller Class :
#Inject
org.eclipse.e4.core.commands.ECommandService commandService;
#Inject
org.eclipse.e4.core.commands.EHandlerService service;
..
..
locationTreeView.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
if (mouseEvent.getClickCount() == 2 && mouseEvent.getButton().equals(MouseButton.PRIMARY)
&& locationTreeView.getSelectionModel().getSelectedItem().isLeaf()) {
try {
Command command = commandService.getCommand(S_CMD_MY_COMMAND_ID);
if (!command.isDefined())
return;
ParameterizedCommand myCommand = commandService.createCommand(S_CMD_MY_COMMAND_ID, null);
service.activateHandler(S_CMD_MY_COMMAND_ID, new ShowImmobilizerPart());
if (!service.canExecute(myCommand))
return;
service.executeHandler(myCommand);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
});
Here, Injected CommandService is null so not able to execute this parametric execute method of my handler class.
I believe there is another CommandService (org.eclipse.fx.core.command.CommandService) for e(fx)clipse but that is also comming null. I am using that as below
Controller Class :
#Inject org.eclipse.fx.core.command.CommandService commandService;
..
..
if (commandService.exists(S_CMD_MY_COMMAND_ID) && commandService.canExecute(S_CMD_MY_COMMAND_ID, null)) {
commandService.execute(S_CMD_MY_COMMAND_ID, null);
}
[Edit] :
My aim is to open new Part in Partstack. So in first code snippet you can see how i am opening part in execute(..). Here, Is there any way to get partService , application and modelService using ContextInjectionFactory or IEclipseContext?
Controller Class :
MyHandler myHandler = new MyHandler();
ContextInjectionFactory.inject(myHandler, iEclipseContext);
//myHandler.execute(); This is woroking if i define execute() method in handler Class.
myHandler.execute(partService,application,modelService); // This is not working as i am injecting this arguments at top of class.

Only classes created by Eclipse from descriptions in the e4xmi file are injected.
If you have a class created some other way you can do injection using:
ContextInjectionFactory.inject(object, context);
where object is the class instance to be injected and context is the IEclipseContext to use. Note that this will not inject the Constructor.
You can also use ContextInjectionFactory.make to create a class using injection.

Related

Eclipse JDT ListRewrite inserts new node at wrong places

I'm trying to add an annotation to some selected fields using Eclipse JDT infrastructure. However, this is not run as a plugin. I added all the required dependencies to a separate project so this can be run in batch mode. However I found out that, the ListRewrite is not inserting my annotation at the right place. I have given the code below. I initially get all the field declarations in a map using a visitor and then add them one by one using the code below.
FieldDeclaration fld = lVrblDet.listStringVarMap.get(propName);
final MarkerAnnotation autoWiredAnnotate = ast.newMarkerAnnotation(); autoWiredAnnotate.setTypeName(ast.newName("MyAnnot"));
lrw = rewriter.getListRewrite(fld, FieldDeclaration.MODIFIERS2_PROPERTY);
lrw.insertLast(autoWiredAnnotate, null);
Document document = new Document(cu.toString());
try {
TextEdit edits = rewriter.rewriteAST(document, null);
edits.apply(document);
} catch (MalformedTreeException | IllegalArgumentException | BadLocationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
However the expected output is sometimes offset by 1 character.The input and output classes have been given below.
Input Class:
#SuppressWarnings("unchecked")
public class SampleClassA {
public SampleClassB classB;
public SampleClassB getClassB() {
return classB;
}
public void setClassB(SampleClassB classB) {
this.classB = classB;
}
#Deprecated
public void printNameFromSmapleClassB() {
System.out.println(this.classB.name);
}
}
Output Class:
#SuppressWarnings("unchecked") public class SampleClassA {
p #MyAnnot
ublic SampleClassB classB;
public SampleClassB getClassB(){
return classB;
}
public void setClassB( SampleClassB classB){
this.classB=classB;
}
#Deprecated public void printNameFromSmapleClassB(){
System.out.println(this.classB.name);
}
}
As you can see in the code above, the Annotation messed with the modifier. I have tried multiple combinations of insertFirst,insertLast.Examples on the net are incomplete. Can somebody point me the mistake/the right resource ?
I just couldn't get it to work with ListRewrite. I don't know what I was doing wrong. So I wrote a visitor to store all the FieldDeclarations in a map.
#Override
public boolean visit(FieldDeclaration node) {
for (Object obj : node.fragments()) {
listStringVarMap.put(((VariableDeclarationFragment) obj).getName().toString(), node);
}
return false;
}
I looped through the map and inserted the annotation nodes as a modifiers, for the declarations that met my criteria. Please do remember to turn on recormodifications for the compilation unit you are modifying.
CompilationUnit cu = jFileAst.getEquivCompilUnit();
cu.recordModifications();
FieldDeclaration fldDecl = lVrblDet.listStringVarMap.get(propName);
importVo = (JavaAnnotImportVo) javaAstNodeCreator
.createASTNode(SpringAnnotationEnum.AutowireAnnotation, ast);
cu.imports().add(importVo.getImpDecl());
fldDecl.modifiers().add(0, importVo.getAnnotNode());
Finally write to file on disk/save back. Formatting(optional) before saving is a good idea, because the node insertions mess up with the code formatting.

How to override installed mappings of Behavior?

In java-9 Skins made it into public scope, while Behaviors are left in the dark - nevertheless changed considerably, in now using InputMap for all input bindings.
CellBehaviorBase installs mouse bindings like:
InputMap.MouseMapping pressedMapping, releasedMapping;
addDefaultMapping(
pressedMapping = new InputMap.MouseMapping(MouseEvent.MOUSE_PRESSED, this::mousePressed),
releasedMapping = new InputMap.MouseMapping(MouseEvent.MOUSE_RELEASED, this::mouseReleased),
new InputMap.MouseMapping(MouseEvent.MOUSE_DRAGGED, this::mouseDragged)
);
A concrete XXSkin now installs the behavior privately:
final private BehaviorBase behavior;
public TableCellSkin(TableCell control) {
super(control);
behavior = new TableCellBehavior(control);
....
}
The requirement is replace the mousePressed behavior (in jdk9 context). The idea is to grab super's field reflectively, dispose all its mappings and install the custom behavior. For some reason that I don't understand, the old bindings are still active (though the old mappings are empty!) and are invoked before the new bindings.
Below is a runnable example to play with: the mapping to mousePressed is simply implemented to do nothing, particularly to not invoke super. To see the old bindings at work, I set a conditional debug breakpoint at CellBehaviorBase.mousePressed like (in Eclipse):
System.out.println("mousePressed super");
new RuntimeException("whoIsCalling: " + getNode().getClass()).printStackTrace();
return false;
Run a debug and click into any cell, then the output is:
mousePressed super
java.lang.RuntimeException: whoIsCalling: class de.swingempire.fx.scene.control.cell.TableCellBehaviorReplace$PlainCustomTableCell
at com.sun.javafx.scene.control.behavior.CellBehaviorBase.mousePressed(CellBehaviorBase.java:169)
at com.sun.javafx.scene.control.inputmap.InputMap.handle(InputMap.java:274)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
//... lots more of event dispatching
// until finally the output in my custom cell behavior
Feb. 02, 2016 3:14:02 NACHM. de.swingempire.fx.scene.control.cell.TableCellBehaviorReplace$PlainCustomTableCellBehavior mousePressed
INFORMATION: short-circuit super: Bulgarisch
I would expect to only see the very last part, that is the printout by my custom behavior. It feels like I'm somehow fundamentally off - but can't nail it. Ideas?
The runnable code (sorry for its length, most is boiler-plate, though):
public class TableCellBehaviorReplace extends Application {
private final ObservableList<Locale> locales =
FXCollections.observableArrayList(Locale.getAvailableLocales());
private Parent getContent() {
TableView<Locale> table = createLocaleTable();
BorderPane content = new BorderPane(table);
return content;
}
private TableView<Locale> createLocaleTable() {
TableView<Locale> table = new TableView<>(locales);
TableColumn<Locale, String> name = new TableColumn<>("Name");
name.setCellValueFactory(new PropertyValueFactory<>("displayName"));
name.setCellFactory(p -> new PlainCustomTableCell<>());
TableColumn<Locale, String> lang = new TableColumn<>("Language");
lang.setCellValueFactory(new PropertyValueFactory<>("displayLanguage"));
lang.setCellFactory(p -> new PlainCustomTableCell<>());
table.getColumns().addAll(name, lang);
return table;
}
/**
* Custom skin that installs custom Behavior. Note: this is dirty!
* Access super's behavior, dispose to get rid off its handlers, install
* custom behavior.
*/
public static class PlainCustomTableCellSkin<S, T> extends TableCellSkin<S, T> {
private BehaviorBase<?> replacedBehavior;
public PlainCustomTableCellSkin(TableCell<S, T> control) {
super(control);
replaceBehavior();
}
private void replaceBehavior() {
BehaviorBase<?> old = (BehaviorBase<?>) invokeGetField(TableCellSkin.class, this, "behavior");
old.dispose();
// at this point, InputMap mappings are empty:
// System.out.println("old mappings: " + old.getInputMap().getMappings().size());
replacedBehavior = new PlainCustomTableCellBehavior<>(getSkinnable());
}
#Override
public void dispose() {
replacedBehavior.dispose();
super.dispose();
}
}
/**
* Custom behavior that's meant to override basic handlers. Here: short-circuit
* mousePressed.
*/
public static class PlainCustomTableCellBehavior<S, T> extends TableCellBehavior<S, T> {
public PlainCustomTableCellBehavior(TableCell<S, T> control) {
super(control);
}
#Override
public void mousePressed(MouseEvent e) {
if (true) {
LOG.info("short-circuit super: " + getNode().getItem());
return;
}
super.mousePressed(e);
}
}
/**
* C&P of default tableCell in TableColumn. Extended to install custom
* skin.
*/
public static class PlainCustomTableCell<S, T> extends TableCell<S, T> {
public PlainCustomTableCell() {
}
#Override protected void updateItem(T item, boolean empty) {
if (item == getItem()) return;
super.updateItem(item, empty);
if (item == null) {
super.setText(null);
super.setGraphic(null);
} else if (item instanceof Node) {
super.setText(null);
super.setGraphic((Node)item);
} else {
super.setText(item.toString());
super.setGraphic(null);
}
}
#Override
protected Skin<?> createDefaultSkin() {
return new PlainCustomTableCellSkin<>(this);
}
}
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setScene(new Scene(getContent(), 400, 200));
primaryStage.setTitle(FXUtils.version());
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
/**
* Reflectively access super field.
*/
public static Object invokeGetField(Class source, Object target, String name) {
try {
Field field = source.getDeclaredField(name);
field.setAccessible(true);
return field.get(target);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
#SuppressWarnings("unused")
private static final Logger LOG = Logger
.getLogger(TableCellBehaviorReplace.class.getName());
}
Edit
The suggestion inherit from the abstract skin XXSkinBase instead of the concrete XXSkin (then you are free to install whatever behavior you want, dude :-) is very reasonable and should be the first option. In the particular case of XX being TableCell, that's currently not possible, as the base class contains abstract package-private methods. Also, there are XX that don't have an abstract base (like f.i. ListCell).
Might be a bug in InputMap:
Digging into the sources I found some internal book-keeping (eventTypeMappings) parallel to mappings (these are the handlers). InputMap is listening to changes in mappings and updates the internal book-keeping on changes
mappings.addListener((ListChangeListener<Mapping<?>>) c -> {
while (c.next()) {
// TODO handle mapping removal
if (c.wasRemoved()) {
for (Mapping<?> mapping : c.getRemoved()) {
removeMapping(mapping);
}
}
// removeMapping
private void removeMapping(Mapping<?> mapping) {
// TODO
}
Meaning that the internal structure is never cleaned, particularly not when the mappings are removed in behavior.dispose(). When looking up eventHandlers - by inputMap.handle(e), see debug stacktrace shown in the question - the old handler is found in the internal book-keeping structure.
Joys of early experiments ... ;-)
At the end, a (very dirty, very hacky!) solution is to take over InputMap's job and force a cleanup of the internals:
private void replaceBehavior() {
BehaviorBase<?> old = (BehaviorBase<?>) invokeGetField(TableCellSkin.class, this, "behavior");
old.dispose();
cleanupInputMap(old.getInputMap());
// at this point, InputMap mappings are empty:
// System.out.println("old mappings: " + old.getInputMap().getMappings().size());
replacedBehavior = new PlainCustomTableCellBehavior<>(getSkinnable());
}
/**
* This is a hack around InputMap not cleaning up internals on removing mappings.
* We remove MousePressed/MouseReleased/MouseDragged mappings from the internal map.
* Beware: obviously this is dirty!
*
* #param inputMap
*/
private void cleanupInputMap(InputMap<?> inputMap) {
Map eventTypeMappings = (Map) invokeGetField(InputMap.class, inputMap, "eventTypeMappings");
eventTypeMappings.remove(MouseEvent.MOUSE_PRESSED);
eventTypeMappings.remove(MouseEvent.MOUSE_RELEASED);
eventTypeMappings.remove(MouseEvent.MOUSE_DRAGGED);
}
BTW: just in case anybody is wondering wtf - without, my hack around the missing commitOnFocusLost when editing a cell stopped working in java-9.
Try in PlainCustomTableCellSkin to inherit from the abstract class TableCellSkinBase rather than from TableCellSkin.
Then you can call the super constructor, which takes an TableCellBehaviorBase object as additional param.
Then you can save your time replacing it, by initializing it directly with the right one.
Just for more claryfication:
TableCellSkin extends TableCellSkinBase
TableCellBehavior extends TableCellBehaviorBase
One more thing. You need to also call super.init(tableCell) in your constructor.
Take the TableCellSkin class as reference.

afterCompose never executes on initialization

I have a controller that extends window and implments IdSpace, AfterCompose.
But the function afterCompose never executes when the controller is initialized. A cant figure out what I am missing. My code for this part:
DataTemplateWindowController.java
public class DataTemplateWindowController extends Window implements IdSpace, AfterCompose {
...
public DataTemplateWindowController() {
Executions.createComponents("dataTemplate.zul", this, null);
Selectors.wireComponents(this, this, false);
Selectors.wireEventListeners(this, this);
}
#Override
public void afterCompose() {
Do something smart!!
}
}
And the initializetion.
HomeWindowController.java
public class HomeWindowController extends SelectorComposer<Component> {
...
#Wire
Window homeWindow;
DataTemplateWindowController fa2;
public void setDataTemplate() {
fa2 = new FA2WindowController();
fa2.setParent(homeWindow);
}
}
The page loads fine, but the afterCompose function never executes.
I know that i can just avoid implementing AfterCompose and then run the function fa2.afterCompose() after initialization but I expect AfterCompose to be able to do the job for me.
As you can see in the javadoc of AfterCompose (of org.zkoss.zk.ui.ext.AfterCompose) interface :
Implemented by a component if it wants to know when ZK loader created
it. If this interface is implemented, {#link #afterCompose} is called,
after ZK loader creates this component, all of its children, and
assigns all properties defined in the ZUML page. It is so-called
"compose".
So the method : "afterCompose" will never be call automatically by your own java code (the code in your method setDataTemplate() in your example). It will only be called if you use your component in a ZUL page.
And you can also see in the Javadoc of org.zkoss.zk.ui.ext.AfterCompose:
If it is created manually, it is caller's job to invoke {#link#afterCompose}.
If you don't need to set any properties or child in you afterCompose process, just don't use this interface and put your code in the constructor, otherwise, you will have to call it manually when you need it (usually in the doAfterCompose of your SelectorComposer) :
public class HomeWindowController extends SelectorComposer<Component> {
...
#Wire
Window homeWindow;
DataTemplateWindowController fa2;
#Override
public void doAfterCompose(Component comp) throws Exception {
super.doAfterCompose(comp);
setDataTemplate();
}
public void setDataTemplate() {
fa2 = new FA2WindowController();
fa2.setParent(homeWindow);
fa2.afterCompose();
}
}

Override TestNG's getTestName method

I execute a TestNG test using a dataProvider.
So I set the testName via #BeforeMethod and I override getTestName().
This works so far, but it seems TestNG is calling the test's getTestName in the beginning
before it starts. This happens when an exception was thrown during configuration, so the #BeforeMethod is not executed and therefore my test name is null.
Is there anyway to call the original method, the one that would have been called if I would not have overwritten it :D since I implement an interface an do not extend from another class I cannot use super.getTestName().
Any way to solve this may be?
#Test(groups = {TestGroups.READY}, description = "check help on each tab")
public class HelpTest extends TestControl implements ITest {
// overriding to return my individual testname, but is null at the beginning
#Override
public String getTestName() {
return TestControl.getCurrentTestName();
}
#DataProvider(name = "tabs")
public Iterator<Object[]> tabs() {
Set<Object[]> list = new LinkedHashSet<Object[]>();
for (Tab tab : Tab.values()) {
list.add(new Object[]{tab});
}
return list.iterator();
}
// before the test below starts, i set my individual testname
#BeforeMethod
public void setTestName(Method method, Object[] testData) {
TestControl.setCurrentTestName(method.getName() + "_" + StringUtils.capitalize(testData[0].toString().toLowerCase()));
}
// executing the test with the given data provider
#Test(dataProvider = "tabs")
public void testHelpSites(Tab tab) throws Exception {
TestActions.goTab(tab).callHelp(tab).checkHelp();
}
}
I guess I figured it out, I also use a TestReporter via AbstractWebDriverEventListener and ITestListener and on its onTestStart(ITestResult result) it's calling the test's name and that's the source of the call before the #BeforeMethod call.
I solved it by checking if result.getName() is null, which calls the test's getTestName() if it implements ITest and if it's null I use the original name from result.getMethod.getMethodName(). Not pretty, but rare :D
I could solve this problem using ITestNGMethod testng class.
ITestNGMethod method = result.getMethod(); // result is ITestResult Object
method.getMethodName(); // This will return method name.
My complete method here:
#Override
public void onTestSuccess(ITestResult result) {
ITestNGMethod method = result.getMethod();
String message = "Test Execution is Successful:"+method.getMethodName();
}
Hope this helps

ClientBundle for multiple "themes"

We have a web application that needs a different theme for each major client. The original developer did this by looking at the URL in javascript and adding a stylesheet to override the default theme.
One problem with this is the site has the default look for a few seconds then suddenly swaps to the correct theme. Another is that it seems to waste a lot of bandwidth/time.
My current idea is to create a "default" ClientBundle with our default look and feel extend that interface and override each entry (as needed) with the client's images using the various annotations like #ImageResouce and pointing to a different location.
Has anybody had experience doing this? One problem I forsee is not being able to use the uibinder style tags as they statically point to a specific resource bundle.
Any ideas?
Overriden bundles
Yes you can.
I've did the override thing with ClientBundles and works fine. One thing you MUST do is inherit the types of the properties too. By example:
BigBundle {
Nestedundle otherBundle();
ImageResource otherImage();
Styles css();
}
And then you must inherit this way:
OtherBigBundle extends BigBundle {
OtherNestedBundle otherBundle(); // if you want to change it
ImageResource otherImage(); // of you want to change it
OtherStyles css(); // of you want to change it
}
and OtherNestedBundle extends NestedBundle
and OtherStyles extends Styles
At least with css's: if the properties are declared NOT USING the child interface they will produce styles for the same CSS classname and all will be mixed. So declare overriden styles with the child interfaces :)
Flexible UIBinders
You can set from outside the bundle to use if you use UiField(provided=true) annotation. In this way you first set the bundle and then call the uibindler. It will use the resource field assuming it's already created.
Deferred binding
You could use GWT.runAsync for loading just the correct bundle.
Some example
The ui.xml
<ui:with field='res' type='your.package.TheBundle'/>
the corresponding class
#UiField(provided=true) TheBundle bundle;
private void createTheThing() {
this.bundle = factory.createBundle();
MyUiBindler binder = GWT.create(MyUiBindler.class);
this.panel = binder.createAndBindUi(this);
...
}
Some bundle interfaces
interface TheBundle extends ClientBundle {
#ImageResource("default.png")
ImageResource image1();
#Source("default.css")
TheCss css();
}
interface Theme1Bundle extends TheBundle {
#ImageResource("one.png")
ImageResource image1(); // type: imageresource is ok
#Source("one.css")
OneCss css(); // type: OneCss => use other compiled css class-names
interface OneCss extends TheCss { // inner-interface, just for fun
// don't need to declare each String method
}
}
If you don't override something it's ok
Options for the bundle factory
1) just altogether
if (...) {
return GWT.create(TheBundle.class);
} else if (...) {
return GWT.create(Theme1Bundle.class);
}
2) runAsync (just load the needed part... but after the initial part is executed)
if (...) {
GWT.runAsync(new RunAsyncCallback() {
public void onSuccess() {
return GWT.create(TheBundle.class);
}
// please program the onFailure method
});
} else if (...) {
GWT.runAsync(new RunAsyncCallback() {
public void onSuccess() {
return GWT.create(Theme1Bundle.class);
}
// please program the onFailure method
});
}
3) use deferred-binding and generators for autogenerating factory in compile-time based on annotated bundles like #ThemeBundle("one")
This example is from the real world. I use a DynamicEntryPointWidgetFactory (DEPWidgetFactory for short) for creating widget based on an identifier string. Each widget is an application screen and each main menu ítem has the widgetName it has to create.
In your case the id will be the theme to create.
Important: if you use runAsync you cannot create the resourcebundle just before creating the UI like in the sample code before. You must ask for the theme and when it's ready (in the callback) pass it to your widget constructor and your widget can assign it to its field.
The factory interface:
public interface DynamicEntryPointWidgetFactory
{
public void buildWidget(String widgetName, AsyncCallback<Widget> callback);
}
The annotation for widgets to generate:
#Target(ElementType.TYPE)
public #interface EntryPointWidget
{
/**
* The name wich will be used to identify this widget.
*/
String value();
}
The module configuration:
It says: the implementation for the Factory will be generated with this class (the other option is to use replace-with, but in our case we don't have predefined options for each locale or browser, but something more dynamic).
<generate-with class="com.dia.nexdia.services.gwt.rebind.entrypoint.DynamicEntryPointFactoryGenerator">
<when-type-assignable class="com.dia.nexdia.services.gwt.client.entrypoint.DynamicEntryPointWidgetFactory" />
</generate-with>
The generator:
public class DynamicEntryPointFactoryGenerator extends Generator {
#Override
public String generate(TreeLogger logger, GeneratorContext context,
String typeName) throws UnableToCompleteException {
PrintWriter pw = context.tryCreate(logger,
"x.services.gwt.client.entrypoint",
"DynamicEntryPointWidgetFactoryImpl");
if (pw != null) {
// write package, imports, whatever
pw.append("package x.services.gwt.client.entrypoint;");
pw.append("import x.services.gwt.client.entrypoint.DynamicEntryPointWidgetFactory;");
pw.append("import com.google.gwt.core.client.GWT;");
pw.append("import com.google.gwt.core.client.RunAsyncCallback;");
pw.append("import com.google.gwt.user.client.rpc.AsyncCallback;");
pw.append("import com.google.gwt.user.client.ui.Widget;");
// the class
pw.append("public class DynamicEntryPointWidgetFactoryImpl implements DynamicEntryPointWidgetFactory {");
// buildWidget method
pw.append(" public void buildWidget(String widgetName, final AsyncCallback<Widget> callback) {");
// iterates over all the classes to find those with EntryPointWidget annotation
TypeOracle oracle = context.getTypeOracle();
JPackage[] packages = oracle.getPackages();
for (JPackage pack : packages)
{
JClassType[] classes = pack.getTypes();
for (JClassType classtype : classes)
{
EntryPointWidget annotation = classtype.getAnnotation(EntryPointWidget.class);
if (annotation != null)
{
String fullName = classtype.getQualifiedSourceName();
logger.log(TreeLogger.INFO, "Entry-point widget found: " + fullName);
pw.append("if (\"" + annotation.value() + "\".equals(widgetName)) {");
pw.append(" GWT.runAsync(" + fullName + ".class, new RunAsyncCallback() {");
pw.append(" public void onFailure(Throwable t) {");
pw.append(" callback.onFailure(t);");
pw.append(" }");
pw.append(" public void onSuccess() {");
pw.append(" callback.onSuccess(new " + fullName + "());");
pw.append(" }");
pw.append(" });");
pw.append(" return;");
pw.append("}");
}
}
}
pw.append("callback.onFailure(new IllegalArgumentException(\"Widget '\" + widgetName + \"' not recognized.\"));");
pw.append(" }");
pw.append("}");
context.commit(logger, pw);
}
// return the name of the generated class
return "x.services.gwt.client.entrypoint.DynamicEntryPointWidgetFactoryImpl";
}