- 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
test driving of java applications
Montag, 14. Dezember 2009
Disable IPv6 in Debian Lenny Linux
And here is how to do this:
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:
Change from:
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.load3. 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 reload5. 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) { ... }
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:
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
... 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:
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
- 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.
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.
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:
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
- 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
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 ;-)
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
Abonnieren
Posts (Atom)
Beitragende
Follower
Archives
-
▼
2009
(26)
-
►
Mai
(11)
- The future of the human race
- EasyMock as an easy to use alternative to jMock
- Sniffing keystrokes from wireless keyboards
- JPA and default values
- Expose for Vista
- Germany - a country full of terrorists
- jQuery Autocomplete Plugin
- sunshine live webradio without the annoying advert...
- UTF-8 character encoding problems with ISO-8859-1 ...
- Hibernate Transactions and Connection Pooling
- How to install Eclipse Subversive SVN Plugin
-
►
Mai
(11)