Skip to content

Commit

Permalink
Change decorators interface to operate on SearchResponse instead of R…
Browse files Browse the repository at this point in the history
…esultMessage (#2482)

* Adding builder to SearchResponse DTO.
* Changing decorators to work on SearchResponse.
* Refresh search results when decorator config changes.
* Improving refresh on decorator changes, preventing refresh on load.
* Remove all traces of MessageDecorator.
* Providing abstract class for plugins to implement simple decorators.
* Adding license header.
  • Loading branch information
dennisoelkers authored and kroepke committed Jul 20, 2016
1 parent 9802a85 commit 975cd7a
Show file tree
Hide file tree
Showing 16 changed files with 130 additions and 137 deletions.
Expand Up @@ -62,7 +62,7 @@
import org.graylog2.plugin.BaseConfiguration;
import org.graylog2.plugin.RulesEngine;
import org.graylog2.plugin.cluster.ClusterConfigService;
import org.graylog2.plugin.decorators.MessageDecorator;
import org.graylog2.plugin.decorators.SearchResponseDecorator;
import org.graylog2.plugin.inject.Graylog2Module;
import org.graylog2.rest.NotFoundExceptionMapper;
import org.graylog2.rest.ScrollChunkWriter;
Expand Down Expand Up @@ -115,7 +115,7 @@ protected void configure() {
bindAdditionalJerseyComponents();
bindEventBusListeners();
install(new AuthenticatingRealmModule());
bindMessageDecorators();
bindSearchResponseDecorators();
}

private void bindProviders() {
Expand Down Expand Up @@ -208,8 +208,8 @@ private void bindEventBusListeners() {
bind(ClusterDebugEventListener.class).asEagerSingleton();
}

private void bindMessageDecorators() {
private void bindSearchResponseDecorators() {
// only triggering an initialize to make sure that the binding exists
final MapBinder<String, MessageDecorator.Factory> messageDecoratorBinder = messageDecoratorBinder();
final MapBinder<String, SearchResponseDecorator.Factory> searchResponseDecoratorBinder = searchResponseDecoratorBinder();
}
}
Expand Up @@ -17,15 +17,12 @@
package org.graylog2.decorators;

import com.google.inject.multibindings.Multibinder;
import org.graylog2.plugin.decorators.MessageDecorator;
import org.graylog2.plugin.decorators.SearchResponseDecorator;
import org.graylog2.plugin.inject.Graylog2Module;

public class DecoratorBindings extends Graylog2Module {
@Override
protected void configure() {
Multibinder<MessageDecorator> messageDecoratorMultibinder = Multibinder.newSetBinder(binder(), MessageDecorator.class);

Multibinder<SearchResponseDecorator> searchResponseDecoratorMultibinder = Multibinder.newSetBinder(binder(), SearchResponseDecorator.class);
}
}
Expand Up @@ -17,14 +17,11 @@
package org.graylog2.decorators;

import com.google.inject.ImplementedBy;
import org.graylog2.indexer.results.ResultMessage;
import org.graylog2.rest.resources.search.responses.SearchResponse;

import java.util.List;
import java.util.Optional;

@ImplementedBy(DecoratorProcessorImpl.class)
public interface DecoratorProcessor {
List<ResultMessage> decorate(List<ResultMessage> messages, Optional<String> stream);
SearchResponse decorate(SearchResponse searchResponse, Optional<String> stream);
}
Expand Up @@ -16,8 +16,6 @@
*/
package org.graylog2.decorators;

import org.graylog2.indexer.results.ResultMessage;
import org.graylog2.plugin.decorators.MessageDecorator;
import org.graylog2.plugin.decorators.SearchResponseDecorator;
import org.graylog2.rest.resources.search.responses.SearchResponse;

Expand All @@ -33,18 +31,6 @@ public DecoratorProcessorImpl(DecoratorResolver decoratorResolver) {
this.decoratorResolver = decoratorResolver;
}

@Override
public List<ResultMessage> decorate(List<ResultMessage> messages, Optional<String> streamId) {
final List<MessageDecorator> messageDecorators = streamId.isPresent() ?
decoratorResolver.messageDecoratorsForStream(streamId.get()) : decoratorResolver.messageDecoratorsForGlobal();
final Optional<MessageDecorator> metaDecorator = messageDecorators.stream()
.reduce((f, g) -> (v) -> f.apply(g.apply(v)));
if (metaDecorator.isPresent()) {
return metaDecorator.get().apply(messages);
}
return messages;
}

@Override
public SearchResponse decorate(SearchResponse searchResponse, Optional<String> streamId) {
final List<SearchResponseDecorator> searchResponseDecorators = streamId.isPresent() ?
Expand Down
Expand Up @@ -17,64 +17,44 @@
package org.graylog2.decorators;

import com.google.inject.Singleton;
import org.graylog2.plugin.decorators.MessageDecorator;
import org.graylog2.plugin.decorators.SearchResponseDecorator;

import javax.annotation.Nullable;
import javax.inject.Inject;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

@Singleton
public class DecoratorResolver {
private final DecoratorService decoratorService;
private final Map<String, MessageDecorator.Factory> messageDecoratorMap;
private final Map<String, SearchResponseDecorator> searchResponseDecoratorsMap;
private final Map<String, SearchResponseDecorator.Factory> searchResponseDecoratorsMap;

@Inject
public DecoratorResolver(DecoratorService decoratorService,
Map<String, MessageDecorator.Factory> messageDecorators,
Set<SearchResponseDecorator> searchResponseDecorators) {
Map<String, SearchResponseDecorator.Factory> searchResponseDecorators) {
this.decoratorService = decoratorService;
this.messageDecoratorMap = messageDecorators;
this.searchResponseDecoratorsMap = searchResponseDecorators.stream().collect(Collectors.toMap((decorator) -> decorator.getClass().toString(), Function.identity()));
}

public List<MessageDecorator> messageDecoratorsForStream(String streamId) {
return this.decoratorService.findForStream(streamId).stream()
.map(this::instantiateMessageDecorator)
.filter(Objects::nonNull)
.collect(Collectors.toList());
}

public List<MessageDecorator> messageDecoratorsForGlobal() {
return this.decoratorService.findForGlobal().stream()
.map(this::instantiateMessageDecorator)
.filter(Objects::nonNull)
.collect(Collectors.toList());
this.searchResponseDecoratorsMap = searchResponseDecorators;
}

public List<SearchResponseDecorator> searchResponseDecoratorsForStream(String streamId) {
return this.decoratorService.findForStream(streamId).stream()
.map(decorator -> this.searchResponseDecoratorsMap.get(decorator.type()))
.map(this::instantiateSearchResponseDecorator)
.filter(Objects::nonNull)
.collect(Collectors.toList());
}

public List<SearchResponseDecorator> searchResponseDecoratorsForGlobal() {
return this.decoratorService.findForGlobal().stream()
.map(decorator -> this.searchResponseDecoratorsMap.get(decorator.type()))
.map(this::instantiateSearchResponseDecorator)
.filter(Objects::nonNull)
.collect(Collectors.toList());
}

@Nullable
private MessageDecorator instantiateMessageDecorator(Decorator decorator) {
final MessageDecorator.Factory factory = this.messageDecoratorMap.get(decorator.type());
private SearchResponseDecorator instantiateSearchResponseDecorator(Decorator decorator) {
final SearchResponseDecorator.Factory factory = this.searchResponseDecoratorsMap.get(decorator.type());
if (factory != null) {
return factory.create(decorator);
}
Expand Down
Expand Up @@ -21,7 +21,7 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.auto.value.AutoValue;
import org.graylog2.plugin.configuration.ConfigurationRequest;
import org.graylog2.plugin.decorators.MessageDecorator;
import org.graylog2.plugin.decorators.SearchResponseDecorator;

@AutoValue
@JsonAutoDetect
Expand Down Expand Up @@ -52,7 +52,7 @@ public static DecoratorTypeInfo create(@JsonProperty(FIELD_TYPE) String type,
return new AutoValue_DecoratorTypeInfo(type, name, humanName, requestedConfiguration, linkToDocs);
}

public static DecoratorTypeInfo create(String type, MessageDecorator.Descriptor descriptor, ConfigurationRequest requestedConfiguration) {
public static DecoratorTypeInfo create(String type, SearchResponseDecorator.Descriptor descriptor, ConfigurationRequest requestedConfiguration) {
return create(type, descriptor.getName(), descriptor.getHumanName(), requestedConfiguration, descriptor.getLinkToDocs());
}
}
@@ -0,0 +1,40 @@
/**
* This file is part of Graylog.
*
* Graylog is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Graylog is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Graylog. If not, see <http://www.gnu.org/licenses/>.
*/
package org.graylog2.plugin.decorators;

import org.graylog2.plugin.Message;
import org.graylog2.rest.models.messages.responses.ResultMessageSummary;
import org.graylog2.rest.resources.search.responses.SearchResponse;

import java.util.List;
import java.util.stream.Collectors;

public abstract class AbstractMessageDecorator implements SearchResponseDecorator {
abstract Message decorate(Message message);

@Override
public SearchResponse apply(SearchResponse searchResponse) {
final List<ResultMessageSummary> results = searchResponse.messages().stream()
.map(resultMessageSummary -> {
final Message decoratedMessage = decorate(new Message(resultMessageSummary.message()));
return ResultMessageSummary.create(resultMessageSummary.highlightRanges(), decoratedMessage.getFields(), resultMessageSummary.index());
})
.collect(Collectors.toList());

return searchResponse.toBuilder().messages(results).build();
}
}

This file was deleted.

Expand Up @@ -16,10 +16,39 @@
*/
package org.graylog2.plugin.decorators;

import org.graylog2.decorators.Decorator;
import org.graylog2.plugin.AbstractDescriptor;
import org.graylog2.plugin.configuration.ConfigurationRequest;
import org.graylog2.rest.resources.search.responses.SearchResponse;

import java.util.function.Function;

@FunctionalInterface
public interface SearchResponseDecorator extends Function<SearchResponse, SearchResponse> {
interface Factory {
SearchResponseDecorator create(Decorator decorator);
Config getConfig();
Descriptor getDescriptor();
}

interface Config {
ConfigurationRequest getRequestedConfiguration();
}

abstract class Descriptor extends AbstractDescriptor {
private final String humanName;

protected Descriptor() {
throw new IllegalStateException("This class should not be instantiated directly, this is a bug.");
}

public Descriptor(String name, boolean exclusive, String linkToDocs, String humanName) {
super(name, exclusive, linkToDocs);
this.humanName = humanName;
}

public String getHumanName() {
return humanName;
}
}
}
Expand Up @@ -26,7 +26,7 @@
import com.google.inject.name.Names;
import org.apache.shiro.realm.AuthenticatingRealm;
import org.graylog2.plugin.dashboards.widgets.WidgetStrategy;
import org.graylog2.plugin.decorators.MessageDecorator;
import org.graylog2.plugin.decorators.SearchResponseDecorator;
import org.graylog2.plugin.indexer.retention.RetentionStrategy;
import org.graylog2.plugin.indexer.rotation.RotationStrategy;
import org.graylog2.plugin.inputs.MessageInput;
Expand Down Expand Up @@ -309,20 +309,19 @@ protected MapBinder<String, PasswordAlgorithm> passwordAlgorithmBinder() {
return MapBinder.newMapBinder(binder(), String.class, PasswordAlgorithm.class);
}


protected MapBinder<String, AuthenticatingRealm> authenticationRealmBinder() {
return MapBinder.newMapBinder(binder(), String.class, AuthenticatingRealm.class);
}

protected MapBinder<String, MessageDecorator.Factory> messageDecoratorBinder() {
return MapBinder.newMapBinder(binder(), String.class, MessageDecorator.Factory.class);
protected MapBinder<String, SearchResponseDecorator.Factory> searchResponseDecoratorBinder() {
return MapBinder.newMapBinder(binder(), String.class, SearchResponseDecorator.Factory.class);
}

protected void installMessageDecorator(MapBinder<String, MessageDecorator.Factory> messageDecoratorBinder,
Class<? extends MessageDecorator> messageDecoratorClass,
Class<? extends MessageDecorator.Factory> messageDecoratorFactoryClass) {
install(new FactoryModuleBuilder().implement(MessageDecorator.class, messageDecoratorClass).build(messageDecoratorFactoryClass));
messageDecoratorBinder.addBinding(messageDecoratorClass.getCanonicalName()).to(messageDecoratorFactoryClass);
protected void installSearchResponseDecorator(MapBinder<String, SearchResponseDecorator.Factory> searchResponseDecoratorBinder,
Class<? extends SearchResponseDecorator> searchResponseDecoratorClass,
Class<? extends SearchResponseDecorator.Factory> searchResponseDecoratorFactoryClass) {
install(new FactoryModuleBuilder().implement(SearchResponseDecorator.class, searchResponseDecoratorClass).build(searchResponseDecoratorFactoryClass));
searchResponseDecoratorBinder.addBinding(searchResponseDecoratorClass.getCanonicalName()).to(searchResponseDecoratorFactoryClass);
}

private static class DynamicFeatureType extends TypeLiteral<Class<? extends DynamicFeature>> {}
Expand Down
Expand Up @@ -21,14 +21,12 @@
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.graylog2.database.NotFoundException;
import org.graylog2.decorators.Decorator;
import org.graylog2.decorators.DecoratorImpl;
import org.graylog2.decorators.DecoratorService;
import org.graylog2.decorators.DecoratorTypeInfo;
import org.graylog2.plugin.configuration.ConfigurationRequest;
import org.graylog2.plugin.decorators.MessageDecorator;
import org.graylog2.plugin.decorators.SearchResponseDecorator;
import org.graylog2.shared.rest.resources.RestResource;
import org.graylog2.shared.security.RestPermissions;

Expand All @@ -53,13 +51,13 @@
@Consumes(MediaType.APPLICATION_JSON)
public class DecoratorResource extends RestResource {
private final DecoratorService decoratorService;
private final Map<String, MessageDecorator.Factory> messageDecorators;
private final Map<String, SearchResponseDecorator.Factory> searchResponseDecorators;

@Inject
public DecoratorResource(DecoratorService decoratorService,
Map<String, MessageDecorator.Factory> messageDecorators) {
Map<String, SearchResponseDecorator.Factory> searchResponseDecorators) {
this.decoratorService = decoratorService;
this.messageDecorators = messageDecorators;
this.searchResponseDecorators = searchResponseDecorators;
}

@GET
Expand All @@ -77,7 +75,7 @@ public List<Decorator> get() {
@ApiOperation(value = "Returns all available message decorations",
notes = "")
public Map<String, DecoratorTypeInfo> getAvailable() {
return this.messageDecorators.entrySet().stream()
return this.searchResponseDecorators.entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getKey, entry -> DecoratorTypeInfo.create(
entry.getKey(),
Expand Down

0 comments on commit 975cd7a

Please sign in to comment.