Vaadin IBM Challenge

Since two weeks the Vaadin IBM challenge is over. While I was only able to do the bare minimum, I really enjoyed the different tasks (see here for list of steps).

Congrats to the winners! And thanks to the Vaading Team & IBM for this exciting experience.

Veröffentlicht unter Vaadin | 4 Kommentare

Things I never blogged about: XPages & Google’s EventBus

This is another topic I wanted to blog about for a long time: The use of Google’s EventBus in XPages applications. EventBus is a replacement for the Java in-process event distribution. It makes life a lot easier.

My first plan was to add the guava.jar into an OSGi plugin because of security reasons (otherwise you have to use the „grant{ permission java.security.AllPermission;}„) but I never had the time. That’s why I created a simple example which uses the jar in the lib/ext folder instead.

To use the EventBus in an application, you first have to define an event. This simple example has a message only, but you can add any properties you want.

package ch.hasselba.xpages;

public class FrontendEvent {

    private final String message;

    public FrontendEvent(final String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

}

Then we need a subscriber. For this we have to add the annotation @Subscribe to a method of a managed bean which should handle an event. The class type of the parameter tells the EventBus what kind of event our method should handle.

This is a managed bean which stores the last message sent over the EventBus:

package ch.hasselba.xpages;

import com.google.common.eventbus.Subscribe;

public class EventSubscriber {

    private String message;

    @Subscribe
    public void handleEvent(FrontendEvent event) {
        this.message = event.getMessage();
    }

    public void getMessage(String msg) {
        this.message = msg;
    }

    public String getMessage() {
        return this.message;
    }
}

Then we have to create a managed bean which has an instance of EventBus, the FrontendEventBus. The bus has a managed property subscribers. As soon the bean is instantiated, the managed property is called and the list of objects is registered to the EventBus instance.

package ch.hasselba.xpages;

import java.io.Serializable;
import java.util.ArrayList;

import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.SubscriberExceptionContext;
import com.google.common.eventbus.SubscriberExceptionHandler;

@SuppressWarnings("serial")
public class FrontendEventBus implements SubscriberExceptionHandler,
        Serializable {

    final EventBus eventBus = new EventBus();
    ArrayList<Object> subscribers;

    /**
     * registers all subscribing managed beans from faces-config.xml
     * 
     * @param subscribers
     *            ArrayList with references to managed beans
     */
    public void setSubscribers(ArrayList<Object> subscribers) {
        this.subscribers = subscribers;
        for (Object subscriber : subscribers) {
            register(subscriber);
        }
    }

    public void post(final Object event) {
        eventBus.post(event);
    }

    public void register(final Object object) {
        eventBus.register(object);
    }

    public void unregister(final Object object) {
        eventBus.unregister(object);
    }

    public final void handleException(Throwable exception,
            SubscriberExceptionContext context) {
        exception.printStackTrace();

    }

}

There is only one problem: If a bean is in a lower scope, the initialization will fail. In this case we have to do the opposite to attach a subscriber to the bus. Instead of telling the bus which subscriber we want to register, we are telling the subscriber which bus to attach to.

package ch.hasselba.xpages;

public class EventSubscriberRequestScope extends EventSubscriber {

    /**
     * registers the current instance to the event bus
     * 
     * @param eventBus
     *            the frontend event bus
     */
    public void setEventBus(FrontendEventBus eventBus) {
        eventBus.register(this);
    }

}

As soon the bean is instantiated, the managed property will have an instance of our FrontendEventBus and the bean can register itself.

The faces-config.xml looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<faces-config>

    <managed-bean>
        <managed-bean-name>frontendEventBus</managed-bean-name>
        <managed-bean-class>ch.hasselba.xpages.FrontendEventBus</managed-bean-class>
        <managed-bean-scope>session</managed-bean-scope>
        <managed-property>
            <property-name>subscribers</property-name>
            <list-entries>
                <value-class>java.lang.Object</value-class>
                <value>#{eventSubscriber}</value>
            </list-entries>
        </managed-property>
    </managed-bean>
    
    
    <managed-bean>
        <managed-bean-name>eventSubscriber</managed-bean-name>
        <managed-bean-class>ch.hasselba.xpages.EventSubscriber</managed-bean-class>
        <managed-bean-scope>session</managed-bean-scope>
    </managed-bean>
    
    
    <managed-bean>
        <managed-bean-name>eventSubscriberRequestScope</managed-bean-name>
        <managed-bean-class>ch.hasselba.xpages.EventSubscriberRequestScope</managed-bean-class>
        <managed-bean-scope>request</managed-bean-scope>
        <managed-property>
            <property-name>eventBus</property-name>
            <value>#{frontendEventBus}</value>
        </managed-property>
    </managed-bean>
    
</faces-config>

The first subscribing bean is in the same scope as the FrontendEventBus, but the second one is a request scoped bean.

Now it’s time to send an event. This can be realized by creating a new instance of our FrontendEvent we have created earlier and posting it to the bus.

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">

    <xp:button
        id="button1" value="Click me">
        
        <xp:eventHandler
            event="onclick"
            submit="true"
            refreshMode="complete">
            <xp:this.action>
                <![CDATA[#{javascript:importPackage( ch.hasselba.xpages );
                    var msg = "Timestamp: " + java.lang.System.currentTimeMillis();
                    var se = new ch.hasselba.xpages.FrontendEvent( msg );
                    frontendEventBus.post( se );
                }]]>
            </xp:this.action>
        </xp:eventHandler>
    
    </xp:button>
    
    <br />
    <br />
    
    <xp:label
        value="#{eventSubscriber.message}"
        id="labelSubscriberMessage">
    </xp:label>
    
    <br />
    
    <xp:label
        value="#{eventSubscriberRequestScope.message}"
        id="labelSubscriberRequestScope">
    </xp:label>
    
</xp:view>

As soon the button is clicked, both beans are receiving the event and updating their message.

2015-12-01 14_04_04-Mozilla Firefox

Hope someone finds it usefull.

Veröffentlicht unter Java, JSF, XPages | Schreib einen Kommentar

Things I never blogged about: The XPagesExecutor Service

The XPages engine has its own executor service to run jobs concurrently in another thread: the XPagesExecutor service. Under the hood the service uses a ThreadPoolExecutor for executing tasks, so it allows to use Runnables or Callables/Futures for asynchronous computation. For fun, you can even run a server instance, the started threads can run as long as you want (e.g. they are not bound to the XPages lifecycle).

Here is a small XPage with a button to start a Runnable via the Executor:

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
    
    <xp:button
        value="run the job"
        id="buttonDoIt">
        <xp:eventHandler
            event="onclick"
            submit="true"
            refreshMode="complete">
            <xp:this.action>
                <![CDATA[#{javascript:
                importPackage(ch.hasselba.xpages);
                new ch.hasselba.xpages.DemoExecutor().doIt();}]]>
            </xp:this.action>
        </xp:eventHandler>
    </xp:button>
    
</xp:view>

To use the Service, you have to aquire it first, then you can execute a Runnable like in this code snippet:

package ch.hasselba.xpages;

import java.util.concurrent.ExecutorService;

import lotus.domino.NotesException;
import lotus.domino.Session;

import com.ibm.domino.xsp.module.nsf.NSFComponentModule;
import com.ibm.domino.xsp.module.nsf.NotesContext;
import com.ibm.domino.xsp.module.nsf.SessionCloner;
import com.ibm.xsp.application.XPagesExecutor;

public class DemoExecutor {
    private final NSFComponentModule module;
    private final SessionCloner sessionCloner = SessionCloner
            .getSessionCloner();

    public DemoExecutor() {
        // get the current NSFComponentModule
        this.module = NotesContext.getCurrent().getModule();
    }

    public void doIt() {
        // aquire the Executor
        ExecutorService exService = XPagesExecutor.acquire();
        
        // run the Runnable
        exService.execute(new DemoRunnable(this.module));
    }

    class DemoRunnable implements Runnable {
        private final NSFComponentModule module;

        public DemoRunnable(NSFComponentModule module) {
            this.module = module;
        }

        public void run() {
            try {

                // init the NotesThread
                NotesContext context = new NotesContext(this.module);
                NotesContext.initThread(context);

                // now do the job...
                System.out.println("Starting the job...");
                Session session = null;
                try {
                    // grab the session
                    session = sessionCloner.getSession();
                    System.out.println("Running as "
                            + session.getEffectiveUserName());
                    Thread.sleep(10000);
                } catch (NotesException e) {
                    e.printStackTrace();
                } finally {
                    DominoUtils.recycle( session );
                }
                System.out.println("Done!");

            } catch (InterruptedException ie) {
                // handle interruption here
            } finally {
                // kill the Notes thread
                NotesContext.termThread();
            }
        }

    }

}

2015-11-29 08_54_13-SH Domain - Dev01_Hasselba_CH - IBM Domino Administrator

Callables must be submitted instead:

   public long doItWithCallable() {

        ExecutorService exService = XPagesExecutor.acquire();
        Future<Long> result = exService.submit(new MyCallable(this.module));
        long returnValue = (-1);

        try {
            returnValue = result.get();
        } catch (InterruptedException ie) {
            ie.printStackTrace();
        } catch (ExecutionException ee) {
            ee.printStackTrace();
        }

        return returnValue;
    }

    class DemoCallable implements Callable {
        private final NSFComponentModule module;

        public DemoCallable(NSFComponentModule module) {
            this.module = module;
        }

        public Long call() throws Exception {
            try {

                // init the NotesThread
                NotesContext context = new NotesContext(this.module);
                NotesContext.initThread(context);

                // now do the job...
                System.out.println("Starting the job...");
                Session session = null;
                try {
                    // grab the session
                    session = sessionCloner.getSession();
                    System.out.println("Running as "
                            + session.getEffectiveUserName());
                    Thread.sleep(10000);
                } catch (NotesException e) {
                    e.printStackTrace();
                } finally {
                    DominoUtils.recycle( session );
                }
                System.out.println("Done!");

            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                // kill the Notes thread
                NotesContext.termThread();
            }

            return System.currentTimeMillis();
        }

    }

Hope someone finds it usefull.

Veröffentlicht unter Java, XPages | 2 Kommentare

[Discontinued] Testing XPages(3): Testing the Business Logic

I will not develop my planned XPages Testing Framework further because for me it has no business case anymore. While there never was enough time to make it to a „real project“ for the daily development (full JUnit integration, deployed as an OSGi plugin etc) and this code is only an example, I used this technique with a similar code base in some projects. It was a big help during development, because it allows to „look inside“ the XPages engine while testing.

How does it work?

In a JUnit test, a local proxy is started which fetches all request / responses between the Selenium WebDriver and the Domino server. Only the first request is relevant, the other requests are the resources like Javascript files, Images and CSS.

During the test, a special HTTP Header is added to the request (X-XPAGES-TEST). It contains EL code and the JSF phase when to execute it. A phase listener (in the application, better in an OSGi plugin) intercepts the HTTP header and executes the code. The result it posted back to the client (encapsulated in another HTTP header). It can then be tested with an assert.

Because of the use of special headers instead of injecting the results into the HTML markup, this can be used with Diffy or similar products to verify the application while refactoring the code base.

Here is the JUnit Test application:


package ch.hasselba.xpages.test.XPagesTester;

import java.util.LinkedList;
import java.util.concurrent.TimeUnit;

import net.lightbody.bmp.core.har.Har;
import net.lightbody.bmp.proxy.ProxyServer;
import net.lightbody.bmp.proxy.http.BrowserMobHttpRequest;
import net.lightbody.bmp.proxy.http.BrowserMobHttpResponse;
import net.lightbody.bmp.proxy.http.RequestInterceptor;
import net.lightbody.bmp.proxy.http.ResponseInterceptor;

import org.apache.http.HttpResponse;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.Proxy;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriver.Options;
import org.openqa.selenium.WebDriver.Timeouts;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.remote.DesiredCapabilities;

public class App
{
  private ProxyServer server;
  private LinkedList httpResponses;
  private LinkedList httpRequests;
  private WebDriver driver;
  private String baseUrl = "http://localhost/Demo.nsf/Test.xsp";
  private StringBuffer verificationErrors = new StringBuffer();
  private final String HTTP_HEADER_NAME = "X-XPAGES-TESTS";
	
  @Before
  public void setUp() throws Exception {
    this.server = new ProxyServer(4444);
    this.server.start();

    Proxy proxy = this.server.seleniumProxy();

    DesiredCapabilities capabilities = new DesiredCapabilities();
    capabilities.setCapability("proxy", proxy);

    ResponseInterceptor interceptor = new ResponseInterceptor() {
      public void process(BrowserMobHttpResponse response, Har har) {
    	  httpResponses.add( response );
      }
    };
    RequestInterceptor requestInterceptor = new RequestInterceptor() {
      public void process(BrowserMobHttpRequest request, Har har) {
    	  httpRequests.add( request );
      }
    };
    this.server.addRequestInterceptor(requestInterceptor);

    this.server.addResponseInterceptor(interceptor);
    this.driver = new FirefoxDriver(capabilities);
    this.driver.manage().timeouts().implicitlyWait(10L, TimeUnit.SECONDS);
  }
  @After
  public void tearDown() throws Exception {
    this.driver.quit();
    String verificationErrorString = this.verificationErrors.toString();
    if (!"".equals(verificationErrorString))
      Assert.fail(verificationErrorString);
  }

  @Test
  public void testDemo() throws Exception
  {
    StringBuffer strBuffer = new StringBuffer();
    strBuffer.append("[");
    strBuffer.append("{");
    strBuffer.append("\"code\": \"#{javascript:java.lang.System.currentTimeMillis()}\"}]");
    this.server.addHeader(HTTP_HEADER_NAME, strBuffer.toString() );
    
    reloadPage();

    System.out.println( "X-PAGES-TESTS: " + getXPageResponse().getHeader(HTTP_HEADER_NAME) );
    
    HttpResponse httpRawResponse = getXPageResponse().getRawResponse();
    Assert.assertTrue("HTTP/1.1 200 OK".equals(httpRawResponse.getStatusLine()
      .toString()));

    Assert.assertTrue("Lotus-Domino".equals(getXPageResponse().getHeader("Server")));

  }

  public void reloadPage()
  {
    this.httpRequests = new LinkedList();
    this.httpResponses = new LinkedList();
    this.driver.get(this.baseUrl);
  }
  
  public BrowserMobHttpResponse getXPageResponse(){
    return this.httpResponses.get(0);
  }
}

And here comes the phase listener:


package ch.hasselba;

import java.util.HashSet;
import java.util.Iterator;

import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import javax.servlet.http.HttpServletRequest;

import com.ibm.commons.util.io.json.JsonEmptyFactory;
import com.ibm.commons.util.io.json.JsonException;
import com.ibm.commons.util.io.json.JsonJavaFactory;
import com.ibm.commons.util.io.json.JsonJavaObject;
import com.ibm.commons.util.io.json.JsonParser;
import com.ibm.xsp.application.ApplicationEx;
import com.ibm.xsp.context.ExternalContextEx;
import com.ibm.xsp.context.FacesContextExImpl;

@SuppressWarnings("serial")
public class TestPhaseListener implements PhaseListener {

  private final String HTTP_HEADER_NAME = "X-XPAGES-TESTS";
	
  public void afterPhase(PhaseEvent event) {}

  public void beforePhase(PhaseEvent event) {
    FacesContextExImpl fc = (FacesContextExImpl) event.getFacesContext();
    ExternalContextEx ec = (ExternalContextEx) fc.getExternalContext();
    HttpServletRequest request = (HttpServletRequest) ec.getRequest();
    ApplicationEx app = fc.getApplicationEx();
    HashSet results = new HashSet();
    try {
      String jsonData = request.getHeader(HTTP_HEADER_NAME);
      // Create the JAVA json factory
      JsonJavaFactory factory = JsonJavaFactory.instanceEx;
      // Turn the sort parameter string into an array of JSON objects
      Object jsonTests;

      jsonTests = JsonParser.fromJson(factory, jsonData);
      // Loop through the JSON objects and do something
      for (Iterator<Object> oSort = factory.iterateArrayValues(jsonTests); oSort
					.hasNext();) {
         JsonJavaObject o = (JsonJavaObject) oSort.next();
	 //String phaseId  o.getJsonProperty("phaseId") );
	 String code = (String) o.getJsonProperty("code");

         try {
           Object result = app.createMethodBinding(code, null).invoke(fc,
						null);
           results.add( result.toString() );
         }catch( Exception e) {
	   results.add( e.getMessage() );
         }
      }

      StringBuffer buffer = new StringBuffer();
      buffer.append( "[" );
      int pos = 0;
      for( String res : results ) {
         buffer.append( "{ \"result\" : \"" + res + "\"}");
         pos++;
	 if( pos < results.size() )
	   buffer.append( "," );
      }
      buffer.append( "]");
			
      fc.getXspResponse().addHeader(HTTP_HEADER_NAME, buffer.toString() );
			
    } catch (JsonException e) {
      e.printStackTrace();
      fc.getXspResponse().addHeader(HTTP_HEADER_NAME,
					e.getLocalizedMessage());
    } catch (Exception e) {
      e.printStackTrace();
      fc.getXspResponse().addHeader(HTTP_HEADER_NAME,
					e.getLocalizedMessage());
    }

  }

  public PhaseId getPhaseId() {
    return PhaseId.ANY_PHASE;
  }

}

Hope someone finds it usefull.

Veröffentlicht unter Java, XPages | Schreib einen Kommentar

Debug Retrofit REST applications

Today I had some problems with designing a Retrofit REST application, so I needed a way to debug the request and the response from the server. After poking around, I found the HttpLoggingInterceptor from OkHttp.  It provides all the functionality I need and is really easy to implement.

First you have create a OkHttpClient instance, add the interceptor and set the debug level to HttpLoggingInterceptor.Level.BODY:

OkHttpClient client = new OkHttpClient();
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
client.interceptors().add(interceptor);    

Next step is to add the client during the building of the Retrofit instance:

Retrofit retrofit = new Retrofit.Builder().client(client).build();

Now you can see the HTTP data sent over the wire:

2015-11-27 21_11_08

Don’t forget to add the two required dependencies to your pom.xml:

<dependency>
   <groupId>com.squareup.okhttp</groupId>
   <artifactId>okhttp</artifactId>
   <version>2.6.0</version>
</dependency>
<dependency>
   <groupId>com.squareup.okhttp</groupId>
   <artifactId>logging-interceptor</artifactId>
   <version>2.6.0</version>
</dependency>
Veröffentlicht unter Java, REST, Web | Schreib einen Kommentar

Testing XPages (2): BrowserMob Proxy

When testing XPages or other web applications, you may want to have more control about the requests and responses during the JUnit testing. For example, if you want to test if a specific HTTP header exists in the response, or if it is required to add some HTTP headers to the request. But you cannot doe this out of the box with Selenium. Instead, you have to add a proxy to the Firefox controller, which then gives you a handle to the HTTP data and allows you to control the flow.

An good solution for this is BrowserMob Proxy, which can be used by adding the required dependency to your Maven pom.xml:

<dependency>
    <groupId>net.lightbody.bmp</groupId>
    <artifactId>browsermob-proxy</artifactId>
    <version>2.0.0</version>
</dependency>

[This is version 2.0.0, the latest stable version]

The proxy runs locally on the specified port as soon the JUnit test starts and ends automatically after finishing the tests.  In order to accomplish this, the setUp method has to be modified:

// start the proxy (listens on port 4444)
server = new ProxyServer(4444);
server.start();

// get the Selenium proxy object
Proxy proxy = server.seleniumProxy();

// configure it as a desired capability
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(CapabilityType.PROXY, proxy);

Now, the proxy setting must be added to the Firefox driver:

driver = new FirefoxDriver(capabilities);

In the test class, three global variables must be defined; these are giving you access to the proxy server and latest the request and response during testing:

private ProxyServer server;
private BrowserMobHttpResponse httpResponse;
private BrowserMobHttpRequest httpRequest;

With the help of a ResponseInterceptor, the httpResponse property is always filled with the latest response. To initialize it, an anonymous class in the setUp method has to be created:

// add a response interceptor
ResponseInterceptor interceptor = new ResponseInterceptor() {
    public void process(BrowserMobHttpResponse response, Har har) {
          httpResponse = response;
    }
};

// add the interceptor to the server
server.addResponseInterceptor(interceptor);

For the RequestInterceptor it is the same procedure:

// add a request interceptor
RequestInterceptor requestInterceptor = new RequestInterceptor() {
    public void process(BrowserMobHttpRequest request, Har har) {
       httpRequest = request;
    }
};

server.addRequestInterceptor(requestInterceptor);

Now, it is possible to use it in a JUnit test:

@Test
public void testDemo() throws Exception {
 
    // add a request header
    server.addHeader("X-FOO", "BAR");
 
    // load the page
    reloadPage();

    // TEST RESPONSE STATUS
    HttpResponse httpRawResponse = httpResponse.getRawResponse();
    assertTrue("HTTP/1.1 200 OK".equals(httpRawResponse.getStatusLine()
       .toString()));
 
    // TEST SERVER HEADER
    assertTrue( "Lotus-Domino".equals( httpResponse.getHeader("Server")) );
 
}

The Browsermob-proxy has a lot of additional features: You can modify the allowed speed for up- and downstreams, use basic authentication, upload files, etc.

Veröffentlicht unter Java, Web, XPages | Verschlagwortet mit , , , , , , , | Schreib einen Kommentar

Testing XPages

When testing XPages with Selenium, you can easily pre-generate the JUnit test code with the browser plugin. But when you then change the structure of the XPage (f.e. by moving the components from an XPage to a custom control), all the IDs of the JUnit test will not work anymore.

That’s why it is better to use CSS selectors to access the generated fields:

driver.findElements(By.cssSelector("input[id*='idOfTheComponent']"));

With the selector „id*=’idOfTheComponent'“ you can access the elements by their component id, idependently of their full generated client id.

Here is an example with a small XPage with a radio group and a listbox:

 

A simple XPage to test (SimpleDemo.xsp)

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">

    <xp:radioGroup
        id="radioGroupSimpleDemo"
        defaultValue="1">
        <xp:selectItem itemLabel="1" itemValue="1" />
        <xp:selectItem itemLabel="2" itemValue="2" />
    </xp:radioGroup>


    <xp:listBox id="listBoxSimpleDemo" multiple="true">
        <xp:selectItem itemLabel="1" itemValue="1" />
        <xp:selectItem itemLabel="2" itemValue="2" />
        <xp:selectItem itemLabel="3" itemValue="3" />
    </xp:listBox>
 
</xp:view>

 The JUnit Test

package ch.hasselba.xpages.test.seleniumdemo;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.util.List;
import java.util.concurrent.TimeUnit;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.Select;

public class SimpleDemo {

	private WebDriver driver;
	private String baseUrl = "http://127.0.0.1/WebTestDemo.nsf/SimpleDemo.xsp";
	private StringBuffer verificationErrors = new StringBuffer();

	@Before
	public void setUp() throws Exception {
		driver = new FirefoxDriver();
		driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
	}

	@After
	public void tearDown() throws Exception {
		driver.quit();
		String verificationErrorString = verificationErrors.toString();
		if (!"".equals(verificationErrorString)) {
			fail(verificationErrorString);
		}
	}

	@Test
	public void testDemo() throws Exception {
		reloadPage();
		List elemRadio = driver.findElements(By
				.cssSelector("input[id*='radioGroupSimpleDemo']"));
		assertTrue(elemRadio.get(0).isSelected());
		assertFalse(elemRadio.get(1).isSelected());

		Select select = new Select(driver.findElement(By
				.cssSelector("select[id*='listBoxSimpleDemo']")));
		List listSelect = select.getOptions();
		for (WebElement listElem : listSelect) {
			assertFalse(listElem.isSelected());
			assertTrue(listElem.isEnabled());
		}

	}

	public void reloadPage() {
		driver.get(baseUrl);
	}
}

The Maven pom.xml file

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
    http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>ch.hasselba.xpages.test</groupId>
    <artifactId>seleniumdemo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>seleniumdemo</name>
    <url>http://hasselba.ch</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>2.46.0</version>
        </dependency>
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-api</artifactId>
            <version>2.46.0</version>
        </dependency>
        <dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-core</artifactId>
            <version>1.3</version>
        </dependency>
        <dependency>
            <groupId>pl.pragmatists</groupId>
            <artifactId>JUnitParams</artifactId>
            <version>1.0.4</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>
Veröffentlicht unter Allgemein, Java, Web, XPages | Verschlagwortet mit , , , , , , , | 3 Kommentare

Android Development

While I had a lot of work to do in my daily business, I was still able to complete five of six MOOCs about Android development during the last monthes. The courses were very cool, especially the ones about Concurrency and Security.

Topics covered during the MOOCs:

  • Screen configurations and sizes
  • Activity Class, Intents and Permission, Fragments
  • Designing user interfaces
  • Notifying users about important events
  • Handling concurrency
  • Acquiring data over the network
  • Leveraging multimedia and graphics
  • Incorporating touch and gestures
  • Working with sensors
  • Android Layers
  • Java Threading Mechanisms
  • Java Built-in Synchronization Mechanisms
  • Android Concurrency Framework Classes
  • Android Looper
  • Android Handler and HaMeR Framework
  •  The AsyncTask Framework
  • Blackbox and Whitebox Frameworks with AsyncTask
  • Monitor Object Pattern
  • Thread-Specific Storage Pattern
  • Command Processor Pattern
  • Active Object Pattern
  • Proxy Pattern
  • Broker Pattern
  • Half-Sync/Half-Async Pattern
  • Started and Bound Services
  • Activity and Service Communication
  • Service to Activity Communication Using Android Messenger
  • Android IntentService
  • Programming Bound Services with Messengers
  • The Android Interface Definition Language (AIDL)
  • Privilege Escalation Concepts
  • Spring, Configuration Annotations, Dependency Injection and Spring Security
  • OAuth
  • Retrofit Client
  • Android Content Providers and Content Resolvers
  • SQLite
  • and much more…

Thanks to Dr. Adam Porter, Dr. Douglas C. Schmidt and Dr. Jules White. It was very interesting and I learned a lot.

Coursera androidpart1 2015

Coursera androidpart2 2015

Coursera posacommunication 2015

Coursera posaconcurrency 2015

Coursera mobilecloudsecurity 2015

Veröffentlicht unter Android | Verschlagwortet mit , | 1 Kommentar

XPages: A ClientSide State

I have created a ClientSide State for XPages, which allows horizontal scaling of XPages applications with a single click.

After installing the OSGi Plugin on the servers and the DDE, you can activate it with a single click:

2015-09-13 20_41_02-XPage Properties Editor - ClientStateDemo - IBM Domino Designer

Then, the State of the XPages application view is stored on client side (in the field „$$clientstate„), and not on the server anymore. The State is AES-128 encrypted and uses some random bytes for a higher security.

2015-09-13 20_52_11-Quelltext von_ http___localhost_ClientStateDemo.nsf_Test.xsp

You can find the code on GitHub.

P.S.

Parts of the code are shamelessly stolen from Jesse.

Veröffentlicht unter OSGi, Server, XPages | Verschlagwortet mit , , , | 7 Kommentare

The XPages EL Directory

I am currently working on an overview of available objects and properties for XPages Expression Language. A first incomplete and horrible designed version can be found here.

 

Veröffentlicht unter Expression Language, XPages | Verschlagwortet mit , , | 2 Kommentare