Storing a Map Using Hibernate

As of right now I don’t believe this is supported in JPA, but it can be done in Hibernate. If you want to persist a Map, something like Map then you’ll need the following annotations:

@org.hibernate.annotations.MapKey(targetElement = String.class,columns = {@Column(name = "locale")})
@JoinTable(name = "organization_urls", joinColumns = @JoinColumn(name = "org_id"))
@CollectionOfElements(targetElement = String.class)
@Column(name="url")

Figured I would post this here since I had trouble locating it.

Verizon Customer Service is Pretty Useless

Verizon FiOS is coming to my area, but its not here yet. I wanted to do a comparison of FiOS to my local cable company to see which one I should switch too (and whether I should wait for FiOS). Unfortunately, if FiOS is not in your area, they make it difficult for you to find any information. Below is my conversation with a customer service representative:

You are now chatting with ‘Sam’

Sam: Hello. Thank you for visiting our chat service. How can I help you bundle up and save with our High Speed Internet and FiOS packages?

Sam: Hi

Sam: How may I assist you?

you: hi. I know fios isn’t available in my area yet but it should be soon so I wanted to get a head start and look at the available bundles to compare them to my local cable company. Unfortunately, the verizon web site isn’t making that easy to do

Sam: I will be happy to help you with that.

you: are the bundles easily accessible from somewhere on the site?

Sam: In that case FiOS may not be available at this to your location. However, you can order High Speed Internet service annual agreement online offer with me today and you get the first month free. We’ll also waive all High Speed Internet early termination fees when FiOS becomes available. You’ll receive a link in your email to upgrade to FiOS online. It’s that easy.

you: I’m not interested in that at the moment. I’m interested in seeing the FiOS bundles so that I can do a comparison. I know its not available yet, but I also know it will be soon.

Sam: You can make the selection of the plans and equipment after making the selection you will get total monthly bill mentioned on the review order page before placing your order.

you: I understand that but since FiOS isn’t in my area yet the site won’t show me the FiOS bundles which is what I want to see.

Sam: Is there anything else I can help you with?

Sam: Yes, you are correct.

you: But I want to see the bundles so I know whether its worth waiting for FiOS or if I should just look at the cable company’s bundles

you: because what you’re saying right now is there is no way I can see what your typical fios bundle prices and packages are

Sam: Yes, you can make the selection of the plans and equipment and you will get your total monthly bill before placing your order to make the decision.

you: but it doesn’t show FiOS options

Sam: FiOS service is not available at your location.

you: I know that

you: but it will be coming

you: and I’d like to be able to compare plans so I know whether its worth waiting for FiOS or if I should just get one of the cable company plans

Sam: We are also working to update our serving offices and systems to provide you FiOS, but the exact timeframe varies on the other work still being completed. Make sure you are on our future notification list by qualifying your phone number or address and look for FiOS information in the mail.

you: I am

you: but that doesn’t show me the package information

you: you guys have packages that you offer in areas that already have fios

you: I can’t imagine it varies that much by region

you: that you can’t show it

you: even for people who can’t get fios yet

Sam: You will get the package information only if the service is available at your location on your page.

you: why?

you: why can’t I see it now?

you: do you guys purposely make it hard to compare?

you: I just want to determine whether its worth waiting for FiOS

you: or if I should look at other options

you: from my cable company

Sam: I understand your concern and your patience is truly appreciated. Unfortunately I am unable to assist you with that information as it is out of my support boundaries because I am an online representative for new set up however let me provide you an appropriate link to the customer service and they would be more than happy to assist you with that.

I don’t know how they’re going to get people to sign up if they’re making it extremely difficult to find out information! I don’t think I asked a hard question!

Using JCaptcha in CAS4

CAS 4, which isn’t out yet, or in any condition to be used in production, now supports using JCaptcha in order to throttle attempts to discern passwords.

Complete details on enabling it are in the JASIG Wiki. We’ve enabled it by default in the demonstration WAR file.

Essentially, we use an algorithm (rather simple, feel free to enhance it and contribute it back) to determine if you’ve had too many failed attempts in a a certain period of time based on your IP address. We don’t use sessions because obviously you could just get a new session ;-)

This is just one of the many enhancements based on community feedback that we’re looking to include in CAS 4.

Using JaValid with Spring to Validate Beans during Post Processing

JaValid is an annotation-based framework for validating fields or methods (i.e. NotNull, NotEmpty, etc.). We initially leveraged it in CAS to provide domain-validation to credential objects. This would allow the domain class to contain all the information about itself (similar to what Grails does).
CAS previously used some custom code in the Inspektr library to validate Spring beans via a BeanPostProcessor. Some of the code in Inspektr and JaValid was similar (i.e. the annotations) such that we figured it might be better to leverage more of JaValid (less code for us to maintain). To that end, we’ve managed to construct a BeanPostProcessor that leverages JaValid for validating the properties of Spring beans after they are created. I’ve pasted it below for anyone who’s interested in doing something similar:

/**
 * Copyright 2008 JA-SIG, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0

 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jasig.cas.server.util;

import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
import org.springframework.beans.BeansException;
import org.springframework.beans.FatalBeanException;
import org.springframework.binding.message.MessageResolver;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.javalid.core.AnnotationValidator;
import org.javalid.core.AnnotationValidatorImpl;
import org.javalid.core.ValidationMessage;

import java.util.List;
import java.util.Locale;

/**
 * Implementation of a {@link org.springframework.beans.factory.config.BeanPostProcessor} that uses Javalid to validate
 * properties of POJOs managed by Spring.
 *
 * @author Scott Battaglia
 * @version $Revision$ $Date$
 * @since 4.0.0
 */
public final class JavalidAnnotationValidatorBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {

    private final AnnotationValidatorImpl annotationValidator;

    private String pathPrefix = "";

    private String group = null;

    private int recursiveLevels = 2;

    private final ResourceBundleMessageSource resourceBundleMessageSource;

    public JavalidAnnotationValidatorBeanPostProcessor(final String configLocation) {
        if (configLocation != null) {
            this.annotationValidator = new AnnotationValidatorImpl(configLocation);
        } else {
            this.annotationValidator = new AnnotationValidatorImpl();
        }

        this.resourceBundleMessageSource = new ResourceBundleMessageSource();
        this.resourceBundleMessageSource.setBasename("org/javalid/core/validator/jv_messages");
    }

    public JavalidAnnotationValidatorBeanPostProcessor() {
        this(null);
    }

    public Object postProcessBeforeInitialization(final Object bean, final String beanName) throws BeansException {
        final List<ValidationMessage> messages = this.annotationValidator.validateObject(bean, this.group, this.pathPrefix, true, this.recursiveLevels);
        final StringBuilder builder = new StringBuilder();

        if (messages.isEmpty()) {
            return bean;
        }

        builder.append("bean '");
        builder.append(beanName);
        builder.append("' encountered errors on properties: '");
        for (final ValidationMessage message : messages) {
            builder.append("[property=");
            builder.append(message.getPath());
            builder.append(";error='");
            builder.append(this.resourceBundleMessageSource.getMessage(message.getMessage(), message.getValues(), Locale.getDefault()));
            builder.append("'] ");
        }

        throw new FatalBeanException(builder.toString());
    }
}

Updating Your CurrentJDK on the Mac

If, like me, you do Java development on the Mac, at some point you’ll need to change the JDK that the Mac uses by default.  Tools such as Eclipse and IntelliJ make life easier as they can point to specific JDKs (and you can tell it which one), but certain tools like Maven determine the correct JDK based on directories, etc.

The Mac makes this extremely frustrating with the way it handles JDKs (weird directories, many symbolic links, etc.) and their Console doesn’t change the current JDK just the Runtime.

I found this link that makes updating your current jdk rather easy.  Its a short command-line script that I can only describe as magic:
Setting Current JDK Programmatically on the Mac.

Spring Web Flow 2 and JUEL Integration

Its a tale of romance and tragedy. Okay, not really. But that’s certainly a better starting sentence than, “hey I got Spring Web Flow 2 to work with JUEL instead of JBoss EL.” Anyway, because CAS 4 is utilizing JaValid for its annotation-based validation logic, we’re required to have JUEL on our classpath (JaValid has some compile-time dependencies on JUEL). Unfortunately, the EL specification states that only one provider can be on the path at a time (at the very least, it complains when I have two). Damn them! Can’t we all just get along? Unfortunately, out of the box Spring Web Flow can either work with JBoss EL, or OGNL. OGNL was causing its own set of problems. Since I couldn’t get JaValid to compile against JBoss EL, that meant getting Spring Web Flow 2 to work with JUEL. You think that’d be easy. Not so much.

Its not exceedingly difficult. It just requires writing some custom code. First, we need a ELResolver for JUEL that can process methods (JUEL doesn’t include one). I “borrowed” the one from Camel and modified it a little bit:

/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jasig.cas.server.web.util;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.Iterator;
import java.beans.FeatureDescriptor;

import javax.el.BeanELResolver;
import javax.el.ELContext;
import javax.el.ELResolver;

/**
 * Allows JUEL to resolve methods.
 *
 * @author Scott Battaglia
 * @version $Revision$ $Date$
 * @since 4.0.0
 */
public class MethodELResolver extends ELResolver {

    @Override
    public Object getValue(final ELContext elContext, final Object base, final Object property) {
        Method method = findMethod(elContext, base, property);
        if (method != null) {
            elContext.setPropertyResolved(true);
            return method;
        }

        return null;
    }

    public boolean isReadOnly(final ELContext elContext, final Object o,final  Object o1) {
        return false;
    }

    public Class<?> getType(ELContext elContext, Object o, Object o1) {
        return null;
    }

    public void setValue(ELContext elContext, Object o, Object o1, Object o2) {
        // nothing to do
    }

    public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext elContext, Object o) {
        return null;
    }

    public Class<?> getCommonPropertyType(ELContext elContext, Object o) {
        return null;
    }

    protected Method findMethod(final ELContext elContext, final Object base, final Object property) {
        if (base != null &amp;amp;&amp;amp; property instanceof String) {
            final Method[] methods = base.getClass().getMethods();
            final List<Method> matching = new ArrayList<Method>();
            for (final Method method : methods) {
                if (method.getName().equals(property) &amp;amp;&amp;amp; Modifier.isPublic(method.getModifiers())) {
                    matching.add(method);
                }
            }
            int size = matching.size();
            if (!matching.isEmpty()) {
                if (size > 1) {
                    // TODO there's currently no way for JUEL to tell us how many parameters there are
                    // so lets just pick the first one that has a single param by default
                    for (final Method method : matching) {
                        final Class<?>[] paramTypes = method.getParameterTypes();
                        if (paramTypes.length == 1) {
                            return method;
                        }
                    }
                }
                // lets default to the first one
                return matching.get(0);
            }
        }
        return null;
    }
}

Since JUEL doesn’t have a ELResolver that handles methods you can’t just give the ExpressionFactory to the existing WebFlowELParser as a construction parameter (methods still won’t work then). You need to construct your own parser based off the existing parser:

/**
 * Copyright 2008 JA-SIG, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0

 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jasig.cas.server.web.util;

import java.util.ArrayList;
import java.util.List;

import javax.el.ELContext;
import javax.el.ELResolver;
import javax.el.FunctionMapper;
import javax.el.VariableMapper;

import org.springframework.binding.expression.el.DefaultELResolver;
import org.springframework.binding.expression.el.ELContextFactory;
import org.springframework.binding.expression.el.ELExpressionParser;
import org.springframework.webflow.execution.RequestContext;
import org.springframework.webflow.expression.el.*;
import de.odysseus.el.ExpressionFactoryImpl;
import de.odysseus.el.tree.impl.Builder;
import de.odysseus.el.tree.impl.Cache;
import de.odysseus.el.tree.TreeStore;

public final class JuelWebFlowELExpressionParser extends ELExpressionParser {

	public JuelWebFlowELExpressionParser() {
		super(new ExpressionFactoryImpl(new TreeStore(new Builder(Builder.Feature.METHOD_INVOCATIONS), new Cache(1000))));
		putContextFactory(RequestContext.class, new RequestContextELContextFactory());
	}

	private static class RequestContextELContextFactory implements ELContextFactory {
		public ELContext getELContext(final Object target) {
			final RequestContext context = (RequestContext) target;
			final List<ELResolver> customResolvers = new ArrayList<ELResolver>();
			customResolvers.add(new RequestContextELResolver(context));
			customResolvers.add(new FlowResourceELResolver(context));
			customResolvers.add(new ImplicitFlowVariableELResolver(context));
			customResolvers.add(new ScopeSearchingELResolver(context));
			customResolvers.add(new SpringBeanWebFlowELResolver(context));
			customResolvers.add(new ActionMethodELResolver());
			customResolvers.add(new MethodELResolver());
			ELResolver resolver = new DefaultELResolver(customResolvers);
			return new WebFlowELContext(resolver);
		}
	}

	private static class WebFlowELContext extends ELContext {

		private final ELResolver resolver;

		public WebFlowELContext(ELResolver resolver) {
			this.resolver = resolver;
		}

		public ELResolver getELResolver() {
			return resolver;
		}

		public FunctionMapper getFunctionMapper() {
			return null;
		}

		public VariableMapper getVariableMapper() {
			return null;
		}
	}
}

Finally, all of this needs to be wired up in your Spring XML configuration file. I’ve included our example here:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:webflow="http://www.springframework.org/schema/webflow-config"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.springframework.org/schema/webflow-config http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd">

    <webflow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices">
        <webflow:flow-location path="/WEB-INF/login/login.xml" id="login"/>
    </webflow:flow-registry>

    <webflow:flow-builder-services expression-parser="expressionParser" id="flowBuilderServices" />

    <bean id="expressionParser" class="org.jasig.cas.server.web.util.JuelWebFlowELExpressionParser" />

    <webflow:flow-executor id="flowExecutor"/>

    <bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter"
          p:flowExecutor-ref="flowExecutor"/>

    <bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping"
          p:flowRegistry-ref="flowRegistry"
          p:order="0"/>
</beans>

Be sure to include JUEL in your Web application and that should be all you need.

Accessing enumerations in JSP

I’m posting this here just because it took me a little while to find. Let’s say you have an enumeration:
enum OperationType {REDIRECT, POST, NONE}

and you need to make some decision in your JSP page based on the chosen OperationType. How do you refer to the enumeration? Apparently you do this:

<c:if test="${myClass.myOperationType == 'REDIRECT'}">

You need to refer to the enumerations not by their fully qualified class name but by the String version of them. Note: I believe this might only work in Unified EL.

el-api.jar Fun!

If you’re developing a new Servlet project and you’re using say Spring Web Flow with oh say, jboss-el (which I recommend), and you build using Maven2, watch out for the fact that the jboss-el pom definition pulls in the el-api jar. You’ll want to exclude that:

<dependency>
<groupId>org.jboss.seam</groupId>
<artifactId>jboss-el</artifactId>
<version>2.0.0.GA</version>
<scope>runtime</scope>
<exclusions>
<exclusion>
<groupId>javax.el</groupId>
<artifactId>el-api</artifactId>
</exclusion>
</exclusions>
</dependency>

If you don’t exclude it, when you deploy to the container (i.e. Tomcat 6), you’ll see a fun message like this when you load up your JSP page:

java.lang.LinkageError: loader constraints violated when linking javax/el/ExpressionFactory class

It would have been nice if the jar file was ignored like the servlet-api is ignored if its pulled into the WAR file deployment.

Upgrading to Spring Web Flow 2 for CAS4

For  better or worse, CAS3 has always used Spring Web Flow 1 even after Spring Web Flow 2 came out. As part of CAS4, we’re looking at upgrading to Spring Web Flow 2.  Overall, Spring Web Flow has simplified a lot of stuff.  Calling our service methods directly (for the most part) instead of creating an action to do the same thing is a huge time and codesaver.

I’ve encountered a few weird things along the way that I’m still working the kinks out on:

1. Configuring an External Validator – Spring Web Flow 2 makes it easy to use validators, as long as you follow their conventions (either a method on the model object or a validator that follows particular naming conventions).  I’m looking at leveraging the Javalid framework, which uses annotations on the model objects and one validator.  This should make it easier for deployers to use their own custom credentials objects and keep their validation logic within their class (reducing maintenance).  One problem, its not clear how to register a custom validator that doesn’t conform to the Spring Web Flow 2 conventions.  I’ve asked for information on the forum for anyone interested: http://forum.springframework.org/showthread.php?t=64418

2. Using Simple Domain/Model Objects – In Spring Web Flow 1 you called setupForm on a FormAction and magical stuff happened to instantiate the appropriate objects, etc.  In Spring Web Flow 2 you can merely call evaluate on a method and put the resulting object in the flow or request scope and use that as the model object.  Powerful!  However, its not clear to me how to merely use a simple object (i.e. an instantiation of UsernamePasswordCredentialsImpl).

For those interested in learning more, I’ve found the following resources useful:

Watch out for the IntelliJ 8.0.1 Upgrade

Not sure if its something I did or not, but I recently upgraded from IntelliJ IDEA 8.0 to IntelliJ IDEA 8.0.1 and it no longer properly imports my projects that are Maven2 based (i.e. CAS!). Reverting back to 8 didn’t solve the problem either.

I checked on my notebook, which I didn’t upgrade and the project still loads fine. Just warning everyone to watch out so it doesn’t happen to them (I’m still not sure why it happened to me).

Overall, I’m happy with IDEA, though currently less happy since its not working for me ;-)

[UPDATE]: Based on a recommendation from the comments, I’ve submitted a support request for this. I’ll update if/when I hear back. For now I’ll be living in the Eclipse world *shudder*

[UPDATE 2]: Apparently JetBrains support is ABSURDLY FAST. Recommended I erase the cache directory and restart the application. That appears to have done the trick. Waiting to hear back on whether the cache just got corrupted during the upgrade. Back in business though.