JavaFX webview: How to forward System.out and System.err to the Firebug Lite console? - javafx-webengine

I've found several examples on how to pipe and redirect messages from System.out and System.err.
Having decided to develop an application using the JavaFX Webview and Dukescript, I've found useful having one place where to display all messages, i.e. the Firebug Lite console.
See below.
PS This is the exact opposite as this

First define an abstract class
public abstract class FirebugConsole extends OutputStream {
abstract void log( String msg );
StringBuilder sb = new StringBuilder();
#Override
public void write(int i) {
sb.append((char)i);
}
#Override
public void flush() {
if( sb.length() >0 && !sb.toString().equals("\r\n"))
log(sb.toString());
sb = new StringBuilder();
}
}
Then extend it with methods that implement native calls into JavaScript. Here's for example how to write log messages
public class FirebugConsoleInfo extends FirebugConsole{
#net.java.html.js.JavaScriptBody(args = { "msg" }, body = ""
+ "Firebug.Console.log(msg);")
public native void log( String msg );
}
Finally, pipe System.out and System.err to those objects
public static void onPageLoad() throws Exception {
...
System.setOut(new PrintStream(new FirebugConsoleInfo(), true));
System.setErr(new PrintStream(new FirebugConsoleError(), true));
...
}
Note: for some reasons the usual console.log() doesn't work for me, I know Firebug doesn't bind a console if a console object is already present, so I suspect the WebFX webview must itself pipe console.log messages to System.out in the first place.
Update
The solution above doesn't work when the messages are generated by a thread other than the browser's. Here's an updated solution based on BrwsrCtx.execute()
public abstract static class FirebugConsole extends OutputStream {
protected final BrwsrCtx ctx;
public FirebugConsole( BrwsrCtx ctx ){
this.ctx = ctx;
}
abstract void logNative( String msg );
void log(String msg) {
ctx.execute(new Runnable(){
#Override
public void run() {
logNative(msg);
}
});
}
StringBuilder sb = new StringBuilder();
#Override
public void write(int i) {
sb.append((char)i);
}
#Override
public void flush() {
if( sb.length() >0 && !sb.toString().equals("\r\n"))
log(sb.toString());
sb = new StringBuilder();
}
}
public static class FirebugConsoleInfo extends FirebugConsole{
public FirebugConsoleInfo(BrwsrCtx ctx) {
super(ctx);
}
#net.java.html.js.JavaScriptBody(args = { "msg" }, body = ""
+ "Firebug.Console.log(msg);")
public native void logNative( String msg );
}
public static class FirebugConsoleError extends FirebugConsole{
public FirebugConsoleError(BrwsrCtx ctx) {
super(ctx);
}
#net.java.html.js.JavaScriptBody(args = { "msg" }, body = ""
+ "Firebug.Console.error(msg);")
public native void logNative( String msg );
}
}
and
public static void onPageLoad() throws Exception {
BrwsrCtx ctx = BrwsrCtx.findDefault(GoGPS_Fx.class);
System.setOut(new PrintStream(new FirebugConsoleInfo(ctx), true));
System.setErr(new PrintStream(new FirebugConsoleError(ctx), true));
}
Note: it's quite slow for large logs, there might be faster alternatives (StringWriter is one). But I suspect the bottleneck is the passing of messages back and forth from Java to JavaScript.

Related

getting error on createObject

i am getting
StartSensor Attempt to invoke virtual method 'void io.realm.ProxyState.setConstructionFinished()' on a null object reference
i try to create a new object with primarykey inside application class.
primarykeyFactory works it set the new key to "1" the database is empty at this moment.
public class SensorRecord extends MainApplication {
private final static String TAG = SensorRecord.class.getSimpleName();
private Realm mRealm;
public SensorRecord() {
Realm.init(this);
mRealm = getInstance(getRealmConfig());
}
public void StartSensor(long startTime) {
long newprimekey = PrimaryKeyFactory.getInstance().nextKey(SensorData.class);
try {
mRealm.beginTransaction();
SensorData mSensorData = mRealm.createObject(SensorData.class, newprimekey);
mSensorData.setstarted_at(startTime);
mRealm.commitTransaction();
mRealm.close();
} catch (Exception e) {
Log.v(TAG, "StartSensor " + e.getMessage());
}
}}
my main application class which init the realm config
public class MainApplication extends RealmBaseApplication {
private final static String TAG = MainApplication.class.getSimpleName();
Realm mRealm;
#Override
public void onCreate() {
super.onCreate();
Realm.init(this);
mRealm = getInstance(getRealmConfig());
initializePrimaryKeyFactory();
}
public void initializePrimaryKeyFactory() {
try {
Log.v(TAG, "Start PrimaryKeyFactory ");
PrimaryKeyFactory.getInstance().initialize(mRealm);
} catch (Exception e) {
Log.v(TAG, "initializePrimaryKeyFactory " + e.getMessage());
}
}}
and my realm config class
public abstract class RealmBaseApplication extends Application {
private RealmConfiguration realmConfiguration;
protected RealmConfiguration getRealmConfig() {
if (realmConfiguration == null) {
realmConfiguration = new RealmConfiguration
.Builder()
.deleteRealmIfMigrationNeeded()
.build();
}
Realm.setDefaultConfiguration(realmConfiguration);
return realmConfiguration;
}
protected void resetRealm() {
Realm.deleteRealm(getRealmConfig());
}}
kind regards
viktoria
ok fixed by myself. had add butterknife tonight. and with that i add apt to my build.gradle... i removed
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
apply plugin: 'com.neenbedankt.android-apt'
and replaced
apt 'com.jakewharton:butterknife-compiler:8.5.1'
with
annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1'

Fail to run test with AndroidAnnotation, Robolectric and PowerMock

I am new to unit test and I am trying to use robolectric to do the test for my android app, but I encountered some problems
DemoPresenterTest
#RunWith(RobolectricTestRunner.class)
#Config(constants = BuildConfig.class, sdk = 23)
#PowerMockIgnore({ "org.mockito.*", "org.robolectric.*", "android.*" })
#PrepareForTest(DemoPresenterImpl_.class)
public class DemoPresenterTest {
#Rule
public MockitoRule rule = MockitoJUnit.rule();
private MockDemoNetworkService mMockDemoNetworkService;
private MockLceView mLceView;
private DemoPresenterImpl_ mPresenter;
#Before
public void setup() {
mMockDemoNetworkService = Mockito.mock(MockDemoNetworkService.class);
mLceView = Mockito.mock(MockLceView.class);
PowerMockito.mockStatic(DemoPresenterImpl_.class);
mPresenter = DemoPresenterImpl_.getInstance_(RuntimeEnvironment.application);
mPresenter.service = mMockDemoNetworkService;
mPresenter.view = mLceView;
}
#Test
public void testDownloadData() {
mPresenter.downloadData();
Mockito.verify(mLceView).onError(Mockito.anyInt());
}
}
DemoPresenterImpl
#EBean
public class DemoPresenterImpl implements DemoPresenter {
#Bean(DemoNetworkService.class)
DemoService service;
protected LceView<Demo> view;
/**
* download the data from server for the first time, data will be saved into the database
* and for the next time it will query the database instead
*/
#Override
#Background(delay = 1000)
public void downloadData() {
try {
List<Demo> result = service.getDemoList();
if (result != null) {
view.setData(result);
} // add else if the result is not return empty list but null
} catch (NetworkFailException e) {
view.onError(e.getResponse().getCode());
}
}
#Override
public void attach(LceView<Demo> view) {
this.view = view;
}
}
MockDemoNetworkService
public class MockDemoNetworkService implements DemoService {
#Override
public List<Demo> getDemoList() throws NetworkFailException {
NetworkFailResponse response = new NetworkFailResponse();
response.setCode(500);
throw new NetworkFailException(response);
}
#Override
public boolean setDemoList(List<Demo> demoList) {
return false;
}
}
When I run the test it returns "Cannot subclass final class class com.*.DemoPresenterImpl_", if I change to DemoPresenterImpl, the test can run but the mLceView never get called
Wanted but not invoked: mockLceView.onError();
-> at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:245)
Actually, there were zero interactions with this mock.
am I doing something wrong?
I think you can remove #PrepareForTest, because you are not mocking the presenter, you are actually testing it. Then you should use DemoPresenterImpl_, because it is containing the needed generated code.

SpringBoot Undertow : how to dispatch to worker thread

i'm currently have a look a springboot undertow and it's not really clear (for me) how to dispatch an incoming http request to a worker thread for blocking operation handling.
Looking at the class UndertowEmbeddedServletContainer.class, it look like there is no way to have this behaviour since the only HttpHandler is a ServletHandler, that allow #Controller configurations
private Undertow createUndertowServer() {
try {
HttpHandler servletHandler = this.manager.start();
this.builder.setHandler(getContextHandler(servletHandler));
return this.builder.build();
}
catch (ServletException ex) {
throw new EmbeddedServletContainerException(
"Unable to start embdedded Undertow", ex);
}
}
private HttpHandler getContextHandler(HttpHandler servletHandler) {
if (StringUtils.isEmpty(this.contextPath)) {
return servletHandler;
}
return Handlers.path().addPrefixPath(this.contextPath, servletHandler);
}
By default, in undertow all requests are handled by IO-Thread for non blocking operations.
Does this mean that every #Controller executions will be processed by a non blocking thread ? or is there a solution to chose from IO-THREAD or WORKER-THREAD ?
I try to write a workaround, but this code is pretty uggly, and maybe someone has a better solution:
BlockingHandler.class
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Documented
public #interface BlockingHandler {
String contextPath() default "/";
}
UndertowInitializer.class
public class UndertowInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
configurableApplicationContext.addBeanFactoryPostProcessor(new UndertowHandlerPostProcessor());
}
}
UndertowHandlerPostProcessor.class
public class UndertowHandlerPostProcessor implements BeanDefinitionRegistryPostProcessor {
#Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
scanner.addIncludeFilter(new AnnotationTypeFilter(BlockingHandler.class));
for (BeanDefinition beanDefinition : scanner.findCandidateComponents("org.me.lah")){
try{
Class clazz = Class.forName(beanDefinition.getBeanClassName());
beanDefinitionRegistry.registerBeanDefinition(clazz.getSimpleName(), beanDefinition);
} catch (ClassNotFoundException e) {
throw new BeanCreationException(format("Unable to create bean %s", beanDefinition.getBeanClassName()), e);
}
}
}
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
//no need to post process defined bean
}
}
override UndertowEmbeddedServletContainerFactory.class
public class UndertowEmbeddedServletContainerFactory extends AbstractEmbeddedServletContainerFactory implements ResourceLoaderAware, ApplicationContextAware {
private ApplicationContext applicationContext;
#Override
public EmbeddedServletContainer getEmbeddedServletContainer(ServletContextInitializer... initializers) {
DeploymentManager manager = createDeploymentManager(initializers);
int port = getPort();
if (port == 0) {
port = SocketUtils.findAvailableTcpPort(40000);
}
Undertow.Builder builder = createBuilder(port);
Map<String, Object> handlers = applicationContext.getBeansWithAnnotation(BlockingHandler.class);
return new UndertowEmbeddedServletContainer(builder, manager, getContextPath(),
port, port >= 0, handlers);
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
...
override UndertowEmbeddedServletContainer.class
public UndertowEmbeddedServletContainer(Builder builder, DeploymentManager manager,
String contextPath, int port, boolean autoStart, Map<String, Object> handlers) {
this.builder = builder;
this.manager = manager;
this.contextPath = contextPath;
this.port = port;
this.autoStart = autoStart;
this.handlers = handlers;
}
private Undertow createUndertowServer() {
try {
HttpHandler servletHandler = this.manager.start();
String path = this.contextPath.isEmpty() ? "/" : this.contextPath;
PathHandler pathHandler = Handlers.path().addPrefixPath(path, servletHandler);
for(Entry<String, Object> entry : handlers.entrySet()){
Annotation annotation = entry.getValue().getClass().getDeclaredAnnotation(BlockingHandler.class);
System.out.println(((BlockingHandler) annotation).contextPath());
pathHandler.addPrefixPath(((BlockingHandler) annotation).contextPath(), (HttpHandler) entry.getValue());
}
this.builder.setHandler(pathHandler);
return this.builder.build();
}
catch (ServletException ex) {
throw new EmbeddedServletContainerException(
"Unable to start embdedded Undertow", ex);
}
}
set initializer to the application context
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).initializers(new UndertowInitializer()).run(args);
}
finaly create a HttpHandler that dispatch to worker thread
#BlockingHandler(contextPath = "/blocking/test")
public class DatabaseHandler implements HttpHandler {
#Autowired
private EchoService echoService;
#Override
public void handleRequest(HttpServerExchange httpServerExchange) throws Exception {
if(httpServerExchange.isInIoThread()){
httpServerExchange.dispatch();
}
echoService.getMessage("my message");
}
}
As you can see, my "solution" is really heavy, and i would really appreciate any help to simplify it a lot.
Thank you
You don't need to do anything.
Spring Boot's default Undertow configuration uses Undertow's ServletInitialHandler in front of Spring MVC's DispatcherServlet. This handler performs the exchange.isInIoThread() check and calls dispatch() if necessary.
If you place a breakpoint in your #Controller, you'll see that it's called on a thread named XNIO-1 task-n which is a worker thread (the IO threads are named XNIO-1 I/O-n).

#Context WebConfig not injected when using JerseyTest 2.0

I have a simple resource like:
#Path("/")
public class RootResource {
#Context WebConfig wc;
#PostConstruct
public void init() {
assertNotNull(wc);
}
#GET
public void String method() {
return "Hello\n";
}
}
Which I am trying to use with JerseyTest (2.x, not 1.x) and the GrizzlyTestContainerFactory.
I can't work out what I need to do in terms of config to get the WebConfig object injected.
I solved this issue by creating a subclass of GrizzlyTestContainerFactory and explicitly loading the Jersey servlet. This triggers the injection of the WebConfig object. The code looks like this:
public class ExtendedGrizzlyTestContainerFactory implements TestContainerFactory {
private static class GrizzlyTestContainer implements TestContainer {
private final URI uri;
private final ApplicationHandler appHandler;
private HttpServer server;
private static final Logger LOGGER = Logger.getLogger(GrizzlyTestContainer.class.getName());
private GrizzlyTestContainer(URI uri, ApplicationHandler appHandler) {
this.appHandler = appHandler;
this.uri = uri;
}
#Override
public ClientConfig getClientConfig() {
return null;
}
#Override
public URI getBaseUri() {
return uri;
}
#Override
public void start() {
if (LOGGER.isLoggable(Level.INFO)) {
LOGGER.log(Level.INFO, "Starting GrizzlyTestContainer...");
}
try {
this.server = GrizzlyHttpServerFactory.createHttpServer(uri, appHandler);
// Initialize and register Jersey Servlet
WebappContext context = new WebappContext("WebappContext", "");
ServletRegistration registration = context.addServlet("ServletContainer", ServletContainer.class);
registration.setInitParameter("javax.ws.rs.Application",
appHandler.getConfiguration().getApplication().getClass().getName());
// Add an init parameter - this could be loaded from a parameter in the constructor
registration.setInitParameter("myparam", "myvalue");
registration.addMapping("/*");
context.deploy(server);
} catch (ProcessingException e) {
throw new TestContainerException(e);
}
}
#Override
public void stop() {
if (LOGGER.isLoggable(Level.INFO)) {
LOGGER.log(Level.INFO, "Stopping GrizzlyTestContainer...");
}
this.server.stop();
}
}
#Override
public TestContainer create(URI baseUri, ApplicationHandler application) throws IllegalArgumentException {
return new GrizzlyTestContainer(baseUri, application);
}
Notice that the Jersey Servlet configuration is being loaded from the ApplicationHandler that is passed in as a parameter using the inner Application object's class name (ResourceConfig is a subclass of Application). Therefore, you also need to create a subclass of ResourceConfig for this approach to work. The code for this is very simple:
package com.example;
import org.glassfish.jersey.server.ResourceConfig;
public class MyResourceConfig extends ResourceConfig {
public MyResourceConfig() {
super(MyResource.class);
}
}
This assumes the resource you are testing is MyResource. You also need to override a couple of methods in your test like this:
public class MyResourceTest extends JerseyTest {
public MyResourceTest() throws TestContainerException {
}
#Override
protected Application configure() {
return new MyResourceConfig();
}
#Override
protected TestContainerFactory getTestContainerFactory() throws TestContainerException {
return new ExtendedGrizzlyTestContainerFactory();
}
#Test
public void testCreateSimpleBean() {
final String beanList = target("test").request().get(String.class);
Assert.assertNotNull(beanList);
}
}
Finally, for completeness, here is the code for MyResource:
#Path("test")
public class MyResource {
#Context WebConfig wc;
#PostConstruct
public void init() {
System.out.println("WebConfig: " + wc);
String url = wc.getInitParameter("myparam");
System.out.println("myparam = "+url);
}
#GET
#Produces(MediaType.APPLICATION_JSON)
public Collection<TestBean> createSimpleBean() {
Collection<TestBean> res = new ArrayList<TestBean>();
res.add(new TestBean("a", 1, 1L));
res.add(new TestBean("b", 2, 2L));
return res;
}
#POST
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public TestBean roundTrip(TestBean s) {
return s;
}
}
The output of running the test shows that the WebConfig is loaded and the init param is now available:
WebConfig: org.glassfish.jersey.servlet.WebServletConfig#107d0f44
myparam = myvalue
The solution from #ametke worked well but wasn't picking up my ExceptionMapper classes. To solve this I simplified the start() method to:
#Override
public void start() {
try {
initParams.put("jersey.config.server.provider.packages", "my.resources;my.config");
this.server = GrizzlyWebContainerFactory.create(uri, initParams);
} catch (ProcessingException | IOException e) {
throw new TestContainerException(e);
}
}
This was based on Problems running JerseyTest when dealing with HttpServletResponse

JSF custom panel with button - action not invoked

I have built a custom component button, but somehow the action is not invoked. When debugging the getAction-Method within the component and invoking the supplied MethodeExpression the Bean-Method is called as expected. But due to some reason, the Expression is not invoked when pressing the button in the browser.
Is there some kind of additional Interface necessary to pass the action to the embedded button-component?
Any help is very appreciated since I am stuck at this issue for some days now
MyClass:
public class MyClass extends UIPanel implements SystemEventListener
{
private UIForm form;
private HtmlCommandButton buttonOk;
public MyClass()
{
FacesContext context = getFacesContext();
UIViewRoot root = context.getViewRoot();
root.subscribeToViewEvent(PostAddToViewEvent.class, this);
}
#Override
public void processEvent(SystemEvent event)
{
this.form = new UIForm();
this.buttonOk = new HtmlCommandButton();
this.buttonOk.setId("okButtonId");
this.buttonOk.setActionExpression(getAction());
this.buttonOk.setValue("OK");
this.form.getChildren().add(this.buttonOk);
getChildren().add(this.form);
}
private enum PropertyKeys
{
action, text, titel
}
public MethodExpression getAction()
{
return (MethodExpression) getStateHelper().eval(PropertyKeys.action);
}
public void setAction(MethodExpression actionExpression)
{
getStateHelper().put(PropertyKeys.action, actionExpression);
}
public String getText()
{
return (String) getStateHelper().eval(PropertyKeys.text);
}
public void setText(String text)
{
getStateHelper().put(PropertyKeys.text, text);
}
public String getTitel()
{
return (String) getStateHelper().eval(PropertyKeys.titel);
}
public void setTitel(String titel)
{
getStateHelper().put(PropertyKeys.titel, titel);
}
#Override
public void encodeAll(FacesContext context) throws IOException
{
ResponseWriter writer = context.getResponseWriter();
writer.startElement(HTML.DIV_ELEM, this);
writer.writeText(getText(), null);
this.form.encodeAll(context);
writer.endElement(HTML.DIV_ELEM);
}
#Override
public void encodeChildren(FacesContext context) throws IOException
{
}
#Override
public boolean isListenerForSource(Object source)
{
return (source instanceof MyClass);
}
}
MyClassHandler:
public class MyClassHandler extends ComponentHandler
{
public MyClassHandler(ComponentConfig config)
{
super(config);
}
#SuppressWarnings("rawtypes")
#Override
protected MetaRuleset createMetaRuleset(Class type)
{
return super.createMetaRuleset(type).addRule(new MethodRule("action", String.class, new Class[] { ActionEvent.class }));
}
}
myView Method:
...
public String myMethod()
{
System.err.println("myMethod");
return "/some/path/yadayada.xhtml";
}
...
MyView.xhtml
<myTag action="#{myView.myMethod}" id="id1" titel="bla" text="bleh" />
Exdending UICommand is enough, since you only want one action to be executed.
You have to provide two additional MethodExpressions via the tag-attributes and within the decode-method you can check which button has been pressed and redirect the particular MethodExpression to the standard-action provided by UICommand. This way, you dont have to worry about the legacy-interface ActionSource, or how Events are broadcasted.
public void decode(FacesContext contex)
{
Map<String,String> map = context.getExternalContext.getRequestParameterMap();
// your rendered buttons need a name you check for
final boolean okPressed = map.containsKey( getClientId + ":ok" );
final boolean cancelPressed = map.containsKey( getClientId + ":cancel" );
if(okPressed || cancelPressed)
{
MethodExpression exp = null;
if(okPressed)
{
exp = getActionOk();
}
else
{
exp = getActionCancel();
}
// redirect to standard action
setActionExpression(exp);
queueEvent(new ActionEvent(this));
}
}
In order to make use of of this you need two attributes (actionOk and actionCancel) which use Method Expressions (setter and getter). Those have to be configured by a ComponentHandler as you did for the action-attribute.

Resources