All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.randombits.confluence.metadata.indexing.graph.DefaultIndexManager Maven / Gradle / Ivy
package org.randombits.confluence.metadata.indexing.graph;
import com.atlassian.confluence.event.events.cluster.ClusterEventWrapper;
import com.atlassian.event.Event;
import com.atlassian.event.api.EventListener;
import com.atlassian.event.api.EventPublisher;
import com.tinkerpop.blueprints.Direction;
import com.tinkerpop.blueprints.Vertex;
import com.tinkerpop.blueprints.VertexQuery;
import com.tinkerpop.blueprints.impls.orient.OrientGraph;
import com.tinkerpop.blueprints.impls.orient.OrientVertex;
import org.apache.commons.lang3.StringUtils;
import org.randombits.confluence.metadata.event.MetadataUpdatedEvent;
import org.randombits.confluence.metadata.FieldNotFoundException;
import org.randombits.confluence.metadata.indexing.IndexManager;
import org.randombits.confluence.metadata.indexing.graph.vertex.Collection;
import org.randombits.confluence.metadata.indexing.graph.vertex.Content;
import org.randombits.confluence.metadata.indexing.graph.vertex.KeyValueField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
/**
* Default implementation of {@link org.randombits.confluence.metadata.indexing.IndexManager}.
*
* @author kaifung
* @since 7.0.0.20150209
*/
@Component
public class DefaultIndexManager implements IndexManager, DisposableBean {
private static final Logger log = LoggerFactory.getLogger(IndexManager.class);
private static final String ORIENTDB_CLASS_PREFIX = "class:";
private final EventPublisher eventPublisher;
private IndexDatabase indexDatabase;
public DefaultIndexManager(EventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
this.eventPublisher.register(this);
}
@Override
public T query(final String contentId, final String fieldName, Class extends T> clazz) throws IllegalArgumentException, FieldNotFoundException {
return query(contentId, null, fieldName, clazz);
}
@Override
public T query(final String contentId, final List path, final String fieldName, Class extends T> clazz) throws IllegalArgumentException, FieldNotFoundException {
if (!String.class.equals(clazz)) {
throw new IllegalArgumentException("Unable to query index with invalid type : " + clazz);
}
if (StringUtils.isEmpty(contentId) || StringUtils.isEmpty(fieldName)) {
throw new IllegalArgumentException("Content ID and field name must not be empty.");
}
T result = indexDatabase.executeTransaction(new IndexDatabase.Transaction() { @Override public T execute(OrientGraph graph) {
T result = null;
for (Vertex content : graph.getVertices(Content.CONTENT_ID.getPrefixedPropertyKey(), contentId)) {
result = findVertex(content, fieldName, path);
}
return result;
}});
if (result == null) {
throw new FieldNotFoundException("Unable to find field with name: " + fieldName);
}
return result;
}
@Override
public void buildIndex(final String contentId, final Map metadata) {
indexDatabase.executeTransaction(new IndexDatabase.Transaction() {
@Override
public Void execute(OrientGraph graph) {
if (graph.countVertices() != 0) {
for (Vertex contentVertex : graph.getVertices(Content.CONTENT_ID.getPrefixedPropertyKey(), contentId)) {
removeVertex(graph, contentVertex);
}
}
Vertex content = graph.addVertex(ORIENTDB_CLASS_PREFIX + Content.CLASS_NAME, Content.CONTENT_ID.toCanonicalValue(), contentId);
indexFields(content, metadata, graph);
return null;
}
});
}
@Override
public void destroy() throws Exception {
eventPublisher.unregister(this);
}
/**
* Listen to {@link org.randombits.confluence.metadata.event.MetadataUpdatedEvent}.
*
* @param metadataUpdatedEvent
*/
@EventListener
public void onEvent(MetadataUpdatedEvent metadataUpdatedEvent) {
if (metadataUpdatedEvent.shouldBuildIndex()) {
buildIndex(
metadataUpdatedEvent.getMetadataStorage().getContent().getIdAsString(),
metadataUpdatedEvent.getMetadataStorage().getBaseMap()
);
}
}
/**
* Listen to events from other nodes in clustered environment.
*
* @param clusterEventWrapper
*/
@EventListener
public void onEvent(ClusterEventWrapper clusterEventWrapper) {
Event event = clusterEventWrapper.getEvent();
if (event instanceof MetadataUpdatedEvent) {
onEvent((MetadataUpdatedEvent) event);
}
}
private static boolean isVertexClass(Vertex vertex, String className) {
if (vertex instanceof OrientVertex) {
return ((OrientVertex) vertex).getLabel().equals(className);
}
return false;
}
private T findVertex(Vertex sourceVertex, String fieldName, List path) {
for (Vertex destinationVertex : sourceVertex.query().direction(Direction.OUT).labels(Content.EDGE_CONTAINS).vertices()) {
if (path == null || path.isEmpty()) {
// Stop traversing to next level.
if (isVertexClass(destinationVertex, KeyValueField.CLASS_NAME)
&& fieldName.equals(destinationVertex.getProperty(KeyValueField.NAME.toCanonicalValue()))) {
return destinationVertex.getProperty(KeyValueField.VALUE.toCanonicalValue());
}
} else {
// Traverse to next level.
if (isVertexClass(destinationVertex, Collection.CLASS_NAME)
&& path.get(0).equals(destinationVertex.getProperty(Collection.NAME.toCanonicalValue()))) {
path.remove(0);
return findVertex(destinationVertex, fieldName, path);
}
}
}
return null;
}
private void removeVertex(OrientGraph graph, Vertex vertex) {
VertexQuery vertexQuery = vertex.query().direction(Direction.OUT).labels(Content.EDGE_CONTAINS);
if (vertexQuery.count() != 0) {
for (Vertex outerVertex : vertexQuery.vertices()) {
removeVertex(graph, outerVertex);
}
}
graph.removeVertex(vertex);
}
private void indexFields(Vertex sourceVertex, Map metadata, OrientGraph graph) {
for (Map.Entry entry : metadata.entrySet()) {
if (entry.getValue() instanceof Map) {
// Add Collection vertex.
Vertex destinationVertex = graph.addVertex(ORIENTDB_CLASS_PREFIX + Collection.CLASS_NAME,
Collection.NAME.toCanonicalValue(), entry.getKey()
);
graph.addEdge(null, sourceVertex, destinationVertex, Content.EDGE_CONTAINS);
indexFields(destinationVertex, (Map) entry.getValue(), graph);
} else {
// Add KeyValueField vertex.
Vertex destinationVertex = graph.addVertex(ORIENTDB_CLASS_PREFIX + KeyValueField.CLASS_NAME,
KeyValueField.NAME.toCanonicalValue(), entry.getKey(),
KeyValueField.VALUE.toCanonicalValue(), entry.getValue()
);
graph.addEdge(null, sourceVertex, destinationVertex, Content.EDGE_CONTAINS);
}
}
}
@Autowired
public void setIndexDatabase(IndexDatabase indexDatabase) {
this.indexDatabase = indexDatabase;
}
}