Commits

Dimitris Zenios committed c8fe2e6

Source indentation

Comments (0)

Files changed (20)

src/main/java/com/zenios/tapestry/breadcrumbs/annotation/BreadCrumb.java

 @Target(ElementType.TYPE)
 @Retention(RetentionPolicy.RUNTIME)
 @Documented
-public @interface BreadCrumb {
+public @interface BreadCrumb
+{
 	boolean ignore() default false;
+
 	boolean reset() default false;
+
 	boolean dynamicTitle() default false;
 }

src/main/java/com/zenios/tapestry/breadcrumbs/components/BreadCrumbInfo.java

 import com.zenios.tapestry.breadcrumbs.other.BreadCrumbsConstants;
 import com.zenios.tapestry.breadcrumbs.other.BreadCrumbsEvents;
 
-public class BreadCrumbInfo {   
-    @Inject
-    private ComponentSource componentSource;
-            
-    @Property
-    @Parameter(required = true, principal = true, autoconnect = true)
-    private BreadCrumbObject crumb;
-    
-    @Parameter(value = "block:before",defaultPrefix = BindingConstants.LITERAL)
-    private Block before;
-    
-    @Parameter(value = "block:after",defaultPrefix = BindingConstants.LITERAL)
-    private Block after;
-    
-    @SuppressWarnings("unused")
+public class BreadCrumbInfo
+{
+	@Inject
+	private ComponentSource componentSource;
+
+	@Property
+	@Parameter(required = true, principal = true, autoconnect = true)
+	private BreadCrumbObject crumb;
+
+	@Parameter(value = "block:before", defaultPrefix = BindingConstants.LITERAL)
+	private Block before;
+
+	@Parameter(value = "block:after", defaultPrefix = BindingConstants.LITERAL)
+	private Block after;
+
+	@SuppressWarnings("unused")
 	@Property
-    @Parameter(value = "block:title",defaultPrefix = BindingConstants.LITERAL)
-    private Block title;
-    
-    @Inject
-    @Symbol(BreadCrumbsConstants.BREADCRUMBS_TITLE_SUFFIX)
-    private String titleSuffix;
-    
-    Object beginRender()
-    {
-    	return before;
-    }
-    
-    Object afterRender()
-    {
-    	return after;
-    }
-        
-   
-    public String getNameTitle() {
+	@Parameter(value = "block:title", defaultPrefix = BindingConstants.LITERAL)
+	private Block title;
+
+	@Inject
+	@Symbol(BreadCrumbsConstants.BREADCRUMBS_TITLE_SUFFIX)
+	private String titleSuffix;
+
+	Object beginRender() {
+		return before;
+	}
+
+	Object afterRender() {
+		return after;
+	}
+
+	public String getNameTitle() {
 		String pageName = crumb.getLogicalPageName();
 		Component page = componentSource.getPage(pageName);
 		String title = null;
-		if(crumb.isTitleEvent()) {
+		if (crumb.isTitleEvent()) {
 			final Holder<String> valueHolder = Holder.create();
-			ComponentEventCallback<String> callback = new ComponentEventCallback<String>() {
-				public boolean handleResult(String result)
-				{
+			ComponentEventCallback<String> callback = new ComponentEventCallback<String>()
+			{
+				public boolean handleResult(String result) {
 					valueHolder.put(result);
-	
+
 					return true;
 				}
 			};
 
-
 			boolean handled = page.getComponentResources().triggerContextEvent(BreadCrumbsEvents.GET_TITLE, crumb.getActivationContext(), callback);
 			if (!handled) {
 				throw new TapestryException(String.format("Request event '%s' (on component %s) was not handled; you must provide a matching event handler method in the component or in one of its containers.", BreadCrumbsEvents.GET_TITLE, page.getComponentResources().getCompleteId()), page, null);
 			}
 			title = valueHolder.get();
 		}
-			
-		if(title == null) {
+
+		if (title == null) {
 			String key = new StringBuilder(pageName).append(titleSuffix).toString();
 			Messages messages = page.getComponentResources().getMessages();
-			if(messages.contains(key)) {
+			if (messages.contains(key)) {
 				title = messages.get(key);
 			}
 		}
-		
+
 		return title != null ? title : pageName;
-    }
-    
-    public String getPage() {
-    	return componentSource.getPage(crumb.getLogicalPageName()).getComponentResources().getCompleteId();
-    }
-    
-    public Object[] getActivationContext() {
-    	EventContext context = crumb.getActivationContext();
-        int count = context.getCount();
-
-        Object[] pageActivationContext = new Object[count];
-
-        for(int i = 0; i < count; i++)
-            pageActivationContext[i] = context.get(Object.class, i);
-        
-        return pageActivationContext; 
-    }
+	}
+
+	public String getPage() {
+		return componentSource.getPage(crumb.getLogicalPageName()).getComponentResources().getCompleteId();
+	}
+
+	public Object[] getActivationContext() {
+		EventContext context = crumb.getActivationContext();
+		int count = context.getCount();
+
+		Object[] pageActivationContext = new Object[count];
+
+		for (int i = 0; i < count; i++)
+			pageActivationContext[i] = context.get(Object.class, i);
+
+		return pageActivationContext;
+	}
 }

src/main/java/com/zenios/tapestry/breadcrumbs/components/BreadCrumbsLoop.java

 import com.zenios.tapestry.breadcrumbs.other.BreadCrumbsTrailConstantsValues;
 
 @SuppressWarnings("unused")
-public class BreadCrumbsLoop {
-
-    @Parameter(cache = false)
-    private String rowClass;
-    
-   	@Parameter
-    private int rowIndex;
-   	        
-    @Parameter(value = "componentResources.container")
-    private BreadCrumbsModel breadCrumbsModel;
-    
-    @Parameter(required = true)
-    @Property(write = false)
-    private BreadCrumbObject row;
-    
-    @Inject
-    private ComponentSource componentSource;
-    	
-    @Component(parameters="crumb=row", publishParameters = "before,after,title")
-    private BreadCrumbInfo breadCrumb;
-    
-    private int dataRowIndex;
-    
-    private int endRow;
-    
-    private int startRow;
-    
-
-    
-    
-    public String getRowClass()
-    {
-        List<String> classes = CollectionFactory.newList();
-
-        String rc = rowClass;
-
-        if (rc != null) classes.add(rc);
-
-        if (dataRowIndex == startRow) classes.add(BreadCrumbsTrailConstantsValues.BREADCRUMBS_FIRST_CLASS);
-
-        if (dataRowIndex == endRow) classes.add(BreadCrumbsTrailConstantsValues.BREADCRUMBS_LAST_CLASS);
-        
-        if(componentSource.getActivePage().getComponentResources().getCompleteId().equals(componentSource.getPage(row.getLogicalPageName()).getComponentResources().getCompleteId())) {
-        	classes.add(BreadCrumbsTrailConstantsValues.BREADCRUMBS_ACTIVE_CLASS);
-        }
-        
-        return TapestryInternalUtils.toClassAttributeValue(classes);
-    }
-    
-    void setupForRow(int rowIndex)
-    {
-        row = breadCrumbsModel.getRow(rowIndex);
-    }
-    
-    boolean setupRender()
-    {
-    	int size = breadCrumbsModel.getSize();
-        startRow = 0;
-        endRow = size - 1;
-
-        dataRowIndex = startRow;
-        
-        return size != 0;
-    }
-    
-    boolean beginRender()
-    {
-        // Setup for this row.
-
-        setupForRow(dataRowIndex);
-
-        // Update the index parameter (which starts from zero).
-        rowIndex = dataRowIndex - startRow;
-
-
-        return row != null;
-    }
-    
-    boolean afterRender()
-    {
-        dataRowIndex++;
-
-        // Abort the loop when we hit a null row, or when we've exhausted the range we need to
-        // display.
-
-        return row == null || dataRowIndex > endRow;
-    }
+public class BreadCrumbsLoop
+{
+
+	@Parameter(cache = false)
+	private String rowClass;
+
+	@Parameter
+	private int rowIndex;
+
+	@Parameter(value = "componentResources.container")
+	private BreadCrumbsModel breadCrumbsModel;
+
+	@Parameter(required = true)
+	@Property(write = false)
+	private BreadCrumbObject row;
+
+	@Inject
+	private ComponentSource componentSource;
+
+	@Component(parameters = "crumb=row", publishParameters = "before,after,title")
+	private BreadCrumbInfo breadCrumb;
+
+	private int dataRowIndex;
+
+	private int endRow;
+
+	private int startRow;
+
+	public String getRowClass() {
+		List<String> classes = CollectionFactory.newList();
+
+		String rc = rowClass;
+
+		if (rc != null)
+			classes.add(rc);
+
+		if (dataRowIndex == startRow)
+			classes.add(BreadCrumbsTrailConstantsValues.BREADCRUMBS_FIRST_CLASS);
+
+		if (dataRowIndex == endRow)
+			classes.add(BreadCrumbsTrailConstantsValues.BREADCRUMBS_LAST_CLASS);
+
+		if (componentSource.getActivePage().getComponentResources().getCompleteId().equals(componentSource.getPage(row.getLogicalPageName()).getComponentResources().getCompleteId())) {
+			classes.add(BreadCrumbsTrailConstantsValues.BREADCRUMBS_ACTIVE_CLASS);
+		}
+
+		return TapestryInternalUtils.toClassAttributeValue(classes);
+	}
+
+	void setupForRow(int rowIndex) {
+		row = breadCrumbsModel.getRow(rowIndex);
+	}
+
+	boolean setupRender() {
+		int size = breadCrumbsModel.getSize();
+		startRow = 0;
+		endRow = size - 1;
+
+		dataRowIndex = startRow;
+
+		return size != 0;
+	}
+
+	boolean beginRender() {
+		// Setup for this row.
+
+		setupForRow(dataRowIndex);
+
+		// Update the index parameter (which starts from zero).
+		rowIndex = dataRowIndex - startRow;
+
+		return row != null;
+	}
+
+	boolean afterRender() {
+		dataRowIndex++;
+
+		// Abort the loop when we hit a null row, or when we've exhausted the
+		// range we need to
+		// display.
+
+		return row == null || dataRowIndex > endRow;
+	}
 
 }

src/main/java/com/zenios/tapestry/breadcrumbs/components/BreadCrumbsTrail.java

 
 @SuppressWarnings("unused")
 @SupportsInformalParameters
-public class BreadCrumbsTrail implements BreadCrumbsModel {
-	
+public class BreadCrumbsTrail implements BreadCrumbsModel
+{
+
 	@SessionState
 	private BreadCrumbsList breadCrumbs;
-	
-    @Parameter(name = "class", defaultPrefix = BindingConstants.LITERAL,value = BindingConstants.SYMBOL + ":" + BreadCrumbsConstants.BREADCRUMBS_TRAIL_CSS_CLASS)
-    @Property(write = false)
-    private String trailClass;
-    
-    @Component(parameters = "class=trailClass", inheritInformalParameters = true)
-    @Property
-    private Any trail;
-    
-    @Component(parameters ="row=row" , publishParameters = "rowIndex,rowClass,before,after,title")
-    @Property
-    private BreadCrumbsLoop trailCrumbs;
-        
-    @Parameter(principal = true)
-    private BreadCrumbObject row;
-    
-
-    private CachingBreadCrumbSource cachingSource;
-    
-    boolean setupRender()
-    {
-    	cachingSource = new CachingBreadCrumbSource(breadCrumbs.getBreadCrumbs());
-    	
-        return cachingSource.getAvailableRows() == 0 ? false : true;
-    }
-    
-    static class CachingBreadCrumbSource
-    {
-        private final List<BreadCrumbObject> delegate;
-
-        private boolean availableRowsCached;
-
-        private int availableRows;
-
-        CachingBreadCrumbSource(List<BreadCrumbObject> delegate)
-        {
-            this.delegate = delegate;
-        }
-
-        public int getAvailableRows()
-        {
-            if (!availableRowsCached)
-            {
-                availableRows = delegate.size();
-                availableRowsCached = true;
-            }
-
-            return availableRows;
-        }
-
-        public BreadCrumbObject getRowValue(int index)
-        {
-            return delegate.get(index);
-        }
-    }
+
+	@Parameter(name = "class", defaultPrefix = BindingConstants.LITERAL, value = BindingConstants.SYMBOL + ":" + BreadCrumbsConstants.BREADCRUMBS_TRAIL_CSS_CLASS)
+	@Property(write = false)
+	private String trailClass;
+
+	@Component(parameters = "class=trailClass", inheritInformalParameters = true)
+	@Property
+	private Any trail;
+
+	@Component(parameters = "row=row", publishParameters = "rowIndex,rowClass,before,after,title")
+	@Property
+	private BreadCrumbsLoop trailCrumbs;
+
+	@Parameter(principal = true)
+	private BreadCrumbObject row;
+
+	private CachingBreadCrumbSource cachingSource;
+
+	boolean setupRender() {
+		cachingSource = new CachingBreadCrumbSource(breadCrumbs.getBreadCrumbs());
+
+		return cachingSource.getAvailableRows() == 0 ? false : true;
+	}
+
+	static class CachingBreadCrumbSource
+	{
+		private final List<BreadCrumbObject> delegate;
+
+		private boolean availableRowsCached;
+
+		private int availableRows;
+
+		CachingBreadCrumbSource(List<BreadCrumbObject> delegate) {
+			this.delegate = delegate;
+		}
+
+		public int getAvailableRows() {
+			if (!availableRowsCached) {
+				availableRows = delegate.size();
+				availableRowsCached = true;
+			}
+
+			return availableRows;
+		}
+
+		public BreadCrumbObject getRowValue(int index) {
+			return delegate.get(index);
+		}
+	}
 
 	public int getSize() {
 		return cachingSource.getAvailableRows();
 	public BreadCrumbObject getRow(int rowIndex) {
 		return cachingSource.getRowValue(rowIndex);
 	}
-	
-    public BreadCrumbObject getRow()
-    {
-        return row;
-    }
-
-    public void setRow(BreadCrumbObject row)
-    {
-        this.row = row;
-    }
+
+	public BreadCrumbObject getRow() {
+		return row;
+	}
+
+	public void setRow(BreadCrumbObject row) {
+		this.row = row;
+	}
 
 }

src/main/java/com/zenios/tapestry/breadcrumbs/filter/BreadcrumbsPageRenderRequestFilter.java

 
 import com.zenios.tapestry.breadcrumbs.services.BreadCrumbsService;
 
-public class BreadcrumbsPageRenderRequestFilter implements PageRenderRequestFilter {
+public class BreadcrumbsPageRenderRequestFilter implements PageRenderRequestFilter
+{
 	private final BreadCrumbsService breadCrumbsService;
-	
+
 	public BreadcrumbsPageRenderRequestFilter(BreadCrumbsService breadCrumbsService) {
 		this.breadCrumbsService = breadCrumbsService;
 	}

src/main/java/com/zenios/tapestry/breadcrumbs/other/BreadCrumbObject.java

 import org.apache.tapestry5.EventContext;
 import org.apache.tapestry5.internal.TapestryInternalUtils;
 
-public class BreadCrumbObject {
+public class BreadCrumbObject
+{
 	private final String logicalPageName;
 	private final EventContext activationContext;
 	private final boolean titleEvent;
-	
-	public BreadCrumbObject(String logicalPageName,EventContext activationContext,boolean titleEvent) {
+
+	public BreadCrumbObject(String logicalPageName, EventContext activationContext, boolean titleEvent) {
 		this.logicalPageName = logicalPageName;
 		this.activationContext = activationContext;
 		this.titleEvent = titleEvent;
 	}
-	
-    public String getLogicalPageName() {
+
+	public String getLogicalPageName() {
 		return logicalPageName;
 	}
-    
+
 	public EventContext getActivationContext() {
 		return activationContext;
 	}
-	
+
 	public boolean isTitleEvent() {
 		return titleEvent;
 	}
-	
 
-	
 	@Override
 	public int hashCode() {
 		final int prime = 31;
 
 	@Override
 	public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-
-        if (obj == null || getClass() != obj.getClass())
-            return false;
-        
-        BreadCrumbObject other = (BreadCrumbObject)obj;
-        return TapestryInternalUtils.isEqual(activationContext, other.getActivationContext()) && 
-        		other.getLogicalPageName().equals(this.logicalPageName) &&
-        		other.isTitleEvent() == this.titleEvent;
+		if (this == obj)
+			return true;
+
+		if (obj == null || getClass() != obj.getClass())
+			return false;
+
+		BreadCrumbObject other = (BreadCrumbObject) obj;
+		return TapestryInternalUtils.isEqual(activationContext, other.getActivationContext()) && other.getLogicalPageName().equals(this.logicalPageName) && other.isTitleEvent() == this.titleEvent;
 	}
 
 }

src/main/java/com/zenios/tapestry/breadcrumbs/other/BreadCrumbsConstants.java

 package com.zenios.tapestry.breadcrumbs.other;
 
-public class BreadCrumbsConstants {
+public class BreadCrumbsConstants
+{
 	public static final String BREADCRUMBS_FILTER = "zbreadcrumbs";
 	public static final String BREADCRUMBS_MAX_CRUMBS_TO_SAVE = "zbreadcrumbs-to-save";
 	public static final String BREADCRUMBS_DISCARD_DUPLICATES = "zbreadcrumbs-discrd-duplicates";
-    public static final String BREADCRUMBS_TRAIL_CSS_CLASS = "zbreadcrumbs-css_class";
-    public static final String BREADCRUMBS_TITLE_SUFFIX = "zbreadcrumbs-title-suffix";
-    public static final String BREADCRUMBS_DEFAULT_STYLESHEET = "zbreadcrumbs-default-stylesheet";
+	public static final String BREADCRUMBS_TRAIL_CSS_CLASS = "zbreadcrumbs-css_class";
+	public static final String BREADCRUMBS_TITLE_SUFFIX = "zbreadcrumbs-title-suffix";
+	public static final String BREADCRUMBS_DEFAULT_STYLESHEET = "zbreadcrumbs-default-stylesheet";
 }

src/main/java/com/zenios/tapestry/breadcrumbs/other/BreadCrumbsConstantsValues.java

 package com.zenios.tapestry.breadcrumbs.other;
 
-public class BreadCrumbsConstantsValues {
-    public static final String BREADCRUMBS_MAX_CRUMBS_TO_SAVE_VALUE = "10";
-    public static final String BREADCRUMB_TRAIL_CSS_CLASS_VALUE = "t-zbreadcrumbs";
-    public static final String BREADCRUMBS_DISCARD_DUPLICATES_VALUE = "true";
-    public static final String BREADCRUMBS_TITLE_SUFFIX_VALUE = "-crumb";
-    public static final String BREADCRUMBS_DEFAULT_STYLESHEET_VALUE = "classpath:/com/zenios/tapestry/breadcrumbs/Assets/default.css";
+public class BreadCrumbsConstantsValues
+{
+	public static final String BREADCRUMBS_MAX_CRUMBS_TO_SAVE_VALUE = "10";
+	public static final String BREADCRUMB_TRAIL_CSS_CLASS_VALUE = "t-zbreadcrumbs";
+	public static final String BREADCRUMBS_DISCARD_DUPLICATES_VALUE = "true";
+	public static final String BREADCRUMBS_TITLE_SUFFIX_VALUE = "-crumb";
+	public static final String BREADCRUMBS_DEFAULT_STYLESHEET_VALUE = "classpath:/com/zenios/tapestry/breadcrumbs/Assets/default.css";
 }

src/main/java/com/zenios/tapestry/breadcrumbs/other/BreadCrumbsEvents.java

 package com.zenios.tapestry.breadcrumbs.other;
 
-public class BreadCrumbsEvents {
+public class BreadCrumbsEvents
+{
 	public static final String GET_TITLE = "zbreadcrumbs-get-title";
 }

src/main/java/com/zenios/tapestry/breadcrumbs/other/BreadCrumbsFilter.java

 {
 	private final String pattern;
 	private final BreadCrumbsFilterType filterType;
-	
+
 	public BreadCrumbsFilter(String pattern, BreadCrumbsFilterType filterType) {
 		this.pattern = pattern;
 		this.filterType = filterType;
 			return false;
 		return true;
 	}
-	
 
-	
 }

src/main/java/com/zenios/tapestry/breadcrumbs/other/BreadCrumbsFilterType.java

 package com.zenios.tapestry.breadcrumbs.other;
 
-public enum BreadCrumbsFilterType {
-	RESET,
-	IGNORE,
-	DYNAMIC_TITLE
+public enum BreadCrumbsFilterType
+{
+	RESET, IGNORE, DYNAMIC_TITLE
 }

src/main/java/com/zenios/tapestry/breadcrumbs/other/BreadCrumbsModel.java

 package com.zenios.tapestry.breadcrumbs.other;
 
-
-public interface BreadCrumbsModel {
+public interface BreadCrumbsModel
+{
 	int getSize();
 
 	BreadCrumbObject getRow(int rowIndex);

src/main/java/com/zenios/tapestry/breadcrumbs/other/BreadCrumbsTrailConstantsValues.java

 package com.zenios.tapestry.breadcrumbs.other;
 
-public class BreadCrumbsTrailConstantsValues {
+public class BreadCrumbsTrailConstantsValues
+{
 	public static final String BREADCRUMBS_FIRST_CLASS = "z-first";
 	public static final String BREADCRUMBS_LAST_CLASS = "z-last";
 	public static final String BREADCRUMBS_ACTIVE_CLASS = "z-active";

src/main/java/com/zenios/tapestry/breadcrumbs/services/BreadCrumbsModule.java

 import com.zenios.tapestry.breadcrumbs.session.BreadCrumbsList;
 import com.zenios.tapestry.breadcrumbs.session.impl.BreadCrumbsListImpl;
 
-public class BreadCrumbsModule {
-	
-	 public static void bind(final ServiceBinder binder) {
-		 binder.bind(BreadCrumbsService.class,BreadCrumbsServiceImpl.class);
-	 }
-	
-    public static void contributeFactoryDefaults(final MappedConfiguration<String, String> configuration) {
-        configuration.add(BreadCrumbsConstants.BREADCRUMBS_MAX_CRUMBS_TO_SAVE, BreadCrumbsConstantsValues.BREADCRUMBS_MAX_CRUMBS_TO_SAVE_VALUE);
-        configuration.add(BreadCrumbsConstants.BREADCRUMBS_DISCARD_DUPLICATES, BreadCrumbsConstantsValues.BREADCRUMBS_DISCARD_DUPLICATES_VALUE);
-        configuration.add(BreadCrumbsConstants.BREADCRUMBS_TRAIL_CSS_CLASS, BreadCrumbsConstantsValues.BREADCRUMB_TRAIL_CSS_CLASS_VALUE);
-        configuration.add(BreadCrumbsConstants.BREADCRUMBS_TITLE_SUFFIX, BreadCrumbsConstantsValues.BREADCRUMBS_TITLE_SUFFIX_VALUE);
-        configuration.add(BreadCrumbsConstants.BREADCRUMBS_DEFAULT_STYLESHEET, BreadCrumbsConstantsValues.BREADCRUMBS_DEFAULT_STYLESHEET_VALUE);
-    }
-    
+public class BreadCrumbsModule
+{
+
+	public static void bind(final ServiceBinder binder) {
+		binder.bind(BreadCrumbsService.class, BreadCrumbsServiceImpl.class);
+	}
+
+	public static void contributeFactoryDefaults(final MappedConfiguration<String, String> configuration) {
+		configuration.add(BreadCrumbsConstants.BREADCRUMBS_MAX_CRUMBS_TO_SAVE, BreadCrumbsConstantsValues.BREADCRUMBS_MAX_CRUMBS_TO_SAVE_VALUE);
+		configuration.add(BreadCrumbsConstants.BREADCRUMBS_DISCARD_DUPLICATES, BreadCrumbsConstantsValues.BREADCRUMBS_DISCARD_DUPLICATES_VALUE);
+		configuration.add(BreadCrumbsConstants.BREADCRUMBS_TRAIL_CSS_CLASS, BreadCrumbsConstantsValues.BREADCRUMB_TRAIL_CSS_CLASS_VALUE);
+		configuration.add(BreadCrumbsConstants.BREADCRUMBS_TITLE_SUFFIX, BreadCrumbsConstantsValues.BREADCRUMBS_TITLE_SUFFIX_VALUE);
+		configuration.add(BreadCrumbsConstants.BREADCRUMBS_DEFAULT_STYLESHEET, BreadCrumbsConstantsValues.BREADCRUMBS_DEFAULT_STYLESHEET_VALUE);
+	}
+
 	public static void contributePageRenderRequestHandler(OrderedConfiguration<PageRenderRequestFilter> configuration) {
 		configuration.addInstance(BreadCrumbsConstants.BREADCRUMBS_FILTER, BreadcrumbsPageRenderRequestFilter.class);
 	}
-	
-    public void contributeMarkupRenderer(OrderedConfiguration<MarkupRendererFilter> configuration,final Environment environment,@Path("${zbreadcrumbs-default-stylesheet}") final Asset defaultStylesheet) {
-        MarkupRendererFilter injectDefaultStylesheet = new MarkupRendererFilter()
-        {
-            public void renderMarkup(MarkupWriter writer, MarkupRenderer renderer)
-            {
-                DocumentLinker linker = environment.peekRequired(DocumentLinker.class);
 
-                linker.addStylesheetLink(new StylesheetLink(defaultStylesheet.toClientURL()));
+	public void contributeMarkupRenderer(OrderedConfiguration<MarkupRendererFilter> configuration, final Environment environment, @Path("${zbreadcrumbs-default-stylesheet}") final Asset defaultStylesheet) {
+		MarkupRendererFilter injectDefaultStylesheet = new MarkupRendererFilter()
+		{
+			public void renderMarkup(MarkupWriter writer, MarkupRenderer renderer) {
+				DocumentLinker linker = environment.peekRequired(DocumentLinker.class);
+
+				linker.addStylesheetLink(new StylesheetLink(defaultStylesheet.toClientURL()));
 
-                renderer.renderMarkup(writer);
-            }
-        };
-        
-        configuration.add("ZBreadCrumbsDefaultStylesheet", injectDefaultStylesheet, "after:InjectDefaultStylesheet");
-    }
-	
-	public static void contributeApplicationStateManager(MappedConfiguration<Class<?>, ApplicationStateContribution> configuration,@Symbol(BreadCrumbsConstants.BREADCRUMBS_MAX_CRUMBS_TO_SAVE) final int crumbsToSave,@Symbol(BreadCrumbsConstants.BREADCRUMBS_DISCARD_DUPLICATES) final boolean discardDuplicates) {
+				renderer.renderMarkup(writer);
+			}
+		};
+
+		configuration.add("ZBreadCrumbsDefaultStylesheet", injectDefaultStylesheet, "after:InjectDefaultStylesheet");
+	}
+
+	public static void contributeApplicationStateManager(MappedConfiguration<Class<?>, ApplicationStateContribution> configuration, @Symbol(BreadCrumbsConstants.BREADCRUMBS_MAX_CRUMBS_TO_SAVE) final int crumbsToSave, @Symbol(BreadCrumbsConstants.BREADCRUMBS_DISCARD_DUPLICATES) final boolean discardDuplicates) {
 		ApplicationStateCreator<BreadCrumbsList> breadCrumbsListCreator = new ApplicationStateCreator<BreadCrumbsList>()
 		{
 			public BreadCrumbsList create() {
-				return new BreadCrumbsListImpl(crumbsToSave,discardDuplicates);
+				return new BreadCrumbsListImpl(crumbsToSave, discardDuplicates);
 			}
 		};
 
 		configuration.add(BreadCrumbsList.class, new ApplicationStateContribution("session", breadCrumbsListCreator));
 	}
-	
-	
-    public static void contributeComponentClassResolver(final Configuration<LibraryMapping> configuration) {
-        configuration.add(new LibraryMapping("zcrumb", "com.zenios.tapestry.breadcrumbs"));
-    }
+
+	public static void contributeComponentClassResolver(final Configuration<LibraryMapping> configuration) {
+		configuration.add(new LibraryMapping("zcrumb", "com.zenios.tapestry.breadcrumbs"));
+	}
 }

src/main/java/com/zenios/tapestry/breadcrumbs/services/BreadCrumbsService.java

 import com.zenios.tapestry.breadcrumbs.other.BreadCrumbsFilter;
 
 @UsesConfiguration(BreadCrumbsFilter.class)
-public interface BreadCrumbsService {
+public interface BreadCrumbsService
+{
 	public void addToBreadCrumbs(PageRenderRequestParameters params);
 }

src/main/java/com/zenios/tapestry/breadcrumbs/services/impl/BreadCrumbsServiceImpl.java

 import com.zenios.tapestry.breadcrumbs.utils.AntPathMatcher;
 import com.zenios.tapestry.breadcrumbs.utils.PatternMatcher;
 
-public class BreadCrumbsServiceImpl implements BreadCrumbsService {
-	
+public class BreadCrumbsServiceImpl implements BreadCrumbsService
+{
+
 	private final ApplicationStateManager applicationStateManager;
 	private final PatternMatcher patternMatcher;
 	private final Collection<BreadCrumbsFilter> pathFilters;
 	private final ComponentSource componentSource;
-	
-	public BreadCrumbsServiceImpl(ApplicationStateManager applicationStateManager,Collection<BreadCrumbsFilter> pathFilters,ComponentSource componentSource) {
+
+	public BreadCrumbsServiceImpl(ApplicationStateManager applicationStateManager, Collection<BreadCrumbsFilter> pathFilters, ComponentSource componentSource) {
 		this.applicationStateManager = applicationStateManager;
 		this.patternMatcher = createPathMatcher();
 		this.pathFilters = pathFilters;
 	}
 
 	public void addToBreadCrumbs(PageRenderRequestParameters params) {
-		
-		if(params.isLoopback()) {
+
+		if (params.isLoopback()) {
 			throw new RuntimeException("IS loopback");
 		}
 		BreadCrumbsListImpl breadCrumbsList = (BreadCrumbsListImpl) applicationStateManager.get(BreadCrumbsList.class);
 		boolean resetCrumbs = false;
 		boolean dynamicTitle = false;
 		Iterator<BreadCrumbsFilter> iter = pathFilters.iterator();
-		while(iter.hasNext()) {
+		while (iter.hasNext()) {
 			BreadCrumbsFilter filter = iter.next();
 			if (patternMatcher.matches(filter.getPattern(), pageName)) {
 				BreadCrumbsFilterType type = filter.getFilterType();
-				if(type == BreadCrumbsFilterType.IGNORE) {
+				if (type == BreadCrumbsFilterType.IGNORE) {
 					ignorePage = true;
 				}
-				
-				if(type == BreadCrumbsFilterType.RESET) {
+
+				if (type == BreadCrumbsFilterType.RESET) {
 					resetCrumbs = true;
 				}
-				
-				if(type == BreadCrumbsFilterType.DYNAMIC_TITLE) {
+
+				if (type == BreadCrumbsFilterType.DYNAMIC_TITLE) {
 					dynamicTitle = true;
 				}
 			}
 		}
-    	Component page = componentSource.getPage(pageName);
-    	BreadCrumb breadCrumb = findAnnotation(page.getClass(),BreadCrumb.class);
-    	if(breadCrumb != null) {
-	    	if(breadCrumb.ignore()) {
-	    		ignorePage = true;
-	    	}
-	    	
-	    	
-	    	if(breadCrumb.reset()) {
-	    		resetCrumbs = true;
-	    	}
-	    	
-	    	if(breadCrumb.dynamicTitle()) {
-	    		dynamicTitle = true;
-	    	}
-    	}    
-    	
-    	if(resetCrumbs) {
-    		breadCrumbsList.clear();
-    	}
-    	
-    	if(ignorePage) {
-    		return;
-    	}
-		breadCrumbsList.add(new BreadCrumbObject(pageName,params.getActivationContext(),dynamicTitle));
+		Component page = componentSource.getPage(pageName);
+		BreadCrumb breadCrumb = findAnnotation(page.getClass(), BreadCrumb.class);
+		if (breadCrumb != null) {
+			if (breadCrumb.ignore()) {
+				ignorePage = true;
+			}
+
+			if (breadCrumb.reset()) {
+				resetCrumbs = true;
+			}
+
+			if (breadCrumb.dynamicTitle()) {
+				dynamicTitle = true;
+			}
+		}
+
+		if (resetCrumbs) {
+			breadCrumbsList.clear();
+		}
+
+		if (ignorePage) {
+			return;
+		}
+		breadCrumbsList.add(new BreadCrumbObject(pageName, params.getActivationContext(), dynamicTitle));
 	}
-	
-	
+
 	private PatternMatcher createPathMatcher() {
-		return new AntPathMatcher() {
+		return new AntPathMatcher()
+		{
 			public boolean matches(String pattern, String source) {
-		    	return super.matches(pattern, source.toLowerCase());
-		    }
+				return super.matches(pattern, source.toLowerCase());
+			}
 		};
 	}
-	
-    private <T extends Annotation> T findAnnotation(final Class<?> clazz, final Class<T> annotation) {
-        T result = clazz.getAnnotation(annotation);
 
-        if (result == null && clazz.getSuperclass() != null) {
-            result = this.findAnnotation(clazz.getSuperclass(), annotation);
-        }
+	private <T extends Annotation> T findAnnotation(final Class<?> clazz, final Class<T> annotation) {
+		T result = clazz.getAnnotation(annotation);
 
-        return result;
-    }
+		if (result == null && clazz.getSuperclass() != null) {
+			result = this.findAnnotation(clazz.getSuperclass(), annotation);
+		}
+
+		return result;
+	}
 }

src/main/java/com/zenios/tapestry/breadcrumbs/session/BreadCrumbsList.java

 
 import com.zenios.tapestry.breadcrumbs.other.BreadCrumbObject;
 
-public interface BreadCrumbsList extends Serializable {
+public interface BreadCrumbsList extends Serializable
+{
 	public List<BreadCrumbObject> getBreadCrumbs();
 }

src/main/java/com/zenios/tapestry/breadcrumbs/session/impl/BreadCrumbsListImpl.java

 import com.zenios.tapestry.breadcrumbs.other.BreadCrumbObject;
 import com.zenios.tapestry.breadcrumbs.session.BreadCrumbsList;
 
-public class BreadCrumbsListImpl implements BreadCrumbsList {
+public class BreadCrumbsListImpl implements BreadCrumbsList
+{
 	private static final long serialVersionUID = -8457209111821626779L;
 	private final List<BreadCrumbObject> items;
 	private final Object mutex;
 	private final int size;
 	private final boolean discardDuplicates;
 
-	public BreadCrumbsListImpl(int size,boolean discardDuplicates) {
+	public BreadCrumbsListImpl(int size, boolean discardDuplicates) {
 		this.items = new ArrayList<BreadCrumbObject>(size);
 		this.mutex = new Object();
 		this.size = size;
 	}
 
 	public void clear() {
-		synchronized(mutex) {
+		synchronized (mutex) {
 			items.clear();
 		}
 	}
 
 	public void add(BreadCrumbObject breadCrumb) {
-		synchronized(mutex) {
+		synchronized (mutex) {
 			final int index = items.lastIndexOf(breadCrumb);
-			/*No need to add the page since is exactly the same
-			 * as the previous one */
-			if(index != -1 && index == items.size() -1) {
+			/*
+			 * No need to add the page since is exactly the same as the previous
+			 * one
+			 */
+			if (index != -1 && index == items.size() - 1) {
 				return;
 			}
-			if (discardDuplicates) {;
-				if(index != -1) {
+			if (discardDuplicates) {
+				;
+				if (index != -1) {
 					items.subList(index + 1, items.size()).clear();
 					return;
 				}
 	}
 
 	public List<BreadCrumbObject> getBreadCrumbs() {
-		synchronized(mutex) {
+		synchronized (mutex) {
 			return new ArrayList<BreadCrumbObject>(items);
 		}
 	}

src/main/java/com/zenios/tapestry/breadcrumbs/utils/AntPathMatcher.java

 import java.util.StringTokenizer;
 
 /**
- * <p>PathMatcher implementation for Ant-style path patterns.
- * Examples are provided below.</p>
- *
- * <p>Part of this mapping code has been kindly borrowed from
- * <a href="http://ant.apache.org">Apache Ant</a>.
- *
- * <p>The mapping matches URLs using the following rules:<br>
+ * <p>
+ * PathMatcher implementation for Ant-style path patterns. Examples are provided
+ * below.
+ * </p>
+ * 
+ * <p>
+ * Part of this mapping code has been kindly borrowed from <a
+ * href="http://ant.apache.org">Apache Ant</a>.
+ * 
+ * <p>
+ * The mapping matches URLs using the following rules:<br>
  * <ul>
  * <li>? matches one character</li>
  * <li>* matches zero or more characters</li>
  * <li>** matches zero or more 'directories' in a path</li>
  * </ul>
- *
- * <p>Some examples:<br>
+ * 
+ * <p>
+ * Some examples:<br>
  * <ul>
  * <li><code>com/t?st.jsp</code> - matches <code>com/test.jsp</code> but also
  * <code>com/tast.jsp</code> or <code>com/txst.jsp</code></li>
  * <code>com</code> directory</li>
  * <li><code>com/&#42;&#42;/test.jsp</code> - matches all <code>test.jsp</code>
  * files underneath the <code>com</code> path</li>
- * <li><code>org/apache/shiro/&#42;&#42;/*.jsp</code> - matches all <code>.jsp</code>
- * files underneath the <code>org/apache/shiro</code> path</li>
+ * <li><code>org/apache/shiro/&#42;&#42;/*.jsp</code> - matches all
+ * <code>.jsp</code> files underneath the <code>org/apache/shiro</code> path</li>
  * <li><code>org/&#42;&#42;/servlet/bla.jsp</code> - matches
  * <code>org/apache/shiro/servlet/bla.jsp</code> but also
  * <code>org/apache/shiro/testing/servlet/bla.jsp</code> and
  * <code>org/servlet/bla.jsp</code></li>
  * </ul>
- *
- * <p><b>N.B.</b>: This class was borrowed (with much appreciation) from the
- * <a href="http://www.springframework.org">Spring Framework</a> with modifications.  We didn't want to reinvent the
- * wheel of great work they've done, but also didn't want to force every Shiro user to depend on Spring</p>
- *
- * <p>As per the Apache 2.0 license, the original copyright notice and all author and copyright information have
- * remained in tact.</p>
- *
+ * 
+ * <p>
+ * <b>N.B.</b>: This class was borrowed (with much appreciation) from the <a
+ * href="http://www.springframework.org">Spring Framework</a> with
+ * modifications. We didn't want to reinvent the wheel of great work they've
+ * done, but also didn't want to force every Shiro user to depend on Spring
+ * </p>
+ * 
+ * <p>
+ * As per the Apache 2.0 license, the original copyright notice and all author
+ * and copyright information have remained in tact.
+ * </p>
+ * 
  * @borrowed: org.apache.shiro.util.AntPathMatcher
  */
-public class AntPathMatcher implements PatternMatcher {
-
-    //TODO - complete JavaDoc
-
-    /**
-     * Default path separator: "/"
-     */
-    public static final String DEFAULT_PATH_SEPARATOR = "/";
-
-    private String pathSeparator = DEFAULT_PATH_SEPARATOR;
-
-
-    /**
-     * Set the path separator to use for pattern parsing.
-     * Default is "/", as in Ant.
-     */
-    public void setPathSeparator(String pathSeparator) {
-        this.pathSeparator = (pathSeparator != null ? pathSeparator : DEFAULT_PATH_SEPARATOR);
-    }
-
-
-    public boolean isPattern(String path) {
-        return (path.indexOf('*') != -1 || path.indexOf('?') != -1);
-    }
-
-    public boolean matches(String pattern, String source) {
-        return match(pattern, source);
-    }
-
-    public boolean match(String pattern, String path) {
-        return doMatch(pattern, path, true);
-    }
-
-    public boolean matchStart(String pattern, String path) {
-        return doMatch(pattern, path, false);
-    }
-
-
-    /**
-     * Actually match the given <code>path</code> against the given <code>pattern</code>.
-     *
-     * @param pattern   the pattern to match against
-     * @param path      the path String to test
-     * @param fullMatch whether a full pattern match is required
-     *                  (else a pattern match as far as the given base path goes is sufficient)
-     * @return <code>true</code> if the supplied <code>path</code> matched,
-     *         <code>false</code> if it didn't
-     */
-    protected boolean doMatch(String pattern, String path, boolean fullMatch) {
-        if (path.startsWith(this.pathSeparator) != pattern.startsWith(this.pathSeparator)) {
-            return false;
-        }
-
-        String[] pattDirs = tokenizeToStringArray(pattern, this.pathSeparator,true,true);
-        String[] pathDirs = tokenizeToStringArray(path, this.pathSeparator,true,true);
-
-        int pattIdxStart = 0;
-        int pattIdxEnd = pattDirs.length - 1;
-        int pathIdxStart = 0;
-        int pathIdxEnd = pathDirs.length - 1;
-
-        // Match all elements up to the first **
-        while (pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd) {
-            String patDir = pattDirs[pattIdxStart];
-            if ("**".equals(patDir)) {
-                break;
-            }
-            if (!matchStrings(patDir, pathDirs[pathIdxStart])) {
-                return false;
-            }
-            pattIdxStart++;
-            pathIdxStart++;
-        }
-
-        if (pathIdxStart > pathIdxEnd) {
-            // Path is exhausted, only match if rest of pattern is * or **'s
-            if (pattIdxStart > pattIdxEnd) {
-                return (pattern.endsWith(this.pathSeparator) ?
-                        path.endsWith(this.pathSeparator) : !path.endsWith(this.pathSeparator));
-            }
-            if (!fullMatch) {
-                return true;
-            }
-            if (pattIdxStart == pattIdxEnd && pattDirs[pattIdxStart].equals("*") &&
-                    path.endsWith(this.pathSeparator)) {
-                return true;
-            }
-            for (int i = pattIdxStart; i <= pattIdxEnd; i++) {
-                if (!pattDirs[i].equals("**")) {
-                    return false;
-                }
-            }
-            return true;
-        } else if (pattIdxStart > pattIdxEnd) {
-            // String not exhausted, but pattern is. Failure.
-            return false;
-        } else if (!fullMatch && "**".equals(pattDirs[pattIdxStart])) {
-            // Path start definitely matches due to "**" part in pattern.
-            return true;
-        }
-
-        // up to last '**'
-        while (pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd) {
-            String patDir = pattDirs[pattIdxEnd];
-            if (patDir.equals("**")) {
-                break;
-            }
-            if (!matchStrings(patDir, pathDirs[pathIdxEnd])) {
-                return false;
-            }
-            pattIdxEnd--;
-            pathIdxEnd--;
-        }
-        if (pathIdxStart > pathIdxEnd) {
-            // String is exhausted
-            for (int i = pattIdxStart; i <= pattIdxEnd; i++) {
-                if (!pattDirs[i].equals("**")) {
-                    return false;
-                }
-            }
-            return true;
-        }
-
-        while (pattIdxStart != pattIdxEnd && pathIdxStart <= pathIdxEnd) {
-            int patIdxTmp = -1;
-            for (int i = pattIdxStart + 1; i <= pattIdxEnd; i++) {
-                if (pattDirs[i].equals("**")) {
-                    patIdxTmp = i;
-                    break;
-                }
-            }
-            if (patIdxTmp == pattIdxStart + 1) {
-                // '**/**' situation, so skip one
-                pattIdxStart++;
-                continue;
-            }
-            // Find the pattern between padIdxStart & padIdxTmp in str between
-            // strIdxStart & strIdxEnd
-            int patLength = (patIdxTmp - pattIdxStart - 1);
-            int strLength = (pathIdxEnd - pathIdxStart + 1);
-            int foundIdx = -1;
-
-            strLoop:
-            for (int i = 0; i <= strLength - patLength; i++) {
-                for (int j = 0; j < patLength; j++) {
-                    String subPat = (String) pattDirs[pattIdxStart + j + 1];
-                    String subStr = (String) pathDirs[pathIdxStart + i + j];
-                    if (!matchStrings(subPat, subStr)) {
-                        continue strLoop;
-                    }
-                }
-                foundIdx = pathIdxStart + i;
-                break;
-            }
-
-            if (foundIdx == -1) {
-                return false;
-            }
-
-            pattIdxStart = patIdxTmp;
-            pathIdxStart = foundIdx + patLength;
-        }
-
-        for (int i = pattIdxStart; i <= pattIdxEnd; i++) {
-            if (!pattDirs[i].equals("**")) {
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    /**
-     * Tests whether or not a string matches against a pattern.
-     * The pattern may contain two special characters:<br>
-     * '*' means zero or more characters<br>
-     * '?' means one and only one character
-     *
-     * @param pattern pattern to match against.
-     *                Must not be <code>null</code>.
-     * @param str     string which must be matched against the pattern.
-     *                Must not be <code>null</code>.
-     * @return <code>true</code> if the string matches against the
-     *         pattern, or <code>false</code> otherwise.
-     */
-    private boolean matchStrings(String pattern, String str) {
-        char[] patArr = pattern.toCharArray();
-        char[] strArr = str.toCharArray();
-        int patIdxStart = 0;
-        int patIdxEnd = patArr.length - 1;
-        int strIdxStart = 0;
-        int strIdxEnd = strArr.length - 1;
-        char ch;
-
-        boolean containsStar = false;
-        for (char aPatArr : patArr) {
-            if (aPatArr == '*') {
-                containsStar = true;
-                break;
-            }
-        }
-
-        if (!containsStar) {
-            // No '*'s, so we make a shortcut
-            if (patIdxEnd != strIdxEnd) {
-                return false; // Pattern and string do not have the same size
-            }
-            for (int i = 0; i <= patIdxEnd; i++) {
-                ch = patArr[i];
-                if (ch != '?') {
-                    if (ch != strArr[i]) {
-                        return false;// Character mismatch
-                    }
-                }
-            }
-            return true; // String matches against pattern
-        }
-
-
-        if (patIdxEnd == 0) {
-            return true; // Pattern contains only '*', which matches anything
-        }
-
-        // Process characters before first star
-        while ((ch = patArr[patIdxStart]) != '*' && strIdxStart <= strIdxEnd) {
-            if (ch != '?') {
-                if (ch != strArr[strIdxStart]) {
-                    return false;// Character mismatch
-                }
-            }
-            patIdxStart++;
-            strIdxStart++;
-        }
-        if (strIdxStart > strIdxEnd) {
-            // All characters in the string are used. Check if only '*'s are
-            // left in the pattern. If so, we succeeded. Otherwise failure.
-            for (int i = patIdxStart; i <= patIdxEnd; i++) {
-                if (patArr[i] != '*') {
-                    return false;
-                }
-            }
-            return true;
-        }
-
-        // Process characters after last star
-        while ((ch = patArr[patIdxEnd]) != '*' && strIdxStart <= strIdxEnd) {
-            if (ch != '?') {
-                if (ch != strArr[strIdxEnd]) {
-                    return false;// Character mismatch
-                }
-            }
-            patIdxEnd--;
-            strIdxEnd--;
-        }
-        if (strIdxStart > strIdxEnd) {
-            // All characters in the string are used. Check if only '*'s are
-            // left in the pattern. If so, we succeeded. Otherwise failure.
-            for (int i = patIdxStart; i <= patIdxEnd; i++) {
-                if (patArr[i] != '*') {
-                    return false;
-                }
-            }
-            return true;
-        }
-
-        // process pattern between stars. padIdxStart and patIdxEnd point
-        // always to a '*'.
-        while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
-            int patIdxTmp = -1;
-            for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
-                if (patArr[i] == '*') {
-                    patIdxTmp = i;
-                    break;
-                }
-            }
-            if (patIdxTmp == patIdxStart + 1) {
-                // Two stars next to each other, skip the first one.
-                patIdxStart++;
-                continue;
-            }
-            // Find the pattern between padIdxStart & padIdxTmp in str between
-            // strIdxStart & strIdxEnd
-            int patLength = (patIdxTmp - patIdxStart - 1);
-            int strLength = (strIdxEnd - strIdxStart + 1);
-            int foundIdx = -1;
-            strLoop:
-            for (int i = 0; i <= strLength - patLength; i++) {
-                for (int j = 0; j < patLength; j++) {
-                    ch = patArr[patIdxStart + j + 1];
-                    if (ch != '?') {
-                        if (ch != strArr[strIdxStart + i + j]) {
-                            continue strLoop;
-                        }
-                    }
-                }
-
-                foundIdx = strIdxStart + i;
-                break;
-            }
-
-            if (foundIdx == -1) {
-                return false;
-            }
-
-            patIdxStart = patIdxTmp;
-            strIdxStart = foundIdx + patLength;
-        }
-
-        // All characters in the string are used. Check if only '*'s are left
-        // in the pattern. If so, we succeeded. Otherwise failure.
-        for (int i = patIdxStart; i <= patIdxEnd; i++) {
-            if (patArr[i] != '*') {
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    /**
-     * Given a pattern and a full path, determine the pattern-mapped part.
-     * <p>For example:
-     * <ul>
-     * <li>'<code>/docs/cvs/commit.html</code>' and '<code>/docs/cvs/commit.html</code> -> ''</li>
-     * <li>'<code>/docs/*</code>' and '<code>/docs/cvs/commit</code> -> '<code>cvs/commit</code>'</li>
-     * <li>'<code>/docs/cvs/*.html</code>' and '<code>/docs/cvs/commit.html</code> -> '<code>commit.html</code>'</li>
-     * <li>'<code>/docs/**</code>' and '<code>/docs/cvs/commit</code> -> '<code>cvs/commit</code>'</li>
-     * <li>'<code>/docs/**\/*.html</code>' and '<code>/docs/cvs/commit.html</code> -> '<code>cvs/commit.html</code>'</li>
-     * <li>'<code>/*.html</code>' and '<code>/docs/cvs/commit.html</code> -> '<code>docs/cvs/commit.html</code>'</li>
-     * <li>'<code>*.html</code>' and '<code>/docs/cvs/commit.html</code> -> '<code>/docs/cvs/commit.html</code>'</li>
-     * <li>'<code>*</code>' and '<code>/docs/cvs/commit.html</code> -> '<code>/docs/cvs/commit.html</code>'</li>
-     * </ul>
-     * <p>Assumes that {@link #match} returns <code>true</code> for '<code>pattern</code>'
-     * and '<code>path</code>', but does <strong>not</strong> enforce this.
-     */
-    public String extractPathWithinPattern(String pattern, String path) {
-        String[] patternParts = tokenizeToStringArray(pattern, this.pathSeparator,true,true);
-        String[] pathParts = tokenizeToStringArray(path, this.pathSeparator,true,true);
-
-        StringBuilder buffer = new StringBuilder();
-
-        // Add any path parts that have a wildcarded pattern part.
-        int puts = 0;
-        for (int i = 0; i < patternParts.length; i++) {
-            String patternPart = patternParts[i];
-            if ((patternPart.indexOf('*') > -1 || patternPart.indexOf('?') > -1) && pathParts.length >= i + 1) {
-                if (puts > 0 || (i == 0 && !pattern.startsWith(this.pathSeparator))) {
-                    buffer.append(this.pathSeparator);
-                }
-                buffer.append(pathParts[i]);
-                puts++;
-            }
-        }
-
-        // Append any trailing path parts.
-        for (int i = patternParts.length; i < pathParts.length; i++) {
-            if (puts > 0 || i > 0) {
-                buffer.append(this.pathSeparator);
-            }
-            buffer.append(pathParts[i]);
-        }
-
-        return buffer.toString();
-    }
-    
-    private String[] tokenizeToStringArray(String str, String delimiters, boolean trimTokens, boolean ignoreEmptyTokens) {
-
-        if (str == null) {
-            return null;
-        }
-        StringTokenizer st = new StringTokenizer(str, delimiters);
-        List<String> tokens = new ArrayList<String>();
-        while (st.hasMoreTokens()) {
-            String token = st.nextToken();
-            if (trimTokens) {
-                token = token.trim();
-            }
-            if (!ignoreEmptyTokens || token.length() > 0) {
-                tokens.add(token);
-            }
-        }
-        return toStringArray(tokens);
-    }
-    
-    private String[] toStringArray(Collection<String> collection) {
-        if (collection == null) {
-            return null;
-        }
-        return (String[]) collection.toArray(new String[collection.size()]);
-    }
+public class AntPathMatcher implements PatternMatcher
+{
+
+	// TODO - complete JavaDoc
+
+	/**
+	 * Default path separator: "/"
+	 */
+	public static final String DEFAULT_PATH_SEPARATOR = "/";
+
+	private String pathSeparator = DEFAULT_PATH_SEPARATOR;
+
+	/**
+	 * Set the path separator to use for pattern parsing. Default is "/", as in
+	 * Ant.
+	 */
+	public void setPathSeparator(String pathSeparator) {
+		this.pathSeparator = (pathSeparator != null ? pathSeparator : DEFAULT_PATH_SEPARATOR);
+	}
+
+	public boolean isPattern(String path) {
+		return (path.indexOf('*') != -1 || path.indexOf('?') != -1);
+	}
+
+	public boolean matches(String pattern, String source) {
+		return match(pattern, source);
+	}
+
+	public boolean match(String pattern, String path) {
+		return doMatch(pattern, path, true);
+	}
+
+	public boolean matchStart(String pattern, String path) {
+		return doMatch(pattern, path, false);
+	}
+
+	/**
+	 * Actually match the given <code>path</code> against the given
+	 * <code>pattern</code>.
+	 * 
+	 * @param pattern
+	 *            the pattern to match against
+	 * @param path
+	 *            the path String to test
+	 * @param fullMatch
+	 *            whether a full pattern match is required (else a pattern match
+	 *            as far as the given base path goes is sufficient)
+	 * @return <code>true</code> if the supplied <code>path</code> matched,
+	 *         <code>false</code> if it didn't
+	 */
+	protected boolean doMatch(String pattern, String path, boolean fullMatch) {
+		if (path.startsWith(this.pathSeparator) != pattern.startsWith(this.pathSeparator)) {
+			return false;
+		}
+
+		String[] pattDirs = tokenizeToStringArray(pattern, this.pathSeparator, true, true);
+		String[] pathDirs = tokenizeToStringArray(path, this.pathSeparator, true, true);
+
+		int pattIdxStart = 0;
+		int pattIdxEnd = pattDirs.length - 1;
+		int pathIdxStart = 0;
+		int pathIdxEnd = pathDirs.length - 1;
+
+		// Match all elements up to the first **
+		while (pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd) {
+			String patDir = pattDirs[pattIdxStart];
+			if ("**".equals(patDir)) {
+				break;
+			}
+			if (!matchStrings(patDir, pathDirs[pathIdxStart])) {
+				return false;
+			}
+			pattIdxStart++;
+			pathIdxStart++;
+		}
+
+		if (pathIdxStart > pathIdxEnd) {
+			// Path is exhausted, only match if rest of pattern is * or **'s
+			if (pattIdxStart > pattIdxEnd) {
+				return (pattern.endsWith(this.pathSeparator) ? path.endsWith(this.pathSeparator) : !path.endsWith(this.pathSeparator));
+			}
+			if (!fullMatch) {
+				return true;
+			}
+			if (pattIdxStart == pattIdxEnd && pattDirs[pattIdxStart].equals("*") && path.endsWith(this.pathSeparator)) {
+				return true;
+			}
+			for (int i = pattIdxStart; i <= pattIdxEnd; i++) {
+				if (!pattDirs[i].equals("**")) {
+					return false;
+				}
+			}
+			return true;
+		} else if (pattIdxStart > pattIdxEnd) {
+			// String not exhausted, but pattern is. Failure.
+			return false;
+		} else if (!fullMatch && "**".equals(pattDirs[pattIdxStart])) {
+			// Path start definitely matches due to "**" part in pattern.
+			return true;
+		}
+
+		// up to last '**'
+		while (pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd) {
+			String patDir = pattDirs[pattIdxEnd];
+			if (patDir.equals("**")) {
+				break;
+			}
+			if (!matchStrings(patDir, pathDirs[pathIdxEnd])) {
+				return false;
+			}
+			pattIdxEnd--;
+			pathIdxEnd--;
+		}
+		if (pathIdxStart > pathIdxEnd) {
+			// String is exhausted
+			for (int i = pattIdxStart; i <= pattIdxEnd; i++) {
+				if (!pattDirs[i].equals("**")) {
+					return false;
+				}
+			}
+			return true;
+		}
+
+		while (pattIdxStart != pattIdxEnd && pathIdxStart <= pathIdxEnd) {
+			int patIdxTmp = -1;
+			for (int i = pattIdxStart + 1; i <= pattIdxEnd; i++) {
+				if (pattDirs[i].equals("**")) {
+					patIdxTmp = i;
+					break;
+				}
+			}
+			if (patIdxTmp == pattIdxStart + 1) {
+				// '**/**' situation, so skip one
+				pattIdxStart++;
+				continue;
+			}
+			// Find the pattern between padIdxStart & padIdxTmp in str between
+			// strIdxStart & strIdxEnd
+			int patLength = (patIdxTmp - pattIdxStart - 1);
+			int strLength = (pathIdxEnd - pathIdxStart + 1);
+			int foundIdx = -1;
+
+			strLoop: for (int i = 0; i <= strLength - patLength; i++) {
+				for (int j = 0; j < patLength; j++) {
+					String subPat = (String) pattDirs[pattIdxStart + j + 1];
+					String subStr = (String) pathDirs[pathIdxStart + i + j];
+					if (!matchStrings(subPat, subStr)) {
+						continue strLoop;
+					}
+				}
+				foundIdx = pathIdxStart + i;
+				break;
+			}
+
+			if (foundIdx == -1) {
+				return false;
+			}
+
+			pattIdxStart = patIdxTmp;
+			pathIdxStart = foundIdx + patLength;
+		}
+
+		for (int i = pattIdxStart; i <= pattIdxEnd; i++) {
+			if (!pattDirs[i].equals("**")) {
+				return false;
+			}
+		}
+
+		return true;
+	}
+
+	/**
+	 * Tests whether or not a string matches against a pattern. The pattern may
+	 * contain two special characters:<br>
+	 * '*' means zero or more characters<br>
+	 * '?' means one and only one character
+	 * 
+	 * @param pattern
+	 *            pattern to match against. Must not be <code>null</code>.
+	 * @param str
+	 *            string which must be matched against the pattern. Must not be
+	 *            <code>null</code>.
+	 * @return <code>true</code> if the string matches against the pattern, or
+	 *         <code>false</code> otherwise.
+	 */
+	private boolean matchStrings(String pattern, String str) {
+		char[] patArr = pattern.toCharArray();
+		char[] strArr = str.toCharArray();
+		int patIdxStart = 0;
+		int patIdxEnd = patArr.length - 1;
+		int strIdxStart = 0;
+		int strIdxEnd = strArr.length - 1;
+		char ch;
+
+		boolean containsStar = false;
+		for (char aPatArr : patArr) {
+			if (aPatArr == '*') {
+				containsStar = true;
+				break;
+			}
+		}
+
+		if (!containsStar) {
+			// No '*'s, so we make a shortcut
+			if (patIdxEnd != strIdxEnd) {
+				return false; // Pattern and string do not have the same size
+			}
+			for (int i = 0; i <= patIdxEnd; i++) {
+				ch = patArr[i];
+				if (ch != '?') {
+					if (ch != strArr[i]) {
+						return false;// Character mismatch
+					}
+				}
+			}
+			return true; // String matches against pattern
+		}
+
+		if (patIdxEnd == 0) {
+			return true; // Pattern contains only '*', which matches anything
+		}
+
+		// Process characters before first star
+		while ((ch = patArr[patIdxStart]) != '*' && strIdxStart <= strIdxEnd) {
+			if (ch != '?') {
+				if (ch != strArr[strIdxStart]) {
+					return false;// Character mismatch
+				}
+			}
+			patIdxStart++;
+			strIdxStart++;
+		}
+		if (strIdxStart > strIdxEnd) {
+			// All characters in the string are used. Check if only '*'s are
+			// left in the pattern. If so, we succeeded. Otherwise failure.
+			for (int i = patIdxStart; i <= patIdxEnd; i++) {
+				if (patArr[i] != '*') {
+					return false;
+				}
+			}
+			return true;
+		}
+
+		// Process characters after last star
+		while ((ch = patArr[patIdxEnd]) != '*' && strIdxStart <= strIdxEnd) {
+			if (ch != '?') {
+				if (ch != strArr[strIdxEnd]) {
+					return false;// Character mismatch
+				}
+			}
+			patIdxEnd--;
+			strIdxEnd--;
+		}
+		if (strIdxStart > strIdxEnd) {
+			// All characters in the string are used. Check if only '*'s are
+			// left in the pattern. If so, we succeeded. Otherwise failure.
+			for (int i = patIdxStart; i <= patIdxEnd; i++) {
+				if (patArr[i] != '*') {
+					return false;
+				}
+			}
+			return true;
+		}
+
+		// process pattern between stars. padIdxStart and patIdxEnd point
+		// always to a '*'.
+		while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
+			int patIdxTmp = -1;
+			for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
+				if (patArr[i] == '*') {
+					patIdxTmp = i;
+					break;
+				}
+			}
+			if (patIdxTmp == patIdxStart + 1) {
+				// Two stars next to each other, skip the first one.
+				patIdxStart++;
+				continue;
+			}
+			// Find the pattern between padIdxStart & padIdxTmp in str between
+			// strIdxStart & strIdxEnd
+			int patLength = (patIdxTmp - patIdxStart - 1);
+			int strLength = (strIdxEnd - strIdxStart + 1);
+			int foundIdx = -1;
+			strLoop: for (int i = 0; i <= strLength - patLength; i++) {
+				for (int j = 0; j < patLength; j++) {
+					ch = patArr[patIdxStart + j + 1];
+					if (ch != '?') {
+						if (ch != strArr[strIdxStart + i + j]) {
+							continue strLoop;
+						}
+					}
+				}
+
+				foundIdx = strIdxStart + i;
+				break;
+			}
+
+			if (foundIdx == -1) {
+				return false;
+			}