Tuesday 30 September 2014

Formatting XML in GEdit with Xmllint

This is just to write down my notes.

Extending Gedit functionality with external tools/scripts is apparently possible and quite easy.

Just go to Edit -> Preferences, select tab Plugins and add the plugin "External Tools".

Once that is done, you can add your own tools, by going to Extra -> Management External Tools -> add your own.

It doesn't really get much easier than that.

I tried it by incorporating xmllint, in the following fashion, and it worked like a charm:

#!/bin/sh
xmllint --format $GEDIT_CURRENT_DOCUMENT_PATH
I did, of course, change some settings, like:
input
document
Output
replace-document
Of course, it could be a lot better, as right now it is using the file on the filesystem, without the changes made in the editor. But for now it suits me just fine.

References

GEdit - ExternalTools
https://wiki.gnome.org/Apps/Gedit/Plugins/ExternalTools

Friday 26 September 2014

JPA: ManyToOne with Composite Primary Key

Had an issue with how to model some classes that were entities and therefore tables in the database.

I thought I'd write a little blog about it, to get my thoughts in order. The subject matter is not that difficult, once you see how it works.

A guild has ranks, and a person who is a member of a guild can be assigned to a certain rank. In the database that would look like follows. (Courtesy of Mysql-Workbench2)

As you can see there are a number of primary keys, and foreign keys.
  • The guild is identified by its name.
  • The guildrank is identified by its ranknumber as well as the guild to which it belongs. Therefore the primary key is a composite of both ranknumber and guild.
  • The guildrank therefore also has a foreign key constraint to the Guild.
  • The user is identified by its name.
  • The user can be a member of a guild, though not mandatory. So there's a foreign key reference to the guild.
  • The user can have a rank within the guild, though not mandatory. So there's a foreign key reference to the guildrank, by means of the two fields guild and rank.
Note: One of the things that are not currently modelled in this database schema is that it should be impossible to have a guildrank, without being in a guild. The combination rank with an empty guild should be impossible.

Aggregation and Composition

We see here an example of both Aggregation and Composition. User and Guild is an example of an aggregation, they are things of themselves but have a relation. Guild and Guildrank is an example of a composition. The guildrank cannot exist without the guild, and they form a parent-child relationship.

The guild

First the easy one, the Guild. This is the only entity that is standalone, i.e. not dependent on any other entity. This makes it quite easy. It just contains collections of ranks (One guild has potentially many ranks, so OneToMany) and members (One guild has potentially many members, so OneToMany).

These collections are not required, but are convenient.

A Guildrank

As a guildrank has a composite primary key, we require a separate object to store the primary key composite. This is the case for most (all?) ORMs as the 'findByIdentifier' method takes an object.

Once again, seeing as a guildrank is used in exactly one guild, it is the reverse of the relation in the Guild, so ManyToOne.

Many users are able to have the same rank in the guild, and therefore this is a OneToMany relation.

GuildrankPK


User

The User can be in a guild and can have a guildrank.

One user can have at most one guild, so it is the reverse of the relation in the guild, therefore ManyToOne.

One user can have at most one guildrank, so it is the reverse of the relation in the guildrank, therefore ManyToOne.

It seems the hard part is taken care of by the fact that there is a annotation @JoinColumns that is able to take care of table relations to more than one field at the same time.



Note: You might end up with a warning/error like the following:
Exception [EclipseLink-48] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.DescriptorException
Exception Description: Multiple writable mappings exist for the field [User.guild]. Only one may be defined as writable, all others must be specified read-only.
Mapping: org.eclipse.persistence.mappings.ManyToOneMapping[guildrank]
Descriptor: RelationalDescriptor(User --> [DatabaseTable(User)])
In order to prevent this, either the guild or the guild-part of the guildrank will have to be read-only. This is done for the guildrank part, by specifying insertable = false, updatable = false in the JoinColumn.

Note

In general I dislike the use of composite primary keys, and I favour the use of identification by meaningless numbers. That way the name of the guild, for example, is not spread out all over the database in essence duplicating information and making it almost impossible to change. This is also called Database Normalization3.

References

[1] Wikibooks - ManyToOne
http://en.wikibooks.org/wiki/Java_Persistence/ManyToOne
[2] MySQL Workbench
http://www.mysql.com/products/workbench/
[3] Wikipedia - Database normalization
http://en.wikipedia.org/wiki/Database_normalization

Friday 19 September 2014

Maven and PlantUML

This blog explains about integrating PlantUML with Netbeans and Maven. For integrating PlantUML with Netbeans and Ant, see my previous blogpost here.

The blog at [2] explained to me how to add PlantUML to my Maven project, using the special plugin developed by jeluard1.

Just adding the following to the plugins did the trick:
<?xml version="1.0" encoding="UTF-8"?>
<plugin>
    <groupId>com.github.jeluard</groupId>
    <artifactId>plantuml-maven-plugin</artifactId>
    <version>1.1</version>
    <configuration>
        <outputInSourceDirectory>false</outputInSourceDirectory>
        <outputDirectory>${basedir}/target/site/apidocs</outputDirectory>
        <sourceFiles>
            <directory>${basedir}/src/main/java/</directory>
            <includes>
                <include>**/*.java</include>
            </includes>
        </sourceFiles>
    </configuration>
    <dependencies>
        <dependency>
            <groupId>net.sourceforge.plantuml</groupId>
            <artifactId>plantuml</artifactId>
            <version>8004</version>
        </dependency>
    </dependencies>
</plugin>

Netbeans and Maven

In Netbeans you can select Actions on your project to perform. There is a coupling between the action and the goals in Maven that are executed3.

These can be changed by going to your Netbeans Project Properties (right-click your project, select properties) - select "Actions" - select "Generate Javadoc".

Then add the plantuml Maven goal, com.github.jeluard:plantuml-maven-plugin:generate. You're likely to end up with the following:
generate-sources javadoc:javadoc com.github.jeluard:plantuml-maven-plugin:generate

References

[1] GitHub - jeluard/maven-plantuml-plugin
https://github.com/jeluard/maven-plantuml-plugin
[2] Smartics - Using PlantUML
http://www.smartics.de/archives/1313
[3] Netbeans - MavenBestPractices
http://wiki.netbeans.org/MavenBestPractices

Friday 12 September 2014

Moving From Ant to Maven

My project "karchangame" is Ant-based, basically because when you create a new project in Netbeans, the Ant configuration is the default.

This has worked well for a long time, until I decided recently to upgrade some of the libraries that I use. Now, in Ant, you just download the libraries you need and put the jar-files in your classpath.

That works fine if your libraries are not complicated. But I noticed that some of my libraries are now dependant on yet other libraries.

In short, I just spent an hour in getting the libraries I need, then getting the required libraries of those libraries, ad infinitum.

Maven takes care of this whole slog, by putting the responsibility for defining the required libraries for a framework/library squarely on the shoulders of that framework/library.

What I was stuck with was finding the best way of changing my Ant-based project into a Maven-based project.

Moving from Ant to Maven


The easiest way that I could come up with is to create a brand new Maven-based project. The original was a Web Application, so the new Maven project should also be a Web Application. As far as I could tell every possibility for a new ant-based project is also available as a new maven-based project.

And then start moving files over to the appropriate place in the new Maven structure.

I really like the fact that Git actually detects these moves instead of like in the old days, when a move was an explicit delete and create of two non-related files, making you lose your entire history of that file.

The difference in the directory structure is as follows:
You do notice that Maven actually has a more layered structure, whereas Netbeans Ant basically dumps everything in the root.

So, the move basically entailed the following:
From antTo Maven
build.xmlpom.xml
-nb-configuration.xml
nbproject-
lib- (actually stored in your m2 repo)
src/confsrc/main/resources
src/javasrc/main/java
websrc/main/webapp
testsrc/test/java
buildtarget
dist/karchangame.wartarget/karchangame-1.0-SNAPSHOT.war

Pom.xml

I only needed to make a few changes to my pom.xml file, in order to get all the dependencies sorted out.

JMockit

Needed to add JMockit, or my testcode didn't compile.
<dependency>

    <groupId>org.jmockit</groupId>
    <artifactId>jmockit</artifactId>
    <version>1.10</version>
    <scope>test</scope>
</dependency>

AntiSamy

AntiSamy to prevent evil hackers from gaining access.
<dependency>
    <groupId>org.owasp.antisamy</groupId>
    <artifactId>antisamy</artifactId>
    <version>1.5.3</version>
</dependency>

URL Validation

<dependency>

    <groupId>commons-validator</groupId>
    <artifactId>commons-validator</artifactId>
    <version>1.4.0</version>
</dependency>
It's amazing to see Maven automatically download all the required libraries.

The last part was adding plantuml back into the mix. But I'll talk about that in the next Blog.

References

Apache Maven
http://maven.apache.org/
Netbeans - MavenBestPractices
http://wiki.netbeans.org/MavenBestPractices

Friday 5 September 2014

Welcome Banners in Linux

Seriously, there are more ways to create a Welcome Banner in Linux than there are to skin a cat.

As a matter of fact, only one of several ways will work on your system. It depends on what kind of system you have.

In my case I wished to automate the process, by referring to a file instead of having to type a new logon banner message every time.

Redhat Enterprise Linux 5

Change your custom.conf1, presumably it can be found somewhere in /etc/gdm/.

Redhat Enterprise Linux 6/Ubuntu 12

The new way2 4, using gconftool-2 to set appropriate key-value pairs.
gconftool-2 --config-source=xml:readwrite:/etc/gconf/gconf.xml.defaults --type bool -s /apps/gdm/simple-greeter/banner_message_enable true
gconftool-2 --config-source=xml:readwrite:/etc/gconf/gconf.xml.defaults --type string -s /apps/gdm/simple-greeter/banner_message_text "Your-Login-Banner"
gconftool-2 --config-source=xml:readwrite:/etc/gconf/gconf.xml.defaults --type string -s /apps/gdm/simple-greeter/banner_message_text "$(cat /opt/tools/info/message_of_the_day)"
gconftool-2 --config-source=xml:readonly:/etc/gconf/gconf.xml.defaults --get /apps/gdm/simple-greeter/banner_message_text

To effect this globally, we'll need to change it in a gconf database. The database used are dependent on who is logged on, but we don't want that.

The file /etc/gconf/2/path will show in which paths the database is consulted. The paths are in order of precedence. This means if an entry is found in one of the first databases, the entry is ignored in one of the latter databases.

By default there is a Mandatory Source, a User Source and a Defaults Source5. They are:
  • xml:readonly:/etc/gconf/gconf.xml.mandatory
  • xml:readwrite:$(HOME)/.gconf
  • xml:readonly:/etc/gconf/gconf.xml.defaults

If you wish you can set the logon message manually, using the gconf-editor tool. If you start it up as root, you will be able to select under "File" different profiles, namely the "Defaults" one and the "Mandatory" one.

Redhat Enterprise Linux 7

The new new way! People are migrating from GConf (gconftool-2, gconf-editor) over to GSettings3 and dconf (dconf-tool, dconf-editor).

Fedora 20

The workaround for Fedora, because the new new way doesn't work6.

Create file /etc/dconf/db/gdm.d/01-mysettings:
[org/gnome/login-screen]
banner-message-enable=true
banner-message-text='hostname: wiggins\n“How often have I said to you that when you have eliminated the impossible,\n whatever remains, however improbable, must be the truth?”\n\n- Sherlock Holmes, The Sign of the Four (1890)'
Don't forget to run, to recreate the database with the new settings:
rm /etc/dconf/db/gdm
dconf update

References

[1] Linux: Display a login banner gfor Gnome (GDM) manager
http://www.cyberciti.biz/tips/howto-unix-linux-change-gnome-login-banner.html
[2] RHEL6: Login Banners | SecureOS
http://secureos.wordpress.com/2011/07/21/rhel6-login-banner/
Wikipedia - GConf
http://en.wikipedia.org/wiki/GConf
[3] Chapter 3. GSettings and dconf
https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Desktop_Migration_and_Administration_Guide/gsettings-dconf.html
[4] GConf configuration system
https://projects.gnome.org/gconf/
[5] Redhat - Introduction GConfiguration Overview
https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/4/html/Desktop_Deployment_Guide/ch-intro-gconf-overview.html
[6] Ask Fedora - How do I disable user list in gdm?
https://ask.fedoraproject.org/en/question/9875/how-do-i-disable-user-list-in-gdm/