JavaFX WebView loading page in background - webview

I have a problem using the JavaFX WebView. What I want to achieve is pre-fetching a web page in the background and visualiszing it only when the page is totally loaded.
I have made a simple exmaple program to reproduce the problem. After the page is loaded I enable a button. A Click on this button then makes the WebView visible.
The problem I have is, that if I click on the button when it gets enabled, the web page is not visible directly. Instead the following happens: At first there is a totally white panel and then after a short time the web page is visible. I don't understand why the page is not visible directly. How can I achieve it, that the web page is directly visible?
The following link points to an animated gif which shows the behaviour:
http://tinypic.com/view.php?pic=oh66bl&s=5#.Ujmv1RddWKk
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class WebViewTest extends javax.swing.JPanel {
private static JFXPanel browserFxPanel;
private WebView webView;
private WebEngine eng;
/**
* Creates new form WebViewTest
*/
public WebViewTest() {
initComponents();
Platform.setImplicitExit(false);
browserFxPanel = new JFXPanel();
Platform.runLater(new Runnable() {
public void run() {
webView = createBrowser();
Scene scene = new Scene(webView);
scene.setFill(null);
browserFxPanel.setScene(
scene);
}
});
}
/**
* This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The
* content of this method is always regenerated by the Form Editor.
*/
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
pnlMain = new javax.swing.JPanel();
showWebpageButton = new javax.swing.JButton();
setLayout(new java.awt.GridBagLayout());
pnlMain.setLayout(new java.awt.BorderLayout());
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.gridwidth = 3;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
add(pnlMain, gridBagConstraints);
showWebpageButton.setText("show web page");
showWebpageButton.setEnabled(false);
showWebpageButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
showWebpageButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 0;
gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10);
add(showWebpageButton, gridBagConstraints);
}// </editor-fold>
private void showWebpageButtonActionPerformed(java.awt.event.ActionEvent evt) {
pnlMain.removeAll();
pnlMain.add(browserFxPanel, BorderLayout.CENTER);
WebViewTest.this.invalidate();
WebViewTest.this.revalidate();
}
// Variables declaration - do not modify
private javax.swing.JPanel pnlMain;
private javax.swing.JButton showWebpageButton;
// End of variables declaration
private WebView createBrowser() {
Double widthDouble = pnlMain.getSize().getWidth();
Double heightDouble = pnlMain.getSize().getHeight();
final WebView view = new WebView();
view.setMinSize(widthDouble, heightDouble);
view.setPrefSize(widthDouble, heightDouble);
eng = view.getEngine();
eng.load("http://todomvc.com/architecture-examples/angularjs/#/");
eng.getLoadWorker().workDoneProperty().addListener(new ChangeListener<Number>() {
public void changed(ObservableValue<? extends Number> ov, Number t, Number t1) {
final double workDone = eng.getLoadWorker().getWorkDone();
final double totalWork = eng.getLoadWorker().getTotalWork();
if (workDone == totalWork) {
showWebpageButton.setEnabled(true);
}
}
});
return view;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
final JFrame f = new JFrame("Navigator Dummy");
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setSize(new Dimension(1024, 800));
final WebViewTest navDummy = new WebViewTest();
f.getContentPane().add(navDummy);
f.setVisible(true);
}
});
}
}

JFX needs a "stage" to show up its face. Modify your codes as following and it will work perfectly
/**
* Creates new form WebViewTest
*/
private Stage stage; // insert this line
public WebViewTest() {
initComponents();
Platform.setImplicitExit(false);
browserFxPanel = new JFXPanel();
Platform.runLater(new Runnable() {
public void run() {
webView = createBrowser();
Scene scene = new Scene(webView);
scene.setFill(null);
stage = new Stage(); // <<<
stage.setScene(scene); // <<<
browserFxPanel.setScene(scene);
}
});
}
...
private void showWebpageButtonActionPerformed(java.awt.event.ActionEvent evt) {
pnlMain.removeAll();
pnlMain.add(browserFxPanel, BorderLayout.CENTER);
WebViewTest.this.invalidate();
WebViewTest.this.revalidate();
stage.show(); // <<< afer click Button
}

Related

Can I bind the return to a condition?

I have the following problem:
My method opens a JDialog with a bunch of buttons (only one in example code). I want to click a button and thereby choose an ImageIcon for my method to return. But the Method does not wait for me to click a button. It opens the window and then returns an empty ImageIcon.
public class Kartenauswahl {
ImageIcon bandit;
public ImageIcon auswahlfenster() {
int bwidth = new Integer(150);
int bheight = new Integer(225);
bandit = new ImageIcon("cover/Bandit.jpe");
bandit.setImage(bandit.getImage().getScaledInstance(bwidth,bheight,Image.SCALE_DEFAULT));
final JDialog kartenwahl = new JDialog();
kartenwahl.setTitle("Kartenwahl");
kartenwahl.setSize(1500,1000);
kartenwahl.setVisible(true);
kartenwahl.setLayout(new FlowLayout());
ImageIcon returnicon= new ImageIcon();
final JButton b1 = new JButton(); //just to get the Icon out of the void loop
JButton B1 = new JButton(bandit); //this is going to be the button I want to click to choose the ImageIcon which is returned
B1.setContentAreaFilled(false);
B1.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
b1.setIcon(bandit);
kartenwahl.dispose();
}
});
kartenwahl.add(B1);
returnicon = (ImageIcon) b1.getIcon();
return returnicon;
}
}
Question: can I bind the return statement to a condition? Like "only return after I clicked that Button B1"?
Hi sorry for the long wait. I have written an custom JDialog that should work for you.
public class CustomDialog extends JDialog {
JButton[] buttons;
ImageIcon selectedImageIcon;
public CustomDialog() {
setSize(500, 500);
setLayout(new GridLayout(4, 6));
ActionListener actionListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
selectedImageIcon = ((ImageIcon) ((JButton) e.getSource()).getIcon());
dispose();
}
};
buttons = new JButton[24];
for(int i = 0; i < 24; i++) {
buttons[i] = new JButton(new ImageIcon("path_to_your_image_file"));
buttons[i].addActionListener(actionListener);
add(buttons[i]);
}
setVisible(true);
}
public ImageIcon getSelectedImageIcon() {
return selectedImageIcon;
}
}
The initial size is not that important the GridLayout is. you mentioned that you would need 24 buttons so I created an grid with 4 rows and 6 columns.
Then I create the buttons in a loop and adding the same Listener to set the selection icon with the icon of the pressed button. Afterwards I dispose the screen triggering an windowClosed event.
You could simply create this Dialog from your main class and wait for the response like so:
public class main {
public static void main(String[] args) {
CustomDialog customDialog = new CustomDialog();
customDialog.addWindowListener(new WindowAdapter() {
#Override
public void windowClosed(WindowEvent e) {
ImageIcon icon = customDialog.getSelectedImageIcon();
//do something with your icon
}
});
}
}
Don't forget to mark this answer as correct if it fixes your problem.
Have a good one!

win:length(2) is fired after first event

I made a very simple test gui based on this brilliant article about getting started with Esper.
What surprises me is that this query is validated to true after the very first tick event is sent, if the price is above 6.
select * from StockTick(symbol='AAPL').win:length(2) having avg(price) > 6.0
As far as I understand, win:length(2) needs TWO ticks before an event is fired, or am I wrong?
Here is a SSCCE for this question, just press the "Create Tick Event" button and you will see the StockTick Event being fired at once.
It needs the following jars which comes bundled with Esper
esper\lib\antlr-runtime-3.2.jar
esper\lib\cglib-nodep-2.2.jar
esper\lib\commons-logging-1.1.1.jar
esper\lib\esper_3rdparties.license
esper\lib\log4j-1.2.16.jar
esper-4.11.0.jar
import javax.swing.JFrame;
import javax.swing.JSplitPane;
import javax.swing.SwingUtilities;
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JButton;
import javax.swing.JScrollPane;
import java.awt.TextArea;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;
import java.util.Random;
import javax.swing.JRadioButton;
import javax.swing.JPanel;
import java.awt.GridLayout;
import javax.swing.JTextArea;
import javax.swing.ScrollPaneConstants;
import com.espertech.esper.client.Configuration;
import com.espertech.esper.client.EPAdministrator;
import com.espertech.esper.client.EPRuntime;
import com.espertech.esper.client.EPServiceProvider;
import com.espertech.esper.client.EPServiceProviderManager;
import com.espertech.esper.client.EPStatement;
import com.espertech.esper.client.EventBean;
import com.espertech.esper.client.UpdateListener;
import javax.swing.JTextField;
public class Tester extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
JButton createRandomValueEventButton;
private JPanel panel;
private JPanel southPanel;
private JPanel centerPanel;
private static JTextArea centerTextArea;
private static JTextArea southTextArea;
private static Random generator = new Random();
private EPRuntime cepRT;
private JSplitPane textSplitPane;
private JButton btnNewButton;
private static JTextField priceTextField;
public Tester() {
getContentPane().setLayout(new BorderLayout(0, 0));
JSplitPane splitPane = new JSplitPane();
createRandomValueEventButton = new JButton("Create Tick Event With Random Price");
splitPane.setLeftComponent(createRandomValueEventButton);
createRandomValueEventButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
createTickWithRandomPrice();
}
});
panel = new JPanel();
splitPane.setRightComponent(panel);
panel.setLayout(new GridLayout(1, 0, 0, 0));
btnNewButton = new JButton("Create Tick Event");
panel.add(btnNewButton);
btnNewButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
createTick();
}
});
priceTextField = new JTextField();
priceTextField.setText(new Integer(10).toString());
panel.add(priceTextField);
priceTextField.setColumns(4);
getContentPane().add(splitPane, BorderLayout.NORTH);
textSplitPane = new JSplitPane();
textSplitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
getContentPane().add(textSplitPane, BorderLayout.CENTER);
centerPanel = new JPanel();
centerPanel.setLayout(new BorderLayout(0, 0));
JScrollPane centerTextScrollPane = new JScrollPane();
centerTextScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
centerTextArea = new JTextArea();
centerTextArea.setRows(12);
centerTextScrollPane.setViewportView(centerTextArea);
southPanel = new JPanel();
southPanel.setLayout(new BorderLayout(0, 0));
JScrollPane southTextScrollPane = new JScrollPane();
southTextScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
southTextArea = new JTextArea();
southTextArea.setRows(5);
southTextScrollPane.setViewportView(southTextArea);
textSplitPane.setRightComponent(southTextScrollPane);
textSplitPane.setLeftComponent(centerTextScrollPane);
setupCEP();
}
public static void GenerateRandomTick(EPRuntime cepRT) {
double price = (double) generator.nextInt(10);
long timeStamp = System.currentTimeMillis();
String symbol = "AAPL";
Tick tick = new Tick(symbol, price, timeStamp);
System.out.println("Sending tick:" + tick);
centerTextArea.append(new Date().toString()+" Sending tick:" + tick+"\n");
cepRT.sendEvent(tick);
}
public static void GenerateTick(EPRuntime cepRT) {
double price = Double.parseDouble(priceTextField.getText());
long timeStamp = System.currentTimeMillis();
String symbol = "AAPL";
Tick tick = new Tick(symbol, price, timeStamp);
System.out.println("Sending tick:" + tick);
centerTextArea.append(new Date().toString()+" Sending tick: " + tick+"\n");
cepRT.sendEvent(tick);
}
public static void main(String[] args){
Tester tester = new Tester();
tester.setSize(new Dimension(570,500));
tester.setVisible(true);
}
private void createTickWithRandomPrice(){
SwingUtilities.invokeLater(new Runnable() {
public void run() {
GenerateRandomTick(getEPRuntime());
}
});
}
private void createTick(){
SwingUtilities.invokeLater(new Runnable() {
public void run() {
GenerateTick(getEPRuntime());
}
});
}
private void setupCEP(){
Configuration cepConfig = new Configuration();
cepConfig.addEventType("StockTick", Tick.class.getName());
EPServiceProvider cep = EPServiceProviderManager.getProvider("myCEPEngine", cepConfig);
cepRT = cep.getEPRuntime();
EPAdministrator cepAdm = cep.getEPAdministrator();
EPStatement cepStatement = cepAdm.createEPL(
"select * from " +
"StockTick(symbol='AAPL').win:length(2) " +
"having avg(price) > 6.0");
cepStatement.addListener(new CEPListener());
//System.out.println("cepStatement.getText(): "+cepStatement.getText());
}
private EPRuntime getEPRuntime(){
public static class Tick {
String symbol;
Double price;
Date timeStamp;
public Tick(String s, double p, long t) {
symbol = s;
price = p;
timeStamp = new Date(t);
}
public double getPrice() {return price;}
public String getSymbol() {return symbol;}
public Date getTimeStamp() {return timeStamp;}
#Override
public String toString() {
return symbol+" Price: " + price.toString();
}
}
public static class CEPListener implements UpdateListener {
}
Actually aggregation and conditions are independent of how many events are in data window. There are functions you could use to check whether a data window is "filled": the "leaving", "count" or "prevcount" for example.
For anyone interested,
changing the query to this solved the problem
select * from StockTick(symbol='AAPL').win:length_batch(2) having avg(price) > 6.0 and count(*) >= 2
Now an event will be triggered for every consecutive tick with the price higher than 6, in batches of two.

JavaFX: scrolling vs. focus traversal with arrow keys

I got a ScrollPane containing focusable Nodes.
The current default behaviour is:
Shift + ←, ↑, →, ↓ moves the focus
←, ↑, →, ↓ scrolls the view
I want it the other way around.
How can I accomplish this or where should I start?
[EDIT] Well, there is another fragile approach.
Instead of messing around with the events, one could mess around with the KeyBindings.
scrollPane.skinProperty().addListener(new ChangeListener<Skin<?>>() {
#Override
public void changed(ObservableValue<? extends Skin<?>> observable, Skin<?> oldValue, Skin<?> newValue) {
ScrollPaneSkin scrollPaneSkin = (ScrollPaneSkin) scrollPane.getSkin();
ScrollPaneBehavior scrollPaneBehavior = scrollPaneSkin.getBehavior();
try {
Field keyBindingsField = BehaviorBase.class.getDeclaredField("keyBindings");
keyBindingsField.setAccessible(true);
List<KeyBinding> keyBindings = (List<KeyBinding>) keyBindingsField.get(scrollPaneBehavior);
List<KeyBinding> newKeyBindings = new ArrayList<>();
for (KeyBinding keyBinding : keyBindings) {
KeyCode code = keyBinding.getCode();
newKeyBindings.add(code == KeyCode.LEFT || code == KeyCode.RIGHT || code == KeyCode.UP || code == KeyCode.DOWN ? keyBinding.shift() : keyBinding);
}
keyBindingsField.set(scrollPaneBehavior, newKeyBindings);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
LOGGER.warn("private api changed.", e);
}
}
});
I think, that could be the cleaner way, if KeyBindings were more non-static, modifyable and public.
Use an event filter to capture the relevant key events and remap them to different key events before the events start to bubble.
Re-mapping default keys is a tricky thing which:
Can confuse the user.
May have unexpected side effects (e.g. TextFields may no longer work as you expect).
So use with care:
import javafx.application.*;
import javafx.event.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.TilePane;
import javafx.stage.Stage;
import java.util.*;
public class ScrollInterceptor extends Application {
#Override
public void start(Stage stage) {
ScrollPane scrollPane = new ScrollPane(
createScrollableContent()
);
Scene scene = new Scene(
scrollPane,
300, 200
);
remapArrowKeys(scrollPane);
stage.setScene(scene);
stage.show();
hackToScrollToTopLeftCorner(scrollPane);
}
private void remapArrowKeys(ScrollPane scrollPane) {
List<KeyEvent> mappedEvents = new ArrayList<>();
scrollPane.addEventFilter(KeyEvent.ANY, new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
if (mappedEvents.remove(event))
return;
switch (event.getCode()) {
case UP:
case DOWN:
case LEFT:
case RIGHT:
KeyEvent newEvent = remap(event);
mappedEvents.add(newEvent);
event.consume();
Event.fireEvent(event.getTarget(), newEvent);
}
}
private KeyEvent remap(KeyEvent event) {
KeyEvent newEvent = new KeyEvent(
event.getEventType(),
event.getCharacter(),
event.getText(),
event.getCode(),
!event.isShiftDown(),
event.isControlDown(),
event.isAltDown(),
event.isMetaDown()
);
return newEvent.copyFor(event.getSource(), event.getTarget());
}
});
}
private TilePane createScrollableContent() {
TilePane tiles = new TilePane();
tiles.setPrefColumns(10);
tiles.setHgap(5);
tiles.setVgap(5);
for (int i = 0; i < 100; i++) {
Button button = new Button(i + "");
button.setMaxWidth(Double.MAX_VALUE);
button.setMaxHeight(Double.MAX_VALUE);
tiles.getChildren().add(button);
}
return tiles;
}
private void hackToScrollToTopLeftCorner(final ScrollPane scrollPane) {
Platform.runLater(new Runnable() {
#Override
public void run() {
scrollPane.setHvalue(scrollPane.getHmin());
scrollPane.setVvalue(0);
}
});
}
public static void main(String[] args) {
launch(args);
}
}

How to make an overlay on top of JavaFX 2 webview?

Is it possible to to overlay any JavaFx2 widgets or canvas on top of a JavaFX 2 webview?
I want to generate a transparent heatmap by means of JavaFX 2 on top of a webview.
Adding overlay is very easy: just put webview and any pane to StackPane.
Another story is to synchronize overlay and webview data. To achieve that you need to ask webview for object coordinates through javascript. Here is an example which finds stackoverflow question area and marks it on overlay:
public class WebOverlay extends Application {
#Override
public void start(Stage stage) {
StackPane root = new StackPane();
WebView webView = new WebView();
final WebEngine webEngine = webView.getEngine();
Canvas overlay = new Canvas(600,600);
overlay.setOpacity(0.5);
final GraphicsContext gc = overlay.getGraphicsContext2D();
gc.setFill(Color.RED);
root.getChildren().addAll(webView, overlay);
stage.setScene(new Scene(root, 600, 600));
webEngine.getLoadWorker().workDoneProperty().addListener((observable, oldValue, newValue) -> {
if (newValue.intValue() == 100) {
// find coordinates by javascript call
JSObject bounds = (JSObject)webEngine.executeScript("document.getElementsByClassName('question-hyperlink')[0].getBoundingClientRect()");
Number right = (Number)bounds.getMember("right");
Number top = (Number)bounds.getMember("top");
Number bottom = (Number)bounds.getMember("bottom");
Number left = (Number)bounds.getMember("left");
// paint on overlaing canvas
gc.rect(left.doubleValue(), top.doubleValue(), right.doubleValue(), bottom.doubleValue());
gc.fill();
}
});
webEngine.load("http://stackoverflow.com/questions/10894903/how-to-make-an-overlay-on-top-of-javafx-2-webview");
stage.show();
}
public static void main(String[] args) { launch(); }
}
Do you mean something like this:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.RectangleBuilder;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.scene.text.TextBuilder;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
public class Demo extends Application {
#Override
public void start(Stage primaryStage) {
WebView webView = new WebView();
webView.getEngine().load("http://www.google.com");
StackPane root = new StackPane();
root.getChildren().addAll(webView, getOverlay());
primaryStage.setScene(new Scene(root, 300, 250));
primaryStage.show();
}
private Pane getOverlay() {
StackPane p = new StackPane();
Rectangle r = RectangleBuilder.create()
.height(100).width(100)
.arcHeight(40).arcWidth(40)
.stroke(Color.RED)
.fill(Color.web("red", 0.1))
.build();
Text txt=TextBuilder.create().text("Overlay")
.font(Font.font("Arial", FontWeight.BOLD, 18))
.fill(Color.BLUE)
.build();
p.getChildren().addAll(r, txt);
return p;
}
public static void main(String[] args) {
launch(args);
}
}

BlackBerry - Get current Process ID

I read Blackberry - How to get the background application process id but I'm not sure I understand it correctly. The following code gets the foreground process id;
ApplicationManager.getApplicationManager().getForegroundProcessId()
I have two processes which execute the same piece of code to make a connection, I want to log the process which made the calls along with all my usual logging data to get a better idea of how the flow is working.
Is it possible to get the id for the process which is currently running the code? One process is in the foreground (UI process) and the other is in the background but both use the same connection library shared via the runtime store.
Thanks in advance!
Gav
So you have three modules: application, library and service.
You need to get descriptor by module name, and then get process id.
UPDATE1
String moduleName = "application";
int handle = CodeModuleManager.getModuleHandle(moduleName);
ApplicationDescriptor[] descriptors = CodeModuleManager
.getApplicationDescriptors(handle);
if (descriptors.length > 0 && descriptors[0] != null) {
ApplicationManager.getApplicationManager().getProcessId(descriptors[0]);
}
Then, to log which module uses library, use
Application.getApplication().getProcessId();
inside library methods. I think its better to implement logging inside library.
When you got process id of application from library code, you can compare it with id's found by module name and then you will know what module uses library code.
UPDATE2
alt text http://img138.imageshack.us/img138/23/eventlog.jpg
library module code:
package library;
import net.rim.device.api.system.Application;
import net.rim.device.api.system.ApplicationDescriptor;
import net.rim.device.api.system.ApplicationManager;
import net.rim.device.api.system.CodeModuleManager;
import net.rim.device.api.system.EventLogger;
public class Logger {
// "AppLibSrvc" converted to long
long guid = 0xd4b6b5eeea339daL;
public Logger() {
EventLogger.register(guid, "AppLibSrvc", EventLogger.VIEWER_STRING);
}
public void log(String message) {
EventLogger.logEvent(guid, message.getBytes());
}
public void call() {
log("Library is used by " + getModuleName());
}
private String getModuleName() {
String moduleName = "";
String appModuleName = "application";
int appProcessId = getProcessIdByName(appModuleName);
String srvcModuleName = "service";
int srvcProcessId = getProcessIdByName(srvcModuleName);
int processId = Application.getApplication().getProcessId();
if (appProcessId == processId)
moduleName = appModuleName;
else if (srvcProcessId == processId)
moduleName = srvcModuleName;
return moduleName;
}
protected int getProcessIdByName(String moduleName) {
int processId = -1;
int handle = CodeModuleManager.getModuleHandle(moduleName);
ApplicationDescriptor[] descriptors = CodeModuleManager
.getApplicationDescriptors(handle);
if (descriptors.length > 0 && descriptors[0] != null) {
processId = ApplicationManager.getApplicationManager()
.getProcessId(descriptors[0]);
}
return processId;
}
}
application module code:
package application;
import java.util.Timer;
import java.util.TimerTask;
import library.Logger;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.container.MainScreen;
public class App extends UiApplication {
public App() {
pushScreen(new Scr());
}
public static void main(String[] args) {
App app = new App();
app.enterEventDispatcher();
}
}
class Scr extends MainScreen {
public Scr() {
Timer timer = new Timer();
TimerTask task = new TimerTask() {
public void run() {
Logger logger = new Logger();
logger.call();
}
};
timer.schedule(task, 3000, 3000);
}
}
service module code:
package service;
import java.util.Timer;
import java.util.TimerTask;
import library.Logger;
import net.rim.device.api.system.Application;
public class App extends Application {
public App() {
Timer timer = new Timer();
TimerTask task = new TimerTask() {
public void run() {
Logger logger = new Logger();
logger.call();
}
};
timer.schedule(task, 3000, 3000);
}
public static void main(String[] args) {
App app = new App();
app.enterEventDispatcher();
}
}

Resources