-実装

以下のように結果、なりました。ExpressionもProcessorも同様にやります。自分的にはJSR245のCompositeELResolverより良い様に思います。もうちょっと考えて後、OKならばJSR245のMLのほうで提案してみましょう。リストをぐるぐる回すだけのCompositeモデルよりいいのは、レゾルバがフィルタのように引数条件を常に変更できる点と、インターセプターのようにシリアライズされた呼び出しだけでなく、ちょうどAOPのAfterのようなタイミングがあるという点で、最初のほうのレゾルバで後のレゾルバの結果が見れるということです。また、レゾルバの引数にELResolverにおけるELContextのように、処理状態を監視するコンテキストオブジェクトを無駄につくらなくて良いこともメリットだと思います。
このアイディアのネタ元は、サーブレットフィルタに、インターセプターの考え方を取り入れたものです。

package org.seasar.maya.impl.builder.specification;
import org.seasar.maya.builder.specification.InjectionChain;
import org.seasar.maya.builder.specification.InjectionResolver;
import org.seasar.maya.engine.Template;
import org.seasar.maya.engine.specification.SpecificationNode;
public class InjectionChainImpl implements InjectionChain {
    private static final InjectionChain NULL_CHAIN = new NullInjectionChain();
    private InternalInjectionChain _first;
    private InternalInjectionChain _last;
    public synchronized void add(InjectionResolver resolver) {
        if(resolver == null) {
            throw new IllegalArgumentException();
        }
        InternalInjectionChain chain = new InternalInjectionChain(resolver);
        if(_first == null) {
            _first = chain;
        }
        if(_last != null) {
            _last.setNext(chain);
        }
        _last = chain;
    }
    public SpecificationNode getNode(
            Template template, SpecificationNode original) {
        if(template == null || original == null) {
            throw new IllegalArgumentException();
        }
        if(_first != null) {
            return _first.getNode(template, original);
        }
        return null;
    }
    private static class NullInjectionChain
            implements InjectionChain {
        public SpecificationNode getNode(
                Template template, SpecificationNode original) {
            return null;
        }        
    }
    private class InternalInjectionChain implements InjectionChain {
        private InjectionResolver _resolver;
        private InjectionChain _next;
        public InternalInjectionChain(InjectionResolver resolver) {
            if(resolver == null) {
                throw new IllegalArgumentException();
            }
            _resolver = resolver;
        }
        public void setNext(InjectionChain next) {
            if(next == null) {
                throw new IllegalArgumentException();
            }
            _next = next;
        }
        public SpecificationNode getNode(
                Template template, SpecificationNode original) {
            if(template == null || original == null) {
                throw new IllegalArgumentException();
            }
            if(_next == null) {
                _next = NULL_CHAIN;
            }
            return _resolver.getNode(template, original, _next);
        }
    }
}