waffel’s Weblog

Februar 27, 2013

testing REST interface with Spring 3.2 and a session scoped bean

Einsortiert unter: java,spring — Thomas Wabner @ 8:00 nachmittags
Tags: , , , , , , , , ,

There are some nice articles around the “spring 3.2 testing capabilities” like the spring documentation itself, this blog and this blog.

I wanted to not only test one request/response action against my REST interface. I wanted to simulate and test more of a conversation as it typical happens in the UI.

Following REST interface I wanted to create and test:

@RequestMapping("/customer")
public interface RESTCustomer {

@RequestMapping(
method = RequestMethod.POST)
@ResponseBody
Customer create(@RequestParam("firstname") final String firstname,
@RequestParam("lastname") final String lastname);

@RequestMapping(
method = RequestMethod.DELETE)
@ResponseStatus(HttpStatus.OK)
void delete(@RequestParam("id") final String... customerIds);

@RequestMapping(
produces = MediaType.APPLICATION_JSON_VALUE,
method = RequestMethod.GET)
@ResponseBody
Collection<Customer> getAll();

@RequestMapping(
value = "/update",
method = RequestMethod.POST)
@ResponseBody
Customer update(@RequestParam("id") final String id, @RequestParam("firstname") final String firstname);

}

Following test steps I had in mind, to test the create method:

  1. Get a list of all customers and remember the count
  2. Create a new customer
  3. Check, that the ID of the returning Customer was updated
  4. Get again a list of all customers
  5. Check the size of the customer list before and after creation … they should differ between one entry/li>

The new Spring Framework version 3.2 introduced some nice feature to do REST testing with minimal effort.

To test such conversion, you need beside the WebApplicationContext a MockHttpSession which has to be used between different mockMvc calls, on one test case.

The following base test structure is required:

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(
  classes = {
    MyConfig.class,
  })
public class RESTCustomerTest {
  
@Autowired
  private WebApplicationContext wac;

  @Autowired
  MockHttpSession session;

  MockMvc mockMvc;

  ObjectMapper jsonObjectMapper;

  @Before
  public void setup() {
    mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
    jsonObjectMapper = new ObjectMapper();
  }

  @Test
  public void testCreate() throws Exception {
    ....
  }
}

Let assume, there is an implementation of the RESTCustomer service interface like this:


@Component
public class CustomerResource implements RESTCustomer {

  private final PlatformService service;

  @Autowired
  public CustomerResource(final PlatformService service) {
    this.service = service;
  }

  @Override
  public Customer create(final String firstname, final String lastname) {
    ...
    return service.createCustomer(firstname, lastname);
  }

  @Override
  public Collection<Customer> getAll() {
    ...
    return service.getAllCustomers();
  }

}

Assume also, that the autowired PlatformService is a Session scoped bean (somewhere configured inside the spring configuration).

Now our testing method can be like this:


  int countCustomers() throws Exception {
    final MvcResult mvcResult = mockMvc.perform(get("/customer").session(session).accept(MediaType.APPLICATION_JSON))
        .andReturn();
    final Collection<Customer> customers = getRawObjects(mvcResult);
    return customers.size();
  }

Collection<Customer> getRawObjects(final MvcResult mvcResult) throws Exception {
    return jsonObjectMapper.readValue(mvcResult.getResponse().getContentAsString(),
        new TypeReference<Collection<Customer>() {
        });
  }

Customer getRawObject(final MvcResult mvcResult) throws Exception {
    return jsonObjectMapper.readValue(mvcResult.getResponse().getContentAsString(),
        new TypeReference<Customer>() {
        });
  }

  @Test
  public void testCreate() throws Exception {
    // get default customer list and count
    final int originalCustomerSize = countCustomers();

    // create new customer
    final MvcResult mvcResult = mockMvc
        .perform(
            post("/customer/?firstname={firstname}&lastname={lastname}","testFirstname", "testLastName").session(session).accept(
                MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andReturn();
    final Customer customerObject = getRawObject(mvcResult);
    assertNotNull("id of new customer should not empty", customerObject.get("id"));
    assertEquals("newly firstname should match", "testFirstname", customerObject.get("firstname");

    // again get list of all customers and check, if one more is available
    assertEquals("after new customer was created, the size should be one more", originalCustomerSize + 1, countCustomers());
  }

To get such conversation to work, you need to pass the session with .session(session) between the mockMvc calls. Else, every new mockMvc call creates a new session and your test fail.

REMEMBER: The trick is to pass the autowired MockHttpSession between the mock MVC requests.

März 28, 2011

Run eclipse RCP application via WebStart

Einsortiert unter: java — Thomas Wabner @ 7:07 nachmittags
Tags: , , , , , , , ,

The last days I need to create a small prototype to demonstrate how to start a eclipse RCP application via webstart. After reading many tutorials and tipps I have now a working setup which I want to share with you.

The main tutorial which I followed was the eclipse help itself. But there are some hidden points which are important to respect.

Lets start:

You need 4 Projects:

  • Eclipse RCP plugin
  • Feature for the plugin
  • Wrapping feature for webstart
  • entry or start JNLP file

At least you need an webserver which can deliver your files.

Create eclipse RCP plugin with a example RCP application provided by eclipse:

This plugin will provide the RCP application with a small demo UI. In a larger project you will normally have more than one plugin. But for demonstration proposed this would be enough.

  1. From the eclipse main menu, go to File > New > Project… (the New Project wizard opens), select Plugin-in Development > Plug-in Project
  2. Press Next > enter “org.test.webstart.demo.plugin” as Project name
  3. Press Next > change the Version to “0.1.0″
  4. Press Next > select RCP application with an view > press Finish

At this point you should have a small RCP “application” which can started from eclipse. Select the project root > select Run from the menu > select Run As > Eclipse Application. Now you should see the demo UI.

Next we need a Eclipse feature project which uses the plugin.

Create eclipse feature which contains the plugin and a reference to the eclipse rcp feature:

We need a feature which depends on the demo plugin and on the eclipse rcp feature. The dependency to the eclipse rcp feature is required to export later all required plugins and features for webstart, to run the complete rcp application.

  1. In the eclipse main menu go to File > New > Project… (the New Project Dialog opens), select Plug-in Development > Feature Project
  2. Press Next > enter “org.test.webstart.demo.feature” as project name > change the Version to “0.1.0″
  3. Press Next > select “org.test.webstart.demo.plugin” from plug-ins list > press Finish

The feature editor opens. Now you need to add the eclipse rcp feature as included feature. To do so select Included Feature tab in the feature editor > add “org.eclipse.rcp” as feature. Save and close the feature editor.

This feature contains now all you need to run your application as a full featured eclipse RCP application. Now we need another wrapping feature to get the Webstart launcher on board.

Create wrapping feature for webstart

This feature will be used to export all required JAR files with the eclipse java webstart exporter into a local filesystem.

  1. From the eclipse main menu select File > New > Project… (the New Project Dialog opens), select Plug-in Development > Feature Project
  2. Press Next > enter “org.test.webstart.demo.wrapperfeature” as project name > change the Version to “0.1.0″
  3. Press Finish. The feature editor opens.

Now we need a dependency to the equinox launcher plugin and include our own feature.

  1. In the feature editor select the Plug-ins tab > add “org.eclipse.equinox.launcher”.
  2. Select the Included Feature tab > add “org.test.webstart.demo.feature” > save the editor.
  3. From the project root select the eclipse main menu > select File > Export… > select Deployable Features (the export wizard opens)
  4. Press Select All
  5. In the Desitination tab select a directory where you want to export the JAR and JNLP files.
  6. In the Options tab only select Package as individual JAR archives. If you select Generate metadata repository nothing will be exported!
  7. In the JAR Signing tab fill in all fields with the information from your keystore. If you do not have an keystore you can create your own by follow these instructions.
  8. In the Java Webstart tab select Create JNLP manifests for the JAR archives > add the Site URL like http://localhost:8080/demoui-webstart > set 1.5+ for the JRE version > pess Finish

Now you should have in your destination folder a folder structure like
– features
– plugins

Under the features folder you should have some JNLP files. Because of an error in the eclipse exporter you need to adjust the JNLP files. For example the JNLP file of the feature looks like:

<?xml version="1.0" encoding="UTF-8"?>
<jnlp spec="1.0+" codebase="http://localhost:8080/demoui-webstart">
	<information>
		<title>Demo_rcp_feature</title>
		<offline-allowed/>
	</information>
	<security>
		<all-permissions/>
	</security>
	<component-desc/>
	<resources>
		<j2se version="1.5+" />
	</resources>
	<resources>
		<extension href="features/org.eclipse.rcp_3.5.2.R35x_v20100119-9SA0FxwFnoCU5XxWItFdXXb27BA6.jnlp" />
		<jar href="plugins/demo_rcp_0.1.0.201103241351.jar"/>
	</resources>
</jnlp

You need to change the tag and add the required vendor information. The resulting information tag should look like

	<information>
		<title>Demo_rcp_feature</title>	
		<vendor>Me</vendor>
		<offline-allowed/>
	</information

You need to do this for all JNLP files in the features folder!

Create start.jnlp file as the entry point for the web application

As a final step you need to create your entry JNLP file which is the starting point of your webstart application. Here is an example for start.jnlp:

<?xml version="1.0" encoding="UTF-8"?>
<jnlp 
    spec="1.0+" 
    codebase="http://localhost:8080/demoui-webstart" 
    href="start.jnlp"> 
  <information>
    <!-- user readable name of the application -->
    <title> Demo UI Application </title>  
    <!-- vendor name -->
    <vendor>Me</vendor>
    <!-- vendor homepage --> 
    <homepage href="http://www.me.org" /> 
    <!-- product description -->
    <description>description</description> 
    <offline-allowed/>
  </information>
 
  <!--request all permissions from the application. This does not change-->
  <security>
    <all-permissions/>
  </security>
 
  <!-- The name of the main class to execute. This does not change-->
  <application-desc main-class="org.eclipse.equinox.launcher.WebStartMain">
    <argument>-nosplash</argument>
  </application-desc>
 
  <resources>
    <!-- Reference to the launcher jar. The version segment must be updated to the version being used-->
    <jar href="plugins/org.eclipse.equinox.launcher_1.0.201.R35x_v20090715.jar"/>
 
    <!-- Reference to all the plugins and features constituting the application -->
    <!-- Here we are referring to the wrapper feature since it transitively refers to all the other plug-ins  necessary -->
    <extension 
        name="Wrapper feature"
        href="features/
org.test.webstart.demo.wrapperfeature_0.1.0.jnlp"/>
 
    <!-- Information usually specified in the config.ini -->
    <property 
        name="osgi.instance.area" 
        value="@user.home/Application Data/demoui-rcp"/>
    <property 
        name="osgi.configuration.area" 
        value="@user.home/Application Data/demoui-rcp"/>
    <!-- The id of the product to run, like found in the overview page of the product editor -->
    <property 
        name="eclipse.application" 
        value="org.demo.webstart.plugin.application"/>
  </resources>

  <!-- Indicate on a platform basis which JRE to use --> 
  <resources os="Windows">
    <j2se version="1.5+"/>
  </resources>
  <resources os="Linux">
    <j2se version="1.5+"/>
  </resources>
</jnlp>

Some remarks according the main JNLP file:

You need to adjust (or take care) of the lines 04, 30, 36, 48.

Line 04 defines the codebase. Every time you want to deploy you application on an websever you need to adjust the codebase (in every JNLP file in your project!) to the web application location.

Line 30 depends on you eclipse distribution (I have used eclipse 3.5 with some updates). You have to check the right version in your plugins folder and update the start.jnlp file.

Line 36 defines the starting feature JNLP file. This file itself refers to the other JNLP files in the features folder (which is automatically done from the eclipse exporter). You need to adjust this line if your project name differs from this example.

Line 48 defines the entry point to your application. This is the application ID from the example plugin. You can find the ID if you open the plugin editor of your example plugin. To do so open your example plugin and open the plugin.xml file. Under the tab Overview you can find the ID: “org.demo.webstart.plugin”. Now you also need to open the tab Extensions. Under the Extensions Details you can find the ID of your application. The complete application ID which you need to refer in the JNLP file is then “org.demo.webstart.plugin.application”.

If you now put the main JNLP file and the plugins + features folders under an webserver which delivers the files from http://localhost:8080/demoui-webstart/ you can see your test application. You should have following structure:

- start.jnlp
|– features
|– plugins

Simple click following link: http://localhost:8080/demoui-webstart/start.jnlp

Hint:
A small problem over which I stumbled while developing the example application:

If you start the application and you get from webstart an exception that plugin with *WTP* are not found, you can have a look into the JNLP files in the features folder. Some of these files define resources which are not exported by the eclipse webstart exporter. I have simple removed these resources from the JNLP files and it works.

Update:
I have created a Github repository with some code examples. You may clone my repo or send me patches with corrections.

Additional update:
I have now finished my github example and pushed also a complete working example. If you want to see how it works you can pull the https://github.com/waffel/Wordpress-examples/tree/master/org.waffel.worpress.demo.webstart.result project. With the help of maven you can simple start the application via

mvn jetty:run

This launches the jetty webserver and you can hit your browser to http://localhost:8080/demoui-webstart/start.jnlp

I have done all the mentioned steps from this blog for myself with a eclipse 3.7.

November 18, 2010

disable maven enforcer rule

Einsortiert unter: software — Thomas Wabner @ 6:33 nachmittags
Tags: , , , ,

Apache maven enforcer rules are very useful in large projects. A common usage of such enforcer rules is to define them in a central point like a project parent pom.xml. For example following enforcer definition can be set in a pom parent:

package-parent pom.xml:

...
<plugin>
  <artifactId>maven-enforcer-plugin</artifactId>
     <executions>
       <execution>
         <id>enforce-java-1_4</id>
         <goals>
           <goal>enforce</goal>
         </goals>
         <configuration>
           <rules>
             <requireProperty>
                <property>java.compiler.version</property>
                <regex>1\.4</regex>
                <regexMessage>You must compile with Java 1.4, as long our servers run in old NetWeaver!</regexMessage>
              </requireProperty>
            </rules>
            <fail>true</fail>
         </configuration>
      </execution>
    </executions>
</plugin>
...

This enforcer rule should ensure that all projects, which using the parent POM using a Java 1.4 compiler.

Often such parent pom defines many other useful properties and settings for projects. If you want to use these definition and ONLY want to disable the enforcer rule you can simple do follow “trick”:

...
<parent>
  <groupId>org.waffel</groupId>
  <artifactId>package-parent</artifactId>
  <version>1.1</version>
</parent>

<build>
   <plugins>
     <!-- we need to overide the enforcer rules here because we have java 1.6 and not the  old 1.4 -->
      <plugin>
        <artifactId>maven-enforcer-plugin</artifactId>
        <executions>
          <execution>
            <id>enforce-java-1_4</id>
            <phase>none</phase>
          </execution>
        </executions>
      </plugin>
   </plugins>
</build>
...

I use the same approach here as described in my article how to diable a inherited maven plugin.

September 7, 2010

Columba – Java based EMail-Client honoured by big IT Magazin in Germany

Einsortiert unter: java,software — Thomas Wabner @ 6:27 nachmittags
Tags: , , , ,

As anybody knows I’am a Co-developer for the last years for a Java based EMail client called Columba. Now the program was honoured by the big german IT magazin Heise.

The last moths, there are no more many code changes in the project and I can say the project is dead (from the developer point of view). I have learned many about open source programming, Java coding and got new friends in this project. It was very funny to work on this EMail client!

Now we got after many years good feedback for our work and it is nice to see that the project still have users which are like this kind of EMail client.

August 16, 2010

fixed attachment creation for testopia

Einsortiert unter: software — Thomas Wabner @ 2:37 nachmittags
Tags: , , , , , , ,

Today I found the time to fix a problem in testopia – the mozilla test extention for Bugzilla.

The problem was, that we where unable to attach files to a test case in the testopia extention. After some research I found out, that the tr_attachment.cgi module uses the Testopia:Attachment perl module to do the database stuff.

I have changed the too simple database insert statement to a more secure prepared statement which uses the type BLOB for the contents and it works perfekt.

To get the fixed file you can download it from the original bug 576524.

Februar 16, 2010

howto disable inherited maven plugin

Einsortiert unter: software — Thomas Wabner @ 3:43 nachmittags
Tags: , , , ,

We using in our department a big hierarchy of maven parents (like the apache community does). Some of these parents define useful plugins.

If I want to use the parents (and often this is a good idea, because the parents defining for example version informations for my dependencies), but I do not want to have a specific plugin invoked while I’am using maven, I can simple disable the plugin with follow configuration in my pom.xml:

...
<build>
  <plugins>
     <plugin>
        <artifactId>thePluginArtifact</artifactId>
        <groupId>thePluginGroup</groupId>
        <executions>
           <execution>
              <id>the-execution-id</id>
              <phase>none</phase>
           </execution>
        </executions>
     </plugin>
  </plugins>
</build>
...

The trick how to disable a plugin is to set the phase of the plugin to none.

November 6, 2009

September 8, 2009

bugs fixed for log4cpp

Einsortiert unter: cpp,log4cpp — Thomas Wabner @ 9:08 vormittags
Tags: , , ,

I have fixed some issues for log4cpp and hope I can go forward to clean up all outstanding tracker entries on sourceforge.

Log4cpp is a library of C++ classes for flexible logging to files, syslog, IDSA and other destinations. It is modeled after the Log for Java library (http://www.log4j.org), staying as close to their API as is reasonable.

Overview of fixed bugs:

I have also changed to current development version from 1.0 to 1.1 and hope I can push a bugfix release in the next month’s out.

There is also an interesting article with a good introduction and a small example from Sun.

September 1, 2009

git over https failed to push some refs

Einsortiert unter: git — Thomas Wabner @ 5:38 nachmittags
Tags: , , ,

I have tried to use our main git repository over https but I had gotten error messages like


PUT 54510da55977f5c1e47e5356b996762f4544b90d failed, aborting (22/403)
MKCOL 3b04e830cf4e221491e38443beac0f2f4a2e61c1 failed, aborting (22/403)
PUT 96496dc5f4115e3b9a90757410158f2ba7d12c80 failed, aborting (22/403)
MKCOL af7988694ce7cc8fbfd6b40deffe78d7231cffc8 failed, aborting (22/403)
Updating remote server info
error: failed to push some refs to 'https://myserver.de/myproject.git'

It was hard to discover whats going wrong here. I have set the GIT_CURL_VERBOSE=1 flag to see if there was an communication problem with my server. The communication itself was ok … but the server returns always a 403 (permission denied).

Next I had a look into my apache logs and I had seen follow error messages:


Permission denied: Unable to create a collection.

This looks like a file permission problem. I have setup a new group for my git repository and give apache the rights for read and write. But the problems still occured.

The solution was to set the correct Limit directive in the configuration for my git repository:

Alias /git /usr/var/git
<directory "/usr/var/git">
  DAV filesystem
  Options +Indexes

  AuthType Basic
  AuthName "git repositories"
  AuthUserFile /etc/apache/git.users.auth

  <limit GET PUT POST DELETE PROPPATCH MKCOL COPY MOVE LOCK UNLOCK>
    Require valid-user
  </limit>
</directory>

After a apache reload the push and pull commands working nice.

August 21, 2009

use your own variable in eclipse code templates

Einsortiert unter: java — Thomas Wabner @ 2:08 nachmittags
Tags: , , ,

On my work we develop eclipse plugins and want to add the current bundle id and bundle version to the since field for class comments. There are not much examples around this problem (we have searched google and eclipse help) so let me explain how you can achive this.

For example we want to define follow code template:

/**
 * @author ${user}
 *
 * ${tags}
 * @since ${bundleId} ${bundleVersion}
 */

The bundleId and bundleVersion variable are not provided by the standard code template variables. Now we have to find out how we can achive this problem.

First of all you need to develop your own eclipse plugin which should provide such feature. The new plugin requires follow dependencies:

  • org.eclipse.core.resources;bundle-version=”3.5.0″,
  • org.eclipse.ui;bundle-version=”3.5.0″,
  • org.eclipse.jface.text;bundle-version=”3.5.0″,
  • org.eclipse.jdt.core;bundle-version=”3.5.0″,
  • org.eclipse.jdt.ui;bundle-version=”3.5.0″,
  • org.eclipse.core.runtime;bundle-version=”3.5.0″,
  • org.eclipse.pde.core;bundle-version=”3.5.0″

The PDE dependency is needed to get the current bundle id and the bundle version. If you need other features (for example a maven project version) you have depend on other plugins. But in this example I’ll show you how to add bundle id and bundle version as extra variable for the eclipse code templates.

Next you have to create a extention to register your own variable resolver at startup. The variable resolvers are the heart of the plugin because they providing new variables for the code templates to be used and resolving the content if you use the code template.

plugin.xml:

< ?xml version="1.0" encoding="UTF-8"?>
< ?eclipse version="3.4"?>
<plugin>
   <extension point="org.eclipse.ui.startup">
      <startup class="yourplugin.eclipse.javadoc.internal.RegisterResolvers">
      </startup>
   </extension>
</plugin>

The RegisterResolvers class implements the IStartup interface from eclipse. This class registers the variable resolvers to the code template context. This is required to have the variables available in the code templates from eclipse.

RegisterResolver:

/**
   * 
   * {@inheritDoc}
   * 
   * @see IStartup#earlyStartup()
   * 
   */
  public void earlyStartup() {
    // check if plug-in org.eclipse.jdt.ui is already active
    final Bundle bundle = Platform.getBundle(PLUGIN_ID);
    if (bundle != null && bundle.getState() == Bundle.ACTIVE) {
      // register resolvers
      registerResolvers();
    } else {
      // register listener to get informed, when plug-in becomes active
      final BundleContext bundleContext = Activator.getDefault().getBundle().getBundleContext();
      bundleContext.addBundleListener(new BundleListener() {
        public void bundleChanged(final BundleEvent pEvent) {
          final Bundle bundle2 = pEvent.getBundle();
          if (!bundle2.getSymbolicName().equals(PLUGIN_ID)) {
            return;
          }
          if (bundle2.getState() == Bundle.ACTIVE) {
            registerResolvers();
            bundleContext.removeBundleListener(this);
          }
        }
      });
    }
  }

/**
   * 
   * Internal method to register resolvers with all context types.
   * 
   */
  private void registerResolvers() {
    final ContextTypeRegistry codeTemplateContextRegistry = JavaPlugin.getDefault().getCodeTemplateContextRegistry();
    final Iterator ctIter = codeTemplateContextRegistry.contextTypes();
    while (ctIter.hasNext()) {
      final TemplateContextType contextType = (TemplateContextType) ctIter.next();
      contextType.addResolver(new BundleIdResolver());
      contextType.addResolver(new BundleVersionResolver());

    }
  }

The bundleIdResolver extends the TemplateVariableResolver and defines (in the default constructor) the variable name which can be used later in the code template, a description and overrides the resolve method.

The resolve method checks if the current project is a plugin project and if so returns the bundle id from the project.

public class BundleIdResolver extends TemplateVariableResolver {
  /**
   * 
   * Constructs a new <code>BundleIdResolver</code>.
   * 
   */
  public BundleIdResolver() {
    super("bundleId", "id of the bundle containing the current compilation unit");
  }

  /**
   * 
   * {@inheritDoc}
   * 
   * @see TemplateVariableResolver#resolve(org.eclipse.jface.text.templates.TemplateContext)
   * 
   */
  @Override
  protected String resolve(final TemplateContext pContext) {
    final CodeTemplateContext context = (CodeTemplateContext) pContext;
    final IPluginModelBase pluginModelBase = PluginRegistry.findModel(context.getJavaProject().getProject());
    if (pluginModelBase == null) {
      return null;
    }
    return pluginModelBase.getBundleDescription().getSymbolicName();
  }
}

Now you can come up with the question why not you can use the standard eclipse extention point mechanism and create your own context.

Well, we want to extend the java context but the current eclipse implementation doe’s not provide such functionality. For sure if you want to have your own context you can do this with the standard extention point mechanism (as the Ant example). There is a small example about the eclipse editor templates.

Thanks to my colleague Marco Lehmann for the complete solution.

Nächste Seite »

The Rubric Theme. Bloggen Sie auf WordPress.com.

Follow

Erhalte jeden neuen Beitrag in deinen Posteingang.

Schließe dich 28 Followern an