package lt.inventi.wicket.component.breadcrumb; import java.lang.reflect.Field; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import org.apache.wicket.Component; import org.apache.wicket.application.IComponentInitializationListener; import org.apache.wicket.markup.html.link.BookmarkablePageLink; import org.apache.wicket.request.mapper.parameter.PageParameters; import org.slf4j.Logger; import org.slf4j.LoggerFactory; class BookmarkableBreadcrumbPageInitializationListener implements IComponentInitializationListener { private static final Logger logger = LoggerFactory.getLogger(BookmarkableBreadcrumbPageInitializationListener.class); private final Class<? extends BookmarkablePageLink<?>> linkTypeToDecorate, linkTypeToNotDecorate; private final IBreadcrumbPageFilter pageFilter; BookmarkableBreadcrumbPageInitializationListener(IBreadcrumbPageFilter pageFilter, Class<? extends BookmarkablePageLink<?>> linkTypeToDecorate, Class<? extends BookmarkablePageLink<?>> linkTypeToNotDecorate) { this.pageFilter = pageFilter; this.linkTypeToDecorate = linkTypeToDecorate; this.linkTypeToNotDecorate = linkTypeToNotDecorate; } @Override public void onInitialize(Component component) { if (!linkTypeToNotDecorate.isAssignableFrom(component.getClass()) && linkTypeToDecorate.isAssignableFrom(component.getClass()) && pageFilter.shouldCreateBreadcrumbFor(component.getPage())) { BookmarkablePageLink<?> link = linkTypeToDecorate.cast(component); if (link.getPage().getPageParameters() == link.getPageParameters()) { cloneParameters(link, link.getPageParameters()); logger.trace("Cloned page parameters for a bookmarkable link {} on page {}.", link, link.getPage()); } BreadcrumbPageParameters.setTrailTo(link.getPageParameters(), link.getPage()); } } private static void cloneParameters(final BookmarkablePageLink<?> link, final PageParameters pageParameters) { /* * Cloning is needed because we cannot modify the page parameters of a page containing a * bookmarkable link as they may already point to an existing breadcrumb trail. By modifying page's parameters * we would make the instance of the page point to itself in the breadcrumb trail. */ try { AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() { @Override public Void run() throws Exception { Field f = BookmarkablePageLink.class.getDeclaredField("parameters"); f.setAccessible(true); f.set(link, new PageParameters(pageParameters)); return null; } }); } catch (PrivilegedActionException e) { throw new RuntimeException(e); } } }