jquery

gist JS

Tuesday, December 18, 2007

The Books of 2007

So, 2007 is coming to a close and there's only so many more days for reading. I'm trying to pick out my Christmas reading by the fire list and I figured I'd take a look to see what I've done in 2007. Of course this is easily done using MyHippocampus so let's start there. Jeff's Books at MyHippocampus If you want to see the timeline, click on the 'eye' and select the timeline view and then zoom around.

The 2007 list as of December 18th
---------------------------------
Voyage Along the Horizon: A Novel

Snow

Ambient Findability: What We Find Changes Who We Become

Goodbye Lemon

The Crying of Lot 49 (Perennial Fiction Library)

The Death of Ivan Ilych

The Revolution Betrayed

Candide (Dover Thrift Editions)

Interpretation of Murder

By Night in Chile

Instance of the Fingerpost

Spies

Maps of the Mind

Atlas Of Experience

Harry Potter

Everything is Illuminated

Heartbreaking Work of Staggering Genius

Box of Matches - Nicholson Baker

Hamlet

Death in a Strange Country Donna Leon

Golden Compass

Secret History - Donna Tartt


I have to say, I'm not a bit displeased with myself. Before I went to look I had the sinking suspicion that there were only going to be a handful of books on there, but there's actually quite a few (or at least more than one a month, which I felt was in no way guaranteed). Go me! And go MyHippocampus for making me feel good! I knew I'd written that site for some reason ;)

Thursday, November 08, 2007

Global Warming 'Greatest Scam in History'

I had John Coleman's Global Warming 'Greatest Scam in History' forwarded to me today as a defense of climate change scepticism. Here's the heart of his argument:
I have read dozens of scientific papers. I have talked with numerous
scientists. I have studied. I have thought about it. I know I am
correct.
Yeah, it does seem tough to argue with this guy. I mean, you could say "he doesn't contradict anything, he just levels a broad claim of conspiracy and says 'he's sure!'", but then again, he does seem SO sure. And offended. Plus that's a LOT of papers to read (literally dozens!). Those things can be really long too.

I know the EPA, UN, World Meteoroligical Association, Nobel Comittee & Big Media, are all in cahoots anyway, but it does seem like it might be worth taking a look at some of their findings.

Wait, better, than above is the summary for policy makers (read: people reading this blog):

Be careful when you read this though, don't let their cold scientist-like objectivity cloud your vision. Remember to ask yourself the 4 questions that determine scientific validity:


  • "Are they 'offended' by reports to the contrary?"

  • "Are their opponents engaged in a 'conspiracy' against them?"

  • "Are non-believers 'wackos'?"

  • "Are they really, really convinced they're right?"


If these aren't true, it's probably not good science.

Using Maps of objects in Freemarker

Because sometimes helpful, well-written FAQ's that address precisely your problem are no substitute for an example, I present you with:

Using Maps of objects in Freemarker, the missing example for:


Why I can't use non-string key in the myMap[myKey] expression? And what to do now?


Here's our class and its HashMap and regular getter:



public class Application implements Serializable {
private <ProcessType, ProcessValue> process = new HashMap<ProcessType,ProcessValue>();

public Map<ProcessType, ProcessValue> getProcess() {
return process;
}


We can't use this getter because it's wrapped by the Freemarker BeanModel and only accepts Strings.

Here's the new getter that we'll add:

    public ProcessValue getTheProcess(ProcessType type) {
return getProcess().get(type);
}
}


And then in our Freemarker template, we call the new getter method.

<#list application.process?keys as processType>
<td>
${application.getTheProcess(processType).pctComplete}
</td>
</#list>



OMG there's a new Neal Stephenson book.

Wednesday, September 19, 2007

Re: You're Probably Storing Passwords Incorrectly

As always the problem with best practices is that you often hear about them after you've gone and implemented something less ideal.

CodingHorror's post was pretty good at guilting me into salting passwords
http://www.codinghorror.com/blog/archives/000953.html
I knew this would be easy with Acegi and of course it was a breeze...

Except for that little problem about existing users who would still like to log in.

Clearly salting passwords is a decision you'd prefer to make BEFORE you've hashed a whole bunch of passwords. As tempting as it is to rainbow attack your own passwords and then convert them to salted versions (which wouldn't work anyway) and without making everyone reset their passwords you're left a bit in the lurch. But never fear, TransitionReflectionSaltSource is here! (Second choice after 'doh!ReflectionSaltSource')

This class allows you to transition to using salt in an AcegiSecurity system. New users get salt, old users still work. You pick the date field and time to start applying salt. This class will salt users from after the useSaltAfterDate. Null useSaltAfterDate will not be salted. You could easily change this to some other User property.

/**
*
* @author Jeff Dwyer (blog) http://jdwyah.blogspot.com
*
*/
public class TransitionReflectionSaltSource extends ReflectionSaltSource {
private static final Logger log = Logger.getLoggerTransitionReflectionSaltSource.class);

private String useSaltAfterDateProperty;
private Date useSaltAfterDate;

@Override
public Object getSalt(UserDetails user) {
try {
Method reflectionMethod = user.getClass().getMethod(this.useSaltAfterDateProperty,
new Class[] {});
Date userDate = (Date) reflectionMethod.invoke(user, new Object[] {});
if (null == userDate userDate.before(useSaltAfterDate)) {
log.debug("No Salt " + user + " " + userDate);
return null;
} else {
log.debug("Using Salt " + user + " " + userDate);
return super.getSalt(user);
}
} catch (Exception exception) {
throw new AuthenticationServiceException(exception.getMessage(), exception);
}
}
@Required
public void setUseSaltAfterDateProperty(String useSaltAfterDateProperty) {
this.useSaltAfterDateProperty = useSaltAfterDateProperty;
}

@Required
public void setUseSaltAfterDate(Date useSaltAfterDate) {
this.useSaltAfterDate = useSaltAfterDate;
}
}



Now we setup our TransitionalReflectionSaltSource to only salt things created after today, (the day we got guilted into fixing this)

<bean id="userSaltSource" class="com.aavu.server.util.TransitionReflectionSaltSource">
<property name="userPropertyToUse" value="getId" />
<property name="useSaltAfterDateProperty" value="getDateCreated" />
<property name="useSaltAfterDate">
<bean class="java.util.Date">
<constructor-arg>
<value>107</value>
</constructor-arg>
<constructor-arg>
<value>8</value>
</constructor-arg>
<constructor-arg>
<value>18</value>
</constructor-arg>
</bean>
</property>
</bean>


Easy! Is there a better way to inject a date though?

Wednesday, May 16, 2007

Acegi OpenID tricks & tribulations

Well, after a couple headaches of my own creation, Acegi OpenID is up and running on MyHippocampus

<bean id="openIDStore" class="com.janrain.openid.store.MemoryStore">
<constructor-arg value="changeThis"/>
</bean>
<bean id="openIDConsumer" class="org.acegisecurity.ui.openid.consumers.JanRainOpenIDConsumer">
<property name="store" ref="openIDStore"/>
</bean>
<bean id="openIDResponseProcess" class="org.acegisecurity.ui.openid.OpenIDResponseProcessingFilter">
<property name="consumer" ref="openIDConsumer"/>
<property name="defaultTargetUrl" value="/site/index.html"/>
<property name="authenticationFailureUrl" value="/site/acegilogin.html?login_error=1"/>
<property name="authenticationManager" ref="authenticationManager"></property>
<property name="rememberMeServices" ref="rememberMeServices"></property>
</bean>
<bean id="openIDAuthProvider" class="org.acegisecurity.providers.openid.OpenIDAuthenticationProvider">
<property name="ssoAuthoritiesPopulator" ref="userDAO"/>
</bean>


Once I realized that my userDAO would make a fine ssoAuthoritiesPopulator and I didn't have to go figure out was CAS was all about I was off and running. Happily I rewrote the OpenIDLoginInitiationServlet to be a OpenIDLoginController so I could back out the changed to web.xml, which is a good thing only because everytime I touch it I feel like something somewhere goes haywire.

The last hurdle, of course was that it all tested fine, but that when deployed, req.getServer() would still return "localhost" instead of my domain name. Here's to the power of opensource! Saving peoples butts by letting you put hardcode in the source and recompile ;) Clearly I'm missing something.


Unfortunately functional logging in is was half the battle.

The real difficulty arises when you'd like to figure out what to store as the eventual username in the database & you go to implement the signup process.

someopenid.myopenid.net
someopenid.myopenid.net/
http://someopenid.myopenid.net
&
http://someopenid.myopenid.net/

may all be the same ID, but they sure aren't the same string. JanRain seems to deal with this ok, and always asks me to lookup something of the form "http://someopenid.myopenid.net/" which seems like it should sort me out.

The trick is when your user goes to create an account. If I just ask them for their ID on the signup page, then I have to go a string munge it myself to put it in the correct form and if they mistype, or I mis-munge things go haywire. Ah, com.janrain.openid.Util.normalizeUrl(userUrl);
Alternatively, I could have them login first, then signup, but if I allow just any old OpenID to login, I end up with these weird sort of 'no-account but I'm technically logged in' users, which makes for a bit of a headache ensuring that they aren't allowed to do things a real user can.

Complicating all of this is that all other manner of things may be acceptable openID identifiers, depending on what FAQ / RFC / random blog posting you read. What's the regular expression that validates an openID identifier when
"=Mary.Jones*Henry" and "=@Example.Corp*Ecuador*Quito"
are valid as well as the above? You've got me.

None of this would be so bad except for the fact that I was hoping to have username@hipcamp.com be a nice simple way for users to email themselves information. I suppose that's what you get when you try to reconcile "nice & simple" with the cutting edge nerd street cred of OpenID.

For now, just supporting URL's & not i-names seems to be what most people do, so that's my plan. Not precisely sure what to do about the email thing. I'm hoping that stripping off the http:// and trailing / is a solution, but is "openid.com/bob" a valid openID? I can't seem to find that answer.

Monday, April 16, 2007

Freemarker Spring

Sorry, another soporific blog post for those of you not building websites.

So you get:
freemarker.template.TemplateModelException: To do URL encoding, the framework that encloses FreeMarker must specify the output encoding or the URL encoding charset, so ask the programmers to fix it. Or, as a last chance, you can set the url_encoding_charset setting in the template, e.g. <#setting url_escaping_charset='ISO-8859-1'>, or give the charset explicitly to the buit-in, e.g. foo?url('ISO-8859-1').

And you feel bad about doing things described as "last chance" but where to specify freemarker variable in you spring config?



<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer" abstract="false"
singleton="true" lazy-init="default" autowire="default" dependency-check="default">
<property name="templateLoaderPath">
<value>/</value>
</property>
<property name="freemarkerSettings">
<props>
<prop key="datetime_format">MM/dd/yyyy</prop>
<prop key="number_format">0.#####</prop>
<prop key="url_escaping_charset">ISO-8859-1</prop>
</props>
</property>
</bean>

Friday, January 19, 2007

Tommy's Oscar preDickies

Woo! Best oscar predictions on the whole world wide web. Tommy's Oscar preDickies

Tuesday, January 16, 2007

Hibernate NonUniqueExceptions

So I knew I was in trouble this morning when I googled "hibernate nonuniqueidentifier" and only came up with references to my own blog. That's happened once before and it's never a good thing to find out that google believes you're the world expert on the very thing you're having a problem with.

Anyway here was the solution to my Hibernate NonUniqueException. I hadn't had any problems until I made the entire service layer transactional with some a little AOP magic, but once I did that all updates started throwing these NonUniqueExceptions.

Here's the code w/ the addition of:
getHibernateTemplate().evict(sameNamed);

to prevent the Exception. Basically Hibernate is just trying to protect me from updating over myself, but since I really do want to just read properties of "sameNamed" Topic and then write over it, eviction is just fine.


public Topic save(Topic t) throws BusinessException {

if(t.getTitle().equals("")){
throw new BusinessException("Empty Title");
}
if(t.mustHaveUniqueName()){
Object[] args = {t.getTitle(),t.getUser()};
Topic sameNamed = (Topic) DataAccessUtils.uniqueResult(getHibernateTemplate().find("from Topic where title = ? and user = ?",args));

if(sameNamed != null && sameNamed.getId() != t.getId()){
throw new BusinessException("Duplicate Name");
}
//need to evict or we'll get a NonUniqueException
getHibernateTemplate().evict(sameNamed);
}
getHibernateTemplate().saveOrUpdate(t);
}