/*
*
* * Copyright 2014 Orient Technologies LTD (info(at)orientechnologies.com)
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * http://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
* *
* * For more information: http://www.orientechnologies.com
*
*/
package com.orientechnologies.orient.server.network.protocol.http;
import com.orientechnologies.common.collection.OMultiValue;
import com.orientechnologies.orient.core.db.ODatabaseRecordThreadLocal;
import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx;
import com.orientechnologies.orient.core.db.record.OIdentifiable;
import com.orientechnologies.orient.core.metadata.schema.OClass;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.orientechnologies.orient.core.serialization.serializer.OJSONWriter;
import com.tinkerpop.blueprints.Direction;
import com.tinkerpop.blueprints.Edge;
import com.tinkerpop.blueprints.impls.orient.OrientEdge;
import com.tinkerpop.blueprints.impls.orient.OrientGraphFactory;
import com.tinkerpop.blueprints.impls.orient.OrientGraphNoTx;
import com.tinkerpop.blueprints.impls.orient.OrientVertex;
import java.io.IOException;
import java.io.StringWriter;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* Graph wrapper to format the response as graph.
*
* @author Luca Garulli
*/
public class OHttpGraphResponse extends OHttpResponse {
public OHttpGraphResponse(final OHttpResponse iWrapped) {
super(iWrapped.getOutputStream(), iWrapped.httpVersion, iWrapped.additionalHeaders, iWrapped.characterSet, iWrapped.serverInfo,
iWrapped.sessionId, iWrapped.callbackFunction, iWrapped.keepAlive, iWrapped.connection);
}
public void writeRecords(final Object iRecords, final String iFetchPlan, String iFormat, final String accept,
final Map<String, Object> iAdditionalProperties, final String mode) throws IOException {
if (iRecords == null){
send(OHttpUtils.STATUS_OK_NOCONTENT_CODE, "", OHttpUtils.CONTENT_TEXT_PLAIN, null, null);
return;
}
if (!mode.equalsIgnoreCase("graph")) {
super.writeRecords(iRecords, iFetchPlan, iFormat, accept, iAdditionalProperties, mode);
return;
}
if (accept != null && accept.contains("text/csv"))
throw new IllegalArgumentException("Graph mode cannot accept '" + accept + "'");
final OrientGraphNoTx graph = (OrientGraphNoTx) OrientGraphFactory.getNoTxGraphImplFactory()
.getGraph((ODatabaseDocumentTx) ODatabaseRecordThreadLocal.INSTANCE.get());
try {
// DIVIDE VERTICES FROM EDGES
final Set<OrientVertex> vertices = new HashSet<OrientVertex>();
final Set<OrientEdge> edges = new HashSet<OrientEdge>();
final Iterator<Object> iIterator = OMultiValue.getMultiValueIterator(iRecords);
while (iIterator.hasNext()) {
Object entry = iIterator.next();
if (entry == null || !(entry instanceof OIdentifiable))
// IGNORE IT
continue;
entry = ((OIdentifiable) entry).getRecord();
if (entry == null || !(entry instanceof OIdentifiable))
// IGNORE IT
continue;
if (entry instanceof ODocument) {
OClass schemaClass = ((ODocument) entry).getSchemaClass();
if (schemaClass != null && schemaClass.isVertexType())
vertices.add(graph.getVertex(entry));
else if (schemaClass != null && schemaClass.isEdgeType()) {
OrientEdge edge = graph.getEdge(entry);
vertices.add(graph.getVertex(edge.getVertex(Direction.IN)));
vertices.add(graph.getVertex(edge.getVertex(Direction.OUT)));
edges.add(edge);
} else
// IGNORE IT
continue;
}
}
final StringWriter buffer = new StringWriter();
final OJSONWriter json = new OJSONWriter(buffer, "");
json.beginObject();
json.beginObject("graph");
// WRITE VERTICES
json.beginCollection("vertices");
for (OrientVertex vertex : vertices) {
json.beginObject();
json.writeAttribute("@rid", vertex.getIdentity());
json.writeAttribute("@class", vertex.getRecord().getClassName());
// ADD ALL THE VERTEX'S EDGES
for (Edge e : vertex.getEdges(Direction.BOTH))
edges.add((OrientEdge) e);
// ADD ALL THE PROPERTIES
for (String field : vertex.getPropertyKeys()) {
final Object v = vertex.getProperty(field);
if (v != null)
json.writeAttribute(field, v);
}
json.endObject();
}
json.endCollection();
// WRITE EDGES
json.beginCollection("edges");
for (OrientEdge edge : edges) {
if (!vertices.contains(edge.getVertex(Direction.OUT)) || !vertices.contains(edge.getVertex(Direction.IN)))
// ONE OF THE 2 VERTICES ARE NOT PART OF THE RESULT SET: DISCARD IT
continue;
json.beginObject();
json.writeAttribute("@rid", edge.getIdentity());
json.writeAttribute("@class", edge.getRecord().getClassName());
json.writeAttribute("out", edge.getVertex(Direction.OUT).getId());
json.writeAttribute("in", edge.getVertex(Direction.IN).getId());
for (String field : edge.getPropertyKeys()) {
final Object v = edge.getProperty(field);
if (v != null)
json.writeAttribute(field, v);
}
json.endObject();
}
json.endCollection();
if (iAdditionalProperties != null) {
for (Map.Entry<String, Object> entry : iAdditionalProperties.entrySet()) {
final Object v = entry.getValue();
if (OMultiValue.isMultiValue(v)) {
json.beginCollection(-1, true, entry.getKey());
formatMultiValue(OMultiValue.getMultiValueIterator(v), buffer, null);
json.endCollection(-1, true);
} else
json.writeAttribute(entry.getKey(), v);
if (Thread.currentThread().isInterrupted())
break;
}
}
json.endObject();
json.endObject();
send(OHttpUtils.STATUS_OK_CODE, "OK", OHttpUtils.CONTENT_JSON, buffer.toString(), null);
} finally {
graph.shutdown();
}
}
}