Hi, Yes, sorry. I am still working on this.
Regards Felix Am 02.02.2012 um 22:40 schrieb Justin Edelson: > This seems to have broken a few tests: > > Results : > > Failed tests: > > testCallFooHtml(org.apache.sling.launchpad.webapp.integrationtest.issues.SLING457Test): > Expected status 200 for > http://localhost:55036/apps/SlingTestingHttpTestBase1/node1.txt > (content=<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> > ...elided... > ) expected:<200> but was:<500> > > testInternalRedirect(org.apache.sling.launchpad.webapp.integrationtest.VanityPathTest): > expected:<200> but was:<404> > > test302Redirect(org.apache.sling.launchpad.webapp.integrationtest.VanityPathTest): > expected:<302> but was:<404> > > test301Redirect(org.apache.sling.launchpad.webapp.integrationtest.VanityPathTest): > expected:<301> but was:<404> > > testRedirectKeepingExtensionAndSelector(org.apache.sling.launchpad.webapp.integrationtest.VanityPathTest): > expected:<302> but was:<404> > > Tests run: 448, Failures: 5, Errors: 0, Skipped: 0 > > Felix - can you doublecheck? > > Justin > On Thu, Feb 2, 2012 at 9:42 AM, <[email protected]> wrote: >> Author: fmeschbe >> Date: Thu Feb 2 14:42:08 2012 >> New Revision: 1239649 >> >> URL: http://svn.apache.org/viewvc?rev=1239649&view=rev >> Log: >> SLING-2321 Refactored event handling such that vanity path removal can be >> tracked >> >> Modified: >> >> sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/MapEntries.java >> >> Modified: >> sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/MapEntries.java >> URL: >> http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/MapEntries.java?rev=1239649&r1=1239648&r2=1239649&view=diff >> ============================================================================== >> --- >> sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/MapEntries.java >> (original) >> +++ >> sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/MapEntries.java >> Thu Feb 2 14:42:08 2012 >> @@ -25,6 +25,7 @@ import java.util.Collection; >> import java.util.Collections; >> import java.util.Dictionary; >> import java.util.HashMap; >> +import java.util.HashSet; >> import java.util.Hashtable; >> import java.util.Iterator; >> import java.util.List; >> @@ -45,9 +46,11 @@ import org.apache.sling.api.resource.Val >> import org.apache.sling.jcr.resource.internal.JcrResourceResolver; >> import org.apache.sling.jcr.resource.internal.JcrResourceResolverFactoryImpl; >> import org.osgi.framework.BundleContext; >> +import org.osgi.framework.Constants; >> import org.osgi.framework.ServiceRegistration; >> import org.osgi.service.event.Event; >> import org.osgi.service.event.EventAdmin; >> +import org.osgi.service.event.EventConstants; >> import org.osgi.service.event.EventHandler; >> import org.osgi.util.tracker.ServiceTracker; >> import org.slf4j.Logger; >> @@ -70,12 +73,12 @@ public class MapEntries implements Event >> >> private final String mapRoot; >> >> - private final String mapRootPrefix; >> - >> private List<MapEntry> resolveMaps; >> >> private Collection<MapEntry> mapMaps; >> >> + private Collection<String> vanityTargets; >> + >> private boolean initializing = false; >> >> private final ServiceRegistration registration; >> @@ -83,13 +86,13 @@ public class MapEntries implements Event >> private final ServiceTracker eventAdminTracker; >> >> private MapEntries() { >> - factory = null; >> - resolver = null; >> - mapRoot = DEFAULT_MAP_ROOT; >> - mapRootPrefix = mapRoot + "/"; >> - >> - resolveMaps = Collections.<MapEntry> emptyList(); >> - mapMaps = Collections.<MapEntry> emptyList(); >> + this.factory = null; >> + this.resolver = null; >> + this.mapRoot = DEFAULT_MAP_ROOT; >> + >> + this.resolveMaps = Collections.<MapEntry> emptyList(); >> + this.mapMaps = Collections.<MapEntry> emptyList(); >> + this.vanityTargets = Collections.<String> emptySet(); >> this.registration = null; >> this.eventAdminTracker = null; >> } >> @@ -101,14 +104,35 @@ public class MapEntries implements Event >> this.resolver = factory.getAdministrativeResourceResolver(null); >> this.factory = factory; >> this.mapRoot = factory.getMapRoot(); >> - this.mapRootPrefix = this.mapRoot + "/"; >> this.eventAdminTracker = eventAdminTracker; >> >> init(); >> + >> + // build a filter which matches if any of the nodeProps (JCR >> + // properties modified) is listed in any of the eventProps (event >> + // properties listing modified JCR properties) >> + // this allows to only get events interesting for updating the >> + // internal structure >> + final String[] nodeProps = { "sling:vanityPath", >> "sling:vanityOrder", "sling:redirect" }; >> + final String[] eventProps = { "resourceAddedAttributes", >> "resourceChangedAttributes", >> + "resourceRemovedAttributes" }; >> + StringBuilder filter = new StringBuilder(); >> + filter.append("(|"); >> + for (String eventProp : eventProps) { >> + filter.append("(|"); >> + for (String nodeProp : nodeProps) { >> + >> filter.append('(').append(eventProp).append('=').append(nodeProp).append(')'); >> + } >> + filter.append(")"); >> + } >> + filter.append("(" + EventConstants.EVENT_TOPIC + "=" + >> SlingConstants.TOPIC_RESOURCE_REMOVED + ")"); >> + filter.append(")"); >> + >> final Dictionary<String, String> props = new Hashtable<String, >> String>(); >> - props.put("event.topics","org/apache/sling/api/resource/*"); >> - props.put("service.description","Map Entries Observation"); >> - props.put("service.vendor","The Apache Software Foundation"); >> + props.put(EventConstants.EVENT_TOPIC, >> "org/apache/sling/api/resource/*"); >> + props.put(EventConstants.EVENT_FILTER, filter.toString()); >> + props.put(Constants.SERVICE_DESCRIPTION, "Map Entries Observation"); >> + props.put(Constants.SERVICE_VENDOR, "The Apache Software >> Foundation"); >> this.registration = >> bundleContext.registerService(EventHandler.class.getName(), this, props); >> } >> >> @@ -132,7 +156,7 @@ public class MapEntries implements Event >> loadResolverMap(resolver, newResolveMaps, newMapMaps); >> >> // load the configuration into the resolver map >> - loadVanityPaths(resolver, newResolveMaps); >> + Collection<String> vanityTargets = loadVanityPaths(resolver, >> newResolveMaps); >> loadConfiguration(factory, newResolveMaps); >> >> // load the configuration into the mapper map >> @@ -141,8 +165,9 @@ public class MapEntries implements Event >> // sort List >> Collections.sort(newResolveMaps); >> >> - this.resolveMaps = newResolveMaps; >> - this.mapMaps = new TreeSet<MapEntry>(newMapMaps.values()); >> + this.vanityTargets = >> Collections.unmodifiableCollection(vanityTargets); >> + this.resolveMaps = Collections.unmodifiableList(newResolveMaps); >> + this.mapMaps = Collections.unmodifiableSet(new >> TreeSet<MapEntry>(newMapMaps.values())); >> >> sendChangeEvent(); >> >> @@ -197,20 +222,31 @@ public class MapEntries implements Event >> >> // ---------- EventListener interface >> >> + /** >> + * Handles the change to any of the node properties relevant for vanity >> URL >> + * mappings. The >> + * {@link #MapEntries(JcrResourceResolverFactoryImpl, BundleContext, >> ServiceTracker)} >> + * constructor makes sure the event listener is registered to only get >> + * appropriate events. >> + */ >> public void handleEvent(final Event event) { >> - boolean handleEvent = false; >> - final String path = (String) >> event.getProperty(SlingConstants.PROPERTY_PATH); >> - if ( this.resolver != null && path != null ) { >> - handleEvent = mapRoot.equals(path) || >> path.startsWith(mapRootPrefix); >> - if ( !handleEvent && >> !event.getTopic().equals(SlingConstants.TOPIC_RESOURCE_REMOVED) ) { >> - final Resource rsrc = this.resolver.getResource(path); >> - final ValueMap props = ResourceUtil.getValueMap(rsrc); >> - handleEvent = props.containsKey("sling:vanityPath") >> - || props.containsKey("sling:vanityOrder") >> - || props.containsKey("sling:redirect"); >> + // check whether a remove event has an influence on vanity paths >> + boolean doInit = true; >> + if (SlingConstants.TOPIC_RESOURCE_REMOVED.equals(event.getTopic())) >> { >> + doInit = false; >> + final Object p = >> event.getProperty(SlingConstants.PROPERTY_PATH); >> + if (p instanceof String) { >> + final String path = (String) p; >> + for (String target : this.vanityTargets) { >> + if (target.startsWith(path)) { >> + doInit = true; >> + break; >> + } >> + } >> } >> } >> - if (handleEvent) { >> + >> + if (doInit) { >> final Thread t = new Thread() { >> public void run() { >> init(); >> @@ -295,10 +331,11 @@ public class MapEntries implements Event >> } >> } >> >> - private void loadVanityPaths(final ResourceResolver resolver, >> + private Collection<String> loadVanityPaths(final ResourceResolver >> resolver, >> List<MapEntry> entries) { >> // sling:VanityPath (uppercase V) is the mixin name >> // sling:vanityPath (lowercase) is the property name >> + final HashSet<String> targetPaths = new HashSet<String>(); >> final String queryString = "SELECT sling:vanityPath, sling:redirect, >> sling:redirectStatus FROM sling:VanityPath WHERE sling:vanityPath IS NOT >> NULL ORDER BY sling:vanityOrder DESC"; >> final Iterator<Resource> i = resolver.findResources( >> queryString, "sql"); >> @@ -335,9 +372,13 @@ public class MapEntries implements Event >> // 2. entry with match supporting selectors and extension >> entries.add(new MapEntry(url + "(\\..*)", status, false, >> redirect + "$1")); >> + >> + // 3. keep the path to return >> + targetPaths.add(redirect); >> } >> } >> } >> + return targetPaths; >> } >> >> private String getVanityPath(final String pVanityPath) { >> >>
