package com.forgerock.elasticsearch.changes; import java.io.IOException; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.logging.log4j.Logger; import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.index.engine.Engine; import org.elasticsearch.index.shard.IndexingOperationListener; import org.elasticsearch.index.shard.ShardId; import org.joda.time.DateTime; /** * Date: 04/05/2017 * Time: 16:54 */ public class WebSocketIndexListener implements IndexingOperationListener { private final Logger log = Loggers.getLogger(WebSocketIndexListener.class); private final Set<Source> sources; private final List<String> filter; private final WebSocketRegister register; WebSocketIndexListener(Set<Source> sources, List<String> filter, WebSocketRegister register) { this.sources = sources; this.filter = filter; this.register = register; } @Override public void postIndex(ShardId shardId, Engine.Index index, Engine.IndexResult result) { ChangeEvent change=new ChangeEvent( shardId.getIndex().getName(), index.type(), index.id(), new DateTime(), result.isCreated() ? ChangeEvent.Operation.CREATE : ChangeEvent.Operation.INDEX, result.getVersion(), index.source() ); addChange(change); } @Override public void postDelete(ShardId shardId, Engine.Delete delete, Engine.DeleteResult result) { ChangeEvent change=new ChangeEvent( shardId.getIndex().getName(), delete.type(), delete.id(), new DateTime(), ChangeEvent.Operation.DELETE, result.getVersion(), null ); addChange(change); } private static boolean filter(String index, String type, String id, Source source) { if (source.getIndices() != null && !source.getIndices().contains(index) ) { boolean result = false; for (String s : source.getIndices() ) { if ( s != null && s.length() > 0 && s.endsWith("*") && index.startsWith(s.substring(0, s.length()-1))) { result = true; break; } } if (result == false ) { return false; } } if (source.getTypes() != null && !source.getTypes().contains(type)) { return false; } if (source.getIds() != null && !source.getIds().contains(id)) { return false; } return true; } static boolean filter(ChangeEvent change, Set<Source> sources) { for (Source source : sources) { if (filter(change.getIndex(), change.getType(), change.getId(), source)) { return true; } } return false; } private void addChange(ChangeEvent change) { if (!filter(change, sources)) { return; } String message; Set<String> filters = new HashSet<>(filter); try { XContentBuilder builder = new XContentBuilder(JsonXContent.jsonXContent, new BytesStreamOutput(), filters); builder.startObject() .field("_index", change.getIndex()) .field("_type", change.getType()) .field("_id", change.getId()) .field("_timestamp", change.getTimestamp()) .field("_version", change.getVersion()) .field("_operation", change.getOperation().toString()); if (change.getSource() != null) { builder.rawField("_source", change.getSource().streamInput(), XContentType.JSON); } builder.endObject(); message = Strings.toString(builder); } catch (IOException e) { log.error("Failed to write JSON", e); return; } for (WebSocketEndpoint listener : register.getListeners()) { try { listener.sendMessage(message); } catch (Exception e) { log.error("Failed to send message", e); } } } }