SpringBeansTemplateHashModelEx.java

package fr.sii.ogham.spring.template.freemarker;

import java.util.Iterator;
import java.util.NoSuchElementException;

import org.springframework.context.ApplicationContext;

import freemarker.ext.beans.BeanModel;
import freemarker.ext.beans.BeansWrapper;
import freemarker.ext.beans.IteratorModel;
import freemarker.ext.beans.StringModel;
import freemarker.template.TemplateCollectionModel;
import freemarker.template.TemplateHashModelEx2;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;

/**
 * Specific model to be able to access Spring beans from template using
 * {@code @beanName.method(args)} syntax.
 * 
 * @author Aurélien Baudet
 *
 */
public class SpringBeansTemplateHashModelEx implements TemplateHashModelEx2 {
	private final ApplicationContext applicationContext;
	private final BeansWrapper beansWrapper;

	public SpringBeansTemplateHashModelEx(ApplicationContext applicationContext, BeansWrapper beansWrapper) {
		super();
		this.applicationContext = applicationContext;
		this.beansWrapper = beansWrapper;
	}

	@Override
	public int size() throws TemplateModelException {
		return applicationContext.getBeanDefinitionCount();
	}

	@Override
	public TemplateCollectionModel keys() throws TemplateModelException {
		return new IteratorModel(new Iterator<String>() {
			private int currentIdx = 0;

			@Override
			public boolean hasNext() {
				return currentIdx < applicationContext.getBeanDefinitionCount();
			}

			@Override
			public String next() {
				if (!hasNext()) {
					throw new NoSuchElementException();
				}
				return "@" + applicationContext.getBeanDefinitionNames()[currentIdx++];
			}

		}, beansWrapper);
	}

	@Override
	public TemplateCollectionModel values() throws TemplateModelException {
		return new IteratorModel(new Iterator<Object>() {
			private int currentIdx = 0;

			@Override
			public boolean hasNext() {
				return currentIdx < applicationContext.getBeanDefinitionCount();
			}

			@Override
			public Object next() {
				if (!hasNext()) {
					throw new NoSuchElementException();
				}
				String name = applicationContext.getBeanDefinitionNames()[currentIdx++];
				return new LazySpringBeanAccessModel(applicationContext, beansWrapper, name);
			}

		}, beansWrapper);
	}

	@Override
	public TemplateModel get(String key) throws TemplateModelException {
		return new BeanModel(applicationContext.getBean(key.startsWith("@") ? key.substring(1) : key), beansWrapper);
	}

	@Override
	public boolean isEmpty() throws TemplateModelException {
		return applicationContext.getBeanDefinitionCount() <= 0;
	}

	@Override
	public KeyValuePairIterator keyValuePairIterator() throws TemplateModelException {
		return new KeyValuePairIterator() {
			private int currentIdx = 0;

			@Override
			public KeyValuePair next() throws TemplateModelException {
				if (!hasNext()) {
					throw new NoSuchElementException();
				}
				KeyValuePair pair = new KeyValuePair() {

					@Override
					public TemplateModel getValue() throws TemplateModelException {
						String name = applicationContext.getBeanDefinitionNames()[currentIdx];
						return new LazySpringBeanAccessModel(applicationContext, beansWrapper, name);
					}

					@Override
					public TemplateModel getKey() throws TemplateModelException {
						return new StringModel(applicationContext.getBeanDefinitionNames()[currentIdx], beansWrapper);
					}
				};
				currentIdx++;
				return pair;
			}

			@Override
			public boolean hasNext() throws TemplateModelException {
				return currentIdx < applicationContext.getBeanDefinitionCount();
			}
		};
	}

}