PostSaveDocument call agent asynchronously - xpages

I have an Xpage page with a single Notes document datasource.
After saving a document I want to (conditionally) trigger an agent. The agent takes some time to process and we don't want the user to have to wait for the result, so it should be executed asynchronously.
I've managed to get it working from client side JS by using an XHR to the agent URL, but I would like to do it server side so I can control the "Next page" better. When using .run() or .runonserver() the client waits till the agent completes.
Any idea how I could trigger an agent (from SSJS) on PostSaveDocument without the client waiting for the result?

Try to look at Thread and Jobs application on OpenNTF.org. There are nice demos of running task in background, check it here

As Martin suggested I used the JobScheduler example on OpenNtf and modified it to suit my needs. Resulting code can be found below. Any comments or improvements are welcome.
import java.security.AccessController;
import java.security.PrivilegedAction;
import lotus.domino.Agent;
import lotus.domino.Database;
import lotus.domino.NotesException;
import lotus.domino.Session;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import com.ibm.domino.xsp.module.nsf.ThreadSessionExecutor;
public class JobRunner {
public static void start(String dbPath, String agentName, String paramDocId) {
synchronized (JobRunner.class) {
runningJob = new ISPJob(dbPath, agentName, paramDocId);
runningJob.addJobChangeListener(new JobChangeAdapter() {
public void done(IJobChangeEvent event) {
System.out.println("Done event");
runningJob = null;
}
});
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
runningJob.schedule();
return null;
}
});
}
}
private static ISPJob runningJob;
private static final class ISPJob extends Job {
private ThreadSessionExecutor<IStatus> executor;
private String docId;
private String dbPath;
private String agentName;
public ISPJob(String paramDbPath, String paramAgentName, String paramDocId) {
super(paramDocId);
this.docId = paramDocId;
this.dbPath = paramDbPath;
this.agentName = paramAgentName;
this.executor = new ThreadSessionExecutor<IStatus>() {
#Override
protected IStatus run(Session session) throws NotesException {
System.out.println("Job started" + docId);
System.out.println(" >> Session created: "
+ session.getUserName() + ", Effective User:"
+ session.getEffectiveUserName());
Database db = session.getDatabase(null,dbPath);
if (db != null) {
try {
if (!db.isOpen()) db.open();
if (db.isOpen()) {
System.out.println(" >> Database opened: "
+ db.getTitle());
Agent agent = db.getAgent(agentName);
try {
System.out.println(" >> Agent Started: " + agent.getName());
agent.run(docId);
System.out.println(" >> Agent Ran: " + agent.getName());
} finally {
agent.recycle();
}
}
} finally {
db.recycle();
}
}
System.out.println("Job completed");
return Status.OK_STATUS;
}
};
}
protected IStatus run(IProgressMonitor monitor) {
try {
return executor.run();
} catch (Exception ex) {
return Status.CANCEL_STATUS;
}
}
};
}

You could use a session bean (so it won't get destroyed) that kicks off an Java thread. Or you could issue in code a server console command. Or you implement a DOTS listener.

This may/may not be an option depending on your application requirements but I am having good success calling function in the onClientLoad event which essentially kicks off the process after the XPage has fully loaded.

Related

TextArea is not updating while zip extraction

I am working on a JavaFx application, there i have a script that extract a zip followed by some other operation like updating files etc.
I want to have a textArea that displays whats going on in background, like "Zip extracting...", "Updating xyz file" etc.
Till now i have tried following way:
MyTask<String> task;
task = new MyTask<String>() {
#Override
protected String call() throws Exception {
File path = new File(exportTo.getAbsolutePath());
updateMessage("Extracting modular app to target directory...");
patcher.unZip(appPath.getAbsolutePath(), path.getAbsolutePath());
if (path.exists()) {
AppInfo info = getAppInfo();
patcher.patchAndroid(info, resourceZip, new File(path.getAbsolutePath() + "/" + appPath.getName().substring(0, appPath.getName().lastIndexOf("."))), this);
showOkAlert("Build completed!");
} else {
showOkAlert("Modular app folder not found");
}
return "";
}
#Override
protected void updateProgress(double workDone, double max) {
patcher.reportLogs(message);
}
private String message;
#Override
public void updateMessage(final String message) {
Platform.runLater(() -> patcher.reportLogs(message));
this.message = message;
//updateProgress(0, 0);
}
};
task.run();
MyTask class
abstract class MyTask<T> extends Task<T> {
abstract public void updateMessage(String message);
}
I have tried using updateProgress method, Platform.runLater() but nothing is working.
All the message i printed in textArea are printed after all operation is done.
Please help.
As javadoc for Task states you need to manually create a Thread to execute your Task:
Thread th = new Thread(task);
th.start();
Currently your task is being run on Application UI thread and blocks UI updates.

Commons Configuration2 ReloadingFileBasedConfiguration

I am trying to implement the Apache Configuration 2 in my codebase
import java.io.File;
import java.util.concurrent.TimeUnit;
import org.apache.commons.configuration2.PropertiesConfiguration;
import org.apache.commons.configuration2.builder.ConfigurationBuilderEvent;
import org.apache.commons.configuration2.builder.ReloadingFileBasedConfigurationBuilder;
import org.apache.commons.configuration2.builder.fluent.Parameters;
import org.apache.commons.configuration2.convert.DefaultListDelimiterHandler;
import org.apache.commons.configuration2.event.EventListener;
import org.apache.commons.configuration2.ex.ConfigurationException;
import org.apache.commons.configuration2.reloading.PeriodicReloadingTrigger;
import org.apache.commons.configuration2.CompositeConfiguration;
public class Test {
private static final long DELAY_MILLIS = 10 * 60 * 5;
public static void main(String[] args) {
// TODO Auto-generated method stub
CompositeConfiguration compositeConfiguration = new CompositeConfiguration();
PropertiesConfiguration props = null;
try {
props = initPropertiesConfiguration(new File("/tmp/DEV.properties"));
} catch (ConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
compositeConfiguration.addConfiguration( props );
compositeConfiguration.addEventListener(ConfigurationBuilderEvent.ANY,
new EventListener<ConfigurationBuilderEvent>()
{
#Override
public void onEvent(ConfigurationBuilderEvent event)
{
System.out.println("Event:" + event);
}
});
System.out.println(compositeConfiguration.getString("property1"));
try {
Thread.sleep(14*1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Have a script which changes the value of property1 in DEV.properties
System.out.println(compositeConfiguration.getString("property1"));
}
protected static PropertiesConfiguration initPropertiesConfiguration(File propsFile) throws ConfigurationException {
if(propsFile.exists()) {
final ReloadingFileBasedConfigurationBuilder<PropertiesConfiguration> builder =
new ReloadingFileBasedConfigurationBuilder<PropertiesConfiguration>(PropertiesConfiguration.class)
.configure(new Parameters().fileBased()
.setFile(propsFile)
.setReloadingRefreshDelay(DELAY_MILLIS)
.setThrowExceptionOnMissing(false)
.setListDelimiterHandler(new DefaultListDelimiterHandler(';')));
final PropertiesConfiguration propsConfiguration = builder.getConfiguration();
PeriodicReloadingTrigger trigger = new PeriodicReloadingTrigger(builder.getReloadingController(),
null, 1, TimeUnit.SECONDS);
trigger.start();
return propsConfiguration;
} else {
return new PropertiesConfiguration();
}
}
}
Here is a sample code that I using to check whether the Automatic Reloading works or not. However when the underlying property file is updated, the configuration doesn't reflect it.
As per the documentation :
One important point to keep in mind when using this approach to reloading is that reloads are only functional if the builder is used as central component for accessing configuration data. The configuration instance obtained from the builder will not change automagically! So if an application fetches a configuration object from the builder at startup and then uses it throughout its life time, changes on the external configuration file become never visible. The correct approach is to keep a reference to the builder centrally and obtain the configuration from there every time configuration data is needed.
https://commons.apache.org/proper/commons-configuration/userguide/howto_reloading.html#Reloading_File-based_Configurations
This is different from what the old implementation was.
I was able to successfully execute your sample code by making 2 changes :
make the builder available globally and access the configuration from the builder :
System.out.println(builder.getConfiguration().getString("property1"));
add the listener to the builder :
`builder.addEventListener(ConfigurationBuilderEvent.ANY, new EventListener() {
public void onEvent(ConfigurationBuilderEvent event) {
System.out.println("Event:" + event);
}
});
Posting my sample program, where I was able to successfully demonstrate it
import java.io.File;
import java.util.concurrent.TimeUnit;
import org.apache.commons.configuration2.PropertiesConfiguration;
import org.apache.commons.configuration2.builder.ConfigurationBuilderEvent;
import org.apache.commons.configuration2.builder.ReloadingFileBasedConfigurationBuilder;
import org.apache.commons.configuration2.builder.fluent.Parameters;
import org.apache.commons.configuration2.event.EventListener;
import org.apache.commons.configuration2.reloading.PeriodicReloadingTrigger;
public class TestDynamicProps {
public static void main(String[] args) throws Exception {
Parameters params = new Parameters();
ReloadingFileBasedConfigurationBuilder<PropertiesConfiguration> builder =
new ReloadingFileBasedConfigurationBuilder<PropertiesConfiguration>(PropertiesConfiguration.class)
.configure(params.fileBased()
.setFile(new File("src/main/resources/override.properties")));
PeriodicReloadingTrigger trigger = new PeriodicReloadingTrigger(builder.getReloadingController(),
null, 1, TimeUnit.SECONDS);
trigger.start();
builder.addEventListener(ConfigurationBuilderEvent.ANY, new EventListener<ConfigurationBuilderEvent>() {
public void onEvent(ConfigurationBuilderEvent event) {
System.out.println("Event:" + event);
}
});
while (true) {
Thread.sleep(1000);
System.out.println(builder.getConfiguration().getString("property1"));
}
}
}
The problem with your implementation is, that the reloading is done on the ReloadingFileBasedConfigurationBuilder Object and is not being returned to the PropertiesConfiguration Object.

Philips Hue Bridge cannot connect to server desktop application

I am trying to connect my Desktop to the PHILIPS Hue light server using java.
When the code runs, it will flow into the Controller.java. When that happens, the FindBridges method in Controller.java runs. This is where the error occurs. In debugging, it displays a NullPointerException in thread "AWT-Event-Queue-0".
I presume that the server/lightbulb cannot be found at all, even though it is turned on and my android application can connect to it.
The error is stated below:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at com.philips.lighting.gui.DesktopView$1.actionPerformed(DesktopView.java:72)
Controller.java
package com.philips.lighting;
import java.util.List;
import java.util.Random;
import javax.swing.JDialog;
import com.philips.lighting.hue.sdk.upnp.*;
import com.philips.lighting.data.HueProperties;
import com.philips.lighting.gui.AccessPointList;
import com.philips.lighting.gui.DesktopView;
import com.philips.lighting.gui.LightColoursFrame;
import com.philips.lighting.gui.PushLinkFrame;
import com.philips.lighting.hue.sdk.PHAccessPoint;
import com.philips.lighting.hue.sdk.PHBridgeSearchManager;
import com.philips.lighting.hue.sdk.PHHueSDK;
import com.philips.lighting.hue.sdk.PHMessageType;
import com.philips.lighting.hue.sdk.PHSDKListener;
import com.philips.lighting.model.PHBridge;
import com.philips.lighting.model.PHBridgeResourcesCache;
import com.philips.lighting.model.PHHueError;
import com.philips.lighting.model.PHHueParsingError;
import com.philips.lighting.model.PHLight;
import com.philips.lighting.model.PHLightState;
public class Controller {
private PHHueSDK phHueSDK;
private DesktopView desktopView;
private PushLinkFrame pushLinkDialog;
private LightColoursFrame lightColoursFrame;
private static final int MAX_HUE=65535;
private Controller instance;
public Controller(DesktopView view) {
this.desktopView = view;
this.phHueSDK = PHHueSDK.getInstance(); // or phHueSDK = PHHueSDK.getInstance();
this.instance = this;
}
public void findBridges() {
//To uniquely identify your app in the bridge whitelist we recommend you set your app name, and the device
phHueSDK.setAppName("SmartShowroomApp"); // e.g. phHueSDK.setAppName("QuickStartApp");
phHueSDK.setDeviceName("SmartDevice"); // e.g. If you are programming for Android: phHueSDK.setDeviceName(android.os.Build.MODEL);
phHueSDK = PHHueSDK.getInstance();
PHBridgeSearchManager sm = (PHBridgeSearchManager) phHueSDK.getSDKService(PHHueSDK.SEARCH_BRIDGE);
sm.search(true, true);
//This starts a UPNP/Portal Search and takes around 10 seconds.
//The PHSDKListener (onAccessPointsFound) will be notified with the bridges found.
}
private PHSDKListener listener = new PHSDKListener() {
#Override
public void onAccessPointsFound(List<PHAccessPoint> accessPointsList) {
// Handle your bridge search results here.
//Typically if multiple results are returned you will want to display them in a list
// and let the user select their bridge.
//If one is found you may opt to connect automatically to that bridge.
phHueSDK = PHHueSDK.getInstance();
desktopView.getFindingBridgeProgressBar().setVisible(false);
if (accessPointsList != null && accessPointsList.size() > 0)
{
AccessPointList accessPointList = new AccessPointList(accessPointsList, instance);
accessPointList.setVisible(true);
accessPointList.setLocationRelativeTo(null); // Centre the AccessPointList Frame
phHueSDK.getAccessPointsFound().clear(); // Clear all connected access points
phHueSDK.getAccessPointsFound().addAll(accessPointsList); // Adds multiple results to the list
}
else
{
PHBridgeSearchManager sm = (PHBridgeSearchManager) phHueSDK.getSDKService(PHHueSDK.SEARCH_BRIDGE);
sm.search(false, false, true);
}
}
#Override
public void onAuthenticationRequired(PHAccessPoint accessPoint) {
// Start the Pushlink Authentication.
phHueSDK = PHHueSDK.getInstance();
desktopView.getFindingBridgeProgressBar().setVisible(false);
phHueSDK.startPushlinkAuthentication(accessPoint);
// Arriving here indicates that Pushlinking is required (to prove the User has physical access to the bridge).
//Typically here you will display a pushlink image (with a timer) indicating to to the user they need to push the button on their bridge within 30 seconds.
pushLinkDialog = new PushLinkFrame(instance);
pushLinkDialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
pushLinkDialog.setModal(true);
pushLinkDialog.setLocationRelativeTo(null); // Center the dialog.
pushLinkDialog.setVisible(true);
}
#Override
public void onBridgeConnected(PHBridge bridge) {
phHueSDK = PHHueSDK.getInstance();
phHueSDK.setSelectedBridge(bridge);
phHueSDK.enableHeartbeat(bridge, PHHueSDK.HB_INTERVAL);
// Here it is recommended to set your connected bridge in your sdk object (as above) and start the heartbeat.
// At this point you are connected to a bridge so you should pass control to your main program/activity.
// Also it is recommended you store the connected IP Address/ Username in your app here.
//This will allow easy automatic connection on subsequent use.
// Remember to disable the heartbeat when exiting your app
//phHueSDK.disableAllHeartbeat();
//If you are only interested in a particular resource (e.g. Lights), you can enable the multi resource heartbeat as follows:
//PHHeartbeatManager heartbeatManager = PHHeartbeatManager.getInstance();
//heartbeatManager.enableLightsHeartbeat(bridge, PHHueSDK.HB_INTERVAL);
// To stop the heartbeat you can use either of the below
//heartbeatManager.disableLightsHeartbeat(bridge);
//heartbeatManager.disableAllHeartbeats(bridge);
desktopView.getFindingBridgeProgressBar().setVisible(false);
String username = HueProperties.getUsername();
String lastIpAddress = bridge.getResourceCache().getBridgeConfiguration().getIpAddress();
System.out.println("On connected: IP " + lastIpAddress);
HueProperties.storeUsername(username);
HueProperties.storeLastIPAddress(lastIpAddress);
HueProperties.saveProperties();
// Update the GUI.
desktopView.getLastConnectedIP().setText(lastIpAddress);
desktopView.getLastUserName().setText(username);
// Close the PushLink dialog (if it is showing).
if (pushLinkDialog!=null && pushLinkDialog.isShowing()) {
pushLinkDialog.setVisible(false);
}
// Enable the Buttons/Controls to change the hue bulbs.s
desktopView.getRandomLightsButton().setEnabled(true);
desktopView.getSetLightsButton().setEnabled(true);
}
#Override
public void onCacheUpdated(List cacheNotificationsList, PHBridge bridge) {
// Here you receive notifications that the BridgeResource Cache was updated. Use the PHMessageType to
// check which cache was updated, e.g.
if (cacheNotificationsList.contains(PHMessageType.LIGHTS_CACHE_UPDATED)) {
System.out.println("Lights Cache Updated ");
}
}
#Override
public void onConnectionLost(PHAccessPoint accessPoint) {
// Here you would handle the loss of connection to your bridge.
phHueSDK = PHHueSDK.getInstance();
if (accessPoint == null)
{
System.out.println("Please reconnect to your bridge.");
}
}
#Override
public void onConnectionResumed(PHBridge bridge) {
PHHueSDK phHueSDK = PHHueSDK.getInstance();
for (int i = 0; i < phHueSDK.getDisconnectedAccessPoint().size(); i++)
{
if (phHueSDK.getDisconnectedAccessPoint().get(i).getIpAddress()
.equals(bridge.getResourceCache().getBridgeConfiguration().getIpAddress())) {
phHueSDK.getDisconnectedAccessPoint().remove(i);
}
}
}
#Override
public void onError(int code, final String message) {
// Here you can handle events such as Bridge Not Responding, Authentication Failed and Bridge Not Found.
if (code == PHHueError.BRIDGE_NOT_RESPONDING) {
desktopView.getFindingBridgeProgressBar().setVisible(false);
desktopView.getFindBridgesButton().setEnabled(true);
desktopView.getConnectToLastBridgeButton().setEnabled(true);
desktopView.showDialog(message);
}
else if (code == PHMessageType.PUSHLINK_BUTTON_NOT_PRESSED) {
pushLinkDialog.incrementProgress();
}
else if (code == PHMessageType.PUSHLINK_AUTHENTICATION_FAILED) {
if (pushLinkDialog.isShowing()) {
pushLinkDialog.setVisible(false);
desktopView.showDialog(message);
}
else {
desktopView.showDialog(message);
}
desktopView.getFindBridgesButton().setEnabled(true);
}
else if (code == PHMessageType.BRIDGE_NOT_FOUND) {
desktopView.getFindingBridgeProgressBar().setVisible(false);
desktopView.getFindBridgesButton().setEnabled(true);
desktopView.showDialog(message);
}
}
#Override
public void onParsingErrors(List<PHHueParsingError> parsingErrorsList) {
// Any JSON parsing errors are returned here.
//Typically your program should never return these.
for (PHHueParsingError parsingError: parsingErrorsList) {
System.out.println("ParsingError : " + parsingError.getMessage());
}
}
};
public PHSDKListener getListener() {
return listener;
}
public void setListener(PHSDKListener listener) {
this.listener = listener;
}
public void randomLights() {
PHBridge bridge = phHueSDK.getSelectedBridge();
PHBridgeResourcesCache cache = bridge.getResourceCache();
// And now you can get any resource you want, for example:
List<PHLight> allLights = cache.getAllLights();
Random rand = new Random();
for (PHLight light : allLights) {
PHLightState lightState = new PHLightState();
lightState.setHue(rand.nextInt(MAX_HUE));
bridge.updateLightState(light, lightState); // If no bridge response is required then use this simpler form.
}
}
public void showControlLightsWindow() {
if (lightColoursFrame == null) {
lightColoursFrame = new LightColoursFrame();
}
lightColoursFrame.setLocationRelativeTo(null); // Centre window
lightColoursFrame.setVisible(true);
}
/**
* Connect to the last known access point.
* This method is triggered by the Connect to Bridge button but it can equally be used to automatically connect to a bridge.
*
*/
public boolean connectToLastKnownAccessPoint() {
String username = HueProperties.getUsername();
String lastIpAddress = HueProperties.getLastConnectedIP();
if (username==null || lastIpAddress == null) {
desktopView.showDialog("Missing Last Username or Last IP. Last known connection not found.");
return false;
}
//Obviously, every time a user opens up their Android hue app or application you don't want them to have to select their bridge, authenticate pushlink everytime.
//The recommended way to overcome this issue is to store the connected IP Address/Username (using your preferred method storage) and if set try to connect automatically.
PHAccessPoint accessPoint = new PHAccessPoint();
accessPoint.setIpAddress(lastIpAddress);
accessPoint.setUsername(username);
phHueSDK.connect(accessPoint);
return true;
//Note that the .connect method returns control to your PHSDKListener, so when connected the onBridgeConnected will be called again, and if your users Bridge IP has changed for example, onError will be called and can be handled programatically.
}
public void enableFindBridgesButton() {
desktopView.getFindBridgesButton().setEnabled(true);
}
public void showProgressBar() {
desktopView.getFindingBridgeProgressBar().setVisible(true);
}
}
DesktopView.java
package com.philips.lighting.gui;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JTextField;
import layout.TableLayout;
import com.philips.lighting.Controller;
import com.philips.lighting.data.HueProperties;
/**
* DesktopView.java
*
* The main GUI showing last connected IP/Username and buttons for Finding Bridges and Changing the Hue Lights, once connected to a bridge.
*
*/
public class DesktopView extends JFrame {
private static final long serialVersionUID = -7469471678945429320L;
private Controller controller;
private JButton setLightsButton;
private JButton randomLightsButton;
private JButton findBridgesButton;
private JButton connectToLastBridgeButton;
private JProgressBar findingBridgeProgressBar;
private JTextField lastConnectedIP;
private JTextField lastUserName;
public DesktopView(){
setTitle("Hue Desktop");
JPanel mainPanel = new JPanel();
// TODO - Move to another class
JPanel controls = new JPanel();
controls.setLayout(new GridLayout(2,3));
findingBridgeProgressBar = new JProgressBar();
findingBridgeProgressBar.setBorderPainted(false);
findingBridgeProgressBar.setIndeterminate(true);
findingBridgeProgressBar.setVisible(false);
//Set up components preferred size
String lastUsername = HueProperties.getUsername();
String lastConnectedIPStr = HueProperties.getLastConnectedIP();
JLabel labelLastConIP = new JLabel("Last Connected IP:");
lastConnectedIP = new JTextField(lastConnectedIPStr);
lastConnectedIP.setEditable(false);
JLabel labelLastUsername = new JLabel("Last UserName:");
lastUserName = new JTextField(lastUsername);
lastUserName.setEditable(false);
findBridgesButton = new JButton("Find New Bridges");
findBridgesButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
findBridgesButton.setEnabled(false);
connectToLastBridgeButton.setEnabled(false);
controller.findBridges();
findingBridgeProgressBar.setBorderPainted(true);
findingBridgeProgressBar.setVisible(true);
}
});
connectToLastBridgeButton = new JButton("Auto Connect");
connectToLastBridgeButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
if (controller.connectToLastKnownAccessPoint()) {
connectToLastBridgeButton.setEnabled(false);
findBridgesButton.setEnabled(false);
findingBridgeProgressBar.setBorderPainted(true);
findingBridgeProgressBar.setVisible(true);
}
}
});
setLightsButton = new JButton("Change Light Colours");
setLightsButton.setEnabled(false);
setLightsButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
controller.showControlLightsWindow();
}
});
randomLightsButton = new JButton("Randomize Lights");
randomLightsButton.setEnabled(false);
randomLightsButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
controller.randomLights();
}
});
double border = 10;
double size[][] =
{{border, 160, 20, 300, 20, 160}, // Columns
{border, 26, 10, 26, 26, 26,6,26}}; // Rows
mainPanel.setLayout (new TableLayout(size));
mainPanel.add(labelLastConIP, " 1, 1");
mainPanel.add(lastConnectedIP, " 3, 1");
mainPanel.add(labelLastUsername, " 1, 3");
mainPanel.add(lastUserName, " 3, 3");
mainPanel.add(findingBridgeProgressBar, " 3, 5");
mainPanel.add(connectToLastBridgeButton, " 5, 1");
mainPanel.add(findBridgesButton, " 5, 3");
mainPanel.add(randomLightsButton, " 5, 5");
mainPanel.add(setLightsButton, " 5, 7");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setPreferredSize(new Dimension(700,270));
getContentPane().add(new JLabel(" An example Java/Swing Desktop Application to control your Hue Lights."), BorderLayout.NORTH);
getContentPane().add(mainPanel, BorderLayout.CENTER);
//4. Size the frame.
pack();
setLocationRelativeTo(null); // Centre the window.
setVisible(true);
}
public void setController(Controller controller) {
this.controller = controller;
}
public JButton getSetLightsButton() {
return setLightsButton;
}
public JButton getRandomLightsButton() {
return randomLightsButton;
}
public JButton getFindBridgesButton() {
return findBridgesButton;
}
public JButton getConnectToLastBridgeButton() {
return connectToLastBridgeButton;
}
public void showDialog(String message) {
JOptionPane.showMessageDialog(this, message);
}
public JProgressBar getFindingBridgeProgressBar() {
return findingBridgeProgressBar;
}
public JTextField getLastConnectedIP() {
return lastConnectedIP;
}
public JTextField getLastUserName() {
return lastUserName;
}
}
HueDesktop.java
package com.philips.lighting;
import com.philips.lighting.data.HueProperties;
import com.philips.lighting.gui.DesktopView;
import com.philips.lighting.hue.sdk.PHHueSDK;
/**
* HueDesktop.java
* An example Java/Swing Desktop application illustrating how to connect to a bridge and change your Hue lights
* using a Java Desktop Application.
*
* For more information on programming for Hue see:
* http://developers.meethue.com
*
*/
class HueDesktop {
public static void main(String args[]) {
new HueDesktop();
}
public HueDesktop() {
PHHueSDK phHueSDK = PHHueSDK.create();
// Load in HueProperties, if first time use a properties file is created.
HueProperties.loadProperties();
// Set Up the View (A JFrame, MenuBar and Console).
DesktopView desktopView = new DesktopView();
// Bind the Model and View
Controller controller = new Controller(desktopView);
desktopView.setController(controller);
// Register the PHSDKListener to receive callbacks from the bridge.
phHueSDK.getNotificationManager().registerSDKListener(controller.getListener());
}
}
Did you ever solve this? In future it is probably best to post hue Java SDK issues on the GitHub site. https://github.com/PhilipsHue/PhilipsHueSDK-Java-MultiPlatform-Android/issues
I would have seen this sooner on here (I wrote this code btw so am possibly the culprit).
I do remember seeing a similar issue before, am pretty sure it was related to Macs and the JDK Compiler level used (I possibly used an incompatible Swing component on Mac and JDK 1.6). Can you let me know your OS and JDK Compiler level and I will check this further?

Call agent asynchronously Xpages

I get this code to Thread and Jobs application on OpenNTF.org
import lotus.domino.NotesException;
import lotus.domino.Session;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import com.ibm.domino.xsp.module.nsf.ThreadSessionExecutor;
public class JobRunner {
public static void start(String dbPath, String agentName, String paramDocId) {
synchronized (JobRunner.class) {
runningJob = new ISPJob(dbPath, agentName, paramDocId);
runningJob.addJobChangeListener(new JobChangeAdapter() {
public void done(IJobChangeEvent event) {
System.out.println("Done event");
runningJob = null;
}
});
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
runningJob.schedule();
return null;
}
});
}
}
private static ISPJob runningJob;
private static final class ISPJob extends Job {
private ThreadSessionExecutor<IStatus> executor;
private String docId;
private String dbPath;
private String agentName;
public ISPJob(String paramDbPath, String paramAgentName, String paramDocId) {
super(paramDocId);
this.docId = paramDocId;
this.dbPath = paramDbPath;
this.agentName = paramAgentName;
this.executor = new ThreadSessionExecutor<IStatus>() {
#Override
protected IStatus run(Session session) throws NotesException {
System.out.println("Job started" + docId);
System.out.println(" >> Session created: "
+ session.getUserName() + ", Effective User:"
+ session.getEffectiveUserName());
Database db = session.getDatabase(null,dbPath);
if (db != null) {
try {
if (!db.isOpen()) db.open();
if (db.isOpen()) {
System.out.println(" >> Database opened: "
+ db.getTitle());
Agent agent = db.getAgent(agentName);
try {
System.out.println(" >> Agent Started: " + agent.getName());
agent.run(docId);
System.out.println(" >> Agent Ran: " + agent.getName());
} finally {
agent.recycle();
}
}
} finally {
db.recycle();
}
}
System.out.println("Job completed");
return Status.OK_STATUS;
}
};
}
protected IStatus run(IProgressMonitor monitor) {
try {
return executor.run();
} catch (Exception ex) {
return Status.CANCEL_STATUS;
}
}
};
}
I used the code (JobRunner class) in a onclick event on a button (SSJS)
<xp:button value="Label" id="button4">
<xp:eventHandler event="onclick" submit="true" refreshMode="partial" refreshId="button4">
<xp:this.action>
<![CDATA[#{javascript:myPck.JobRunner.start(database.getFilePath(),"(Export)",docTemp.getUniversalID())}]]>
</xp:this.action>
</xp:eventHandler>
</xp:button>
Returns me the following error
"Error 500 http web server command not handled exception"
What can be the problem?
If you are experiencing ClassNotFoundException for Eclipse runtime classes (in workspace/logs folder), it means that XPages prevent you to use those classes for security. Normally, granting all permissions using java.policy file should solve this problem.
However, I have experienced buggy and inconsistent behviour in ThreadSessionExecuter class for different Domino versions. I have also tested your code on 9.0.1 and had such an issue on my test server as well.
You might use an alternative approach. You might refer to my blog entry that contains links to the demo database and slide deck from ICONUK 2013.
http://lotusnotus.com/lotusnotus_en.nsf/dx/iconuk-2013-slidedeck-demo-application-and-a-surprize....htm
Also check XPages Toolkit project from OpenNTF. It provides a plugin framework for running background tasks.
Into my log i have an "ClassNotFoundException",
i have modify my file java.policy and restart the server but the error 500 continue
C:\Program Files\IBM\Lotus\Domino\jvm\lib\security
// Notes java code gets all permissions
grant codeBase "file:${notes.binary}/*" {
permission java.security.AllPermission;
};
grant codeBase "file:${notes.binary}/rjext/*" {
permission java.security.AllPermission;
};
grant codeBase "file:${notes.binary}/ndext/*" {
permission java.security.AllPermission;
};
grant codeBase "file:${notes.binary}/xsp/-" {
permission java.security.AllPermission;
};
grant codeBase "file:${notes.binary}/osgi/-" {
permission java.security.AllPermission;
};
// My new line
grant {
permission java.security.AllPermission;
};

Debugging Package Manager Console Update-Database Seed Method

I wanted to debug the Seed() method in my Entity Framework database configuration class when I run Update-Database from the Package Manager Console but didn't know how to do it. I wanted to share the solution with others in case they have the same issue.
Here is similar question with a solution that works really well.
It does NOT require Thread.Sleep.
Just Launches the debugger using this code.
Clipped from the answer
if (!System.Diagnostics.Debugger.IsAttached)
System.Diagnostics.Debugger.Launch();
The way I solved this was to open a new instance of Visual Studio and then open the same solution in this new instance of Visual Studio. I then attached the debugger in this new instance to the old instance (devenv.exe) while running the update-database command. This allowed me to debug the Seed method.
Just to make sure I didn't miss the breakpoint by not attaching in time I added a Thread.Sleep before the breakpoint.
I hope this helps someone.
If you need to get a specific variable's value, a quick hack is to throw an exception:
throw new Exception(variable);
A cleaner solution (I guess this requires EF 6) would IMHO be to call update-database from code:
var configuration = new DbMigrationsConfiguration<TContext>();
var databaseMigrator = new DbMigrator(configuration);
databaseMigrator.Update();
This allows you to debug the Seed method.
You may take this one step further and construct a unit test (or, more precisely, an integration test) that creates an empty test database, applies all EF migrations, runs the Seed method, and drops the test database again:
var configuration = new DbMigrationsConfiguration<TContext>();
Database.Delete("TestDatabaseNameOrConnectionString");
var databaseMigrator = new DbMigrator(configuration);
databaseMigrator.Update();
Database.Delete("TestDatabaseNameOrConnectionString");
But be careful not to run this against your development database!
I know this is an old question, but if all you want is messages, and you don't care to include references to WinForms in your project, I made some simple debug window where I can send Trace events.
For more serious and step-by-step debugging, I'll open another Visual Studio instance, but it's not necessary for simple stuff.
This is the whole code:
SeedApplicationContext.cs
using System;
using System.Data.Entity;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;
namespace Data.Persistence.Migrations.SeedDebug
{
public class SeedApplicationContext<T> : ApplicationContext
where T : DbContext
{
private class SeedTraceListener : TraceListener
{
private readonly SeedApplicationContext<T> _appContext;
public SeedTraceListener(SeedApplicationContext<T> appContext)
{
_appContext = appContext;
}
public override void Write(string message)
{
_appContext.WriteDebugText(message);
}
public override void WriteLine(string message)
{
_appContext.WriteDebugLine(message);
}
}
private Form _debugForm;
private TextBox _debugTextBox;
private TraceListener _traceListener;
private readonly Action<T> _seedAction;
private readonly T _dbcontext;
public Exception Exception { get; private set; }
public bool WaitBeforeExit { get; private set; }
public SeedApplicationContext(Action<T> seedAction, T dbcontext, bool waitBeforeExit = false)
{
_dbcontext = dbcontext;
_seedAction = seedAction;
WaitBeforeExit = waitBeforeExit;
_traceListener = new SeedTraceListener(this);
CreateDebugForm();
MainForm = _debugForm;
Trace.Listeners.Add(_traceListener);
}
private void CreateDebugForm()
{
var textbox = new TextBox {Multiline = true, Dock = DockStyle.Fill, ScrollBars = ScrollBars.Both, WordWrap = false};
var form = new Form {Font = new Font(#"Lucida Console", 8), Text = "Seed Trace"};
form.Controls.Add(tb);
form.Shown += OnFormShown;
_debugForm = form;
_debugTextBox = textbox;
}
private void OnFormShown(object sender, EventArgs eventArgs)
{
WriteDebugLine("Initializing seed...");
try
{
_seedAction(_dbcontext);
if(!WaitBeforeExit)
_debugForm.Close();
else
WriteDebugLine("Finished seed. Close this window to continue");
}
catch (Exception e)
{
Exception = e;
var einner = e;
while (einner != null)
{
WriteDebugLine(string.Format("[Exception {0}] {1}", einner.GetType(), einner.Message));
WriteDebugLine(einner.StackTrace);
einner = einner.InnerException;
if (einner != null)
WriteDebugLine("------- Inner Exception -------");
}
}
}
protected override void Dispose(bool disposing)
{
if (disposing && _traceListener != null)
{
Trace.Listeners.Remove(_traceListener);
_traceListener.Dispose();
_traceListener = null;
}
base.Dispose(disposing);
}
private void WriteDebugText(string message)
{
_debugTextBox.Text += message;
Application.DoEvents();
}
private void WriteDebugLine(string message)
{
WriteDebugText(message + Environment.NewLine);
}
}
}
And on your standard Configuration.cs
// ...
using System.Windows.Forms;
using Data.Persistence.Migrations.SeedDebug;
// ...
namespace Data.Persistence.Migrations
{
internal sealed class Configuration : DbMigrationsConfiguration<MyContext>
{
public Configuration()
{
// Migrations configuration here
}
protected override void Seed(MyContext context)
{
// Create our application context which will host our debug window and message loop
var appContext = new SeedApplicationContext<MyContext>(SeedInternal, context, false);
Application.Run(appContext);
var e = appContext.Exception;
Application.Exit();
// Rethrow the exception to the package manager console
if (e != null)
throw e;
}
// Our original Seed method, now with Trace support!
private void SeedInternal(MyContext context)
{
// ...
Trace.WriteLine("I'm seeding!")
// ...
}
}
}
Uh Debugging is one thing but don't forget to call:
context.Update()
Also don't wrap in try catch without a good inner exceptions spill to the console.
https://coderwall.com/p/fbcyaw/debug-into-entity-framework-code-first
with catch (DbEntityValidationException ex)
I have 2 workarounds (without Debugger.Launch() since it doesn't work for me):
To print message in Package Manager Console use exception:
throw new Exception("Your message");
Another way is to print message in file by creating a cmd process:
// Logs to file {solution folder}\seed.log data from Seed method (for DEBUG only)
private void Log(string msg)
{
string echoCmd = $"/C echo {DateTime.Now} - {msg} >> seed.log";
System.Diagnostics.Process.Start("cmd.exe", echoCmd);
}

Resources