Freies Blasen Alles muss raus

2Aug/110

How to use a servlet as welcome-file in Tomcat

When writing a Web-Application, direct access to a servlet is desired when opening the domain-URL.
Here is, how to use a non-static welcome-file in Tomcat5.5.

In Tomcat 5.5 it is only possible to add static files to the welcome-file-list in the web.xml

<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>

Thus, when running the application at contextpath "/" at freies-blasen.de, Tomcat will send index.html for a request to http://freies-blasen.de .

In most cases, there is none such static index page wanted in a dynamic web application.
Let's assume, the site's main page is a servlet at URL http://freies-blasen.de/home.action.(Im am using struts2 actions in this article, but plain Java servlets will do, too)

Traditionally, this situation was solved using a static index.html page containing a javascript to forward to the actual index page. But there is better.

9Apr/110

Strange behaviour of Objective-C properties / synthesized accessors

Today I wanted to override the - (void) isEqual:(id) method of a custom, but very simple subclass of NSObject:


@interface Resolution : NSObject {
NSUInteger mWidth;
NSUInteger mHeight;
}

-(id) initWithWidth:(NSUInteger) width andHeight:(NSUInteger) height;
-(BOOL) isValidResolution;

 

@property NSUInteger width;
@property NSUInteger height;
@end

All the custom implementation of - (void) isEqual:(id) performs, is to compare width and height.

This simple comparison failed. To find out, where I expanded it to


- (BOOL)isEqual:(id)object {
if ([object isKindOfClass:[Resolution class]]){
NSUInteger oWidth = [object width];
NSUInteger oHeight = [object height];
NSUInteger sWidth = [self width];
NSUInteger sHeight = [self height];
BOOL isSameWidth = oWidth == sWidth;
BOOL isSameHeight = oHeight == sHeight;
return isSameWidth && isSameHeight;
}
return NO;
}

Surprisingly, oWidth was 0 instead of the expected value of 300. BUT, according to gdb, object.mWidth was 300.

See this screenshot:

merkwürdiger gdb

Finally, the method succeeded, when it was changed to


- (BOOL)isEqual:(id)object {
if ([object isKindOfClass:[Resolution class]]){
Resolution *cmpRes = (Resolution*) object;
NSUInteger oWidth = cmpRes.width;
NSUInteger oHeight = cmpRes.height;
NSUInteger sWidth = self.width;
NSUInteger sHeight = self.height;
BOOL isSameWidth = oWidth == sWidth;
BOOL isSameHeight = oHeight == sHeight;
return isSameWidth && isSameHeight;
}
return NO;
}

Who can explain this behavior to me? Why is oWidth != object.mWidth ? How can that happen?

 

Update: The behaviour was explained to me on the cocoa-dev mailing list by Stephen J. Butler:

It's an artifact of how Objective-C searches for selector
implementations. You're calling @selector(width) on an "id", and of
course "id" doesn't implement @selector(width).

So what Objective-C does is search for the first implementation of
@selector(width) that it finds. My guess is it finds the one in AppKit
first (greping the frameworks):

NSTableColumn.h:- (CGFloat)width;

Then when the compiler sets up the call site it does it expecting a
CGFloat return and that is handled differently than an integer. So the
call site and the implementation of how your width is done disagree
and you get some strange heisenvalue back.

When you cast the variable to "Result*", Objective-C now knows to use
YOUR implementation of @selector(width) and it sets up the call site
properly.

While this is all sound, it made me think sending messages to id isn't a useful feature of objective-c.
Here is, what Quincey Morris responded to this complaint on the mailing list:

The general rule is to avoid defining any method whose selector is the same as another method with the same selector but incompatible parameter/return types. That's not unexpected in a C-based language, because polymorphism can't work unless there are some rules about compatibility of calling/return conventions.

The case you ran into is an unfortunate corner case (which has caught lots of experienced Objective-C developers too), because in the architecture you were compiling for, sizeof (NSUInteger) == sizeof (CGFloat), and by default the compiler doesn't complain in that case, if the message is sent to a receiver of type 'id' in the source code method invocation.

There a couple of things you should do:

1. Turn on the "strict selector matching" compiler warning in your build settings.

2. Try to avoid naming your methods with names that seem likely to conflict with declarations already in the frameworks. Yes, I know this is ridiculous advice, because you can't be expected to know the name of every method that's already been declared, but in practical terms it's worth avoiding simple one-word method names like "width" or "size" or "name". The more specific your own method names are, the more likely you are to avoid clashes. Plus, it enhances your code's self-documentation characteristics!

3. Pay attention to syntax coloring. In your preferences, make sure the "project" colors are different from the "other" colors. (They were by default in Xcode 3. I'm not sure they are different by default in Xcode 4).

In this case, if the color preferences were different, you would have noticed that the width/height invocations were the "wrong" color, and that would have been a clue to figure out why your own method signatures weren't being used.

24Mrz/111

Neue Hochtöner im Peugeot 407

Da ich mit den werksseitig eingebauten Lautsprechern meines Peugeot 407 nicht glücklich war, habe ich mich dazu entschlossen, das vordere Paar durch Eton POW 172 Compression zu ersetzen.