public List<Stream> match(Message message) {
        final Set<Stream> result = Sets.newHashSet();
        final Set<String> blackList = Sets.newHashSet();

        for (final Rule rule : rulesList) {
            if (blackList.contains(rule.getStreamId())) {
                continue;
            }

            final StreamRule streamRule = rule.getStreamRule();
            final StreamRuleType streamRuleType = streamRule.getType();
            final Stream.MatchingType matchingType = rule.getMatchingType();
            if (!ruleTypesNotNeedingFieldPresence.contains(streamRuleType)
                    && !message.hasField(streamRule.getField())) {
                if (matchingType == Stream.MatchingType.AND) {
                    result.remove(rule.getStream());
                    // blacklist stream because it can't match anymore
                    blackList.add(rule.getStreamId());
                }

                continue;
            }

            final Stream stream;
            if (streamRuleType != StreamRuleType.REGEX) {
                stream = rule.match(message);
            } else {
                stream = rule.matchWithTimeOut(message, streamProcessingTimeout, TimeUnit.MILLISECONDS);
            }

            if (stream == null) {
                if (matchingType == Stream.MatchingType.AND) {
                    result.remove(rule.getStream());
                    // blacklist stream because it can't match anymore
                    blackList.add(rule.getStreamId());
                }
            } else {
                result.add(stream);
                if (matchingType == Stream.MatchingType.OR) {
                    // blacklist stream because it is already matched
                    blackList.add(rule.getStreamId());
                }
            }
        }

        final Stream defaultStream = defaultStreamProvider.get();
        boolean alreadyRemovedDefaultStream = false;
        for (Stream stream : result) {
            if (stream.getRemoveMatchesFromDefaultStream()) {
                if (alreadyRemovedDefaultStream || message.removeStream(defaultStream)) {
                    alreadyRemovedDefaultStream = true;
                    if (LOG.isTraceEnabled()) {
                        LOG.trace("Successfully removed default stream <{}> from message <{}>", defaultStream.getId(), message.getId());
                    }
                } else {
                    // A previously executed message processor (or Illuminate) has likely already removed the
                    // default stream from the message. Now, the message has matched a stream in the Graylog
                    // MessageFilterChain, and the matching stream is also set to remove the default stream.
                    // This is usually from user-defined stream rules, and is generally not a problem.
                    cannotRemoveDefaultMeter.inc();
                    if (LOG.isTraceEnabled()) {
                        LOG.trace("Couldn't remove default stream <{}> from message <{}>", defaultStream.getId(), message.getId());
                    }
                }
            }
        }

        return ImmutableList.copyOf(result);
    }
@Test
    public void testOrMatchingShouldNotMatch() {
        final String dummyField = "dummyField";
        final String dummyValue = "dummyValue";

        final Stream stream = mock(Stream.class);
        when(stream.getMatchingType()).thenReturn(Stream.MatchingType.OR);
        final StreamRule streamRule1 = getStreamRuleMock("StreamRule1Id", StreamRuleType.EXACT, dummyField, "not" + dummyValue);
        final StreamRule streamRule2 = getStreamRuleMock("StreamRule2Id", StreamRuleType.EXACT, dummyField, "alsoNot" + dummyValue);

        when(stream.getStreamRules()).thenReturn(Lists.newArrayList(streamRule1, streamRule2));

        final Message message = mock(Message.class);
        when(message.getField(eq(dummyField))).thenReturn(dummyValue);

        final StreamRouterEngine engine = newEngine(Lists.newArrayList(stream));

        final List<Stream> result = engine.match(message);

        assertThat(result).isEmpty();
    }