Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

2014/09/21

Lookup Methods in Enums

There is often the need to map numeric values of a Java enum to the enum instances, aka lookup.
It seems as a simple task yet I saw and even used different approaches until finally came with something acceptable. Below is short comparison of witnessed approaches, ending with what I see as the best one.



First the list approaches I tried (or witnessed) and refused.
In the following examples the numeric value to look-up is in variable code, method getCode() returns the numeric value of the enumeration instance.

Rummaging Through the Values Using For Loop

for(EnumType value : values)
{ 
  if (value.getCode()==code) { return value; } 
}

Pros: zero maintenance
Cons: waste of cycles

Look-up Values Hard-Coded in the Switch Statement

public static EnumType fromInt (int code) 
{
  EnumType result = UNKNOWN; // fallback value
  switch (code)
  {
    case 1: result = ENUM_ONE; break;
    //... 
  }
  return result;
}

Pros: fast lookup
Cons: needs maintenance, needs test for assuring the conversion is reflexive (all known values are converted to proper instances)

Storing Values in Hard-Coded Map

private static Map<Integer,EnumType> lookupMap = new HashMap<>()
static 
{
  lookupMap.put(1,ENUM_ONE);
  lookupMap.put(2,ENUM_TWO);
}

public static EnumType fromInt (int code) 
{
   return lookupMap.get(code);
} 
 
Pros: fast lookup
Cons: needs maintenance


Using Load-Time Constructed Map

The solution merges fast lookup with zero maintenance - it is based on a Map populated with values in static initialization block. This is possible to do for enums as at the moment when the map is going to be filled, all the enum constants are already instantiated (guaranteed by JVM).
private static Map<Integer,EnumType> lookupMap;

static
{ 
  EnumType[] values = values();
  lookupMap = new HashMap<Integer,EnumType>(values.length);
  for (EnumType value : values)
  {
    lookupMap.put(value.getCode(),value);
  }
}

public static EnumType fromInt (int code) 
{
   return lookupMap.get(code);
}

2014/05/12

Testing REST Service in Spring Boot with RestTemplate

I have decided to add my bit to Spring Boot's well-deserved popularity -- one must appreciate how fast you can create a simple application without compromising the design.

Of course, if you take your work seriously there is no way you can get by without  tests. An example is better than hours of explaining -- below you see testing of real service (no mocks) running locally:
  • in first case sending POST request to create a new record and creating an object to from the response
  • in second case GET request is send and the failure message is treaded as "raw" JSON


import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.IntegrationTest;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.boot.test.TestRestTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.util.Collections;

import static org.hamcrest.Matchers.*;
import static org.springframework.test.util.MatcherAssertionErrors.assertThat;


@RunWith (SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration (classes = Config.class)
@WebAppConfiguration
@IntegrationTest
public class UserControllerTest
{
  final String BASE_URL = "http://localhost:9999/customer/";

  @Test
  public void shouldCreateNewUser() {

    final String USER_NAME = "Leif Ericson";
    final String USER_ADDRESS = "Vinland";

    User user = new User();
    user.setName(USER_NAME);
    user.setAddress(USER_ADDRESS);

    RestTemplate rest = new TestRestTemplate();

    ResponseEntity<User> response = 
       rest.postForEntity(BASE_URL, user, User.class, Collections.EMPTY_MAP);
    assertThat( response.getStatusCode() , equalTo(HttpStatus.CREATED));

    User userCreated = response.getBody();
    assertThat( userCreated.getId() , notNullValue() );
    assertThat( userCreated.getName() , equalTo(CUSTOMER_NAME) );
    assertThat( userCreated.getAddress() , equalTo(CUSTOMER_ADDRESS) );
  }

  @Test
  public void shouldFailToGetUnknownUser()
  throws IOException {

    final int UNKNOWN_ID = Integer.MAX_VALUE;
    final String EXPECTED_ANSWER_MESSAGE = "user with id : '" + UNKNOWN_ID+ "' does not exist";

    RestTemplate rest = new TestRestTemplate();

    ResponseEntity<String> response = rest.getForEntity(BASE_URL + UNKNOWN_ID, String.class);

    assertThat( response.getStatusCode() , equalTo(HttpStatus.NOT_FOUND));

    ObjectMapper objectMapper = new ObjectMapper();
    JsonNode responseJson = objectMapper.readTree(response.getBody());
    JsonNode messageJson = responseJson.path("message");

    assertThat( messageJson.isMissingNode() , is(false) );
    assertThat( messageJson.asText() , equalTo(EXPECTED_ANSWER_MESSAGE) );
  }
}

2013/06/05

Resolving Properties With Spring

It is a well known (and not surprising at all) fact, that you can use properties in Spring. You can reference them in you application context configuration file(s), or by the new Spring 3 @Value annotation.

In the XML config the reference to the property named "x.y.z" this simple: 
<bean name="theBean" class="myBean">
  <property name="parameter" value="${x.y.z}" /> 
</bean>

This is usually accompanied by the element from context namespace setting the name of the configuration file:
<context:property-placeholder location="classpath:app.properties"/>

This is good approach for simple scenarios. In a more complex setup things can get a bit unwieldy. 

First of all each occurrence of <context:property-placeholder> element causes creation of a new instance of the class responsible for property names resolving - PropertyPlaceholderConfigurer instance. You can enjoy lot of fun with unresolved placeholders in your application, once the library you're using brings its application context configuration containing <context:property-placeholder>. Even if you set ignoreUnresolvablePlaceholders=false for the element, it does not change the fact you have multiple PropertyPlaceholderconfigurers where you need only one.

You may want to the properties loaded by Spring to a Spring unaware class or further customize the property resolving. In such case you'll create a custom PropertyPlaceholderConfigurer ... and get more collisions with default ones created by the <context:property-placeholder>. 

Custom PropertyPlaceholderConfigurer


The solution is simple, remove all the occurrences of <context:property-placeholder> and create a custom PropertyPlaceholderConfigurer, that will fulfill your desires. Example of one is below. The static method getProperty() can serve properties to Spring unaware code.

import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import java.util.*;

class MyPropertyResolver extends PropertyPlaceholderConfigurer
{

    private static Map<String, String> propertiesMap = new HashMap<String, String>();

    @Override
    protected void processProperties
    (ConfigurableListableBeanFactory beanFactory, Properties properties)
    {
        super.processProperties(beanFactory, properties);
        for ( Object propertyKey : properties.keySet())
        {
            propertiesMap.put
            (
               propertyKey.toString(),
               // Spring 3.x
               resolvePlaceholder(propertyKey.toString(), properties)
               // for Spring 2.5 :
               // parseStringValue(propertyKey.toString(), properties, Collections.EMPTY_SET)
            );
        }
    }

    public static String getProperty(String name)
    {
        return propertiesMap.get(name);
    }
}
 
Following configuration of bean named appProperties provides setup for multiple property files - the last one is the application property file overriding default values provided by libraries. Option ignoreResorceNotFound=true ensures that the missing files are not taken for an error.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <!-- load it early, provides properties to other classes -->
    <bean id="appProperties" class="MyPropertyResolver">
        <property name="ignoreResourceNotFound" value="true"/>
        <property name="locations">
            <list>
                <!-- Ordering matters, properties in the later loaded files 
                     override values from the previous files -->
                <value>classpath:lib.properties</value>
                <value>classpath:app.properties</value>
            </list>
        </property>
    </bean>

</beans>

Adding to an Application Context


The last thing you need to do to make it working is to put the bean into your application context and use it. Following setup for a web application ensures that the bean is instantiated ASAP during application context initialization.
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" version="2.4" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
                             http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> 

  <context-param> 
    <param-name>contextConfigLocation</param-name> 
    <param-value> 
      classpath:spring-resources.xml 
      ... 
    </param-value> 
  </context-param> 

</web-app>

For command-line application it's very simple too:
ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(
                                            new String[] {"spring-resources.xml"});
MyPropertyResolver resolver = (MyPropertyResolver) appContext.getBean("appProperties");

2013/03/27

Renamed Logback Config File for Web Application

There are four frameworks frequently used for logging in Java - java.util.logging aka JUL, Apache Commons Logging aka JCL, log4j 1.x, and slf4j. I had "luck" to find them all used by a single web application.

It was impossible to tell what component uses what logging API for what messages. To make the logging manageable I modified the code base to use SLF4J API with Logback - changes to several places in code were made and bridges were added for third-party libraries.

The last request was to name the configuration file uniquely so it can be in the same directory with configuration files for other applications. The problem is Logback  is not particularly  flexible when it comes to the naming of its config files - it looks for logback.groovy,  for logback-test.xml, logback.xml and then fails with JoranException.

According to documentation, there is a system property logback.configurationFile that allows to set a different name for the file.

It can be set on a command line (java -Dlogback.configurationFile=/path/to/config.xml), but that is not what you want or can use for a web application. Usual way how to pass settings to a web application is to use <context-param> in web.xml:
<context-param>
  <param-name>logback.configurationFile</param-name>
  <param-value>custom-logback.xml</param-value>
</context-param> 

The problem is that servlet context parameters are not copied into system properties, so SLF4J ContextInitializer ends up looking for the "usual suspects"  and then gives up:

ContextInitializer.autoConfig()
     -> findURLOfDefaultConfigurationFile()
         -> findConfigFileURLFromSystemProperties()
            // logback.configurationFile is not a system property, returns null:    
            -> OptionHelper.getSystemProperty(CONFIG_FILE_PROPERTY)
         -> getResource("logback.groovy")
         -> getResource("logback-test.xml")
         -> getResource("logback.xml")
         : returns null 
      -> 3/ BasicConfigurator.configure(loggerContext)



The solution is to get the  context-param as soon as possible during web application initialization and pass it to JoranConfigurator. You have to implement custom ServletContextListener and put the logic inside contextInitialized method:

public class CustomServletContextListener 
implements ServletContextListener 
{
  @Override
  public void contextInitialized(ServletContextEvent contextEvent) 
  { 
    String logbackConfigFile = contextEvent.getServletContext().getInitParameter("logback.configurationFile"); 
    URL configFileURL;
    if (logbackConfigFile != null) 
    { 
      configFileURL = Thread.currentThread().getContextClassLoader().getResource(logbackConfigFile);
      if (configFileURL != null)
      {
        JoranConfigurator configurator = new JoranConfigurator(); 
        LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory(); 
        loggerContext.reset(); 
        configurator.setContext(loggerContext); 
        try { configurator.doConfigure(configFileURL); } 
        catch (JoranException ex) { throw new RuntimeException(ex); } 
      }
    }
  } 
To be sure the initialization happens as soon as possible, put the context listener to the top of the listeners list in web.xml:
<listener>
  <listener-class>org.bithill.CustomServletContextListener</listener-class>
</listener>

2012/10/21

Accessing Oracle User-Defined Type with Spring JDBC

It's not so long I wrote some single-purpose utility which called a stored procedure in Oracle database. The procedure returned as its result an user-defined data type.

Definition of the type looked approximately as this one:

CREATE OR REPLACE TYPE Summary as OBJECT 
( 
  ID Number(10),
  Sum1 NUMBER(20,3),
  Sum2 NUMBER(20,3)

  CONSTRUCTOR FUNCTION Summary RETURN SELF AS RESULT
);

I could have specified the mappings between Oracle object and Java class by implementing the SQLData interface, the approach supported by Spring Data. But I had only Spring JDBC available so I used the SqlReturnType.

First Maven dependencies:

<?xml version="1.0" encoding="UTF-8"?>
<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>org.bithill.projectx</groupId>
 <artifactId>MyTestUtil</artifactId>
 <version>1.0</version>

 <dependencies>

  <dependency>
    <groupId>com.oracle.oracle</groupId>
    <artifactId>ojdbc14</artifactId>
    <version>10.2.0.4</version>
  </dependency>

  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>3.0.7.RELEASE</version>
  </dependency>

 </dependencies>
   
</project> 
 
The utility to read the data is really simple - just load the driver, define the SimpleJdbcCall and call it and get the result. Only thing you have to remember,is to register the hendler for the user-defined type.

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.SqlOutParameter;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import java.sql.SQLException;

import static java.lang.System.out;
import static oracle.jdbc.OracleTypes.*;

public class Main
{
   public static void main (String... args) throws SQLException 
   {
      String connectionString = args[0]; // JDBC URL

      DriverManagerDataSource ds = new DriverManagerDataSource();
      ds.setDriverClassName("oracle.jdbc.OracleDriver");
      ds.setUrl(connectionString);

      SimpleJdbcCall sumProcCall = new SimpleJdbcCall(new JdbcTemplate(ds))
        .withSchemaName("SCHEMA").withCatalogName("PKG")
        .withProcedureName("GET_SUMMARY")
        .declareParameters
        (
          // IN params
          new SqlParameter("P_Id", NUMBER),
          new SqlParameter("P_OrgUnit", VARCHAR),

          // OUT params
          new SqlOutParameter("P_Summary", STRUCT, "SUMMARY", new SummaryHandler() ),
          new SqlOutParameter("P_err_msg", VARCHAR),
          new SqlOutParameter("P_err_code", NUMBER)
        );

       (Summary)sumProcCall.execute
       ( Integer.valueOf(1),"ou.subsidiary1").get("P_Summary");

} 
 
Here is the type handler converting the raw information from Oracle's STRUCT to a Java class.

import oracle.sql.STRUCT;
import org.springframework.jdbc.core.SqlReturnType;

import java.sql.CallableStatement;
import java.sql.SQLException;

public class SummaryHandler implements SqlReturnType
{
    // struct data from jdbc
    private Object[] data;

    public Object getTypeValue(CallableStatement cs, int paramIndex, int sqlType, String typeName)
    throws SQLException
    {
        data = ((STRUCT)cs.getObject(INDEX_OF_SUMMARY_PARAMETER)).getAttributes();

        Summary result = new Summary
        (new SummaryLine( (BigDecimal)data[0]) /*, ...*/);

        return result;
    }
}

2012/04/09

Using Smart Card as Keystore in Java, signing

This is the promised sequel of the article from September 8th 2011.
It does not represent the only one way how to achieve the desired result, especially when it comes to manipulation with certificates and keys certificate management.

Loading Certificate into the Card


It seems that the easiest approach is to prepare the key store on disk and load it  into the card when ready. For that we use mostly two tools - openssl to transform keys and certificates and keytool to manage the key store.

Create the key store on disk and fill with certificates

Create a private key entry, i.e. a certificate containing a private key, by converting our certificate and private key to PKCS12 format: openssl pkcs12 -export -out cert.p12 -in cert.pem -inkey key.pem

I used org.apache.commons.ssl.KeyStoreBuilder to build a keystore from the p12 file. The password is used both for decryption of private key and encryption of the newly created Java key store. 
java -cp commons-ssl.jar org.apache.commons.ssl.KeyStoreBuilder password cert.p12

Now you can check the content of the file-based key store: keytool -keystore newkeystore.jks -list

Load the file-base key store into the card

keytool -keystore NONE -storetype PKCS11 -providerName SunPKCS11-OpenSC-PKCS11 -importkeystore -srckeystore newkeystore.jks

Check the content of the on-card key store.
keytool -keystore NONE -storetype PKCS11 -providerName SunPKCS11-OpenSC-PKCS11 -list

Signing and Verification with the On-Card Certificate


All the error handling was intentionally removed to make following example shorter. I also skipped creation of PKCS7 signed messages - you can you Bouncy Castle CMSSignedDataGenerator for that easily.

import java.security.*;
import java.security.cert.*;
import java.security.cert.Certificate;
import java.io.*;

...

// loading the key from file:
KeyStore keyStore = KeyStore.getInstance("JCEKS");
FileInputStream inputStream = new FileInputStream(storeFileName);
keyStore.load(inputStream, storePassword.toCharArray());
KeyStore.ProtectionParameter protectParameter = new KeyStore.PasswordProtection(certPass.toCharArray()); }

// loading the key from token:
KeyStore keyStore = KeyStore.getInstance("PKCS11");
KeyStore.ProtectionParameter protectParameter = null;
keyStore.load(null, storePassword.toCharArray());

// the rest does not depend on the type of the store: 
String signatureAlgorithmName = "SHA1withRSA";
KeyStore.Entry entry = keyStore.getEntry(alias, protectParam);
boolean isPrivateKeyEntry = keyStore.entryInstanceOf(alias, KeyStore.PrivateKeyEntry.class);
if (isPrivateKeyEntry)
{
  Signature signatureAlgorithm = Signature.getInstance(signatureAlgorithmName);

  // signing
  KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)entry;
  PrivateKey privateKey = privateKeyEntry.getPrivateKey();  
  signatureAlgorithm.initSign (privateKey);
  signatureAlgorithm.update (message);
  byte[] signature = signatureAlgorithm.sign();

  // verification
  Certificate[] chain = privateKeyEntry.getCertificateChain();
  X509Certificate certificate = (X509Certificate) chain[chain.length-1];
  PublicKey publicKey = certificate.getPublicKey();
  signatureAlgorithm.initVerify(publicKey);
  signatureAlgorithm.update (data);
  boolean verified = signatureAlgorithm.verify(signature);
}

2012/02/23

Maven: Creating Executable JAR with Shade Plugin

I was pleasantly surprised by versatility of Maven shade plugin. Creating a custom-named executable JAR and bundle only the dependencies you really need is a piece of cake. The documentation is partly is online, partly in the plugin's help and provides all necessary information.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-shade-plugin</artifactId>
  <version>1.5</version>
  <executions>
     <execution>
       <phase>package</phase>
       <goals><goal>shade</goal></goals>
       <configuration>
         <outputFile>target/tool.jar</outputFile>
         <artifactSet>
           <includes>
              <include>org.springframework:spring-core</include>
              <include>org.springframework:spring-beans</include>
           </includes>
         </artifactSet>
         <transformers>
           <transformer 
             implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
             <mainClass>org.bithill.example.Tool</mainClass>
           </transformer>
         </transformers>
       </configuration>
     </execution>
  </executions>
</plugin>

2011/11/20

Book Review: Apache Maven 3 Cookbook

I have decided to review new book about Maven from Packt Publishing: Apache Maven 3 Cookbook by Srirangan promising on its cover "Quick anwers to common problems".

The book is divided to nine chapters:
  1. basics
    Maven installation and environment settings. Generating, compiling and testing simple project. POM structure, build lifecycle and profiles.
  2. software engineering techniques
    Modularization, dependency management, static code analysis, JUnit, Selenium.
  3. agile team collaboration
    Nexus, Hudson, version control, offline mode.
  4. reporting and documentation
    Mvn site, javadocs, test and code quality reports, dahsboard.
  5. Java development
    Building and running web application (jetty), JEE, Spring, Hibernate, Seam.
  6. Google development
    Android, GWT, App Engine.
  7. Scala, Groovy and Flex
  8. IDE integration
    Eclipse, NetBeans, Intellij IDEA
  9. extending Maven
    plugin development basics
The book is certainly not material for beginners. Some terms are used without former definition or even explaining. Experienced Maven users will already know or will be able to find the missing pieces but beginners must be terribly confused. I think providing at least a description of Maven's standard directory layout for project or repository would be beneficial.

It is not so much about Maven as I expected, and says nothing about what is new in Maven 3. It should be exhaustive at least in the purely Maven parts, but even there is not enough information to make me happy. I would expect a description of template languages in the part dedicated to site plugin.

If you like puzzles and do not mind to use internet to search for missing pieces or you just cannot recall some setting covered in the book, you will like the book. It can also be used as a good starting point to show what tools, frameworks or languages can be used from/with Maven - do you like Maven and wanted to try GWT or Scala ? The book helps to lower entrance barrier by providing examples how to get working "playground" project in no time.

Would I buy it ? No. My bookcase has limited capacity and since the necessity to use internet to fill the gaps or correct bugs (although not many) in the book, I will be better with the online sources only.

2011/11/06

Shortcuts in Eclipse / Intellij Idea

I decided to publish this long ago started list of keyboard shortcuts for Eclipse and Intellij Idea to make the transition from one IDE to the other one easier for my colleague. I hope it will be useful for other developers in similar situation too. Where you see only one shortcut in the list, it means it is identical in both IDEs.

List Shortcuts: Ctrl+Shift+L / ? (Help - Default Keymap Reference)
Search Actions: ? / Ctrl+Shift+A

Editor


Select All: Ctrl+A
Reformat: Ctrl+Shift+F / Ctrl+Alt+L
Open File By Name: Ctrl+Shift+R / Ctrl+Shift+N
Open Class By Name: Ctrl+Shift+T / Ctrl+N
Go to Matching Bracket:  Ctrl+Shift+P / Ctrl+{, Ctrl+}
Paste from Clipboard Stack: ? / Ctrl+Shift+V
Vertical Blocks: ? / Alt+Shift+Insert

Code Navigation and Manipulation

Navigate Forward in History: Alt+right arrow / Ctrl+Alt+right arrow
Navigate Backward in History: Alt+left arrow / Ctrl+Alt+left arrow

Go to Line: Ctrl+L / Ctrl+G

Delete Line: Ctrl+D / Ctrl+Y

Open Documentation: "mouse over" / Ctrl+Q
Open Declaration: F3 / Ctrl+B
Open Hierarchy: F4 / Ctrl+H
Find Implementation: ? / Ctrl+Alt+ B

Find Usages: Ctrl+Alt+G / Alt+F7
Usages Pop-Up: ? / Ctrl-Alt-F7

Code Completion: Ctrl+Space
Optimize Imports: Ctrl+Shift+O / Ctrl+Alt+O
List of Methods to Override/Implement: ? / Ctrl+O
Generate...: Ctrl+Shift+G / Alt+Insert

Comment LineCtrl + /
Comment BlockCtrl + Shift + /

Code FoldCtrl+"numpad +"  / or Ctrl+"+" 
Code UnfoldCtrl+"numpad -"  /  Ctrl+"-" 

Move Code Up: Alt+Up / Ctrl+Shift+Up
Move Code Down: Alt+Down / Ctrl+Shift+Down 

Create Test: ? / Ctrl+Shift+T

Refactoring

Rename: Alt+Shift+R / Shift+F6
Extract Method: Alt+Shift+M / Ctrl+Alt+M
Introduce Variable: Ctrl+Shift+M / Ctrl+Alt+V

Search

In Current File: Ctrl+F
In All Files: Ctrl+H / Ctrl+Shift+F

Version Control

Commit Changes: Alt+C / Ctrl+K
Update: Alt+U / Ctrl+T
VCS Popup: ? / Alt+` (back qoute)

Windows

Maximize: Ctrl+M / Ctrl+Shift+F12

Debugging

Debug: F11 / Shif+F9
Step Into: F5 / F7
Selective/smart Step Into:  Ctrl+F5 / Shift+F7
Step Over: F6 / F8
Step Out: F7 / Shift+F8
Resume: F8 / F9

Evaluate Expression: Ctrl+Shift+I / Alt+F8

Jump To Caller: ? / Ctrl+Alt+F7
Show the Caller Hierarchy:  ? / Ctrl+Alt+H

I want to continually update this list depending on what IDE I use - if you have anything that should be added to the list or you know replacement for some question mark in it, let me know. Thanks to all who already contributed.

2011/10/17

Remarkable Changes in Past Versions of Selenium 2 WebDriver

For a long time I kept the code base of our tests running on Selenium 2.0a6. The reasons for not upgrading were different for different Selenium 2 versions - perceived stability problems in InternetExplorer or Firefox, changes being not to enough beneficial for our tests and sometimes even lack of time for the change.

Now it seems Selenium 2.8 is a good candidate for upgrade.  Following enumeration summarizes the changes we waited for and I want to use it as a thanks to all the Selenium 2 developers who participated in the effort. I also hope it wil help to anybody upgrading or considering the upgrade to a newer Selenium 2 .

1/  RenderedWebElement deprecated and removed in 2.0rc3,  method isDisplayed() was moved to WebElement class.

2/ Mouseover works since 2.0 RC2:

import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.interactions.Action;
Actions builder = new Actions(driver);
Action hoverAction = builder.moveToElement(mouseOverElement).build();
hoverAction.perform();

3/ For some time it was necessary to send Enter to a button in MSIE to press it,
but since version 2.2 clicking on buttons (WebElement.click()) seems to work flawlessly.

4/ Version 2.3 brought the nice Alert class for confirmation and alert dialogs, rendering thus JavaScript workarounds obsolete:

package org.openqa.selenium;
public interface Alert
{
  void dismiss();
  void accept();
  String getText();
  void sendKeys(String keysToSend);
}

the usage:

Alert prompt = driver.switchTo().alert();
// some short sleep here
log.debug( prompt.getText() );
prompt.sendKeys("AAA");
// some short sleep here
prompt.accept();

5/ And finally, since 2.8 important parts of the advanced interactions, double-click and right-click, work both for MSIE end FF (since 2.5for MSIE):

Actions builder = new Actions(driver);
Action doubleClick = builder.doubleClick(element).build();
doubleClick.perform();

Actions builder = new Actions(driver);
Action rightClick = builder.contextClick(element).build();
rightClick.perform();