Source: eatliver.com
Sed is a great tool when it comes to string replacement. With simple command like:
$ sed -i -e 's/log4j\.rootLogger=debug/log4j\.rootLogger=warn/' log4j.properties
, it will change appropriate value in log4j.properties file. It is especially useful in automatic scripts which customize configuration.
The problem I have encountered lately was connected with using sed for string replacement in xml files. I tried different regular expressions, and multi-line matching, and it was a real pain. I needed a kind of "xmlsed" in fact. Then I realized that even I don't know sed script syntax good enough, I know language which is tailored at manipulation of XML, which is XSLT. :)
For example when we have xml log4j configuration like this:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p %c{1} - %m%n"/>
</layout>
</appender>
<root>
<priority value ="debug" />
<appender-ref ref="console" />
</root>
</log4j:configuration>
We have to prepare appropriate filtering xslt file:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="root/priority/@value">
<xsl:attribute name="value">warn</xsl:attribute>
</xsl:template>
<xsl:template match="@*|*">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="comment()">
<xsl:copy />
</xsl:template>
</xsl:stylesheet>
, and then call:
$ xsltproc -o log4j.xml filter.xsl log4j.xml
The XSLT file could look a bit verbose, but in fact only first template match is specific. The rest will just copy xml from input to output. Using this technique we can also strip some attributes or semantically replace more structured XML fragments. And all of this without removing XML comments.
The only drawback is that DOCTYPE will not be preserved.
If you want to match specific attribute value:
<xsl:template match="Connector/@port[.='8080']">
<xsl:attribute name="port">8180</xsl:attribute>
</xsl:template>
Nexus is very cool Maven Repository Manager, and debian is as cool server OS platform. I tried to match them. There was some pain, however finally I succeeded :).
Nexus is bundled as war now, thus the description is about installing it on tomcat.
In case of using debian etch (current stable), you may consider installing jdk 1.6 from backports. With jdk 1.6 you have to specify new JAVA_HOME=/usr/lib/jvm/java-6-sun in /etc/default/tomcat5.5.
Debian's tomcat has security manager turned on by default. Of course it could be easily disabled in /etc/default/tomcat5.5, however I feel safer when it is turned on :). Establishing security policy is not easy. My solution to the problem is based on work described in Mark Petrovic's article. I tweaked it a bit not to generate redundant rules. In case of nexus the resulting file looks as follows:
grant codeBase "file:${catalina.home}/bin/tomcat-juli.jar" {
permission java.io.FilePermission "${catalina.base}/webapps/nexus/WEB-INF/classes/logging.properties", "read";
};
grant codeBase "file:${catalina.base}/webapps/nexus/WEB-INF/lib/-" {
permission java.util.PropertyPermission "*", "read,write";
permission java.io.FilePermission "/", "read";
permission java.io.FilePermission "${catalina.base}/logs", "read";
permission java.io.FilePermission "${catalina.base}/webapps/nexus/localhost/nexus/WEB-INF/plexus.properties", "read";
permission java.io.FilePermission "${catalina.base}/webapps/nexus/localhost/nexus/WEB-INF/plexus.xml", "read";
permission java.io.FilePermission "${catalina.base}/webapps/nexus/WEB-INF/log4j.properties", "read";
permission java.io.FilePermission "${catalina.base}/temp", "read,write";
permission java.io.FilePermission "${catalina.base}/temp/-", "read,write,delete";
permission java.lang.RuntimePermission "defineClassInPackage.java.lang", "";
permission java.lang.RuntimePermission "createClassLoader", "";
permission java.lang.RuntimePermission "setContextClassLoader", "";
permission java.lang.RuntimePermission "accessDeclaredMembers", "";
permission java.lang.RuntimePermission "getenv.*", "";
permission java.lang.RuntimePermission "accessClassInPackage.sun.misc", "";
permission java.lang.RuntimePermission "accessClassInPackage.sun.reflect", "";
permission java.lang.RuntimePermission "reflectionFactoryAccess", "";
permission java.lang.RuntimePermission "getClassLoader", "";
permission java.lang.RuntimePermission "modifyThread", "";
permission java.io.FilePermission "${catalina.home}/sonatype-work", "read,write";
permission java.io.FilePermission "${catalina.home}/sonatype-work/-", "read,write,delete";
permission java.net.SocketPermission "*", "connect,resolve";
permission java.lang.reflect.ReflectPermission "suppressAccessChecks", "";
permission java.util.logging.LoggingPermission "control", "";
};
grant codeBase "file:${catalina.base}/webapps/nexus/WEB-INF/classes/-" {
permission java.util.PropertyPermission "*", "read,write";
permission java.io.FilePermission "${catalina.base}/webapps/nexus/localhost/nexus/WEB-INF/plexus.properties", "read";
permission java.io.FilePermission "${catalina.base}/webapps/nexus/localhost/nexus/WEB-INF/plexus.xml", "read";
permission java.io.FilePermission "${catalina.base}/webapps/nexus/WEB-INF/log4j.properties", "read";
permission java.io.FilePermission "${catalina.home}/sonatype-work", "read,write";
permission java.io.FilePermission "${catalina.home}/sonatype-work/-", "read,write,delete";
permission java.lang.RuntimePermission "getenv.*", "";
permission java.lang.RuntimePermission "defineClassInPackage.java.lang", "";
permission java.lang.RuntimePermission "createClassLoader", "";
permission java.lang.RuntimePermission "setContextClassLoader", "";
permission java.lang.RuntimePermission "accessDeclaredMembers", "";
permission java.lang.RuntimePermission "modifyThread", "";
permission java.util.logging.LoggingPermission "control", "";
};
Copy these rules into 60nexus.policy file and place it in /etc/default/tomcat5.5. Restart of JVM is required to make these rules effective.
The line:
permission java.io.FilePermission "/", "read";
is redundant with other rules. The need of reading the whole filesystem seems to be a security flaw. I hope it will be eliminated in future nexus releases. I will fill the bug for this.
These security rules should work ok not only on debian, but also on any other system where tomcat is deployed. There are two system properties in use: catalina.home and catalina.base. This seems to be debian specific. In case of other systems catalina.home should be enough.
Nexus would create sonatype-work directory in user.home which is /usr/share/tomcat5.5 in case of debian. However with security manager we have to create it by ourselves.
host# mkdir /var/opt/sonatype-work host# chown tomcat55:adm /var/opt/sonatype-work host# ln -s /var/opt/sonatype-work /usr/share/tomcat5.5
The /var/opt/sonatype-work will become storage which should be backed up carefully when nexus is used not only as proxy, but also as local maven repository.
Now we can download the latest nexus from http://nexus.sonatype.org/using/download.html
Create logging.properties file with the following contents:
org.apache.juli.FileHandler.level = WARNING java.util.logging.ConsoleHandler.level = WARNING
and put it into WEB-INF/classes inside the war.
Without this modification nexus would log every single HTTP request on console which would be redirected to catalina.out log file. To much verbose default logging seems to be another nexus bug.
Strip the version number from war file, stop tomcat with:
host# /etc/init.d/tomcat5.5 stop
Put nexus.war in
host# /etc/init.d/tomcat5.5 start
Nexus should be visible at http://debianhost:8180/nexus/
Upgradges should be as easy as putting new nexus war in webapps.
GWT modules are defined in special XML format. Developer of a new module has to maintain such file as well as module's java source code. Documentation of the GWT project explains each option which can be put in module descriptor, however one thing is missing there - reference to XML Schema or DTD.
Appropriate DTD has been submitted some time ago, and you can find it here. In order to use it in your own modules just add this DOCTYPE to your module xml file :
<!DOCTYPE module SYSTEM "http://google-web-toolkit.googlecode.com/svn/releases/1.5/distro-source/core/src/gwt-module.dtd">
Some time ago I spotted job offer (polish) posted by a friend of mine. Marek initiated a start up company and now is looking for a new member of his team. The offer is very interesting because it contains a kind of "applicant sieve". :)
There is a task to do for a person who wants to apply - algorithm implemented in any language which solves the following problem:
Having integer numbers array of size N which contains values from range 1 to N, find if there are any duplicated values.
The problem is quite interesting because there are many possible solutions of different properties. Though I am not looking for a new job, I tried to solve the problem. Simple solutions are quite obvious, others which could be called "optimal" become much more complicated. When taking some restrictions into account like O(n) computational complexity, O(1) memory consumption and so on, the solution becomes strightforward. I wonder if it is possible to write an algorithm which will take all restrictions into account and will treat the input array as read-only structure. I tried to implement it, but I failed. :(
In order to achieve the goal I started with testing code. Having some different algorithms I decided to compare their "real life" effectiveness. As you probably know microbenchmarking is loosely connected with real life. :) Anyway writhing them is a good fun. I decided to put everything as open source project called finding-duplicates. I hope Marek won't be angry - the project is spoiling his offer. :) The task was posted some time ago, I hope he has employed someone already. I am quite surprised by the reactions this offer has caused when mentioned on Jacek Laskowski's blog. This is the reason I hope that some people could be interested in my project. I hope that all this buzz will sooner or later bring Marek more candidates. :)
If you have more "optimal" solution then one collected here, just send it to me, or better drop me a line and I will make you a member of this project. I wonder if I have collected all the possible categories of solutions. Special thantks to Adam Woźniak for his implementation. :)
With one additional assumption - array elements are less then N - it would be possible to use algorithm described here, and here. Probably it could be somehow adapted to Marek's problem. For example by adding "virtual" last element to the array. It should has the value less then N (it could be even random number) if we find duplicate and its value is the same as the last element value, then one more pass through the array would be required. Any ideas?
I have been using Maven Integration for Eclipse plugin for some time and I am very fond of it. It is awesome. I imagine there is no a single solution to the problem of bridging two java project meta-descriptors - maven's represented by pom.xml and eclipse's represented by artifacts like .classpath and .project. The way it is implemented in this plugin is just awesome.
There was only one problem I have encountered while using m2eclipse plugin. After upgrade to 0.9.4 release, my eclipse-maven projects stopped working with ClassNotFound exception when being run from eclipse as whether Applications or JUnit tests. It was caused by a change introduced in default eclipse output folders for maven projects. It use to be target-eclipse/classes and is target/classes now - just like standard maven output directory. There is a rationale behind this change.
In order to fix the problem just select a project and choose Maven > Update Project Configuration from context menu. I've spent some time trying to understand what is going on - probably some kind of warning should be shown in case of projects with legacy paths. I hope this entry could help someone having similar problem.
m2eclipse plugin is on a good way to become a project under eclipse umbrella, great.
The phrase "rejoicing in virility" is translated etymology of term ganymede. Ganymedes was the most handsome among mortals - a mythical hero of ancient Greek cluture.
Term ganymede is associated with some memes - probably quite selfish ones. As long as they are referred in this post and as they are understood by readers of this post I assume the last statement being proved. :) In evolution of culture some old memes die, some other are born, some other gain a new life.
Memes of ancient Greek culture often influence birth of new memes and then persist somehow within new ideas. Soon after Galileo discovered moons of Jupiter, one of them was named Ganymede.
A new meme associated with term Ganymede has been born recently. I suppose it's life will be relatively short (about year), although very intensive. For sure it will cause creation of new memes.
If I was asked some time ago what eclipse is, I would not have much problem with the answer - another Java IDE. Now eclipse is much more. We can call it a platform for hosting different development components. Every day connotations of the term eclipse grow like branches of a big tree.
As eclipse is astronomical term, the ganymede used for naming software follows this convention. If I was asked what this Ganymede is I would say: it is an attempt to steer some specific evolutionary process associated with software development. An attempt to stop this evolution for a while. An attempt to match different software projects in the shape they interoperate the best. There is a reason the platform is called ecosystem.
It is not the first time that Eclipse Foundation freezes the evolution at some specific stage. It is called "simultaneous releases" and so far we had two previous releases of this kind also named after moons of Jupiter - Calisto and Europa.
This introduction was long and boring. :) What really interest me as [not-so-]pragmatic programmer, and probably interests you who is reading this post right now, is a comparison between Ganymede and Europa.
Ganymede could be downloaded from a new site. What is nice here - special link for downloading Linux AMD64 version. Finding proper version for this platform was a pain in the past. I have downloaded Mac OS X version numbered as RC3.
I have checked that the Mac OS X version comes with eclipse.ini file adjusted for more realistic usage scenario
-Xms40m -Xmx512m -XX:MaxPermSize=256m
Good, I won't have to tweak it by hand. It was probably fixed also in the latest Europa bundles, but for sure not in the initial ones.
During eclipse start I spotted new splash screen, quite interesting to see what else could be arranged with the same conceptual graphical elements and the same color scheme.
My workspace seems to be upgraded quite smoothly. From the first sight I cannot see anything new in eclipse appearance. Although generally being liberal I tend to be conservative on some topics. One of them is look and behavior of tools I am using and I got use to. It is not about software only. It could be about hammer or screwdriver, any extension of human body or human mind. :)
Although version Eclipse IDE for Java EE Developers provides quite comprehensive development environment there are still some missing futures I use on day to day basis.
Installation of eclipse plugins has been completely redesigned. Now it is simpler and clearer and works without much ambiguity as it use to be. New option of Automatic Updates was added to general eclipse preferences, nice. However there seems to be some software update related bug in RC3, eclipse is trying to install the same upgrades forever. Fortunately when I came back to eclipse.org there was RC4 release available which upgrades without any problem.
I see only one drawback comparing to previous Software Updates functionality. Selecting plugin to install will not show brief description. The description could be find in General Information after right clicking and choosing Properties.
Ganymede comes with dozens of new features comparing to Europa. Some of them I have been using already however specifying Update Site manually. Now these releases are synchronized available from predefined sources. I will just name things important to me:
The last feature is quite interesting:
The Usage Data Collector collects information about how individuals are using the Eclipse platform. This information is periodically uploaded to servers hosted by The Eclipse Foundation (though this is configurable). The intent is to use this data to help committers and organizations better understand how developers are using Eclipse.
Target Users of the Data:
- Users of Eclipse
- Committers working on Eclipse projects
- ISVs and organization creating Eclipse based software
- Enterprise IT departments that make extensive use of Eclipse Foundation
- Academic researchers that want to study how developer work Data to Be Collected
Captured data is associated with a user through a combination of workstation and workspace ids that are automatically generated by the collector. This identification is not tied to any personal information about the user.
The usage data monitors:
- Start up and shutdown times of a workspace
- What is being used and when (timestamp), including
- Loaded bundles
- Commands accessed via keyboard shortcuts
- Actions invoked via menus or toolbars
- Perspective changes
- View usage
- Editor usage
Where possible, the usage data collector also capture the symbolic name and version of the bundle contributing the command/action/perspective/view/editor.
This functionality reminds me Debian Popularity Contents. Did I say something about evolution. It is definitely a kind of convergence.
Subversive plugin is now part of the distribution. Unfortunately it still depends on connectors provided by Polarion. I added:
http://www.polarion.org/projects/subversive/download/eclipse/2.0/update-site/
to my Update Sites, nice feature here (or rather lack of annoyance :) ) - I am not longer forced to provide Site Name - just URL.
I installed SVNKit 1.1.7.
Now it is a time for Maven Integration Plugin plugin, I installed:
BTW there is a proposal to create Eclipse Integration for Apache Maven (IAM) under the umbrella of the Eclipse Foundation, great.
I installed additional plugins without any problem:
And now a little bit about new features I can see from the first sight:
Unfortunately the most annoying bug (at least for Mac OS X users) of the latest Europa updates remains in Ganymede (I suppose it is connected with SWT). :(
I can see italics text in case of attributes shown in XML editor, interesting.
While browsing available views and perspectives I spotted some interesting things I hadn't tried.
That's all for now. I hope to write more when I will start using these new features. So far ganymede looks very promising and interesting.
Valueable memes never die. :) Eclipse Foundation is quite good in spreading own memes. It is very interesting to see what kind of "social engineering" is used in order to attract mass attention for products of open source movement . Firefox is a perfect example with todays Download Day 2008.
I though that it is an axiom of Java language specification - one cannot call new method defined in anonymous class outside the scope of this class. I was wrong. :)
public class AnonymousClassMethod { public static void main(String[] args) { (new Object() { void foo() { System.out.println("foo"); } }).foo(); } }
This code just prints foo
But what is the purpose of such construct. Here is simple example which came to my mind:
public class Caller { public static void main(String[] args) { System.out.println((new Subject()).getCallerClass()); } }
public class Subject { public Class getCallerClass() { return (new SecurityManager() { Class getCallerClass() { return getClassContext()[1]; } }).getCallerClass(); } }
Crazybob has another example.
GWT module library should be prepared according to specific convention. The part of module source code which is compiled from Java into Java Script, resides in org.foo.module.client package by default. GWT compiler will use Java sources, not compiled Java bytecode, thus it is important to include "client side" sources inside module library jar file. Building proper jar requires some modification to project's standard pom.xml file:
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/client/**</include>
<include>**/public/**</include>
<include>**/*.gwt.xml</include>
</includes>
</resource>
</resources>