SyntaxHighlighter

Thursday, October 16, 2008

Facelets Support in NetBeans 6.1

After getting Seam working by manually deploying a .war, I moved onto the next step of integrating Seam into an IDE. Eclipse is a clunky heap of rubbish. I'd say its problem is that it is too flexible. There's a million ways to do one simple thing, but no single way to do one simple thing properly.

After serveral hours wasted on Eclipse, I moved over to NetBeans (6.1). There's a great little tutorial on getting your NetBeans environment setup over at Edem Morny's tech blog. Everything went smoothely, up to the part where one installs Facelets Support, where I get this nasty little message:
Missing required modules for Plugin Facelets Support:
JSP Parser [module org.netbeans.modules.web.jspparser/3 = 200805300101]
This can be avoided by not updating NetBeans. Fortunately there is a bit of a hack to get around this issue:
1. Go to your netbeans-6.1/enterprise5/modules directory
2. Unjar the org-netbeans-modules-web-jspparser.jar file
jar xf org-netbeans-modules-web-jspparser.jar
3. Create a backup of the orignal org-netbeans-modules-web-jspparser.jar just in case.
4. Edit the META-INF/MANIFEST.MF file.
5. Change the OpenIDE-Module-Implementation-Version: to match the verion the facelet is complaining about. In this instance 200805300101.
6. Save the file and jar the whole thing again (by explicitly adding the modified manifest file)
jar cfm org-netbeans-modules-web-jspparser.jar META-INF/MANIFEST.MF org

Thursday, September 25, 2008

Manaully clean your Gentoo world file

I've been in a love-hate relationship with Gentoo for over 3 years now. Luckily there's a lot more love than hate these days. Well 3 years is a long time and it's time to clean this bad boy up...

There's a lot of articles on-line on how to remove cruft and deprecated packages etc. But I struggled to find one that will help you clean up your world file. Being a bit of a quick fix kind of guy, I hammered this little python script together, which will loop through your world file and find the package description for each entry. The script isn't perfect, but it gets the job done for the most part. I still have to manually edit the world file, but at least now I get a description of each entry as I step through the file.

Here's what you need to do:

Log in as root and fire up a text editor:
nano print_world_file_details.py

And paste the following:
import os
import string
import sys

if __name__ == '__main__':
f_in = open("/var/lib/portage/world")

lines = f_in.readlines()

for line in lines:
index = line.find("/")
length = len(line) - 1

if(index > 0):
print ""
print "--------------------------------------"
print line[index+1:length]
print ""
cmd = "emerge -s " + line[index+1:length] + " | grep -A7 '" + line[:length] + "' "
os.system(cmd)

sys.stdin.readline()

f_in.close()
Exit and save (Ctrl+x, Enter). Run the script:
python print_world_file_details.py
Just hit enter after each lookup and manually remove the entry from your world file. Since the script uses grep to filter the ermerge -s results you might get multiple descriptions for some packages. Like dev-java/java-config will list dev-java/java-config-wrapper too. A slight nuisance, but who cares?

Note: It is not considered safe to update your world file manually, so don't mess around if you don't know what you're doing. Please make a backup before editing.

Tuesday, September 23, 2008

Get JBoss Seam going on Gentoo Linux with Tomcat

I've been given a web app to do for an open source driven organization. I like the ideology behind open source, but I must say that the complexities involved in just getting started, must be the single biggest hurdle in the adoption of OSS.

Most Java and Linux fanboys might rupture a vain for me saying this, but to get any sort of Java web app going is massive pain in butt. To get Asp.Net going, one merely install visual studio and off you go. You don't even need IIS these days. To get a Java web app (dev environment) going you have to install a web server, an application server, a java framework, an IDE, IDE plugins to support the java framework and perhaps additional frameworks / tools which will allow you to work in a "code-behind" fashion. Then you have to decide on a web frameworks and the choices are endless: Spring MVC, Struts, Seam, JSF, Tapestry, Wicket, Hibernate, Stripes, etc. You can Google until you're blue in the face, but every single framework claims to be the best and all have their own following of groupies. To be honest, it is a big geeky mess!

Unfortunately I don't have the luxury of cleaning up this steaming pile of rubbish, so I'll have to get my hands dirty and figure out what the best solution is through trial and error (very scientific).

My client already has Tomcat running, so luckily I don't have to bother about figuring out which application server is the best. A further requirement is that the web framework should be quite lightweight. It seems as if JBoss' Seam framework isn't too much of a brute, so I'll go with that and probably get burned half-way in.

Even though I detest overcomplicated systems, I've grown quite fond of Gentoo. Once you've mastered this beast, it is quite pleasant to work with. (Perhaps I'll have the same feelings towards Java web apps once I've finished here, but for now it's not looking good.) So I'll run through the steps of getting Seam going on Gentoo.

To start off with, we'll need JDK (or JRE). Login as root, emerge sun-jdk (in my case version 1.6.0.07) and logout. After that we need to get Tomcat.

Note: You can try to get Tomcat going through portage, but you'll end up pulling your hair out, because Seam uses the naming-factory-dbcp.jar, which is not included in the build for some bizarre reason.

cd ~
mkdir applications
cd applications
wget http://apache.mirrors.hoobly.com/tomcat/tomcat-6/v6.0.18/bin/apache-tomcat-6.0.18.tar.gz
tar -xf apache-tomcat-6.0.18.tar.gz
Now let's set the environmental variables needed:
nano ~/.bashrc
and add these lines:
export JRE_HOME=/opt/sun-jdk-1.6.0.07
export TOMCAT_HOME=/home/yourname/applications/apache-tomcat-6.0.18
export CATALINA_HOME=$TOMCAT_HOME
export CATALINA_BASE=$TOMCAT_HOME

Note: You might want to emerge the tomcat-native package, since it will add the Apache Tomcat Native library. I'm not sure if Seam needs this, but I noticed Tomcat having a bit of a fit when it couldn't find it. The message in the $TOMCAT_HOME/logs/catalina.out was "INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path"

One can also configure an admin user, but this is not necessarily required. Edit the tomcat-users.xml file like this:
nano $TOMCAT_HOME/conf/tomcat-users.xml

<tomcat-users>
<role rolename="manager">
<user username="root" password="irock" roles="manager">
</user>
One can now start Tomcat:
cd $TOMCAT_HOME/bin
./startup.sh

You should now be able to access Tomcat on http://localhost:8080

Tomcat will display $TOMCAT_HOME/webapps/ROOT/index.html

So we can now follow Seam's Tomcat guide, which I had to modify a bit:

1. Go into the jboss-seam/examples/jpa directory
2. Copy the lib/hsqldb.jar into $TOMCAT_HOME/lib
3. Run ant tomcat6 to build the application
4. Stop Tomcat $TOMCAT_HOME/bin/shutdown.sh
5. Remove previous any exiting deployments: rm -r $TOMCAT_HOME/webapps/jboss-seam-jpa
6. Copy war file: cp dist-tomcat6/jboss-seam-jpa.war $TOMCAT_HOME/webapps
7. Start Tomcat $TOMCAT_HOME/bin/starup.sh
8. Access the app at http://localhost:8080/jboss-seam-jpa

And Bob's you're uncle!

Wednesday, September 17, 2008

Linq Context.Add Renamded To

A number of Linq to Sql tutorials online are based on intial "Orcas" (now 3.5) release of the .Net Framework. A number of namechanges were made and I picked one up whilst learning Linq. Here's the error I received:
'System.Data.Linq.Table<Namespace>' does not contain a definition for 'Add' and no extension method
'Add' accepting a first argument of type 'System.Data.Linq.Table<Namespace>' could be found
(are you missing a using directive or an assembly reference?)

The context.Add methods was changed to context.InsertOnUpdate.

Wednesday, September 10, 2008

Apply themes to Images in Asp.Net

The Asp.Net Themes approach is somewhat lacking when it comes to images. It is easy enough to switch between CSS and Skin files, but switching between images aren't as trivial. Luckily there is a relatively simple way to do this.

My thinking was to set the image folder dynamically. First, we'll have to figure out what our image path is. Say one use the following structure for your image folders:

App_Themes/Theme1/Images
App_Themes/Theme2/Images
...

The following ImagePath accessor can be used to determine the current theme's image path (I would recommend you to put this in a Base class for this to be accessible to all pages/controls):
public string ImagePath
{
get
{
return string.Format("{0}://{1}{2}/App_Themes/{3}", Request.Url.Scheme, Request.Url.Authority, Request.ApplicationPath, Page.Theme);
}
}

Now that we know where the currently selected theme's images are, we need to set the path for the controls in the aspx page. This is easy enough if you using normal HTML controls as follows:
<img src='<% Response.Write(ImagePath); %>/Image.jpg' />

But this approach does not work for server controls. If you use the following line, you'll receive an error:

<asp:Image ImageUrl="<% Response.Write(ImagePath); %>/Image.jpg" runat="server" />

Error:
Server tags cannot contain <% ... %> constructs.

One could set the asp:image's ImageUrl in the codebehind, but I find it to be a bit clunky. In order to use the ImagePath in the aspx file, one can use an approach by Dave Reed.

Create a class in the App_Code called CodeExpressionBuilder:
using System;
using System.CodeDom;
using System.Web.Compilation;
using System.Web.UI;

[ExpressionPrefix("Code")]
class CodeExpressionBuilder : ExpressionBuilder
{
public override object ParseExpression(string expression, Type propertyType, ExpressionBuilderContext context)
{
return expression;
}

public override CodeExpression GetCodeExpression(BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
{
return new CodeSnippetExpression(parsedData.ToString());
}
}


One can now set the ImageUrl in the aspx file as follows:
<asp:Image ImageUrl='<%$ Code: ImagePath + "/Image.jpg" %>' runat="server" />

Wednesday, August 20, 2008

AJAX ProgressUpdate issue

I had an issue with the UpdatePanel and ProgressUpdate AJAX extensions controls in ASP.NET.

The following error occurred in the Javascript:
if (this._dynamicLayout) this.get_element().style.display = 'block';

I solved the problem by moving my ProgressUpdate control out of the UpdatePanel's tags. I guess I was looking for trouble when I did that.

Having the ProgressUpdate within the UpdatePanel work in certain instances, but I also had another UpdatePanel in the same UserControl, so it got a bit hairy.

I'd like to verify this, but as always, the deadline looms.

Wednesday, August 13, 2008

Constraint cannot be special class 'object'

I was busy creating a generic method to convert a List to a DataTable when I received the error:
Constraint cannot be special class 'object'
on this statement:
public DataTable ListToDataTable(IList list) where T : Object

Blegh... why would this be? Anyhow, I did a workaround by changing the statement to the following:
public DataTable ListToDataTable(T list) where T : IList

A bit annoying, since now one has to send a List and can't simply pass a List.

Another workaround is to use a blank interface, with the statement as:
public DataTable ListToDataTable(IList list) where T : IBlank

Now one can send List if MyClass 'implements' the IBlank interface.

I'm not really too happy with any of these workarounds. I see no reason why the Object class is "too special" to be used as a generic placeholder.

Oh, and merely for interest sake. Here is the generic List to DataTable converter method:
public DataTable ListToDataTable(List list) where T : IBlank
{
DataTable dataTable = new DataTable();

Type type = typeof(T);
PropertyInfo[] properties = type.GetProperties();

// Create the columns
foreach (PropertyInfo property in properties)
dataTable.Columns.Add(property.Name, property.PropertyType);

// Populate the rows
foreach (T obj in list)
{
DataRow newRow = dataTable.NewRow();

foreach (PropertyInfo property in properties)
newRow[property.Name] = property.GetValue(obj, null);

dataTable.Rows.Add(newRow);
}

return dataTable;
}