Montag, 14. Dezember 2009

Disable IPv6 in Debian Lenny Linux

And here is how to do this:
  • At first the stuff every web site is telling us: In /etc/modprobe.d/aliases replace/add the following mappings: alias net-pf-10 off alias ipv6 off (I found this at fak3r.com)
  • If you are using a firewall script which loads all available module before setting up the firewall, add the following lines to /etc/modprobe.d/aliases: alias ip6_queue.ko off alias ip6table_filter.ko off alias ip6table_mangle.ko off alias ip6table_raw.ko off alias ip6table_security.ko off alias ip6_tables.ko off alias ip6t_ah.ko off alias ip6t_eui64.ko off alias ip6t_frag.ko off alias ip6t_hbh.ko off alias ip6t_hl.ko off alias ip6t_HL.ko off alias ip6t_ipv6header.ko off alias ip6t_LOG.ko off alias ip6t_mh.ko off alias ip6t_REJECT.ko off alias ip6t_rt.ko off alias nf_conntrack_ipv6.ko off You can do this by executing: for module in `ls /lib/modules/YOUR-KERNEL-VERSION/kernel/net/ipv6/netfilter/`; do echo "alias $module off" >> /etc/modprobe.d/aliases; done
Hope this helps :-)

Donnerstag, 3. Dezember 2009

Apache2 httpd, Apache Tomcat6 and rewrite problems

While configuring a Apache2 as Proxy for a bunch of Tomcats behind I found many postings that says "Use mod_rewrite and this set of rules" or "you have to use ajp and mod_jk". After some rtfm I found out that setting up a Apache2 httpd with multiple Apache Tomcats behind mapped using mod_proxy is pretty simple and straight forward. here is the HowTo:
1. Add a site to the apache2:
cat /etc/apache2/sites-enabled/artifactory
<Location /artifactory/>
    ProxyPass http://127.0.0.1:8100/artifactory/
    Order deny,allow
    Allow from all
</Location>
2. Enable mod_proxy by creating the following links (ln -s target) in /etc/apache2/mods-enabled/
proxy.conf -> ../mods-available/proxy.conf
proxy_http.load -> ../mods-available/proxy_http.load
proxy.load -> ../mods-available/proxy.load
3. Modify the content of /etc/apache2/mods-enabled/proxy.conf :
<IfModule mod_proxy.c>
ProxyRequests Off

<Proxy *>
    Order deny,allow
    Allow from all
</Proxy>

</IfModule>
4. reload the apache2 server:
/etc/init.d/apache2 reload
5. modify $TOMCAT_HOME/conf/server.xml
Change from:
<Connector port="8100" protocol="HTTP/1.1"
connectionTimeout="20000" redirectPort="8443" />
to
<Connector port="8100" protocol="HTTP/1.1"
connectionTimeout="20000" redirectPort="8443"
proxyName="YourDomain.YourTLD" proxyPort="80"/>

Montag, 14. September 2009

DragImagePainter or Getting Around isDragImageSupported() on Windows

Last week I had an interesting conversation with a project manager at a meeting of the Scrum User Group in Dresden. He asked me why so many common tasks need to be reprogrammed in every project. I tried to answer that question and argued that things need to be implemented in a different way for different purposes... But today I came to the conclusion the he's right. Reimplementing common tasks is expensive and it happens too often. "The customer wants to relayout some components on the fly using Drag and Drop. While dragging a small drag image of the dragged component should be visible near the mouse pointer." - Sounds like a common use case to me. But Drag and Drop (DnD) in Swing does not support this. Of course Swing supports Drag and Drop out of the box - but only for a small amount of components. I don't know why this feature is missing in a framework which is in use since a decade. On my way implementing this feature I stumble upon the method isDragImageSupported() of the class java.awt.dnd.DragSource. Windows does not support adding a DragImage to the mouse pointer. Google told me to look at Geertjan's Blog. He wrote a nice and informative article how to implement this feature. Nicely done! But doing it the way he did means doing it again and again and the poor customer needs to pay for this :) As I want customers of IT companies to be happy I tried to save the world. First of all I called my brother in arms rosh. With combined holy hand grenades we wrote a kewl class called DragImagePainter. It needs to be instantiated in the java.awt.dnd.DragSourceListener. In method dragOver of the java.awt.dnd.DragSourceListener a call to the function paintDragImage will do the magic. Feel free to use AND REUSE the following piece of code:
/**
* Utility class for painting a scaled and opaque image representation of a
* dragged component while it's being dragged.
*
* @author Richi
*
*/
public class DragImagePainter {
private final AlphaComposite ALPHA_COMPOSITE = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f);
private final JComponent rootComponent;
private final JComponent draggableComponent;
private final int offsetY;
private final int imageWidth;

private Point lastKnownCursorPosition;

/**
 * @param rootComponent
 *            the root component of the current window
 * @param draggableComponent
 *            the component which is going to be dragged
 */
public DragImagePainter(JComponent rootComponent, JComponent draggableComponent) {
 this.rootComponent = rootComponent;
 this.draggableComponent = draggableComponent;
 this.offsetY = -15;
 this.imageWidth = 50;
}

/**
 * Paints a scaled and opaque image representation of the draggableComponent
 * provided in the constructor near the current mouse pointer position.
 *
 * @param currentCursorPositionX
 * @param currentCursorPositionY
 */
public void handleDragOver(int currentCursorPositionX, int currentCursorPositionY) {
 boolean imagePositionChanged = imagePositionChanged(currentCursorPositionX, currentCursorPositionY);
 if (imagePositionChanged) {
  double scaleFactor = calculateScaleFactor();
  int imageHeight = calculateImageHeight(scaleFactor);
  if (!isFirstRun())
   repaintLastKnownImageArea(imageHeight);
  Graphics2D rootComponentGraphics = (Graphics2D) rootComponent.getGraphics();
  paintDragImage(currentCursorPositionX, currentCursorPositionY, scaleFactor, rootComponentGraphics);
  lastKnownCursorPosition = new Point(currentCursorPositionX, currentCursorPositionY);
 }
}

/**
 * Needs to be called on {@link DragSourceListener}.dragEnd() to repaint the
 * area of the last painted drag image
 */
public void handleDropEnd() {
 double scaleFactor = calculateScaleFactor();
 int imageHeight = calculateImageHeight(scaleFactor);
 repaintLastKnownImageArea(imageHeight);
}

double calculateScaleFactor() {
 return (double) imageWidth / draggableComponent.getWidth();
}

private int calculateImageHeight(double scaleFactor) {
 return (int) Math.ceil(draggableComponent.getHeight() * scaleFactor);
}

boolean imagePositionChanged(int currentCursorPositionX, int currentCursorPositionY) {
 return isFirstRun() || lastKnownCursorPosition.x != currentCursorPositionX
   || lastKnownCursorPosition.y != currentCursorPositionY;
}

void repaintLastKnownImageArea(int height) {
 rootComponent.paintImmediately(lastKnownCursorPosition.x, lastKnownCursorPosition.y + offsetY, imageWidth,
   height);
}

boolean isFirstRun() {
 return lastKnownCursorPosition == null;
}

void paintDragImage(int currentCursorPositionX, int currentCursorPositionY, double scaleFactor,
  Graphics2D rootComponentGraphics) {
 Graphics2D dragPictureGraphics = (Graphics2D) rootComponentGraphics.create();

 dragPictureGraphics.translate(currentCursorPositionX, currentCursorPositionY + offsetY);
 dragPictureGraphics.scale(scaleFactor, scaleFactor);
 dragPictureGraphics.setComposite(ALPHA_COMPOSITE);

 draggableComponent.paint(dragPictureGraphics);
}

}
Use in this way:
@Override
public void dragDropEnd(DragSourceDropEvent dragSourceDropEvent) {
dragImagePainter.handleDropEnd();
}
@Override
public void dragOver(DragSourceDragEvent dragSourceDragEvent) {
dragImagePainter.handleDragOver(dragSourceDragEvent.getX(), dragSourceDragEvent.getY());
}

Freitag, 11. September 2009

Who is doing QA on selfhtml.org?

Not many words on this:
if (document.Testform.Art[0].checked == true) { ... }

Donnerstag, 3. September 2009

Sony Ericsson W995, Google Calendar and Google Sync

After a long time a shorty:
I'm using gmail and the google calendar. I was searching for a cell phone which is able to sync with my google accounts. I've chosen the W995 since its price is the half of a G-Phone/I-Phone or Palm Pre and it fits my needs. Its fast, has a good battery AND since today it's able to synchronize my google calendar items and mails. All you have to do is to go to menu>organizer>synchronisation and set up a new Exchange Active Sync account:
  • Server address : https://m.google.com
  • Domain : Empty - this means leave this field blank
  • Username : your.name@googlemail.com (your full email address)
  • Password : 31337

Samstag, 20. Juni 2009

Stripes Image Streamingresolution

I'm often asked how to stream an image from sources like a database blob or a folder which is not shared by the servlet container to the client using stripes. This is done by extending the class net.sourceforge.stripes.action.StreamingResolution. The most simple way:
public Resolution view( ) {
  ...
  String mimeType = getContext().getServletContext().getMimeType(fileName);
  final byte[] file = readFileToByteArray(absolutFilePath);//this method needs to be implemented
  return new StreamingResolution(mimeType) {
     @Override
     protected void stream(HttpServletResponse response) throws Exception {
        response.getOutputStream().write(file);
     }
  };
}
When streaming static content I'd recommend a more complex solution using headers to modify file names or caching behavior of the browser:
public Resolution view( ) {
  ...
  String mimeType = getContext().getServletContext().getMimeType(fileName);
  final byte[] file = readFileToByteArray(absolutFilePath);//this method needs to be implemented
  return new StreamingResolution(mimeType) {
     @Override
     protected void stream(HttpServletResponse response) throws Exception {
        setFilename("TheHolyHandGranade.gif");
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DAY_OF_YEAR, 30);
        Date expires = calendar.getTime();
        response.setDateHeader("Expires", expires.getTime());
        response.getOutputStream().write(file);
     }
  };
}
Hope this helps :-)

Donnerstag, 18. Juni 2009

Partially mocking the class under test

When writing a class it sometimes happens that you have to write a method which invokes methods of the same instance. I was wondering how to test those methods in isolation. Here is an abstract example demonstrating the problem: Class XYZ
  • method doThisIfCase1OrThatOtherwise
  • method doThis
  • method doThat
Testing doThis and doThat should not be a problem. But testing doThisIfCase1OrThatOtherwise without testing doThis and doThat again seemed impossible to me. Of course it would be possible to extract doThis and doThat into a separate class and then mock this class when testing doThisIfCase1OrThatOtherwise. But there are cases doing this smells a bit like over engineering. In cases I don't know what to do I ask Misko my test and clean code oracle. As always he provided me with a solution: Override the methods doThis and doThat and assert that they get called. This is an example from my "real" world: The class under test:
...
public void openAndCreateIfNotExists() throws IOException {
if (!destinationClassPathFile.exists()) {
 createEmptyClassPathFile();
} else {
 openExistingClassPathFile();
}
}

void createEmptyClassPathFile() {
eclipseClassPathDocument = DocumentHelper.createDocument();
eclipseClassPathDocument.addElement("classpath");
}

void openExistingClassPathFile() throws IOException {
SAXReader reader = new SAXReader();
try {
 eclipseClassPathDocument = reader.read(destinationClassPathFile);
} catch (DocumentException e) {
 throw new IOException("Invalid class path file " + destinationClassPathFile.getCanonicalPath(), e);
}
}
...
The test:
@Test
public void testOpenAndCreateIfNotExistsCreates() throws IOException {
File file = new File("src-test/testOpenAndCreateIfNotExistsCreates.testFile");
if (file.exists())
 file.delete();
file.deleteOnExit();
assertFalse(file.exists());
final StringBuilder stringBuilder = new StringBuilder();
EclipseClassPathManipulator eclipseClassPathManipulator = new EclipseClassPathManipulator(file) {
 @Override
 void createEmptyClassPathFile() {
  stringBuilder.append("igotcalled");
 }
};
eclipseClassPathManipulator.openAndCreateIfNotExists();
assertEquals("igotcalled", stringBuilder.toString());
}

@Test
public void testOpenAndCreateIfNotExistsOpens() throws IOException {
final StringBuilder stringBuilder = new StringBuilder();
File file = new File("src-test/testOpenAndCreateIfNotExistsOpens.testFile");
file.createNewFile();
file.deleteOnExit();
assertTrue(file.exists());
EclipseClassPathManipulator eclipseClassPathManipulator = new EclipseClassPathManipulator(file) {
 @Override
 void openExistingClassPathFile() throws IOException {
  stringBuilder.append("igotcalled");
 }
};
eclipseClassPathManipulator.openAndCreateIfNotExists();
assertEquals("igotcalled", stringBuilder.toString());
}

Mittwoch, 17. Juni 2009

java.io.FileFilter - a pragmatic and powerful way to select files

Today I discovered the FileFilter interface. A little bit late maybe - but better late than never!
File[] libs = libDir.listFiles(new FileFilter() {
  public boolean accept(File pathname) {
     return !pathname.isDirectory() && pathname.getName().endsWith(".jar");
  }
});
This example is a very simple one but since this is a method instead of a pattern like *.jar there are no limitations how the filtering is done. Regular expressions, web services, databases, relations of file names, ... I do like that approach since even it is powerful it's still simple and easy to use. If all API's were designed like this software development would be simpler and faster.

Dienstag, 2. Juni 2009

Providing user specific style sheets (using Stripes)

Customers often want to have a web application in their own CI. Stripes doesn't ship with a ready to use solution for this problem - but that would be impossible since every application has its own requirements for such a feature. But Stripes ships with a feature called user friendly urls. IMHO there are a lot of other web frameworks providing this feature so the following solution is not strictly tied the Stripes framework. The main idea behind this is to include standard css files in a common way:
<link rel="stylesheet" type="text/css" href="/css/ci.css">
and override special style definitions with user specific ones:
<link rel="stylesheet" type="text/css" href="/user-styles/css/ci.css">
The folder css is a real existing one. The folder user-styles is an action bean bound to the url /user-styles/ with a default handler method. The part after /user-styles(/css/default.css) is mapped to a property called "requestedFile". The default handler now builds a real path in some way like this: "<userSpecificStyleFolder>/<userId>/requestedFile" Then the default handler loads this file using the real path(java.nio provides a fast way to read files) and streams it out. If all the images are defined in the css files using a relative path, these images will also be requested using the default handler. So even user specific images are supported. If the users are organized in companies a company wide style could be achieved if the userId is replaced with the companyId when building the real path("<userSpecificStyleFolder>/<companyId>/requestedFile"). In Stripes the action bean would look like this:
@StrictBinding
@UrlBinding("/user-styles/{requestedFile}")
public class UserStyleAction implements ActionBean {
 private static final Log log = LogFactory.getLog(UserStyleAction.class);
 static final String FILE_SEPARATOR = System.getProperty("file.separator");
 private ActionBeanContext actionBeanContext;
 private String requestedFile;
 private String basePath;
 private User user;

 public UserStyleAction() {}

 public UserStyleAction(String basePath) {
  this.basePath = basePath;
 }

 @Before(on="serveFile")
 public Resolution loadUserFromSessionAndSendErrorIfNotLoggedIn() {
  user = (User) actionBeanContext.getRequest().getSession().getAttribute(User.class.toString());
  if (user == null)
   return new ErrorResolution(404);
  return null;
 }

 @Before
 public void initBasePath() throws IOException {
  // This is done to make this project run in every eclipse --> use a config
  // file in real world apps
  String realPathOfClass = actionBeanContext.getServletContext().getRealPath("UserStyleAction.class");
  String webAppFolder = realPathOfClass.replace("UserStyleAction.class", "");
  basePath = new File(webAppFolder + FILE_SEPARATOR + "WEB-INF" + FILE_SEPARATOR + "user-styles").getCanonicalPath();
 }

 @DefaultHandler
 public Resolution serveFile() throws IOException {
  try {
   String mimeType = actionBeanContext.getServletContext().getMimeType(requestedFile);
   File file = new File(buildAbsoluteFilePath(basePath, user));
   throwExceptionInCaseOfDirectoryTraversalAttack(basePath, file);
   FileInputStream fileInputStream = new FileInputStream(file);
   StreamingResolution streamingResolution = new StreamingResolution(mimeType, fileInputStream);
   return streamingResolution;
  } catch (Exception e) {
   if (log.isDebugEnabled())
    log.debug("Error reading file " + requestedFile + " requested by user " + user, e);
   return new ErrorResolution(404);
  }
 }

 String buildAbsoluteFilePath(String basePath, User user) {
  return basePath + FILE_SEPARATOR + user.getId() + FILE_SEPARATOR + requestedFile;
 }

 void throwExceptionInCaseOfDirectoryTraversalAttack(String basePath, File file) throws IOException {
  if (!file.getCanonicalPath().startsWith(basePath + FILE_SEPARATOR + user.getId()))
   throw new RuntimeException("Attempt to hack the application");
 }

 @Validate
 public void setRequestedFile(String requestedFile) {
  this.requestedFile = requestedFile;
 }

 @Override
 public ActionBeanContext getContext() {
  return actionBeanContext;
 }

 @Override
 public void setContext(ActionBeanContext context) {
  this.actionBeanContext = context;
 }

}
A full sample is available at the svn repository

Sonntag, 31. Mai 2009

The future of the human race

This science fiction future theory differs from the golden future theories of movies like Star Trek. It predicts no nuclear war but is more frightening than Terminator or The Chronicles of Riddick. Its theory seems also more presumably than the other ones: via videosift.com

Samstag, 30. Mai 2009

EasyMock as an easy to use alternative to jMock

EasyMock does exactly what its name promises: It provides an easy way to mock objects. I never really liked the way jMock needs to be used. mockery.checking takes an ExpectationBuilder named expectations as single parameter. But this parameter is a special initialized object of type Expectations - I always had to look into the docs and count the brackets. The auto completition feature of eclipse also works bad for this way of programming. Here is a sample test using jMock:

@Test
  public void testInterceptWithWrongSetSessionMethod( ) throws Throwable {
      final Method[] methods = getSortedMethods();
      final HibernateHelper hibernateHelper = mockery.mock(HibernateHelper.class);
      final IAnnotatedMethodLocator methodLocator = mockery.mock(IAnnotatedMethodLocator.class);
      final MockServiceBean serviceBean = mockery.mock(MockServiceBean.class);
      final Session transactional = mockery.mock(Session.class);
      final MethodInvocation invocation = mockery.mock(MethodInvocation.class);
      mockery.checking(new Expectations() {
          {
              one(invocation).getMethod();
              will(returnValue(methods[1]));
              one(hibernateHelper).openTransactionalSession();
              will(returnValue(transactional));
              one(invocation).getThis();
              will(returnValue(serviceBean));
              one(methodLocator).getAnnotatedMethod(invocation, HBSISetSession.class);
              will(returnValue(methods[1]));
          }
      });
      HibernateBasedServiceInterceptor interceptor = new HibernateBasedServiceInterceptor(hibernateHelper, methodLocator);
      try {
          interceptor.invoke(invocation);
          fail("exception expected");
      } catch (ServiceException e) {
      }
      mockery.assertIsSatisfied();
  }
And the next beautiful test method is using EasyMock:

@Test
  public void testInterceptWithWrongSetSessionMethodEasyMock( ) throws Throwable {
      Method[] methods = getSortedMethods();
      HibernateHelper hibernateHelper = EasyMock.createMock(HibernateHelper.class);
      IAnnotatedMethodLocator methodLocator = EasyMock.createMock(IAnnotatedMethodLocator.class);
      MockServiceBean serviceBean = EasyMock.createMock(MockServiceBean.class);
      Session transactional = EasyMock.createMock(Session.class);
      MethodInvocation invocation = EasyMock.createMock(MethodInvocation.class);
      EasyMock.expect(invocation.getMethod()).andReturn(methods[1]);
      EasyMock.expect(hibernateHelper.openTransactionalSession()).andReturn(transactional);
      EasyMock.expect(invocation.getThis()).andReturn(serviceBean);
      EasyMock.expect(methodLocator.getAnnotatedMethod(invocation, HBSISetSession.class)).andReturn(methods[1]);
      EasyMock.replay(hibernateHelper, methodLocator, serviceBean, transactional, invocation);
      HibernateBasedServiceInterceptor interceptor = new HibernateBasedServiceInterceptor(hibernateHelper, methodLocator);
      try {
          interceptor.invoke(invocation);
          fail("exception expected");
      } catch (ServiceException e) {
      }
      EasyMock.verify(hibernateHelper, methodLocator, serviceBean, transactional, invocation);
  }
Clean Java code using a nice and easy to use API.

Sniffing keystrokes from wireless keyboards

I'm currently @ ph-neutral in Berlin and listening to an interesting talk about wireless keyboards. It seems to be very easy to sniff the keystrokes since the encryption is done using xor. If anyone is interested in additional information about this topic he should look out for the keykeriki project home page.

Donnerstag, 28. Mai 2009

JPA and default values

Today I found out that it is not possible to define default values of fields which are mapped to a column of table in a database. The workaround is to do the work in the default constructor and a manual tweak of the generated database schema. IMHO this is one of the cases which prevents fully automatic schema generation and increases the development time and chance of bugs :-(

Mittwoch, 27. Mai 2009

Expose for Vista

Many software developers are fighting a war against the chaos of many open windows at the same time. A few weeks ago I found the holy hand grenade on a Kubuntu box built by the secret research institution of the developers fraction: a feature called expose. It arranges all open windows next to each other and zooms out so its easy to catch a glimpse of them. Since the Kubuntu box didn't run very stable I searched a solution for Vista. Found many commercial and noncommercial versions and decided to use the one called switcher. It's kewl, very configurable, free and stable. It can be downloaded from the product website http://insentient.net/. I already shared it with my brothers in arms and got quiet a response so I thought it might be worth blogging about it...

Mittwoch, 20. Mai 2009

Germany - a country full of terrorists

*attention - sarcasm*
Today I saw it in the news on youtube: 82 million terrorists are living in Germany. Thank god the german state pays attention and is going to hunt down all the black hats:

Dienstag, 12. Mai 2009

jQuery Autocomplete Plugin

jQuery doesn't ship with an auto complete UI component. I found a very nice, and very very very very flexible jQuery Plugin doing this job named Autocomplete. It supports static and dynamic data and cause of its event model it's very flexible. For instance it's no problem to have a autocomplete text field for a ZIP code which automatically fills in an additional city field. It also has formatters which can be used to format the proposals - eg. the ZIP field fills in ZIP codes but provides ZIP - CITY as proposal.

sunshine live webradio without the annoying advertisments popup

Quick access to pure dance / trance / techno music without any overhead of pictures, advertisements and clicks is available at this url: Sunshine Live - Livestream

UTF-8 character encoding problems with ISO-8859-1 encoded Java property files

Java property files need to be ISO-8859-1 encoded. But when it comes to i18n of an application you'll have to overcome the limitations of this character set. In short: ISO-8859-1 does not support all required characters. Changing the encoding of property files to utf-8 is not (yet) supported by Java. To overcome this limitation the guys from http://propedit.sourceforge.jp built an editor named PropertiesEditor. It writes the property file with properly escaped UTF8 symbols.

Donnerstag, 7. Mai 2009

Hibernate Transactions and Connection Pooling

After 2 years of Java development using hibernate I noticed that my understanding of hibernate sessions and transactions was completely wrong. I thought:
  • I can interact with the database within and without a transaction.
  • Performance is better without a transaction.
  • Inserting a single entity without a transaction is good thing.
  • I don't need to step into the details of connection pooling until performance issues occurs.
  • If I call session.close() the session is closed and hibernate takes care of open transactions
I got it all wrong. After a bit of rtfm'ing and testing I noticed:
  • Interaction with a database always requires a transaction in hibernate. There is a feature called auto-commit which opens a transaction before executing a statement and closes it immediately after execution of the statement. This behavior is causing performance issues if a huge amount of queries is executed(Lazy Collections). So if I'm working with hibernate, I have to define the scope of the transaction(s).
  • Performance difference between commit and rollback within a transaction which not issued any write access is really hard to measure - there is no real difference.
  • Inserting a single entity without a transaction is impossible.
  • [ INFO] 21:17:01 org.hibernate.connection.DriverManagerConnectionProvider:64 - Using Hibernate built-in connection pool (not for production use!)
  • If I call session.close() using built in connection pooling the last transaction is untouched and reused by the next session obtained by sessionFactory.openSession(). Worst case scenario is one day of inserts and updates and the next day a transaction.rollBack() causes a heavy data loss. Using an alternative connection pooling (eg C3p0) is a must do, not a nice to have.
I created a simple test project named 'de.rhauswald.learning.hibernate.transactions' and committed it to this repository.

How to install Eclipse Subversive SVN Plugin

1. Adding the required update sites to the Eclipse Update/Add-On Manager Open Eclipse and navigate to Help->Software Updates...

Switch to the Available Software tab und use the Add Site... Button to the following URL's:


http://download.eclipse.org/technology/subversive/0.7/update-site/
http://www.polarion.org/projects/subversive/download/eclipse/2.0/update-site/

Note that these URL's may change over the time. Have a look at the Eclipse project site of Subversive to get fresh URL's.

2. Selecting and installing the required components The following components needs to be checked:
Subversive SVN Connectors
Subversive SVN Team Provider
SVNKit 1.3.0 Implementation

Click Install... and restart Eclipse after installation finished.

If you are new to the whole topic, you should rtfm the documentation of the plugin

Freitag, 17. April 2009

Using Derby in a comfortable way in eclipse

Today I decided to test if Derby is better then hsqldb from the usablility poit of view. After a few hours I found a very comfortable way to integrate derby into my eclipse. I created a small test project with a hibernate setup and tests. Everything worked fine. IMHO Derby is simple to set up and its simple to have a look in the database tables. At least more simple than it is using hsqldb. If anyone is interested in the manuals that helped me to set up the environment, heres a link list:
  • Integrating derby into eclipse:
    http://db.apache.org/derby/integrate/plugin_howto.html

    Note: In the projects properties you can modify the path, where Derby stores the database files.
  • Starting the database network server:
    http://db.apache.org/derby/integrate/plugin_help/start_server.html
  • Using Squirrel as front end:
    http://db.apache.org/derby/integrate/SQuirreL_Derby.html
This is the hibernate setup I used:

public static SessionFactory createDerbyFactory() {
 AnnotationConfiguration annotationConfiguration = new AnnotationConfiguration();
 annotationConfiguration.setProperty("hibernate.connection.driver_class", "org.apache.derby.jdbc.ClientDriver");
 annotationConfiguration.setProperty("hibernate.connection.url", "jdbc:derby://localhost:1527/simpletest");
 annotationConfiguration.setProperty("hibernate.connection.username", "user");
 annotationConfiguration.setProperty("hibernate.connection.password", "user");
 annotationConfiguration.setProperty("hibernate.dialect", "org.hibernate.dialect.DerbyDialect");
 annotationConfiguration.setProperty("hibernate.show_sql", "true");
 annotationConfiguration.setProperty("hibernate.format_sql", "true");
 annotationConfiguration.setProperty("hibernate.hbm2ddl.auto", "create-drop");
 annotationConfiguration.addAnnotatedClass(Person.class);
 return annotationConfiguration.buildSessionFactory();
}


In order to use this setup, you need to create a derby database. How to do this, is described here:
http://db.apache.org/derby/integrate/SQuirreL_Derby.html

Dienstag, 14. April 2009

Ein Witz in der Java API Doc

May the force be with you :-) --> http://java.sun.com/j2se/1.4.2/docs/api/java/text/MessageFormat.html

Here are some examples of usage:

     Object[] arguments = {
         new Integer(7),
         new Date(System.currentTimeMillis()),
         "a disturbance in the Force"
     };

     String result = MessageFormat.format(
         "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.",
         arguments);

     output: At 12:30 PM on Jul 3, 2053, there was a disturbance
               in the Force on planet 7.

Donnerstag, 26. Februar 2009

Hibernate Basisklasse für saubere Datenbanken und einfaches Testen

Ich stolpere öfters über Entity Objekte aus Hibernate, die zum Teil String, int, long, Integer oder auch Long als Datentyp haben. Ich will nicht auf die Nachteile von Strings oder ints als Primary Key eingehen, aber auf einen Weiteren: Einfaches Testen von Apps mit InMemory Mockdaten. Wer für jedes Entity Objekt einen eigenen InMemory Service schreiben muss, produziert zwar viele Zeilen Code, tut dabei aber nichts sinnvolles. Wenn man seine Entities von einer Abstrakten Basislasse ableitet, welche den PK, die Version, hashCode() und equals() enthält, kann man auch mit einer generischen InMemoryService Implementation arbeiten. Hier der Code:

@MappedSuperclass
public abstract class PersistantObject implements Serializable {
 private static final String TO_STRING_FORMAT = "ID: {0}, Version: {1}";
 private static final long serialVersionUID = -2782842909081144965L;
 protected Long id;
 protected Long version;

 public PersistantObject() {
 }

 @Id
 @GeneratedValue(strategy = GenerationType.IDENTITY)
 public Long getId() {
  return id;
 }

 public void setId(Long id) {
  this.id = id;
 }

 @Version
 public Long getVersion() {
  return version;
 }

 public void setVersion(Long version) {
  this.version = version;
 }

 @Override
 public int hashCode() {
  if (id == null)
   return super.hashCode();
  final int prime = 31;
  int result = 1;
  result = prime * result + id.hashCode();
  return result;
 }

 @Override
 public boolean equals(Object obj) {
  if (obj == null)
   return false;
  if (!(obj.getClass().equals(this.getClass())))
   return false;
  PersistantObject checkMe = (PersistantObject) obj;
  if (this.id == null && checkMe.id == null)
   return super.equals(obj);
  if (this.id == null)
   return false;
  if (checkMe.id == null)
   return false;
  if (!id.equals(checkMe.id))
   return false;
  return version.equals(checkMe.version);
 }
 
 @Override
 public String toString() {
  return MessageFormat.format(TO_STRING_FORMAT, id, version);
 }
}

public class InMemoryService {
 private List data;

 public InMemoryService() {
  data = new ArrayList();
 }

 public void insert(T entity) {
  if (data.size() == 0)
   entity.setId(0L);
  else
   entity.setId(data.get(data.size() - 1).getId() + 1L);
  entity.setVersion(0L);
  data.add(entity);
 }

 public T get(Long id) throws ServiceException {
  for (T entity : data)
   if (entity.getId().equals(id))
    return entity;
  throw new ElementNotFoundException();
 }

 public void update(T entity) throws ServiceException {
  T old = get(entity.getId());
  if (!old.getVersion().equals(entity.getVersion()))
   throw new RuntimeException(
     "Concurrent modification");
  data.remove(old);
  entity.setVersion(entity.getVersion() + 1L);
  data.add(entity);
 }

 public void delete(Long id) throws ServiceException {
  data.remove(get(id));
 }

 public List getAll() {
  return data;
 }
}
Natürlich ist der InMemoryService nicht ThreadSafe, aber er ist ja auch nur zum Testen da :-)

Mittwoch, 18. Februar 2009

JavaScript Injection für einen guten Zweck

Auf Arbeit muss ich meine Zeit Minutengenau mit einem selbst entwickelten Tool auf die einzelnen Tasks meiner Projekte buchen. Dieses Tool hat jedoch einen (gewollten) Bug, wenn man die Tasks vom Vortag nachträgt. Es gibt einen DatePicker, mit dem man das gestrige Datum auswählt und 3 Textfelder für Datum, Start und Ende des zu trackenden Tasks. Das Feld für das Datum wird bei jedem Request auf das aktuelle Datum gesetzt, auch wenn im DatePicker das gestrige ausgewählt ist. Zum Glück ist das Tool anfällig für JS Injection, was mir einen bequemen Einstiegspunkt für meinen Bugfix bietet. An Meinen Vornamen hänge ich also meinen Bugfix Code an: Alter Vorname: Richard Neuer Vorname: Richard<script language="JavaScript">Event.stopObserving(window, 'load');Event.observe(window, 'load', function() { if(document.getElementById('e_date')) {Event.observe($('day_task_beginT'),'focus',function(){var mydate=$('e_date').calendar_date_select.selected_date;$('day_task_date').value=(mydate.getDate() + '.' + (mydate.getMonth()+1) + '.' + mydate.getFullYear())})}});</script>
Dank Prototype ist es leicht ein passendes Event zu binden und das Aktualisieren des Datums-Textfelds auf das im DatePicker ausgewählte Datum zu automatisieren. Also liebe Webentwickler, passt auf, dass Ihr alle Ausgaben aus der Datenbank auch wirklich ordentlich quoted ;-)

Montag, 9. Februar 2009

Update von Hibernate gemappten Beans mit eingebetten Listen weiterer Hibernate Beans und CascadeType DeleteOrphan

Ich bin heute auf ein interessantes Problem gestoßen, als ich einer Mutti eins ihrer Kinder wegnehmen wollte. Ich habe 2 Hibernate gemappte Beans, Mutti und Kind. Die Mutti hat eine Liste von Kindern. Die Kinder eine Referenz auf die Mutti. Die Mutti und die Kinder werden in einem Webservice in eine Datenbank persistiert und in einer separaten Webanwendung bearbeitet. Also sind die Muttis und Kinder nur im Webservice mit einer Hibernate Session assoziiert. Wenn jetzt in der Webanwendung einer Mutti ein Kind genommen wird, kommt eine reine, saubere Mutti ohne Hibernate Proxies in den Webservice. Wenn jetzt der Webservice ein session.update(mutti)[Die Mutti "mutti" ist die mit einem Kind weniger] ausführt, verhält sich Hibernate sehr human und mitfühlend und nimmt der Mutti "mutti", trotz gesetzter Annotation
@Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
, nicht das Kind weg. In meinen Unit Tests hat das allerdings super funktioniert. Nach vergeblicher Suche nach einer unmenschlichen Hibernate Implementation hab ich das Problem genauer analysiert und festgestellt, dass mein Problem nichts mit dem sozialen Bewusstsein von Hibernate zu tun hat, sondern daran liegt, dass die Mutti "mutti" auf der Reise vom und wieder zurück zum Webservice "nur" eine ArrayList und keine Hibernate PersistantBag-Implementation bekommen hat. Diese war in meinen Unit Tests allerdings vorhanden. Daraus folgt, dass ein DELETE_ORPHAN nur zusammen mit einem PersistantBag funktioniert, den man nur bekommt, wenn das Objekt, in unserem Fall die Mutti "mutti", von einer Hibernate Session erzeugt wurde. Nach Studium der Doku zu session.merge kam ich zu folgender Lösung des Problems:

Mutti backendMutti = (Mutti) session.merge(frontendMutti);
session.update(backendMutti);
Jetzt kann mein Hibernate Muttis auch die Kinder wegnehmen :-)

Donnerstag, 5. Februar 2009

Einfaches und Standardisiertes Exception Handling in Service Beans

Während der letzten beiden Jahre habe ich zu viele Service Klassen wie diese gesehen:

public LoginResponse handleLogin(LoginRequest request) {
 try {
  //Do something
 } catch (AuthenticationException e) {
    logger.warn("authentication exception", e);
    throw e;
 } catch (ServiceException e) {
    throw new ServiceException();
 } catch (Throwable e) {
    logger.fatal("Fatal error " + e.getMessage(), e);
    throw new ServiceException();
 }
}

public LogutResponse handleLogout(LogoutRequest request) {
 try {
  //Do something
 } catch (AuthenticationException e) {
    logger.warn("authentication exception", e);
    throw e;
 } catch (ServiceException e) {
    throw new ServiceException();
 } catch (Throwable e) {
    logger.fatal("Fatal error " + e.getMessage(), e);
    throw new ServiceException();
 }
}

public XYResponse handleXY(XYRequest request) {
 try {
  //Do something
 } catch (AuthenticationException e) {
    logger.warn("authentication exception", e);
    throw e;
 } catch (ServiceException e) {
    throw new ServiceException();
 } catch (Throwable e) {
    logger.fatal("Fatal error " + e.getMessage(), e);
    throw new ServiceException();
 }
}

//Think of plenty more methods like this one, all doing the same try catch stuff
Da ich copy&paste verabscheue habe ich nach einer Lösung für dieses Problem gesucht und im AOP Teil des Guice Frameworks gefunden: Da die meisten Service Beans einheitliche Exceptions werfen ist es ohne weiteres möglich auf das Try Catch in den Service Bean Methoden zu verzichten und diese in einen Interceptor zu packen. Dieser hat nur einen Methodenaufruf der mit einem Try Catch versehen wird, in dem alle relevanten Exceptions gefangen werden: Interceptor

//...
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
//...
public class ServiceXYExceptionInterceptor implements MethodInterceptor {
private static final Logger logger = Logger.getLogger(ServiceXYExceptionInterceptor.class);

public ServiceXYExceptionInterceptor() {
}

public Object invoke(MethodInvocation invocation) throws Throwable {
 try {
  return invocation.proceed();
 } catch (AuthenticationException e) {
  logger.warn("authentication exception", e);
  throw e;
 } catch (ServiceException e) {
  logger.error(MessageFormat.format("Service exception on {0} with params {1}", invocation.getMethod().getDeclaringClass(),
    Arrays.toString(invocation.getArguments())), e);
  throw e;
 } catch (Throwable e) {
  logger.fatal(MessageFormat.format("Unexpected Throwable on {0} with params {1}", invocation.getMethod().getDeclaringClass(),
    Arrays.toString(invocation.getArguments())), e);
  throw new ServiceException();
 }
}
}
The new Service Class

public LoginResponse handleLogin(LoginRequest request) {
  //Do something
  return response;
}

//Think of plenty more methods like this one, all ignoring the exceptions :-)
Damit man diese schicken Service Klassen auch sicher verwenden kann, muss der Interceptor noch mit Guice an die Service Bean gebastelt werden:

bindInterceptor(Matchers.subclassesOf(ServiceXY.class), Matchers.any(), new ServiceXYExceptionInterceptor());
Weitere Informationen zu diesem Thema sind unter folgenden Sites verfügbar: Tembrel's Tome - Injecting method interceptors in Guice 1.0 Guice Project Home

  © Blogger template 'Morning Drink' by Ourblogtemplates.com 2008

Back to TOP