20 February 2013

Getting started with Hudson Continuous Integration

This documents my first attempt to use Hudson for building preview and release versions of a .Net ClickOnce application. The version control system is CVS.


Install Hudson

Download Hudson from eclipse.org/hudson (currently 3.0)

Install a cvs client e.g. cvsnt

Drop the war file in tomcat (I'm using v7)

Add 'set "HUDSON_HOME=d:\HUDSON"' to tomcat's startup.bat. This is where all the build configurations and workspaces are saved so there needs to be enough space.

Start Hudson and install the recommended plugins

Install plugins: Manage Hudson->Plugins. Need MSBuild, CVS, CVS-Tag

Configure Hudson





Create a job

My approach is to debug and test the application locally. Only when I want to create a preview/stage or production version do I need Hudson. Hudson should do a build and publish. When successful, a new CVS tag should be created.

The following job settings do not contain any deploy location information (stage/prod). The job always publishes to a temp location on D:. I want to change this later.





01 August 2012

Using a connection profile store with BIRT

After a bit of trial-and-error I managed to get connection profiles to work with BIRT. It is important to keep to the following sequence.

  • Open the Data Source Explorer view
  • Create all the connection profiles you need. e.g. test, staging and production for each connection type. Give them names which indicate the environment they are in (MS_SQL_Test, MS_SQL_Prod etc.)
  • Export the required connection profiles to a file in the report project e.g. connectionStore.xml
  • In the report project, create a new DataSource and select the second radio button 'Create from a connection profile in the profile store'
  • Select the profile store file and choose a connection profile. Perhaps deselect the 'Use default data source name' and enter a environment-independant name (e.g. MS_SQL instead of MS_SQL_Test). Choose Ok to end
  • Open the Data Source and select 'Property Binding'
  • Edit 'Connection Profile Name' -- params["__runtime"].value.toLowerCase() == 'prod' ? 'MS SQL Prod' : 'MS SQL Test' -- or something similar. The returned value must correspond to the name of a connection profile in the store.
  • Define a parameter named '__runtime' and use the Combo Box option to set the valid values: 'test', 'prod' etc
  • That's it
You should now be able to select the connection environment using the report parameter.
Update
When I deployed this to the server (websphere) the profile switching between prod & test did not work. This was because the profile store was not being found. Unfortunately, there is no error message - it just takes the default connection settings. The connection store needs to be placed in the server's context root.

16 March 2012

Success with pvc.webcontainer

Finally got my little app working with com.ibm.pvc.webcontainer. I installed the Domino upgrade 8.5.3 and my plugin works! Seems there were problems with 8.5.2.

One important point is to refresh the target definition in eclipse: Window->Prefs->Plug-in Dev->Target. Reload. Otherwise there will be unresolved plugins in the projects.


06 September 2011

15 June 2011

Mixing Linq-to-SQL and Linq-to-XMl

I have been trying to select a column containing XML text from a database and then selecting nodes from the XML using Linq. It didn't work. My guess is that deferred execution causes the queries to be mixed and taken as Linq-to-SQL. As a result the XML stuff causes problems.

My solution was to force an intermediate result so that there is a break between SQL and XML queries. My code for LinqPad is as follows.

var all = from bm in mytable
          select new { name=bm.SPP_USER_ID, xml=(string)bm.SPP_BOOKMARKS_XML};

var docs = from x in all
           select XDocument.Parse(x.xml);
var docs2 = docs.ToList(); // FORCE RESULT

XNamespace ns = "http://acme/bookmarks";
var href = from h in docs2.Descendants(ns + "href")
           select h.Value;  

15 April 2011

Strange and annoying problem with {NOBR}

I wrote a web app about 10 years ago which used Javascript to pop up a hidden table when an input field gets focus. Each cell in the table contains a checkbox and text which are surrounded by a NOBR to keep them together.

Recently users with IE8 complained that the first cell is not visible when the table pops up. After MUCH trial and error I narrowed it down to the NOBR tag. I replaced it with a SPAN with style set to white-space : nowrap and this seems to solve the problem :-/

05 April 2011

Using 3rd party libraries in Silverlight

I downloaded a 3rd party library for a Silverlight app I am writing. When I ran the app I got an error message telling me to add

<loadFromRemoteSources enabled="true"/>

to 'devenv.exe.config' (Usually in 'C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE').

It seems you also need to edit the 'Blocked' property of the DLL.

See How to: Use an Assembly from the Web in Visual Studio for full details.

10 March 2011

RAP + BIRT on Websphere

I used the blog from Tim Pietrusky to get started: http://blog.tim-pietrusky.de/2009/rich-ajax-platform-rap/integrating-birt-into-rap-applications/

Perhaps I did something wrong but all the image links in the resulting HTML were broken. The URL to my dynamically-generated images was invalid. Even the examples from the RAP wiki showed the same problem.

In the end I decided to store my images under /rwt-resources/birt as I noticed that all the images from RWT are loaded from this address. I also changed the URL to use a context-relative address and not a fully-defined URL with host and port. On Websphere the result was an IP address and the port of the AppServer which was not accessible directly from the client.

I set the resources extension point as follows:

<extension point="org.eclipse.equinox.http.registry.resources">
  <resource
    alias="/resources/birt"
    base-name="/rwt-resources/birt">
  </resource>
</extension>


The modified View part looks like this (sorry about the formatting):


public class ChartView extends ViewPart {
public static final String ID = "com.acme.fair.views.ChartView";

private static final String reportName = "simplechart.rptdesign";
private static final String reportDirLocal = "/resources/birt/";
private static final String reportDirServer = "/rwt-resources/birt/";

private Browser browser;
private String reportDesign; // Full path to the local BIRT report file
private String URL;

private IReportEngine engine = null;
private EngineConfig config = null;
private IReportRunnable design = null;
private IRunAndRenderTask task;

@SuppressWarnings("restriction")
public void createPartControl(Composite parent) {
this.setPartName("BIRT in RAP");
browser = new Browser(parent, SWT.NONE);
configureURL();

try {
config = new EngineConfig();
IReportEngineFactory factory = (IReportEngineFactory) Platform
.createFactoryObject(IReportEngineFactory.EXTENSION_REPORT_ENGINE_FACTORY);
engine = factory.createReportEngine(config);

InputStream fs = null;
try {
URL url = Activator.getDefault().getBundle().getResource("/resources/birt/simplechart.rptdesign");
fs = url.openStream();
} catch (MalformedURLException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
}

design = engine.openReportDesign(fs);

// Create task to run and render the report
task = engine.createRunAndRenderTask(design);

// Set the dataset for the chart as report parameter
task.setParameterValue("CHART_DATASET", MesseSql.getFairsPerYear());

// Render the report to HTML
HTMLRenderOption renderOptions = new HTMLRenderOption();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
renderOptions.setOutputFormat(HTMLRenderOption.HTML);
renderOptions.setOutputStream(outputStream);

// Get the path to the local context directory to save the rendered
// chart image
String webAppBase = (ContextProvider.getWebAppBase()).replaceAll("\\\\", "/");
String path = webAppBase + reportDirServer + RWT.getSessionStore().getId();

// Handle the image path
renderOptions.setImageHandler(new HTMLServerImageHandler());
renderOptions.setImageDirectory(path);
renderOptions.setBaseImageURL(RWT.getRequest().getContextPath() + reportDirServer + RWT.getSessionStore().getId());

task.setRenderOption(renderOptions);
task.run();
task.close();

// Set the HTML output to the Browser widget
browser.setText(outputStream.toString());

engine.destroy();

} catch (Exception ex) {
ex.printStackTrace();
}
}

// Set the URL for the BIRT report for different environments.
private void configureURL() {

// Protocol, ip & port
ServletContext sc = RWT.getRequest().getSession().getServletContext();
String realPath = sc.getRealPath("/");
HttpServletRequest request = RWT.getRequest();
String protocol = "http://";
String ip = request.getLocalAddr();
int port = request.getLocalPort();
URL = protocol + ip + ":" + port;
String webAppName = "";

if (realPath == null) { // Start application locally within Eclipse
// (Windows)
reportDesign = URL + reportDirLocal + reportName;
} else { // Start application on a server (Apache Tomcat or so)
webAppName = sc.getContextPath();
reportDesign = URL + webAppName + reportDirLocal + reportName;
URL = URL + webAppName;
}
}

public void setFocus() {
}

/**
* Execute the given script, for example to print the

* content of the Browser
*
* @param script
* String to be executed
*/
public void executeScript(String script) {
browser.execute(script);
}
}

11 February 2011

RAP: Useful snippets

Just want to record some handy code snippets...

Save/Restore workbench state

In the Application WorkbenchAdvisor


/**
* set auto restore of workbench state
*/

public void initialize( IWorkbenchConfigurer configurer ) {
    getWorkbenchConfigurer().setSaveAndRestore( true );
    super.initialize( configurer );
}

10 February 2011

RAP: App suddenly stopped working

I edited the Preference feature in my app and could not start the app. I was getting the following error:

java.lang.IllegalArgumentException: no layout registered with default id (LayoutRegistry.DEFAULT_LAYOUT_ID) or no layout activated over branding extension.
at org.eclipse.rap.ui.interactiondesign.layout.ElementBuilder.<init>(ElementBuilder.java:96)
at org.eclipse.rap.internal.design.example.builder.DummyBuilder.<init>(DummyBuilder.java:23)
at org.eclipse.rap.internal.design.example.managers.CoolBarManager.<init>(CoolBarManager.java:140)
Turns out that the cookies have got themselves in a muddle and need to be deleted. I don't like to delete all my cookies so I (in IE8) opened Tools -> Internet options -> Browsing history -> Settings -> View files. This shows all the temp files. I sorted by last changed date and deleted the files which looked like 'Cookie@127.0.0.1'

Then it all worked again.

09 February 2011

RAP: First deploy to WebSphere

It didn't work first time but it didn't take too long to get the first results. This is what I did.

  • Ensure RAP WAR Products feature installed -- http://wiki.eclipse.org/RAP/Equinox_WAR_products
  • Create a new WAR Product Configuration in the plugin project. New -> Other... -> Plugin Development
  • Select parent folder, name the product and choose the lauch configuration
  • Open the WAR product file and enter an ID and Name
  • On the configuration page add the JARs used by the project
  • Return to the Overview page and select Validate
  • If necessary, add the missing plugins or JARs
  • Start the export wizard and enter the name of the output file. Press Finish.
  • The WAR file has now been exported
  • Open the Websphere Integrated Solutions Console
  • Create new Application Server. I called it RAP_TEST.
  • I had to modify a few ports because the defaults clashed with other App Servers
  • Install new Enterprise Application and enter the name of the WAR file
  • Accept all defaults and enter a context root such as /apps/rap
  • Finish
  • Might need to sync nodes etc but should now work
  • <servername>/apps/rap/fair?startup=fair (in my case)
So, my app kind of works. Unfortunately, the whole branding is missing so there are no images, styles etc. When I find the cause, I'll post more here.

Missing images problem

I set up a simple Tomcat server to check that it wasn't a WAS problem. I then noticed that there was an exception in the logs. Something to do with Jetty and an 'Address already in use' bind error. I was surprised that Jetty would be active on the Tomcat server so I checked my plugin dependencies. In the end I removed all the dependencies and added the 'Required plugins'. That seemed to cure the problem. After redeploying, there were no Jetty exceptions and I get the images which were missing.

08 February 2011

Strangeness(?) with RAP i18n

Just made my first attempt to add multi-language support to my RAP app. I created a default bundle for English and then one for German.

messages.properties
messages_de.properties

My browser was setup to accept German and English in that order so I got the German texts. I then swapped the language prefs in the browser to put English first but I still got German. I tried closing the browser, restarting the app etc. but I still got German. Finally, I added a new bundle, messages_en.properties and now I get English.

Is this the correct behaviour? It is not what I expected but I guess nothing is known about the default bundle and the browser is saying that German is acceptable (if not preffered), Hmmm...


UPDATE
the explanation is as follows:

your VM is set to German, right? What happens is that the
Browser asks for English, but RWT does not find a messages_en.properties
file. So it tries the default locale, in your case German and Bingo!
there is a messages_de.properties file. So you get German. If you want to
have English as your fallback, set your VM to English. Does this explain
the behavior?

Regards, Ralf

--
Ralf Sternberg

I18n in RAP. What a chore!

I18n is bad enough, but in RAP there is even more typing to do :-(

You need to create a Messages class and add a public field for every string you need to translate. You then have to create a properties file for each language and add the texts. The convention for key names is Classname_fieldname.

For example:

Messages.java
...
public String MyView_controltext;
...

Messages.properties
...
MyView_controltext = Hello World
...

MyView.java
...
control.setText(Messages.get().MyView_controltext);
...

I made life a liitle easier by adding a template. Window -> Preferences -> Java -> Editor -> Templates -> New...
Name = msg (or whatever you like)
Pattern = Messages.get().${enclosing_type}_${cursor}

Now I can just type 'msg' <Ctrl>+Space and I get most of what I need.

I can also recommend the Eclipse ResourceBundle Editor at http://sourceforge.net/projects/eclipse-rbe/.

25 January 2011

Proxy frustrations

Wasting heaps of time trying to access the eclipse & RAP CVS repositories from behind the company firewall & proxy. Been through all the help pages I can find but no success. The admins here say that SOCKS is not allowed but it ought to be possible to get at proxy.eclipse.org using port 80. Why is it not working?!

Grrrrr :-(

21 January 2011

Using the JFace forms package from the RAP incubator

I wanted to use the collapsible Section control so I downloaded the JFace Forms package from the RAP source repository :pserver:dev.eclipse.org:/cvsroot/rt .

Just import org.eclipse.rap.ui.forms and add to the main plugin Dependencies and it's done. As I understand it, the forms package is not yet official so I guess there might be some bugs. In fact, the section twistie doesn't react to the mouse click but the title section does so it's not a major problem.

19 January 2011

Coding vs Configuration

After a very frustrating afternoon trying to understand the configuration of ActionSets, Activities, Services etc - without success - I am wondering just how necessary it all is when writing a one-off RAP application. There is just the one plug-in and it will never be added to another plug-in set and will never have to co-operate or negotiate with other plug-ins.

So is it really necessary to do all this configuration? Can I do away with x layers of abstraction and just code the stuff I need directly? That would seem to be the pragmatic approach but I wonder what the consequences are are the project gets bigger.