Warning: Issue fixed in NetBeans 6.1 :-)

Date May 25, 2008

An issue that really could be quite annoying for NetBeans Platform developers, Issue 96711, has been fixed in 6.1. Sounds like great news, but better have a look at your code so you don’t get in trouble!

The bug, or feature as some might see it, was that some classes were intentionally not loaded from the rt.jar in NetBeans platform applications although they are part of the standard JRE. That can be a good idea in some cases, where there are already newer implementations or your application depends on a specific one (JAXB is a good example). But if you didn’t know about this bug/feature it could be quite strange to have the correct jre in place but the classes simply wouldn’t get loaded. As soon as I had found out why, I liked it as a feature and used it for my Webservice clients. I provided a library wrapper module containing exactly the version of JAX-WS that I needed, and I didn’t have to care which version of java 6 my users had (or torture them with endorsed dirs ).

I just found that out that the bug has been fixed a few days ago when I tried to port an application from 6.0 to 6.1. Suddenly my Webservice clients didn’t work any more, complaining that they need JAXB 2.1 instead of 2.0 which was loaded from the bootstrap classloader. “bootstrap????? what the …?”. Then -again- I tried to find out what went wrong and -again- I had to search a lot until I finally found out that 96711 got me again.

Luckily it’s very easy to get everything to work as intended again. The attachment Jesse Glick has added to the issue shows how to prevent loading the packages via bootstrap:

OpenIDE-Module-Hide-Classpath-Packages: javax.jws.**, javax.xml.bind.**, javax.xml.stream.**, javax.xml.ws.**, javax.xml.soap.**, javax.annotation.**

When I knew the property name I also found some more information here. You simpy need to add this to your library wrapper and all dependent modules will use the classes you provided in the library wrapper instead of the standard ones. Great solution, now it’s definitely a feature and not a bug!
But what would have happened if I had used the latest version of Java 6 to test? The latest edition contains all the jars and I would probably never have recognized that my application suddenly has a bug and I would have shipped the broken version. So watch out and check your code if you have used the same workaround as I did!

Creating Extension Points in NetBeans Platform Applications

Date May 25, 2008

One of the main benefits of the NetBeans platform is the module system. Regardless of which module system is best ( my guess is there will soon be a version of NeBeans that can also run as OSGi bundles ) it’s important to have a system that enables you to create a modular architecture for your application. It’s an invitation to create a clean and maintainable architecture with defined dependencies and to create nice APIs with clearly defined and easy to use extension points. If you follow these principles others can extend your application easily. Maybe the easiest way to provide extension points in NetBeans is via the layer.xml.

In NetBeans modules the layer file is the central configuration file. NetBeans IDE uses the layer a lot to provide extension points for APIs. Objects can be created declaratively there and you can use the lookup to listen for changes. You will use it whenever you create new Actions or TopComponents. This quick tutorial shows how you can provide your own extension points via the layer:

Prerequisites:

  1. NetBeans (I’m using 6.1, but this will also work with older versions)
  2. Create a new ModuleSuite :
    1. Choose File > New Project (Ctrl-Shift-N). Under Categories, select NetBeans Plug-in Modules. Under projects, select “NetBeans Platform Application” or ( “Module Suite Project” on older versions ) and click Next.
    2. In the Name and Location panel, type “layerextensionpoints” in Project Name. Change the Project Location to any directory on your computer, such as c:\mymodules. Click Finish.
  3. Now create four modules inside the suite “extensionpointinterface”, “messagereader”, “messageprovider1″ and “messageprovider2″:
    1. Choose File > New Project (Ctrl-Shift-N) again. Under Categories, select NetBeans Plug-in Modules. Under projects, select Module Project and click Next.
    2. In the Name and Location panel, type the name in Project Name. The default in the wizard should be to create the module underneath the directory where you just created the suite, which is fine. Click Next.
    3. In the Basic Module Configuration panel, replace the Code Name Base with de.eppleton.<modulename>. Click Finish.

Create a Service interface

We will use module “extensionpointinterface” to define an interface that will be used by the Service Providers as well as by the module that uses the extension point. Inside that module create interface “MessageProviderInterface” with the single method getMessage() that returns a String:


public interface MessageProviderInterface {

public String getMessage();

}

To make this part of the public API right click the project node, select API Versioning and select the check box of de.eppleton.extensionpointinterface. Now this package is accessible by other modules.

Create Service Provider implementations

Now we need some modules that implement the ExtensionPointInterface. We will use the modules “messageprovider1″ and “messageprovider2″ to do that. To implement the interface they both need a dependency on module “extensionpointinterface”. For each of them do the following:

  1. Right click the project node, select the “Libraries” category.
  2. Click “Add Dependency”.
  3. Select “extensionpointinterface”, and click “OK”.

Now that we have access to the interface in our modules we can implement it. Again for both modules do the following:

  1. Select “New” > “Java Class”.
  2. In the Wizard type “MessageProvider1″ or “MessageProvider2″ in the name field respectively.
  3. Implement the interface. Each of them should provide a different String e.g. “Hello ” in MessageProvider1 and “World!” in MessageProvider2:

8<———–MessageProvider1——————->8


import de.eppleton.extensionpointinterface.MessageProviderInterface;

public class MessageProvider1 implements MessageProviderInterface {

public String getMessage() {

return "Hello ";

}

}

8<——————————>8

8<———–MessageProvider2——————->8


import de.eppleton.extensionpointinterface.MessageProviderInterface;

public class MessageProvider2 implements MessageProviderInterface {

public String getMessage() {

return "World!";

}

}

8&lt;——————————&gt;8

In order to make our MessageProviders available as services add these entries in the layer of the two modules. In 6.0 and earlier version the layer should be there anyway. In 6.1 you will need to create the layer.xml yourself:

<ol>

<li>In “Important files” open “Module Manifest”.</li>

<li>In the manifest add this line: OpenIDE-Module-Layer: de/eppleton/messageprovider2/layer.xml or OpenIDE-Module-Layer: de/eppleton/messageprovider1/layer.xml respectively.

That indicates the location where you put the layer.xml later on.</li>

<li>Create the layer.xml files in their respective package. (”New” &gt; “XML” &gt; “XML Document”) , use “layer” in the name field and add:</li>

</ol>


<xml version="1.0" encoding="UTF-8">

<DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.1//EN" "http://www.netbeans.org/dtds/filesystem-1_1.dtd">

<ilesystem></filesystem>

In the layer files <filesystem> add:


<folder name = "MessageProviders>

<file  name="de-eppleton-messageprovider1-MessageProvider1.instance" >

</file>

</folder>

and


<folder name = "MessageProviders">

<file  name="de-eppleton-messageprovider2-MessageProvider2.instance" ></file>

</folder>

respectively. This will create an instance of our MessageProviders using the standard constructor. The trick is that those instances will be accessible from outside via the SystemFileSystem. The next step shows how you can access these Services without a module dependency.

<h3 id=”section-VisualDatabaseExplorer-CreateACookieAction”>Find and use Service Providers</h3>

We will use module “messagereader” to display messages from all MessageProviders. To do so we will create a TopComponent:

<ol>

<li>Set a dependency on “extensionpointinterface” as shown above.</li>

<li>Click “New” &gt; “WindowComponent”. “Output” is ok for the location. Make it show on startup by ticking the box.</li>

<li>Enter “MessageReader” for the class name prefix and click “Finish”.</li>

<li>The TopComponent class will open in Design View. Drop a JScrollPane from the palette in the window, make it fill the whole area and add a JTextPane to it.</li>

<li>In the source view add this to the end of the constructor:</li>

</ol>


Lookup lkp = Lookups.forPath("MessageProviders");

Collection &amp;lt;MessageProviderInterface&amp;gt; coll =  (Collection&amp;lt;MessageProviderInterface&amp;gt;)  lkp.lookupAll(MessageProviderInterface.class);

for (Iterator&amp;lt;MessageProviderInterface&amp;gt; it = coll.iterator();  it.hasNext();) {

MessageProviderInterface messageProviderInterface = it.next();

jTextArea1.append(messageProviderInterface.getMessage());

}

This will lookup the folder you created via the layer file ( Lookups.forPath(”MessageProviders”) ), search for classes implementing the interface ( lookupAll(MessageProviderInterface.class) ) and call the interface method on all instances. Let’s try it out:

Run the ModuleSuite. You will see the window either displaying “Hello World!” or “World!Hello “. As we can see in this very simple example, the order in which the ServiceProviders are called can be important for the result. So in the next step I will show you a trick to guarantee the correct order:

Sort Service Providers

NetBeans provides a way to sort layer entries. This mechanism is e. g. used to provide an order for actions in menus and toolbars. Since 6.0 (I think) this is done via the position attribute. So this probably won’t work in older versions:

In the layer of the two modules add these entries:


<folder name = "MessageProviders">

<file  name="de-eppleton-messageprovider1-MessageProvider1.instance" >

<attr name="position" intvalue="30"/>

</file>

</folder>

and


<folder name = "MessageProviders">

<file  name="de-eppleton-messageprovider2-MessageProvider2.instance">

<attr name="position" intvalue="40"/>

</file>

</folder>

respectively.

Now the messages will always be displayed in the correct order “Hello world!”. Simply swap these values to reverse the order of the messages. When you do something like this make sure that you choose your values big enough to add Services in between the initial ones so there’s room for your application to grow. Try what happens when you set the same value for both attributes!

Summary

The intention of this tutorial is to illustrate how simple it is to implement loose coupling via the layer.xml in a NetBeans Platform application. Note that the module that uses the services has no dependencies on the modules that provide the services. And not only does NetBeans provide a very simple mechanism to provide and lookup Services, but also an easy way to declaratively order them.

Will Code HTML for food

Date April 26, 2008

My entry for Geertjan’s first annual “Will Code HTML for food” competition

RefactorIt open sourced - NB6.X Plugin

Date April 8, 2008

Developers who joined us for the NUGM meeting in munich with the SQE team have already heard the rumours, but now it’s official: RefactorIT has been open sourced.

Sven Reimers just sent me the news: NetBeans Adventures, Java and more: RefactorIt open sourced. As I posted earlier the freeware version of RefactorIT only had a plugin for NB 5.5. Project SQE is now looking for volunteers to help with porting the cool metrics and audits to NB 6.x. Thanks to Sven for working on this great project!

SQE in munich with some interesting news…

Date March 26, 2008

SQE, the Software Quality Environment is an Open Source project at java.net to provide first class integration for the best software quality tools available in the NetBeans platform. Sven Reimers from the SQE team will be in munich at the NetBeans Usergroup meeting tomorrow, march 27.

Sven at the NetBeans day in Frankfurt

The SQE team seems to be very exited about a new collaboration. There’s a lot of discussion going on in the background with many rumors afloat that there will be some very interesting announcements at the meeting. So join us for an interesting discussion and some beers at the community get-together in a nearby bar. As always good questions will be awarded with a cool T-shirt in a box.

links for 2008-02-29

Date March 1, 2008

links for 2008-02-22

Date February 23, 2008

Android: IMAP Inbox Part 3 - Display Message Text

Date February 16, 2008

message.PNG

In the last blog entry of this series I explored how to connect to an imap server and show the message subjects in alist. Here’s how to read a selected message. As a prerequisite you’ll need to add the java.awt.datatransfer package to your sources as described here.

Then create a new Activity to show the Message. I named mine “MessageDisplay” and registered it in the AndroidManifest.xml:

8<————————————————->8

<?xml version=”1.0″ encoding=”utf-8″?>
<manifest xmlns:android=”http://schemas.android.com/apk/res/android”
package=”de.eppleton.mail.imap”>
<application android:icon=”@drawable/icon”>
<activity class=”.ShowInbox” android:label=”@string/app_name”>
<intent-filter>
<action android:value=”android.intent.action.MAIN” />
<category android:value=”android.intent.category.LAUNCHER” />
</intent-filter>

</activity>
<activity class=”.MessageDisplay” android:label=”message”></activity>
</application>
</manifest>

8<————————————————->8

Then implement the class:

8<————————————————->8

package de.eppleton.mail.imap;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class MessageDisplay extends Activity {
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
TextView resultView = new TextView(this);
Bundle extras = getIntent().getExtras();
String value = “empty”;
if (extras != null) {
value = extras.getString(”message”);
}

resultView.setText(value);
setContentView(resultView);
}
}

8<————————————————->8

It simply displays the message String in a TextView. The trickiest part is to get data from your Main Activity to the subactivity. This is done via the Intent. Data is added in the main Activity to the Intent by calling putExtra(String key, Object value), and retrieved as shown above (in boldface).

Now we can use this view from the main activity (Changed part in boldface):

8<————————————————>8

package de.eppleton.mail.imap;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;

import javax.mail.Message;
import javax.mail.MessagingException;

import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;

public class ShowInbox extends ListActivity {
private static final int ACTIVITY_CREATE = 0;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
Message[] messages = new Message[] {};
try {
messages = ImapClient.getMail();
} catch (MessagingException e1) {
e1.printStackTrace();
}
setListAdapter(new ArrayAdapter<Message>(this,
android.R.layout.simple_list_item_1, messages) {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Message message = getItem(position);
TextView resultView = null;
if (null == convertView || !(convertView instanceof TextView)) {
resultView = new TextView(super.getContext());
}
try {
resultView.setText(message.getSubject());
} catch (MessagingException e) {
e.printStackTrace();
}
return resultView;
}

});
}

protected void onListItemClick(ListView l, View v, int position, long id) {
Message message = (Message) l.getAdapter().getItem(position);
String messageString = readMessage(message);
showMessage(messageString);
}

private void showMessage(String messageString) {
Intent i = new Intent(this, MessageDisplay.class);
i.putExtra(”message”, messageString);
startSubActivity(i, ACTIVITY_CREATE);
}

private String readMessage(Message message) {
String messageString = “”;
String contentType;
try {
contentType = message.getContentType();
if (contentType.startsWith(”text/plain”)
|| contentType.startsWith(”text/html”)) {
Object content = message.getContent();
if (content instanceof String) {
messageString = (String) message.getContent();
} else if (content instanceof InputStream) {
BufferedReader in = new BufferedReader(
new InputStreamReader((InputStream) content));
StringBuffer buffer = new StringBuffer();
String line;
while ((line = in.readLine()) != null) {
buffer.append(line);
buffer.append(”\n”);
}
messageString = buffer.toString();
} else {
messageString = “Can’t read this!”;
}
} else
messageString = contentType;
} catch (Exception e) {
e.printStackTrace();
return e.getMessage();
}
return messageString;
}

}

8<————————————————>8

The only interesting thing here is how to receive the event from the list -that is done via overriding onListItemClick-, and how to start the MessageDisplay activity - that is done in showMessage. First the Intent is created, then the message is added to the Bundle via putExtra, and startSubActivity launches MessageDisplay. Actually startActivity should work equally well here, since we don’t implement onActivityResult() yet.

Now you can launch the Application and click the subjects to display the message text.



Android: IMAP Inbox Part 2 - Customizing the ListView

Date February 10, 2008

In a recent posting I showed how to read messages from an imap server and show them in a ListView. So far the ListView only showed the subject line from a String Array. There is no easy way back to the message object, so we need to change this.

I’ve improved this a little bit now after reading this article on how to customize an ArrayAdapter. The getMessages() method now returns the Message [], which is wrapped in the ArrayAdapter. To show the subject line in the list we simply override the getView method:

8<———————————————->8

package de.eppleton.mail;

import javax.mail.Message;
import javax.mail.MessagingException;

import android.app.ListActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

public class ShowInbox extends ListActivity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
//setContentView(R.layout.main);
Message[] messages = new Message[] { };
try {
messages = ImapClient.getMail();
} catch (MessagingException e1) {
e1.printStackTrace();
}
setListAdapter(new ArrayAdapter<Message>(this,
android.R.layout.simple_list_item_1, messages){
@Override
public View getView(int position, View convertView,
ViewGroup parent) {
Message message =getItem(position);
TextView resultView = null;
if (null == convertView ||!(convertView instanceof TextView)){
resultView = new TextView(super.getContext());
}
try {
resultView.setText(message.getSubject());
} catch (MessagingException e) {
e.printStackTrace();
}
return resultView;
}

});
}
}

8<———————————————->8

And the ImapClient looks like this:

8<———————————————->8

package de.eppleton.mail.imap;

import java.net.ConnectException;
import java.security.Security;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.NoSuchProviderException;
import javax.mail.Session;
import javax.mail.Store;

public class ImapClient {
static {
Security
.addProvider(new org.apache.harmony.xnet.provider.jsse.JSSEProvider());
}
static Session session;
static Store store;

public static Message[] getMail() throws MessagingException {
connect();
Folder folder = store.getFolder(”INBOX”);
folder.open(Folder.READ_ONLY);
Message[] messages = folder.getMessages();
return messages;
}

private static void connect() throws MessagingException {
if (null != session)
return;
java.util.Properties props = new java.util.Properties();
props.setProperty(”mail.imap.socketFactory.class”,
“javax.net.ssl.SSLSocketFactory”);
props.setProperty(”mail.imap.socketFactory.fallback”, “false”);
props.setProperty(”mail.imap.socketFactory.port”, “993″);
session = Session.getDefaultInstance(props);
store = session.getStore(”imap”);
store.connect(”mailserver”,”userid”,”password”);
}
}

8<———————————————->8

Well, the result looks almost the same, except multiline subbjects are supported:

inbox2.PNG

NetBeans RCP - Another German RCP book

Date February 10, 2008

I’m really surprised to see yet another NetBeans RCP book in German language. That’s great! So far my impression was, that there aren’t as many NetBeans enthusiasts in germany as in most other countries, but it seems I was wrong :-). I’ll try to get a copy of NetBeans RCP - Das Entwicklerheft ( = NetBeans RCP - Developer Notebook) as soon as possible and review it here. The book has 288 pages and covers RCP specific topics as well as general IDE stuff like designing forms. There’s also a chapter about Update Management including a section on Installers. That might be interesting since installers haven’t been covered in depth before.

Android: IMAP Inbox Part 1

Date February 10, 2008

inbox.PNG

Here’s how to view your email inbox with Android. You need to add additional libraries to the project to get this running. Unfortunately I couldn’t get the java mail and activation libraries on the phone with the NetBeans Undroid module. If you know how to do that, let me know. I added the two mail and ativation libraries to the project and the build went fine, but when I launch the application I get a “NoClassDefFoundError” for javax/mail/Session. So I’m using the Eclipse plugin for this, until I figure out how to do it in NetBeans:

1. Create a new Android Project (new Project -> Android -> Android Project), name it “inbox”, Package “de.eppleton.inbox”, Activity Name “ShowInbox”, Application Name “inbox”

2. Create a new Class ImapClient and replace the boldface entries with your credentials:
8<———————————->8
package de.eppleton.mail;

import java.security.Security;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Store;

public class ImapClient {
static {
Security.addProvider(new org.apache.harmony.xnet.provider.jsse.JSSEProvider());
}

public static String [] getMail() throws MessagingException {
java.util.Properties props = new java.util.Properties();
props.setProperty(”mail.imap.socketFactory.class”, “javax.net.ssl.SSLSocketFactory”);
props.setProperty(”mail.imap.socketFactory.fallback”, “false”);
props.setProperty(”mail.imap.socketFactory.port”, “993″);

Session session = Session.getDefaultInstance(props);

Store store = session.getStore(”imap”);
store.connect(”mail.mailserver.com”, “you”, “yourpassword”);

Folder folder = store.getFolder(”INBOX”);
folder.open(Folder.READ_ONLY);

Message[] message = folder.getMessages();
String [] titles = new String[message.length];
for (int i = 0, n = message.length; i < n; i++) {
titles[i] = message[i].getSubject();
}
// Close connection
folder.close(false);
store.close();
return titles;
}
}

8<———————————->8

3. Add the missing libraries ( Referenced Libraries -> build path -> configure build path -> Add External JARs… ). Y ou’ll need activation-1.1.jar and mail-1.4.jar from sun

4. Change the ShowInbox class to a ListActivity and add this code:
8<———————————->8
package de.eppleton.mail;

import javax.mail.MessagingException;

import de.eppleton.mail.ImapClient;
import android.app.ListActivity;
import android.os.Bundle;
import android.widget.ArrayAdapter;

public class ShowInbox extends ListActivity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
String[] messages = new String[] { “empty” };
try {
messages = ImapClient.getMail();
} catch (MessagingException e1) {
e1.printStackTrace();
}
setListAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, messages));
}
}
8<———————————->8

5. Launch the application, and your done.

Update: here’s the next step, using a Message[] in the ListView

If you want to send mail check this out:

Android - Send email via GMail (actually via SMTP) « Show me the code!

NetBeans news in JavaTools Community Newsletter

Date February 10, 2008

JavaTools is a Community at dev.java.net where lots of cool projects are hosted, e.g. Hudson and it’s NetBeans plugin. This week our JavaTools Community Newsletter has lots of NetBeans news. In this issue:

- NetBeans-Blogger (Embed blogging features into NetBeans)

- Mogwai ER-Designer NG NetBeans Plugin available

- Android plugin for NetBeans

- Solaris Express developer Edition (SXDE), The only OS a developer ever needs :-)

- NBPython (Python support for Netbeans)

… and many other tips and tricks, enjoy!

ARM Google phone & Developer contest deadline extended

Date February 8, 2008

I started playing with the Undroid plugin recently. It works well and it’s fun to play around with the emulator, although I’d rather play with a real Google phone like the one that will be presented on monday. So you better speed up when you want to develop the killer app to finance your sabbatical. On the other hand, Google has extended the deadline for the developer contest.

icon.png

By the way, if you -like me- don’t like the steampunk default application gear, here’s how to change the default icon of your application:

Create a folder “drawable” in the resources dir of your android project and move your Icon there. I used this as an example:

mizu_icon.png

Now go to the files tab and add a reference to the application element (android:icon) in your AndroidManifest.xml :

<?xml version=”1.0″ encoding=”UTF-8″?>
<manifest xmlns:android=”http://schemas.android.com/apk/res/android”
package=”org.me.mizuandroid”>
<application android:icon=”@drawable/mizu_icon”>
<activity class=”.MainActivity” android:label=”Mizu”>
<intent-filter>
<action android:value=”android.intent.action.MAIN”/>
<category android:value=”android.intent.category.LAUNCHER”/>
</intent-filter>
</activity>
</application>
</manifest>

You can also change the application name here (android:label) When you run your application the default icon is replaced:

mizu.PNG

That’s it, happy coding!

links for 2008-02-05

Date February 6, 2008

  • This release includes the latest tools (NetBeans 6.0 and NetBeans PHP support, Sun Studio), and technologies (JDK 1.6, Apache 2.2, PHP 5.2.4, MySQL 5, PostgresQL 8, Ruby, GlassFish Java EE 5), to create applications for the Open Solaris OS, Java Applica
  • Major new features include : GORM features ORM DSL for advanced mappings, support for easy to use Filters, Content Negotiation support, REST support, automatic XML/JSON unmarshalling, support for mapping foreign key columns and join tables and JNDI suppor
    (tags: grails java)

How to add a third-party module to your RCP

Date February 5, 2008

In a recent blog entry “Branding & Substance plugin” I mentioned that the substance plugin would be great to change the look & feel of a NetBeans based application. I just received an email asking for more details how to do this:

I have started to create an application based on the netbeans platform.
After having seen the substance LAF, I have tried to use it for the netbeans application platform.

First, I have installed the substance netbeans plugin. It works like a charm.
Then, I de-install the substance plugin.
My goal is to use the substance LAF only for the target application, and not the development platform.

How to use the substance LAF on a netbeans application platform
1. On possibility is to include the update center to the target application and then include the netbeans substance plugin. It works, but I do not like this manual operation

2. Another possibility would be to run the target application with the substance LAF.
In the project.properties file of my netbeans application I set the following:
run.args.extra=–laf org.jvnet.substance.SubstanceLookAndFeel –cp:p “C:/Java/substance.jar”
It works but it is not totally perfect. The tabbed container is a netbeans specific component and it not recognized by the LAF.

So I have decided to add in the classpath, jar: org-jvnet-substance-netbeans.jar (I found it in the substance netbeans plugin).

Unfortunatly, this produces a crash

So my question would be: how to run a netbeans application platform using substance LAF without having to download the substance plugin from the target platform ?

That’s a good question, so how can we go about it? Can you take an existing nbm and add it to your distribution? The files should all be there in the nbm.

Some of you might ask now: “Toni, why don’t you just check out the project from cvs at https://substance-netbeans.dev.java.net/ move it to your module_suite, right click the modules node of the suite, select “add existing” from the context menu and choose “substance-netbeans”?”.

And, again, that’s a fair question :), but let’s just pretend we only have the nbm, so what can we do? So far solution 1, installing the module manually has the best result, but needs user interaction. One thing you can do about this is to copy the nbm into the update/download directory of your suite.