summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteffen Kriese2011-03-21 04:53:49 (EDT)
committerSteffen Kriese2011-03-21 04:53:49 (EDT)
commit7c17078cd95ac24aa5f1a381fef2fa627f9daba2 (patch)
tree2750b997f2f52ed67155720ff2e9110dd7990917
parent5fc1a2703c3194c2c4440201865a73029eaa5d13 (diff)
downloadorg.eclipse.riena-7c17078cd95ac24aa5f1a381fef2fa627f9daba2.zip
org.eclipse.riena-7c17078cd95ac24aa5f1a381fef2fa627f9daba2.tar.gz
org.eclipse.riena-7c17078cd95ac24aa5f1a381fef2fa627f9daba2.tar.bz2
RESOLVED - bug 337521: AbstractSimpleNavigationNodeProvider should provide a way to build nodes asynchronous
https://bugs.eclipse.org/bugs/show_bug.cgi?id=337521
-rw-r--r--org.eclipse.riena.example.client/src/org/eclipse/riena/example/client/controllers/NavigateSubModuleController.java7
-rw-r--r--org.eclipse.riena.example.client/src/org/eclipse/riena/example/client/navigation/model/ComboAndListNodeAssembler.java14
-rw-r--r--org.eclipse.riena.example.client/src/org/eclipse/riena/example/client/navigation/model/TableTextAndTreeNodeAssembler.java6
-rw-r--r--org.eclipse.riena.example.client/src/org/eclipse/riena/example/client/views/NavigateSubModuleView.java1
-rw-r--r--org.eclipse.riena.navigation/META-INF/MANIFEST.MF3
-rw-r--r--org.eclipse.riena.navigation/src/org/eclipse/riena/navigation/INavigationNode.java29
-rw-r--r--org.eclipse.riena.navigation/src/org/eclipse/riena/navigation/NavigationArgument.java20
-rw-r--r--org.eclipse.riena.navigation/src/org/eclipse/riena/navigation/model/AbstractSimpleNavigationNodeProvider.java83
-rw-r--r--org.eclipse.riena.navigation/src/org/eclipse/riena/navigation/model/NavigationNode.java12
-rw-r--r--org.eclipse.riena.navigation/src/org/eclipse/riena/navigation/model/RunAsync.java19
10 files changed, 180 insertions, 14 deletions
diff --git a/org.eclipse.riena.example.client/src/org/eclipse/riena/example/client/controllers/NavigateSubModuleController.java b/org.eclipse.riena.example.client/src/org/eclipse/riena/example/client/controllers/NavigateSubModuleController.java
index fb389c1..0da403c 100644
--- a/org.eclipse.riena.example.client/src/org/eclipse/riena/example/client/controllers/NavigateSubModuleController.java
+++ b/org.eclipse.riena.example.client/src/org/eclipse/riena/example/client/controllers/NavigateSubModuleController.java
@@ -42,11 +42,11 @@ public class NavigateSubModuleController extends SubModuleController {
public void configureRidgets() {
final IActionRidget comboAndList = getRidget(IActionRidget.class, "comboAndList"); //$NON-NLS-1$
- comboAndList.setText("Combo and List (SubApplication 1)"); //$NON-NLS-1$
+ comboAndList.setText("Combo and List (async) (SubApplication 1)"); //$NON-NLS-1$
comboAndList.addListener(new ComboAndListListener());
final IActionRidget tableTextAndTree = getRidget(IActionRidget.class, "tableTextAndTree"); //$NON-NLS-1$
- tableTextAndTree.setText("Table, Text and Tree (SubApplication 2) [First Position]"); //$NON-NLS-1$
+ tableTextAndTree.setText("Table, Text and Tree (async) (SubApplication 2) [First Position]"); //$NON-NLS-1$
tableTextAndTree.addListener(new TableTextAndTreeListener());
final IActionRidget textAssembly = getRidget(IActionRidget.class, "textAssembly"); //$NON-NLS-1$
@@ -107,7 +107,6 @@ public class NavigateSubModuleController extends SubModuleController {
}
});
-
}
private class ComboAndListListener implements IActionListener {
@@ -125,7 +124,7 @@ public class NavigateSubModuleController extends SubModuleController {
public void callback() {
final NavigationArgument naviAgr = new NavigationArgument();
naviAgr.setNodePositioner(NodePositioner.ADD_BEGINNING);
- getNavigationNode().navigate(
+ getNavigationNode().createAsync(
new NavigationNodeId("org.eclipse.riena.example.navigate.tableTextAndTree"), naviAgr); //$NON-NLS-1$
}
diff --git a/org.eclipse.riena.example.client/src/org/eclipse/riena/example/client/navigation/model/ComboAndListNodeAssembler.java b/org.eclipse.riena.example.client/src/org/eclipse/riena/example/client/navigation/model/ComboAndListNodeAssembler.java
index 83d4df5..118c583 100644
--- a/org.eclipse.riena.example.client/src/org/eclipse/riena/example/client/navigation/model/ComboAndListNodeAssembler.java
+++ b/org.eclipse.riena.example.client/src/org/eclipse/riena/example/client/navigation/model/ComboAndListNodeAssembler.java
@@ -27,12 +27,14 @@ import org.eclipse.riena.navigation.NavigationArgument;
import org.eclipse.riena.navigation.NavigationNodeId;
import org.eclipse.riena.navigation.model.ModuleGroupNode;
import org.eclipse.riena.navigation.model.ModuleNode;
+import org.eclipse.riena.navigation.model.RunAsync;
import org.eclipse.riena.navigation.model.SubModuleNode;
import org.eclipse.riena.ui.workarea.WorkareaManager;
/**
- *
+ * Sample for asynchronous buildNode(..)
*/
+@RunAsync
public class ComboAndListNodeAssembler extends AbstractNavigationAssembler {
private Set<String> knownTargetIds = null;
@@ -78,10 +80,20 @@ public class ComboAndListNodeAssembler extends AbstractNavigationAssembler {
ListSubModuleView.ID, false);
subModule.addChild(subModule4);
+ sleep(3);
+
module.addChild(subModule);
return new IModuleGroupNode[] { node };
}
+ private void sleep(final int i) {
+ try {
+ Thread.sleep(i * 1000);
+ } catch (final InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
/**
* @see org.eclipse.riena.navigation.INavigationAssembler#acceptsTargetId(String)
*/
diff --git a/org.eclipse.riena.example.client/src/org/eclipse/riena/example/client/navigation/model/TableTextAndTreeNodeAssembler.java b/org.eclipse.riena.example.client/src/org/eclipse/riena/example/client/navigation/model/TableTextAndTreeNodeAssembler.java
index ffec57e..afffff6 100644
--- a/org.eclipse.riena.example.client/src/org/eclipse/riena/example/client/navigation/model/TableTextAndTreeNodeAssembler.java
+++ b/org.eclipse.riena.example.client/src/org/eclipse/riena/example/client/navigation/model/TableTextAndTreeNodeAssembler.java
@@ -50,6 +50,12 @@ public class TableTextAndTreeNodeAssembler extends AbstractNavigationAssembler {
public IModuleGroupNode[] buildNode(final NavigationNodeId presentationId,
final NavigationArgument navigationArgument) {
+ try {
+ Thread.sleep(3000);
+ } catch (final InterruptedException e) {
+ e.printStackTrace();
+ }
+
final IModuleGroupNode node = new ModuleGroupNode(new NavigationNodeId(
"org.eclipse.riena.example.navigate.tableTextAndTree")); //$NON-NLS-1$
final IModuleNode module = new ModuleNode(null, "Table,Text&Tree"); //$NON-NLS-1$
diff --git a/org.eclipse.riena.example.client/src/org/eclipse/riena/example/client/views/NavigateSubModuleView.java b/org.eclipse.riena.example.client/src/org/eclipse/riena/example/client/views/NavigateSubModuleView.java
index 6625511..dcf0271 100644
--- a/org.eclipse.riena.example.client/src/org/eclipse/riena/example/client/views/NavigateSubModuleView.java
+++ b/org.eclipse.riena.example.client/src/org/eclipse/riena/example/client/views/NavigateSubModuleView.java
@@ -95,7 +95,6 @@ public class NavigateSubModuleView extends SubModuleView {
final Button validation = UIControlsFactory.createButton(parent);
fillFactory.applyTo(validation);
addUIControl(validation, "validation"); //$NON-NLS-1$
-
}
}
diff --git a/org.eclipse.riena.navigation/META-INF/MANIFEST.MF b/org.eclipse.riena.navigation/META-INF/MANIFEST.MF
index 8a07427..9a9355d 100644
--- a/org.eclipse.riena.navigation/META-INF/MANIFEST.MF
+++ b/org.eclipse.riena.navigation/META-INF/MANIFEST.MF
@@ -7,7 +7,8 @@ Bundle-Activator: org.eclipse.riena.internal.navigation.Activator
Require-Bundle: org.eclipse.riena.core,
org.eclipse.riena.ui.core,
org.eclipse.riena.ui.ridgets,
- org.eclipse.riena.ui.filter;visibility:=reexport
+ org.eclipse.riena.ui.filter;visibility:=reexport,
+ org.eclipse.swt
Bundle-ActivationPolicy: lazy
Export-Package: org.eclipse.riena.internal.navigation;x-internal:=true,
org.eclipse.riena.navigation,
diff --git a/org.eclipse.riena.navigation/src/org/eclipse/riena/navigation/INavigationNode.java b/org.eclipse.riena.navigation/src/org/eclipse/riena/navigation/INavigationNode.java
index cec4bc9..2831a7b 100644
--- a/org.eclipse.riena.navigation/src/org/eclipse/riena/navigation/INavigationNode.java
+++ b/org.eclipse.riena.navigation/src/org/eclipse/riena/navigation/INavigationNode.java
@@ -619,6 +619,35 @@ public interface INavigationNode<C extends INavigationNode<?>> extends ITypecast
void create(NavigationNodeId targetId, NavigationArgument argument);
/**
+ * Creates the specified navigation node on a worker-thread and adds it to
+ * the application model if does not already exist. It also adds the
+ * NavigationArgument to the context of the NavigationNode.
+ *
+ * @param targetId
+ * ID of the node to create. Also refers to an extension point
+ * describing the target node that is used to create it if it
+ * does not exist.
+ * @param argument
+ * The optional NavigationArgument
+ * @see INavigationAssembler
+ * @see NavigationArgument
+ */
+ void createAsync(NavigationNodeId targetId, NavigationArgument argument);
+
+ /**
+ * Creates the specified navigation node on a worker-thread and adds it to
+ * the application model if does not already exist. It also adds the
+ * NavigationArgument to the context of the NavigationNode.
+ *
+ * @param targetId
+ * ID of the node to create. Also refers to an extension point
+ * describing the target node that is used to create it if it
+ * does not exist.
+ * @see INavigationAssembler
+ */
+ void createAsync(final NavigationNodeId targetId);
+
+ /**
* Moves this node to the node identified by the targetId. When moving a
* node as child to another keep in mind that you have to honor the strict
* type hierarchy of the nodes in the navigation model.
diff --git a/org.eclipse.riena.navigation/src/org/eclipse/riena/navigation/NavigationArgument.java b/org.eclipse.riena.navigation/src/org/eclipse/riena/navigation/NavigationArgument.java
index 43ae59d..a8189e6 100644
--- a/org.eclipse.riena.navigation/src/org/eclipse/riena/navigation/NavigationArgument.java
+++ b/org.eclipse.riena.navigation/src/org/eclipse/riena/navigation/NavigationArgument.java
@@ -32,6 +32,11 @@ public class NavigationArgument {
private String ridgetId;
private boolean prepareAll;
private NodePositioner nodePositioner;
+ /**
+ * internal flag that indicated creation of nodes on a worker-thread
+ *
+ */
+ private boolean createNodesAsync;
/**
*/
@@ -112,6 +117,21 @@ public class NavigationArgument {
}
/**
+ * @return the createNodesAsync
+ */
+ public boolean isCreateNodesAsync() {
+ return createNodesAsync;
+ }
+
+ /**
+ * @param createNodesAsync
+ * the createNodesAsync to set
+ */
+ public void setCreateNodesAsync(final boolean createNodesAsync) {
+ this.createNodesAsync = createNodesAsync;
+ }
+
+ /**
* @return ID of the ridget that will get the initial focus in the view
* associated with the opened node
* @since 1.2
diff --git a/org.eclipse.riena.navigation/src/org/eclipse/riena/navigation/model/AbstractSimpleNavigationNodeProvider.java b/org.eclipse.riena.navigation/src/org/eclipse/riena/navigation/model/AbstractSimpleNavigationNodeProvider.java
index 155354a..a0c38fe 100644
--- a/org.eclipse.riena.navigation/src/org/eclipse/riena/navigation/model/AbstractSimpleNavigationNodeProvider.java
+++ b/org.eclipse.riena.navigation/src/org/eclipse/riena/navigation/model/AbstractSimpleNavigationNodeProvider.java
@@ -19,11 +19,15 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
+import java.util.concurrent.Callable;
+import java.util.concurrent.atomic.AtomicBoolean;
import org.osgi.service.log.LogService;
import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.equinox.log.Logger;
+import org.eclipse.swt.widgets.Display;
import org.eclipse.riena.core.Log4r;
import org.eclipse.riena.core.util.StringUtils;
@@ -41,6 +45,7 @@ import org.eclipse.riena.navigation.StartupNodeInfo.Level;
import org.eclipse.riena.navigation.extension.ICommonNavigationAssemblyExtension;
import org.eclipse.riena.navigation.extension.INavigationAssembly2Extension;
import org.eclipse.riena.navigation.extension.INode2Extension;
+import org.eclipse.riena.ui.core.uiprocess.UIProcess;
/**
* This class provides navigation nodes that are defined by assemlies2
@@ -133,14 +138,12 @@ public abstract class AbstractSimpleNavigationNodeProvider implements INavigatio
* the ID of the target node
* @param argument
* contains information passed used for providing the target node
+ * @param createNodeAsync
* @return target node
*/
@SuppressWarnings("rawtypes")
protected INavigationNode<?> provideNodeHook(final INavigationNode<?> sourceNode, final NavigationNodeId targetId,
final NavigationArgument argument) {
-
- // System.err.println("\ntree:");
- // printNodeTree(getRootNode(sourceNode), 0);
INavigationNode<?> targetNode = findNode(getRootNode(sourceNode), targetId);
if (targetNode == null) {
if (LOGGER.isLoggable(LogService.LOG_DEBUG)) {
@@ -150,13 +153,37 @@ public abstract class AbstractSimpleNavigationNodeProvider implements INavigatio
final INavigationAssembler assembler = getNavigationAssembler(targetId, argument);
if (assembler != null) {
final NavigationNodeId parentTypeId = getParentTypeId(argument, assembler);
- // Call of findNode() on the result of method provideNodeHook() fixes problem for the case when the result
- // is not the node with typeId parentTypeId but one of the nodes parents (i.e. when the nodes assembler also
- // builds some of its parent nodes).
+ // Call of findNode() on the result of method provideNodeHook() fixes problem for the case when the result
+ // is not the node with typeId parentTypeId but one of the nodes parents (i.e. when the nodes assembler also
+ // builds some of its parent nodes).
final INavigationNode parentNode = findNode(provideNodeHook(sourceNode, parentTypeId, null),
parentTypeId);
prepareNavigationAssembler(targetId, assembler, parentNode);
- final INavigationNode<?>[] targetNodes = assembler.buildNode(targetId, argument);
+
+ INavigationNode<?>[] targetNodes = null;
+ if ((null != argument && argument.isCreateNodesAsync()) || shouldRunAsync(assembler)) {
+ final Callable<INavigationNode<?>[]> callable = new Callable<INavigationNode<?>[]>() {
+
+ public INavigationNode<?>[] call() throws Exception {
+ return assembler.buildNode(targetId, argument);
+ }
+ };
+ // Could be done with ExecutorService and Future. Using an UIProcess because of rap thread context attachment!
+ final NodeBuilderProcess process = new NodeBuilderProcess(callable);
+ process.start();
+ // FIXME addeed a dependecy to org.eclipse.swt so we can use the Display for dispatching.
+ // maybe we could move this code to UISynchronizer instead and get rid of the dependency
+ final Display display = Display.getCurrent();
+ // dispatch events
+ while (!process.isFinished()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ targetNodes = process.getResult();
+ } else {
+ targetNodes = assembler.buildNode(targetId, argument);
+ }
if ((targetNodes != null) && (targetNodes.length > 0)) {
prepareNodesAfterBuild(targetNodes, argument, parentNode, assembler, targetId, sourceNode);
targetNode = targetNodes[0];
@@ -177,6 +204,48 @@ public abstract class AbstractSimpleNavigationNodeProvider implements INavigatio
return targetNode;
}
+ /**
+ * @param assembler
+ * @return <code>true</code> if the given assembler has a {@link RunAsync}
+ * annotation, otherwise <code>false</code>
+ */
+ private boolean shouldRunAsync(final INavigationAssembler assembler) {
+ return assembler.getClass().isAnnotationPresent(RunAsync.class);
+ }
+
+ private class NodeBuilderProcess extends UIProcess {
+
+ private final AtomicBoolean finished = new AtomicBoolean(false);
+ private final Callable<INavigationNode<?>[]> command;
+ private INavigationNode<?>[] result = null;
+
+ public NodeBuilderProcess(final Callable<INavigationNode<?>[]> command) {
+ super("worker", false); //$NON-NLS-1$
+ this.command = command;
+ }
+
+ @Override
+ public boolean runJob(final IProgressMonitor monitor) {
+ try {
+ result = command.call();
+ } catch (final Exception e) {
+ LOGGER.log(LogService.LOG_ERROR, e.getMessage());
+ } finally {
+ finished.set(true);
+ }
+ return true;
+ }
+
+ private boolean isFinished() {
+ return finished.get();
+ }
+
+ private INavigationNode<?>[] getResult() {
+ return result;
+ }
+
+ }
+
// private void printNodeTree(final INavigationNode<?> root, final int depth) {
// final StringBuffer b = new StringBuffer();
// for (int i = 0; i < depth; i++) {
diff --git a/org.eclipse.riena.navigation/src/org/eclipse/riena/navigation/model/NavigationNode.java b/org.eclipse.riena.navigation/src/org/eclipse/riena/navigation/model/NavigationNode.java
index 1a4824e..3a34765 100644
--- a/org.eclipse.riena.navigation/src/org/eclipse/riena/navigation/model/NavigationNode.java
+++ b/org.eclipse.riena.navigation/src/org/eclipse/riena/navigation/model/NavigationNode.java
@@ -1040,6 +1040,18 @@ public abstract class NavigationNode<S extends INavigationNode<C>, C extends INa
getNavigationProcessor().create(this, targetId, argument);
}
+ public void createAsync(final NavigationNodeId targetId, NavigationArgument argument) {
+ if (null == argument) {
+ argument = new NavigationArgument();
+ }
+ argument.setCreateNodesAsync(true);
+ getNavigationProcessor().create(this, targetId, argument);
+ }
+
+ public void createAsync(final NavigationNodeId targetId) {
+ createAsync(targetId, null);
+ }
+
public void moveTo(final NavigationNodeId targetId) {
throw new UnsupportedOperationException("Only ModuleNodes can be moved to a new target."); //$NON-NLS-1$
diff --git a/org.eclipse.riena.navigation/src/org/eclipse/riena/navigation/model/RunAsync.java b/org.eclipse.riena.navigation/src/org/eclipse/riena/navigation/model/RunAsync.java
new file mode 100644
index 0000000..9b431a3
--- /dev/null
+++ b/org.eclipse.riena.navigation/src/org/eclipse/riena/navigation/model/RunAsync.java
@@ -0,0 +1,19 @@
+package org.eclipse.riena.navigation.model;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.eclipse.riena.navigation.INavigationAssembler;
+
+/**
+ * Defines that the buildNode() method of an {@link INavigationAssembler} should
+ * be run on a worker-thread. The UI events will be dispatched, while the worker
+ * is running so the UI does not freeze.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.TYPE })
+public @interface RunAsync {
+
+} \ No newline at end of file