Interceptors sort order
denis-karpov May 17, 2006 8:16 AMHi
I have found that order of seam interceptors sometimes violates constraints, defined by @Within and @Around annotations.
You can see it if You look at two beans in "booking" example, one with @LoggedIn interceptor another without. The relative position of ConversationInterceptor, BijectionInterceptor changes.
...... ConversationInterceptor, BijectionInterceptor ......
...... BijectionInterceptor, ConversationInterceptor ......
======================================
I have fix it, by reimplementing sorter.
Sorry, if i post it in wrong place.
Changed file (modified function)
org.jboss.seam.Component.java
.... private void initInterceptors() { initDefaultInterceptors(); for (Annotation annotation: beanClass.getAnnotations()) { if ( annotation.annotationType().isAnnotationPresent(Interceptors.class) ) { interceptors.add( new Interceptor(annotation, this) ); } } // new Sorter<Interceptor>() { // protected boolean isOrderViolated(Interceptor outside, Interceptor inside) // { // Class<?> insideClass = inside.getUserInterceptor().getClass(); // Class<?> outsideClass = outside.getUserInterceptor().getClass(); // Around around = insideClass.getAnnotation(Around.class); // Within within = outsideClass.getAnnotation(Within.class); // return ( around!=null && Arrays.asList( around.value() ).contains( outsideClass ) ) || // ( within!=null && Arrays.asList( within.value() ).contains( insideClass ) ); // } // }.sort(interceptors); newSort(interceptors); log.trace("interceptor stack: " + interceptors); } ......
Changed file (new function)
org.jboss.seam.Component.java
....... private List<Interceptor> newSort(List<Interceptor> list){ List<SortItem<Interceptor>> siList = new ArrayList<SortItem<Interceptor>>(); Map<Class<?>,SortItem<Interceptor>> ht = new HashMap<Class<?>,SortItem<Interceptor>>(); for (Interceptor i : list){ SortItem<Interceptor> si = new SortItem<Interceptor>(i); siList.add(si); ht.put(i.getUserInterceptor().getClass(),si); } for (SortItem<Interceptor> si : siList){ Class<?> clazz = si.getObj().getUserInterceptor().getClass(); Around around = clazz.getAnnotation(Around.class); Within within = clazz.getAnnotation(Within.class); if (around!=null){ for (Class<?> cl : Arrays.asList( around.value() ) ){ si.getAround().add( ht.get(cl) ); } } if (within!=null){ for (Class<?> cl : Arrays.asList( within.value() ) ){ si.getWithin().add( ht.get(cl) ); } } } //===========// SorterNew<Interceptor> sList = new SorterNew<Interceptor>(); siList = sList.sort(siList); //siList = SortItem.sort(siList); //===========// list.clear(); for (SortItem<Interceptor> si : siList){ list.add(si.getObj()); } return list ; } .......
New file:
org.jboss.seam.util.SorterNew
package org.jboss.seam.util; import java.util.ArrayList; import java.util.List; public class SorterNew<T> { private List<SortItem<T>> list = null; //new ArrayList(); public List<SortItem<T>> sort(List<SortItem<T>> lst){ this.list = lst; List<SortItem<T>> res = new ArrayList<SortItem<T>>(); SortItem<T> inmost = null; do{ inmost = getInmost(); if (inmost!=null){ res.add(inmost); remove(inmost); } }while(list.size()>0 && inmost!=null); if (list.size()>0){ throw new RuntimeException("Can not sort interceptors list:"+list.toString()); } return res; } private void remove(SortItem<T> item){ list.remove(item); for(SortItem<T> o : list){ o.getAround().remove(item); } } private SortItem<T> getInmost() { SortItem<T> res=null; for(SortItem<T> o : list){ if ((o.getAround().size()==0) && testNobodyWantsWithin(o) ){ res = o; break; } } return res; } private boolean testNobodyWantsWithin(SortItem<T> item){ boolean res = true; for (SortItem<T> o : list){ if (o.getWithin().contains(item)){ res = false; break; } } return res; } }
[New file:
org.jboss.seam.util.SortItem
package org.jboss.seam.util; import java.util.ArrayList; import java.util.List; public class SortItem<T> { private T obj; private List<SortItem> around = new ArrayList<SortItem>(); private List<SortItem> within = new ArrayList<SortItem>(); public SortItem(T obj){ this.obj = obj; } public T getObj(){ return obj; } public List<SortItem> getAround() { return around; } public List<SortItem> getWithin() { return within; } }