use of org.apache.jackrabbit.oak.plugins.observation.filter.ChangeSetFilterImpl in project jackrabbit-oak by apache.
the class ObservationTest method doTestAggregate6.
private void doTestAggregate6(OakEventFilter oef, String[] expectedSubTrees, String[] expectedPrefilterPaths) throws Exception {
assumeTrue(observationManager instanceof ObservationManagerImpl);
ObservationManagerImpl oManager = (ObservationManagerImpl) observationManager;
ExpectationListener listener = new ExpectationListener();
oManager.addEventListener(listener, oef);
ChangeProcessor cp = oManager.getChangeProcessor(listener);
assertNotNull(cp);
FilterProvider filterProvider = cp.getFilterProvider();
assertNotNull(filterProvider);
assertMatches(filterProvider.getSubTrees(), expectedSubTrees);
ChangeSetFilterImpl changeSetFilter = (ChangeSetFilterImpl) PrivateAccessor.getField(filterProvider, "changeSetFilter");
assertNotNull(changeSetFilter);
assertMatches(changeSetFilter.getRootIncludePaths(), expectedPrefilterPaths);
Node parent = getAdminSession().getRootNode().addNode("parent", "nt:unstructured");
Node bar = parent.addNode("bar", "nt:unstructured");
Node zetDotJsp = bar.addNode("zet.jsp", "nt:unstructured");
listener.expect(zetDotJsp.getPath() + "/jcr:primaryType", PROPERTY_ADDED);
Node c = bar.addNode("c", "nt:unstructured");
Node fooDotJsp = c.addNode("foo.jsp", "oak:Unstructured");
listener.expect(fooDotJsp.getPath() + "/jcr:primaryType", PROPERTY_ADDED);
Node jcrContent = fooDotJsp.addNode("jcr:content", "nt:unstructured");
jcrContent.setProperty("jcr:data", "foo");
listener.expectAdd(jcrContent);
listener.expect(jcrContent.getPath() + "/jcr:data", "/parent/bar/c/foo.jsp", PROPERTY_ADDED);
parent.getSession().save();
Thread.sleep(1000);
List<Expectation> missing = listener.getMissing(TIME_OUT, TimeUnit.SECONDS);
List<Event> unexpected = listener.getUnexpected();
assertTrue("Unexpected events: " + unexpected, unexpected.isEmpty());
assertTrue("Missing events: " + missing, missing.isEmpty());
// OAK-5096 : this is what OAK-5096 is all about: when you change
// the property jcr:content/jcr:data it should be reported with
// identifier of the aggregate - even though it is not in the original glob path
jcrContent.setProperty("jcr:data", "bar");
listener.expect(jcrContent.getPath() + "/jcr:data", "/parent/bar/c/foo.jsp", PROPERTY_CHANGED);
parent.getSession().save();
Thread.sleep(1000);
missing = listener.getMissing(TIME_OUT, TimeUnit.SECONDS);
unexpected = listener.getUnexpected();
assertTrue("Unexpected events: " + unexpected, unexpected.isEmpty());
assertTrue("Missing events: " + missing, missing.isEmpty());
// cleanup
Session session = getAdminSession();
session.getRootNode().getNode("parent").remove();
session.save();
oManager.removeEventListener(listener);
}
use of org.apache.jackrabbit.oak.plugins.observation.filter.ChangeSetFilterImpl in project jackrabbit-oak by apache.
the class ObservationManagerImpl method addEventListener.
@Override
public void addEventListener(EventListener listener, JackrabbitEventFilter filter) throws RepositoryException {
OakEventFilterImpl oakEventFilter = null;
if (filter instanceof OakEventFilterImpl) {
oakEventFilter = (OakEventFilterImpl) filter;
}
int eventTypes = filter.getEventTypes();
boolean isDeep = filter.getIsDeep();
String[] uuids = filter.getIdentifiers();
String[] nodeTypeName = filter.getNodeTypes();
boolean noLocal = filter.getNoLocal();
boolean noExternal = filter.getNoExternal() || listener instanceof ExcludeExternal;
boolean noInternal = filter.getNoInternal();
Set<String> includePaths = getOakPaths(namePathMapper, filter.getAdditionalPaths());
String absPath = filter.getAbsPath();
if (absPath != null) {
includePaths.add(namePathMapper.getOakPath(absPath));
}
Set<String> excludedPaths = getOakPaths(namePathMapper, filter.getExcludedPaths());
PathUtils.unifyInExcludes(includePaths, excludedPaths);
if (oakEventFilter != null) {
String[] includeGlobPaths = oakEventFilter.getIncludeGlobPaths();
if (includeGlobPaths != null) {
includePaths.addAll(Arrays.asList(includeGlobPaths));
}
}
if (includePaths.isEmpty()) {
LOG.warn("The passed filter excludes all events. No event listener registered");
return;
}
FilterBuilder filterBuilder = new FilterBuilder();
String depthPattern = isDeep ? STAR + '/' + STAR_STAR : STAR;
List<Condition> includeConditions = newArrayList();
filterBuilder.addPathsForMBean(includePaths);
for (String path : includePaths) {
final String deepenedPath;
if (path.endsWith(STAR)) {
// that's the case for a glob ending with * already, so
// no need to add another * or **
deepenedPath = path;
} else if (path.contains(STAR)) {
// for any other glob path that doesn't end with *
// we only add a single *, not a **
deepenedPath = concat(path, STAR);
} else {
// for any non-glob path we do it the traditional way
deepenedPath = concat(path, depthPattern);
}
includeConditions.add(filterBuilder.path(deepenedPath));
if (oakEventFilter != null && oakEventFilter.getIncludeAncestorsRemove()) {
// the subtree here as a result.
continue;
}
// only register the part leading to the first STAR:
filterBuilder.addSubTree(pathWithoutGlob(path));
}
List<Condition> excludeConditions = createExclusions(filterBuilder, excludedPaths);
final String[] validatedNodeTypeNames = validateNodeTypeNames(nodeTypeName);
Selector nodeTypeSelector = Selectors.PARENT;
boolean deleteSubtree = true;
if (oakEventFilter != null) {
Condition additionalIncludes = oakEventFilter.getAdditionalIncludeConditions(includePaths);
if (additionalIncludes != null) {
includeConditions.add(additionalIncludes);
}
filterBuilder.aggregator(oakEventFilter.getAggregator());
if (oakEventFilter.getApplyNodeTypeOnSelf()) {
nodeTypeSelector = Selectors.THIS;
}
if (oakEventFilter.getIncludeSubtreeOnRemove()) {
deleteSubtree = false;
}
}
if (deleteSubtree) {
excludeConditions.add(filterBuilder.deleteSubtree());
}
Condition condition = filterBuilder.all(filterBuilder.all(excludeConditions), filterBuilder.any(includeConditions), // filterBuilder.deleteSubtree(), // moved depending on deleteSubtree on excludeConditions
filterBuilder.moveSubtree(), filterBuilder.eventType(eventTypes), filterBuilder.uuid(Selectors.PARENT, uuids), filterBuilder.nodeType(nodeTypeSelector, validatedNodeTypeNames), filterBuilder.accessControl(permissionProviderFactory));
if (oakEventFilter != null) {
condition = oakEventFilter.wrapMainCondition(condition, filterBuilder, permissionProviderFactory);
}
filterBuilder.includeSessionLocal(!noLocal).includeClusterExternal(!noExternal).includeClusterLocal(!noInternal).condition(condition);
// FIXME support multiple path in ListenerTracker
ListenerTracker tracker = new WarningListenerTracker(!noExternal, listener, eventTypes, absPath, isDeep, uuids, nodeTypeName, noLocal);
Set<String> additionalIncludePaths = null;
if (oakEventFilter != null) {
additionalIncludePaths = oakEventFilter.calcPrefilterIncludePaths(includePaths);
}
// OAK-5082 : node type filtering should not only be direct but include derived types
// one easy way to solve this is to 'explode' the node types at start by including
// all subtypes of every registered node type
HashSet<String> explodedNodeTypes = null;
if (validatedNodeTypeNames != null) {
explodedNodeTypes = newHashSet();
for (String nt : validatedNodeTypeNames) {
explodeSubtypes(nt, explodedNodeTypes);
}
}
// OAK-4908 : prefiltering support. here we have explicit yes/no/maybe filtering
// for things like propertyNames/nodeTypes/nodeNames/paths which cannot be
// applied on the full-fledged filterBuilder above but requires an explicit 'prefilter' for that.
filterBuilder.setChangeSetFilter(new ChangeSetFilterImpl(includePaths, isDeep, additionalIncludePaths, excludedPaths, null, explodedNodeTypes, null));
addEventListener(listener, tracker, filterBuilder.build());
}
Aggregations