package org.cytoscape.rest.internal.resource;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import javax.inject.Singleton;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.cytoscape.io.read.AbstractCyNetworkReader;
import org.cytoscape.io.read.CyNetworkReader;
import org.cytoscape.model.CyEdge;
import org.cytoscape.model.CyEdge.Type;
import org.cytoscape.model.CyIdentifiable;
import org.cytoscape.model.CyNetwork;
import org.cytoscape.model.CyNode;
import org.cytoscape.model.CyRow;
import org.cytoscape.model.CyTable;
import org.cytoscape.model.CyTableUtil;
import org.cytoscape.model.subnetwork.CyRootNetwork;
import org.cytoscape.model.subnetwork.CySubNetwork;
import org.cytoscape.rest.internal.datamapper.MapperUtil;
import org.cytoscape.rest.internal.task.HeadlessTaskMonitor;
import org.cytoscape.task.AbstractNetworkCollectionTask;
import org.cytoscape.task.select.SelectFirstNeighborsTaskFactory;
import org.cytoscape.view.model.CyNetworkView;
import org.cytoscape.view.presentation.property.BasicVisualLexicon;
import org.cytoscape.view.vizmap.VisualStyle;
import org.cytoscape.work.ObservableTask;
import org.cytoscape.work.Task;
import org.cytoscape.work.TaskIterator;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qmino.miredot.annotations.ReturnType;
@Singleton
@Path("/v1/networks")
public class NetworkResource extends AbstractResource {
@Context
protected SelectFirstNeighborsTaskFactory selectFirstNeighborsTaskFactory;
// Preset types
private static final String DEF_COLLECTION_PREFIX = "Created by cyREST: ";
public NetworkResource() {
super();
}
/**
*
* @summary Get number of networks in current session
*
* @return Number of networks in current Cytoscape session
*
*/
@GET
@Path("/count")
@Produces(MediaType.APPLICATION_JSON)
public Response getNetworkCount() {
final String result = getNumberObjectString(JsonTags.COUNT, networkManager.getNetworkSet().size());
return Response.ok(result).build();
}
/**
*
* @summary Get number of nodes in the network
*
* @param id
* Network SUID
* @return Number of nodes in the network with given SUID
*/
@GET
@Path("/{networkId}/nodes/count")
@Produces(MediaType.APPLICATION_JSON)
public Response getNodeCount(@PathParam("networkId") Long networkId) {
final String result = getNumberObjectString(JsonTags.COUNT, getCyNetwork(networkId).getNodeCount());
return Response.ok(result).build();
}
/**
*
* @summary Get number of edges in the network
*
* @param networkId
* Network SUID
*
* @return number of edges in the network
*/
@GET
@Path("/{networkId}/edges/count")
@Produces(MediaType.APPLICATION_JSON)
public Response getEdgeCount(@PathParam("networkId") Long networkId) {
final String result = getNumberObjectString(JsonTags.COUNT, getCyNetwork(networkId).getEdgeCount());
return Response.ok(result).build();
}
private final Collection<Long> getByQuery(final Long id, final String objType, final String column,
final String query) {
final CyNetwork network = getCyNetwork(id);
CyTable table = null;
List<? extends CyIdentifiable> graphObjects;
if (objType.equals("nodes")) {
table = network.getDefaultNodeTable();
graphObjects = network.getNodeList();
} else if (objType.equals("edges")) {
table = network.getDefaultEdgeTable();
graphObjects = network.getEdgeList();
} else {
throw getError("Invalid graph object type: " + objType, new IllegalArgumentException(),
Response.Status.INTERNAL_SERVER_ERROR);
}
if (query == null && column == null) {
// Simply return rows
return graphObjects.stream()
.map(obj->obj.getSUID())
.collect(Collectors.toList());
} else if (query == null || column == null) {
throw getError("Missing query parameter.", new IllegalArgumentException(),
Response.Status.INTERNAL_SERVER_ERROR);
} else {
Object rawQuery = MapperUtil.getRawValue(query, table.getColumn(column).getType());
final Collection<CyRow> rows = table.getMatchingRows(column, rawQuery);
final Set<Long> selectedSuid = rows.stream()
.map(row->row.get(CyIdentifiable.SUID, Long.class))
.collect(Collectors.toSet());
final Set<Long> allSuid = graphObjects.stream()
.map(obj->obj.getSUID())
.collect(Collectors.toSet());
// Return intersection
allSuid.retainAll(selectedSuid);
return allSuid;
}
}
/**
*
* Returns list of networks as an array of network SUID.
*
* @summary Get SUID list of networks
*
* @param column Optional. Network table column name to be used for search.
* @param query Optional. Search query.
*
* @return Matched networks as list of SUIDs. If no query is given, returns all network SUIDs.
*
*/
@GET
@Path("/")
@Produces(MediaType.APPLICATION_JSON + "; charset=UTF-8")
public Collection<Long> getNetworksAsSUID(@QueryParam("column") String column, @QueryParam("query") String query) {
Collection<CyNetwork> networks = new HashSet<>();
if (column == null && query == null) {
networks = networkManager.getNetworkSet();
} else {
if(column == null || column.length() == 0) {
throw getError("Column name parameter is missing.", new IllegalArgumentException(), Response.Status.INTERNAL_SERVER_ERROR);
}
if(query == null || query.length() == 0) {
throw getError("Query parameter is missing.", new IllegalArgumentException(), Response.Status.INTERNAL_SERVER_ERROR);
}
try {
networks = getNetworksByQuery(query, column);
} catch(Exception e) {
throw getError("Could not get networks.", e, Response.Status.INTERNAL_SERVER_ERROR);
}
}
final Collection<Long> suids = new HashSet<Long>();
for(final CyNetwork network: networks) {
suids.add(network.getSUID());
}
return suids;
}
/**
*
* @summary Get a network in Cytoscape.js format
*
* @param networkId
* Network SUID
*
* @return Network with all associated tables in Cytoscape.js format.
*
*/
@GET
@Path("/{networkId}")
@Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
@ReturnType("org.cytoscape.rest.internal.model.CyJsNetwork")
public String getNetwork(@PathParam("networkId") Long networkId) {
return getNetworkString(getCyNetwork(networkId));
}
/**
* @summary Get matching nodes
*
* @param networkId Network SUID
* @param column Optional. Node table column name to be used for search.
* @param query Optional. Search query.
*
* @return List of matched node SUIDs. If no parameter is given, returns all node SUIDs.
*/
@GET
@Path("/{networkId}/nodes")
@Produces(MediaType.APPLICATION_JSON)
public Collection<Long> getNodes(@PathParam("networkId") Long networkId, @QueryParam("column") String column,
@QueryParam("query") String query) {
return getByQuery(networkId, "nodes", column, query);
}
/**
* @summary Utility to get selected nodes as SUID list
*
* @param networkId Network SUID
*
* @return Selected nodes as a list of SUID
*/
@GET
@Path("/{networkId}/nodes/selected")
@Produces(MediaType.APPLICATION_JSON)
public Response getSelectedNodes(@PathParam("networkId") Long networkId) {
final CyNetwork network = getCyNetwork(networkId);
final List<CyNode> selectedNodes = CyTableUtil.getNodesInState(network, CyNetwork.SELECTED, true);
final List<Long> selectedNodeIds = selectedNodes.stream()
.map(node -> node.getSUID())
.collect(Collectors.toList());
return Response.ok(selectedNodeIds).build();
}
/**
*
* The return value does not includes originally selected nodes.
*
* @summary Utility to get all neighbors of selected nodes
*
* @param networkId Network SUID
*
* @return Neighbors as list. Note that this does not includes original nodes.
*/
@GET
@Path("/{networkId}/nodes/selected/neighbors")
@Produces(MediaType.APPLICATION_JSON)
public Response getNeighborsSelected(@PathParam("networkId") Long networkId) {
final CyNetwork network = getCyNetwork(networkId);
final List<CyNode> selectedNodes = CyTableUtil.getNodesInState(network, CyNetwork.SELECTED, true);
final Set<Long> res = selectedNodes.stream()
.map(node -> network.getNeighborList(node, Type.ANY))
.flatMap(List::stream)
.map(neighbor -> neighbor.getSUID())
.collect(Collectors.toSet());
return Response.ok(res).build();
}
/**
* @summary Utility to get all selected edges
*
* @param networkId Network SUID
*
* @return Selected edges as a list of SUID
*/
@GET
@Path("/{networkId}/edges/selected")
@Produces(MediaType.APPLICATION_JSON)
public Response getSelectedEdges(@PathParam("networkId") Long networkId) {
final CyNetwork network = getCyNetwork(networkId);
final List<CyEdge> selectedEdges = CyTableUtil.getEdgesInState(network, CyNetwork.SELECTED, true);
final List<Long> selectedEdgeIds = selectedEdges.stream()
.map(edge -> edge.getSUID())
.collect(Collectors.toList());
return Response.ok(selectedEdgeIds).build();
}
/**
* @summary Get matching edges
*
* @param networkId Network SUID
* @param column Optional. Edge table column name to be used for search.
* @param query Optional. Search query.
*
* @return List of matched edge SUIDs. If no parameter is given, returns all edge SUIDs.
*/
@GET
@Path("/{networkId}/edges")
@Produces(MediaType.APPLICATION_JSON)
public Collection<Long> getEdges(@PathParam("networkId") Long networkId, @QueryParam("column") String column,
@QueryParam("query") String query) {
return getByQuery(networkId, "edges", column, query);
}
/**
*
* @summary Get a node
*
* @param networkId
* Network SUID
* @param nodeId
* Node SUID
*
* @return Node with associated row data.
*
*/
@GET
@Path("/{networkId}/nodes/{nodeId}")
@Produces(MediaType.APPLICATION_JSON)
@ReturnType("org.cytoscape.rest.internal.model.Node")
public String getNode(@PathParam("networkId") Long networkId, @PathParam("nodeId") Long nodeId) {
final CyNetwork network = getCyNetwork(networkId);
final CyNode node = network.getNode(nodeId);
if (node == null) {
throw new NotFoundException("Could not find node with SUID: " + nodeId);
}
return getGraphObject(network, node);
}
/**
*
* @summary Get an edge
*
* @param networkId
* Network SUID
* @param edgeId
* Edge SUID
*
* @return Edge with associated row data
*
*/
@GET
@Path("/{networkId}/edges/{edgeId}")
@Produces(MediaType.APPLICATION_JSON)
@ReturnType("org.cytoscape.rest.internal.model.Edge")
public String getEdge(@PathParam("networkId") Long networkId, @PathParam("edgeId") Long edgeId) {
final CyNetwork network = getCyNetwork(networkId);
final CyEdge edge = network.getEdge(edgeId);
if (edge == null) {
throw new NotFoundException("Could not find edge with SUID: " + edgeId);
}
return getGraphObject(network, edge);
}
/**
* @summary Get source/target node of an edge
*
* @param networkId
* Network SUID
* @param edgeId
* Edge SUID
* @param type
* "source" or "target"
*
* @return SUID of the source/target node
*
*/
@GET
@Path("/{networkId}/edges/{edgeId}/{type}")
@Produces(MediaType.APPLICATION_JSON)
public String getEdgeComponent(@PathParam("networkId") Long networkId, @PathParam("edgeId") Long edgeId,
@PathParam("type") String type) {
final CyNetwork network = getCyNetwork(networkId);
final CyEdge edge = network.getEdge(edgeId);
if (edge == null) {
throw getError("Could not find edge: " + edgeId, new RuntimeException(), Response.Status.NOT_FOUND);
}
Long nodeSUID = null;
if (type.equals(JsonTags.SOURCE)) {
nodeSUID = edge.getSource().getSUID();
} else if (type.equals(JsonTags.TARGET)) {
nodeSUID = edge.getTarget().getSUID();
} else {
throw getError("Invalid parameter for edge: " + type, new IllegalArgumentException(), Response.Status.INTERNAL_SERVER_ERROR);
}
return getNumberObjectString(type, nodeSUID);
}
/**
*
* @summary Get edge directionality
*
* @param networkId
* Network SUID
* @param edgeId
* Target edge SUID
*
* @return true if the edge is directed.
*
*/
@GET
@Path("/{networkId}/edges/{edgeId}/isDirected")
@Produces(MediaType.APPLICATION_JSON)
public Boolean getEdgeDirected(@PathParam("networkId") Long networkId, @PathParam("edgeId") Long edgeId) {
final CyNetwork network = getCyNetwork(networkId);
CyEdge edge = network.getEdge(edgeId);
if (edge == null) {
throw getError("Could not find edge: " + edgeId, new RuntimeException(), Response.Status.NOT_FOUND);
}
return edge.isDirected();
}
/**
*
* @summary Get adjacent edges for a node
*
* @param networkId
* Network SUID
* @param nodeId
* Target node SUID
*
* @return List of connected edges (as SUID)
*
*/
@GET
@Path("/{networkId}/nodes/{nodeId}/adjEdges")
@Produces(MediaType.APPLICATION_JSON)
public Collection<Long> getAdjEdges(@PathParam("networkId") Long networkId, @PathParam("nodeId") Long nodeId) {
final CyNetwork network = getCyNetwork(networkId);
final CyNode node = getNode(network, nodeId);
final List<CyEdge> edges = network.getAdjacentEdgeList(node, Type.ANY);
return getGraphObjectArray(edges);
}
/**
* @summary Get network pointer (nested network SUID)
*
* @param networkId
* Network SUID.
* @param nodeId
* target node SUID.
*
* @return Nested network SUID
*/
@GET
@Path("/{networkId}/nodes/{nodeId}/pointer")
@Produces(MediaType.APPLICATION_JSON)
public Response getNetworkPointer(@PathParam("networkId") Long networkId, @PathParam("nodeId") Long nodeId) {
final CyNetwork network = getCyNetwork(networkId);
final CyNode node = getNode(network, nodeId);
final CyNetwork pointer = node.getNetworkPointer();
if (pointer == null) {
throw getError("Could not find network pointer.", new RuntimeException(), Response.Status.NOT_FOUND);
}
return Response.ok(getNumberObjectString(JsonTags.NETWORK_SUID, pointer.getSUID())).build();
}
/**
*
* @summary Get first neighbors of the node
*
* @param networkId
* Target network SUID.
* @param nodeId
* Node SUID.
*
* @return Neighbors of the node as a list of SUIDs.
*
*/
@GET
@Path("/{networkId}/nodes/{nodeId}/neighbors")
@Produces(MediaType.APPLICATION_JSON)
public Response getNeighbours(@PathParam("networkId") Long networkId, @PathParam("nodeId") Long nodeId) {
final CyNetwork network = getCyNetwork(networkId);
final CyNode node = getNode(network, nodeId);
final List<CyNode> nodes = network.getNeighborList(node, Type.ANY);
return Response.status(Response.Status.OK).entity(getGraphObjectArray(nodes)).build();
}
/**
*
* Get SUIDs for given collection of graph objects.
*
* @param objects
* @return
*/
private final Collection<Long> getGraphObjectArray(final Collection<? extends CyIdentifiable> objects) {
return objects.stream()
.map(CyIdentifiable::getSUID)
.collect(Collectors.toList());
}
/**
* Add new node(s) to the network. Body should include an array of new node names.
* <br/>
*
* <pre>
* [ "nodeName1", "nodeName2", ... ]
* </pre>
*
* <br />
* Node name will be used for "name" column.
*
* @summary Add node(s) to existing network
*
* @param networkId Network SUID
*
* @return SUID of the new node(s) with the name.
*/
@POST
@Path("/{networkId}/nodes")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response createNode(@PathParam("networkId") Long networkId, final InputStream is) {
final CyNetwork network = getCyNetwork(networkId);
final ObjectMapper objMapper = new ObjectMapper();
JsonNode rootNode = null;
try {
rootNode = objMapper.readValue(is, JsonNode.class);
} catch (IOException e) {
throw getError("Could not JSON root node.", e, Response.Status.INTERNAL_SERVER_ERROR);
}
// Single or multiple
if (rootNode.isArray()) {
final JsonFactory factory = new JsonFactory();
String result = null;
try {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
JsonGenerator generator = null;
generator = factory.createGenerator(stream);
generator.writeStartArray();
for (final JsonNode node : rootNode) {
final String nodeName = node.textValue();
final CyNode newNode = network.addNode();
network.getRow(newNode).set(CyNetwork.NAME, nodeName);
generator.writeStartObject();
generator.writeStringField(CyNetwork.NAME, nodeName);
generator.writeNumberField(CyIdentifiable.SUID, newNode.getSUID());
generator.writeEndObject();
}
generator.writeEndArray();
generator.close();
result = stream.toString("UTF-8");
stream.close();
updateViews(network);
} catch (Exception e) {
throw getError("Could not create node list.", e, Response.Status.INTERNAL_SERVER_ERROR);
}
return Response.status(Response.Status.CREATED).entity(result).build();
} else {
throw getError("Need to post as array.", new IllegalArgumentException(),
Response.Status.PRECONDITION_FAILED);
}
}
/**
* Add new edge(s) to the network. Body should include an array of new node names.
* <pre>
* [
* {
* "source": SOURCE_NODE_SUID,
* "target": TARGET_NODE_SUID,
* "directed": (Optional boolean value. Default is True),
* "interaction": (Optional. Will be used for Interaction column. Default value is '-')
* } ...
* ]
* </pre>
*
* @summary Add edge(s) to existing network
*
* @param networkId Network SUID
*
* @return SUIDs of the new edges with source and target SUIDs.
*
*/
@POST
@Path("/{networkId}/edges")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response createEdge(@PathParam("networkId") Long networkId, final InputStream is) {
final CyNetwork network = getCyNetwork(networkId);
final ObjectMapper objMapper = new ObjectMapper();
JsonNode rootNode = null;
try {
rootNode = objMapper.readValue(is, JsonNode.class);
} catch (IOException e) {
throw getError("Could not find root node in the given JSON..", e, Response.Status.PRECONDITION_FAILED);
}
// Single or multiple
if (rootNode.isArray()) {
final JsonFactory factory = new JsonFactory();
String result = null;
try {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
JsonGenerator generator = null;
generator = factory.createGenerator(stream);
generator.writeStartArray();
for (final JsonNode node : rootNode) {
JsonNode source = node.get(JsonTags.SOURCE);
JsonNode target = node.get(JsonTags.TARGET);
JsonNode interaction = node.get(CyEdge.INTERACTION);
JsonNode isDirected = node.get(JsonTags.DIRECTED);
if (source == null || target == null) {
continue;
}
final Long sourceSUID = source.asLong();
final Long targetSUID = target.asLong();
final CyNode sourceNode = network.getNode(sourceSUID);
final CyNode targetNode = network.getNode(targetSUID);
final CyEdge edge;
if (isDirected != null) {
edge = network.addEdge(sourceNode, targetNode, isDirected.asBoolean());
} else {
edge = network.addEdge(sourceNode, targetNode, true);
}
final String sourceName = network.getRow(sourceNode).get(CyNetwork.NAME, String.class);
final String targetName = network.getRow(targetNode).get(CyNetwork.NAME, String.class);
final String interactionString;
if (interaction != null) {
interactionString = interaction.textValue();
} else {
interactionString = "-";
}
network.getRow(edge).set(CyEdge.INTERACTION, interactionString);
network.getRow(edge).set(CyNetwork.NAME, sourceName + " (" + interactionString + ") " + targetName);
generator.writeStartObject();
generator.writeNumberField(CyIdentifiable.SUID, edge.getSUID());
generator.writeNumberField(JsonTags.SOURCE, sourceSUID);
generator.writeNumberField(JsonTags.TARGET, targetSUID);
generator.writeEndObject();
}
generator.writeEndArray();
generator.close();
result = stream.toString("UTF-8");
stream.close();
updateViews(network);
} catch (Exception e) {
e.printStackTrace();
throw getError("Could not create edge.", e, Response.Status.INTERNAL_SERVER_ERROR);
}
return Response.status(Response.Status.CREATED).entity(result).build();
} else {
throw getError("Need to POST as array.", new IllegalArgumentException(),
Response.Status.INTERNAL_SERVER_ERROR);
}
}
// //////////////// Delete //////////////////////////////////
/**
*
* @summary Delete all networks in current session
*/
@DELETE
@Path("/")
public Response deleteAllNetworks() {
this.networkManager.getNetworkSet().stream()
.forEach(network->this.networkManager.destroyNetwork(network));
return Response.ok().build();
}
/**
* @summary Delete a network
*
* @param networkId Network SUID
*/
@DELETE
@Path("/{networkId}")
public Response deleteNetwork(@PathParam("networkId") Long networkId) {
final CyNetwork network = getCyNetwork(networkId);
this.networkManager.destroyNetwork(network);
return Response.ok().build();
}
/**
* @summary Delete all nodes in the network
*
* @param networkId
* Network SUID.
*/
@DELETE
@Path("/{networkId}/nodes")
public Response deleteAllNodes(@PathParam("networkId") Long networkId) {
final CyNetwork network = getCyNetwork(networkId);
network.removeNodes(network.getNodeList());
updateViews(network);
return Response.ok().build();
}
/**
* @summary Delete all edges in the network
*
* @param networkId
* Network SUID
*/
@DELETE
@Path("/{networkId}/edges")
public Response deleteAllEdges(@PathParam("networkId") Long networkId) {
final CyNetwork network = getCyNetwork(networkId);
network.removeEdges(network.getEdgeList());
updateViews(network);
return Response.ok().build();
}
/**
*
* @summary Delete a node in the network
*
* @param networkId Network SUID
* @param nodeId Node SUID
*
*/
@DELETE
@Path("/{networkId}/nodes/{nodeId}")
public Response deleteNode(@PathParam("networkId") Long networkId, @PathParam("nodeId") Long nodeId) {
final CyNetwork network = getCyNetwork(networkId);
final CyNode node = network.getNode(nodeId);
if (node == null) {
throw new NotFoundException("Node does not exist.");
}
final List<CyNode> nodes = new ArrayList<CyNode>();
nodes.add(node);
network.removeNodes(nodes);
updateViews(network);
return Response.ok().build();
}
/**
*
* @summary Delete an edge in the network.
*
* @param networkId
* Network SUID
* @param edgeId
* SUID of the edge to be deleted
*/
@DELETE
@Path("/{networkId}/edges/{edgeId}")
public Response deleteEdge(@PathParam("networkId") Long networkId, @PathParam("edgeId") Long edgeId) {
final CyNetwork network = getCyNetwork(networkId);
final CyEdge edge = network.getEdge(edgeId);
if (edge == null) {
throw new NotFoundException("Edge does not exist.");
}
final List<CyEdge> edges = new ArrayList<CyEdge>();
edges.add(edge);
network.removeEdges(edges);
updateViews(network);
return Response.ok().build();
}
/**
* Update view of each network
*
* @param network
*/
private final void updateViews(final CyNetwork network) {
final Collection<CyNetworkView> views = networkViewManager.getNetworkViews(network);
for (final CyNetworkView view : views) {
view.updateView();
}
}
// ///////////////////// Object Creation ////////////////////
/**
* @summary Create a new network from Cytoscape.js JSON or Edgelist
*
* @param collection Name of new network collection
* @param title Title of the new network
* @param source Optional. "url"
* @param format "edgelist" or "json"
*
* @return SUID of the new network
*/
@POST
@Path("/")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public String createNetwork(@DefaultValue(DEF_COLLECTION_PREFIX) @QueryParam("collection") String collection,
@QueryParam("source") String source, @QueryParam("format") String format,
@QueryParam("title") String title, final InputStream is,
@Context HttpHeaders headers) {
// 1. If source is URL, load from the array of URL
if (source != null && source.equals(JsonTags.URL)) {
try {
return loadNetwork(collection, is);
} catch (IOException e) {
throw getError("Could not load networks from given locations.", e,
Response.Status.INTERNAL_SERVER_ERROR);
}
}
// Check user agent if available
final List<String> agent = headers.getRequestHeader("user-agent");
String userAgent = "";
if (agent != null) {
userAgent = agent.get(0);
}
final String collectionName;
if (collection == null) {
collectionName = DEF_COLLECTION_PREFIX + userAgent;
} else {
collectionName = collection;
}
final TaskIterator it;
if (format != null && format.trim().equals(JsonTags.FORMAT_EDGELIST)) {
it = edgeListReaderFactory.createTaskIterator(is, collection);
} else {
it = cytoscapeJsReaderFactory.createTaskIterator(is, collection);
}
final CyNetworkReader reader = (CyNetworkReader) it.next();
try {
reader.run(new HeadlessTaskMonitor());
} catch (Exception e) {
e.printStackTrace();
throw getError("Could not parse the given network JSON.", e, Response.Status.PRECONDITION_FAILED);
}
final CyNetwork[] networks = reader.getNetworks();
final CyNetwork newNetwork = networks[0];
if(title!= null && title.isEmpty() == false) {
try {
newNetwork.getTable(CyNetwork.class, CyNetwork.LOCAL_ATTRS).getRow(newNetwork.getSUID()).set(CyNetwork.NAME, title);
} catch(Exception e) {
e.printStackTrace();
}
}
addNetwork(networks, reader, collectionName);
try {
is.close();
} catch (IOException e) {
throw getError("Could not close the network input stream.", e, Response.Status.INTERNAL_SERVER_ERROR);
}
// Return SUID-to-Original map
return getNumberObjectString(JsonTags.NETWORK_SUID, newNetwork.getSUID());
}
/**
*
* If body is empty, it simply creates new network from current selection.
* Otherwise, select from the list of SUID.
*
* @summary Create a subnetwork from selected nodes and edges
*
* @param networkId Network SUID
*
* @return SUID of the new network.
*
*/
@POST
@Path("/{networkId}")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public String createNetworkFromSelected(
@PathParam("networkId") Long networkId,
@QueryParam("title") String title,
final InputStream is,
@Context HttpHeaders headers) {
final CyNetwork network = getCyNetwork(networkId);
final TaskIterator itr = newNetworkSelectedNodesAndEdgesTaskFactory.createTaskIterator(network);
// TODO: This is very hackey... We need a method to get the new network
// SUID.
AbstractNetworkCollectionTask viewTask = null;
while (itr.hasNext()) {
final Task task = itr.next();
try {
task.run(new HeadlessTaskMonitor());
if (task instanceof AbstractNetworkCollectionTask && task instanceof ObservableTask) {
viewTask = (AbstractNetworkCollectionTask) task;
} else {
}
} catch (Exception e) {
throw getError("Could not create sub network from selection.", e, Response.Status.INTERNAL_SERVER_ERROR);
}
}
try {
is.close();
} catch (IOException e) {
throw getError("Could not close the stream.", e, Response.Status.INTERNAL_SERVER_ERROR);
}
if (viewTask != null) {
final Collection<?> result = ((ObservableTask) viewTask).getResults(Collection.class);
if (result.size() == 1) {
final CyNetwork newSubNetwork = ((CyNetworkView) result.iterator().next()).getModel();
final Long suid = newSubNetwork.getSUID();
if(title != null) {
newSubNetwork.getRow(newSubNetwork).set(CyNetwork.NAME, title);
}
return getNumberObjectString(JsonTags.NETWORK_SUID, suid);
}
}
throw getError("Could not get new network SUID.", new IllegalStateException(), Response.Status.INTERNAL_SERVER_ERROR);
}
private final String loadNetwork(final String collectionName, final InputStream is) throws IOException {
final ObjectMapper objMapper = new ObjectMapper();
final JsonNode rootNode = objMapper.readValue(is, JsonNode.class);
final Map<String, Long[]> results = new HashMap<String, Long[]>();
// Input should be array of URLs.
for (final JsonNode node : rootNode) {
final String sourceUrl = node.asText();
TaskIterator itr = loadNetworkURLTaskFactory.loadCyNetworks(new URL(sourceUrl));
CyNetworkReader currentReader = null;
while (itr.hasNext()) {
final Task task = itr.next();
try {
if (task instanceof CyNetworkReader) {
currentReader = (CyNetworkReader) task;
if(currentReader instanceof AbstractCyNetworkReader && collectionName != null) {
((AbstractCyNetworkReader)currentReader).getRootNetworkList().setSelectedValue(collectionName);
}
currentReader.run(new HeadlessTaskMonitor());
} else {
task.run(new HeadlessTaskMonitor());
}
} catch (Exception e) {
throw new IOException("Could not execute network reader.", e);
}
}
final CyNetwork[] networks = currentReader.getNetworks();
final Long[] suids = new Long[networks.length];
int counter = 0;
for (CyNetwork network : networks) {
if(collectionName != null) {
final CyRootNetwork rootNetwork = ((CySubNetwork)network).getRootNetwork();
rootNetwork.getRow(rootNetwork).set(CyNetwork.NAME, collectionName);
}
suids[counter] = network.getSUID();
counter++;
}
results.put(sourceUrl, suids);
}
is.close();
return generateNetworkLoadResults(results);
}
private final String generateNetworkLoadResults(final Map<String, Long[]> results) {
final JsonFactory factory = new JsonFactory();
String result = null;
ByteArrayOutputStream stream = new ByteArrayOutputStream();
JsonGenerator generator = null;
try {
generator = factory.createGenerator(stream);
generator.writeStartArray();
for (final String url : results.keySet()) {
generator.writeStartObject();
generator.writeStringField("source", url);
generator.writeArrayFieldStart(JsonTags.NETWORK_SUID);
for (final Long suid : results.get(url)) {
generator.writeNumber(suid);
}
generator.writeEndArray();
generator.writeEndObject();
}
generator.writeEndArray();
generator.close();
result = stream.toString("UTF-8");
stream.close();
} catch (IOException e) {
throw getError("Could not create object count.", e, Response.Status.INTERNAL_SERVER_ERROR);
}
return result;
}
/**
* Add network to the manager
*
* @param networks
* @param reader
* @param collectionName
*/
private final void addNetwork(final CyNetwork[] networks, final CyNetworkReader reader, final String collectionName) {
final VisualStyle style = vmm.getCurrentVisualStyle();
final List<CyNetworkView> results = new ArrayList<CyNetworkView>();
final Set<CyRootNetwork> rootNetworks = new HashSet<CyRootNetwork>();
for (final CyNetwork net : networkManager.getNetworkSet()) {
final CyRootNetwork rootNet = cyRootNetworkManager.getRootNetwork(net);
rootNetworks.add(rootNet);
}
for (final CyNetwork network : networks) {
// Set network name
String networkName = network.getRow(network).get(CyNetwork.NAME, String.class);
if (networkName == null || networkName.trim().length() == 0) {
if (networkName == null)
networkName = collectionName;
network.getRow(network).set(CyNetwork.NAME, networkName);
}
networkManager.addNetwork(network);
final int numGraphObjects = network.getNodeCount() + network.getEdgeCount();
int viewThreshold = 10000;
if (numGraphObjects < viewThreshold) {
final CyNetworkView view = reader.buildCyNetworkView(network);
networkViewManager.addNetworkView(view);
vmm.setVisualStyle(style, view);
style.apply(view);
if (!view.isSet(BasicVisualLexicon.NETWORK_CENTER_X_LOCATION)
&& !view.isSet(BasicVisualLexicon.NETWORK_CENTER_Y_LOCATION)
&& !view.isSet(BasicVisualLexicon.NETWORK_CENTER_Z_LOCATION))
view.fitContent();
results.add(view);
} else {
// results.add(nullNetworkViewFactory.createNetworkView(network));
}
}
// If this is a subnetwork, and there is only one subnetwork in the
// root, check the name of the root network
// If there is no name yet for the root network, set it the same as its
// base subnetwork
if (networks.length == 1) {
if (networks[0] instanceof CySubNetwork) {
CySubNetwork subnet = (CySubNetwork) networks[0];
final CyRootNetwork rootNet = subnet.getRootNetwork();
String rootNetName = rootNet.getRow(rootNet).get(CyNetwork.NAME, String.class);
rootNet.getRow(rootNet).set(CyNetwork.NAME, collectionName);
if (rootNetName == null || rootNetName.trim().length() == 0) {
// The root network does not have a name yet, set it the same
// as the base subnetwork
rootNet.getRow(rootNet).set(CyNetwork.NAME, collectionName);
}
}
}
}
}