/* Copyright 2008-2010 Gephi Authors : Mathieu Bastian <mathieu.bastian@gephi.org> Website : http://www.gephi.org This file is part of Gephi. DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. Copyright 2011 Gephi Consortium. All rights reserved. The contents of this file are subject to the terms of either the GNU General Public License Version 3 only ("GPL") or the Common Development and Distribution License("CDDL") (collectively, the "License"). You may not use this file except in compliance with the License. You can obtain a copy of the License at http://gephi.org/about/legal/license-notice/ or /cddl-1.0.txt and /gpl-3.0.txt. See the License for the specific language governing permissions and limitations under the License. When distributing the software, include this License Header Notice in each file and include the License files at /cddl-1.0.txt and /gpl-3.0.txt. If applicable, add the following below the License Header, with the fields enclosed by brackets [] replaced by your own identifying information: "Portions Copyrighted [year] [name of copyright owner]" If you wish your version of this file to be governed by only the CDDL or only the GPL Version 3, indicate your decision by adding "[Contributor] elects to include this software in this distribution under the [CDDL or GPL Version 3] license." If you do not indicate a single choice of license, a recipient has the option to distribute your version of this file under either the CDDL, the GPL Version 3 or to extend the choice of license to its licensees as provided above. However, if you add GPL Version 3 code and therefore, elected the GPL Version 3 license, then the option applies only if the new code is made subject to such option by the copyright holder. Contributor(s): Portions Copyrighted 2011 Gephi Consortium. */ package org.gephi.io.importer.impl; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.ObjectList; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import org.gephi.graph.api.AttributeUtils; import org.gephi.graph.api.Interval; import org.gephi.graph.api.TimeFormat; import org.gephi.graph.api.TimeRepresentation; import org.gephi.graph.api.types.TimeSet; import org.gephi.io.importer.api.ColumnDraft; import org.gephi.io.importer.api.Container; import org.gephi.io.importer.api.ContainerLoader; import org.gephi.io.importer.api.ContainerUnloader; import org.gephi.io.importer.api.EdgeDirection; import org.gephi.io.importer.api.EdgeDirectionDefault; import org.gephi.io.importer.api.EdgeDraft; import org.gephi.io.importer.api.EdgeMergeStrategy; import org.gephi.io.importer.api.ElementDraft; import org.gephi.io.importer.api.ElementIdType; import org.gephi.io.importer.api.Issue; import org.gephi.io.importer.api.Issue.Level; import org.gephi.io.importer.api.NodeDraft; import org.gephi.io.importer.api.Report; import org.joda.time.DateTimeZone; import org.openide.util.NbBundle; /** * * @author Mathieu Bastian */ public class ImportContainerImpl implements Container, ContainerLoader, ContainerUnloader { protected static final int NULL_INDEX = -1; //MetaData private String source; //Factory private final ElementFactoryImpl factory; //Parameters private final ImportContainerParameters parameters; //Maps and Data private final ObjectList<NodeDraftImpl> nodeList; private final ObjectList<EdgeDraftImpl> edgeList; private final Object2IntMap<String> nodeMap; private final Object2IntMap<String> edgeMap; private final Object2IntMap edgeTypeMap; private Class lastEdgeType; private Long2ObjectMap<int[]>[] edgeTypeSets; private EdgeDirectionDefault edgeDefault = EdgeDirectionDefault.MIXED; private final Object2ObjectMap<String, ColumnDraft> nodeColumns; private final Object2ObjectMap<String, ColumnDraft> edgeColumns; //Config private ElementIdType elementIdType = ElementIdType.STRING; //Management private boolean dynamicGraph = false; private boolean dynamicAttributes = false; private Report report; //Counting private int directedEdgesCount = 0; private int undirectedEdgesCount = 0; private int selfLoops = 0; //Dynamic private TimeFormat timeFormat = TimeFormat.DOUBLE; private TimeRepresentation timeRepresentation = TimeRepresentation.INTERVAL; private DateTimeZone timeZone = DateTimeZone.getDefault(); private Double timestamp; private Interval interval; //Report flag private boolean reportedUnknownNode; private boolean reportedParallelEdges; public ImportContainerImpl() { parameters = new ImportContainerParameters(); nodeMap = new Object2IntOpenHashMap<>(); edgeMap = new Object2IntOpenHashMap<>(); nodeMap.defaultReturnValue(NULL_INDEX); edgeMap.defaultReturnValue(NULL_INDEX); nodeList = new ObjectArrayList<>(); edgeList = new ObjectArrayList<>(); edgeTypeMap = new Object2IntOpenHashMap(); edgeTypeSets = new Long2ObjectMap[0]; factory = new ElementFactoryImpl(this); nodeColumns = new Object2ObjectOpenHashMap<>(); edgeColumns = new Object2ObjectOpenHashMap<>(); } @Override public ContainerLoader getLoader() { return this; } @Override public synchronized ContainerUnloader getUnloader() { return this; } @Override public ElementFactoryImpl factory() { return factory; } @Override public void setSource(String source) { this.source = source; } @Override public String getSource() { return source; } @Override public void addNode(NodeDraft nodeDraft) { checkElementDraftImpl(nodeDraft); NodeDraftImpl nodeDraftImpl = (NodeDraftImpl) nodeDraft; if (nodeMap.containsKey(nodeDraftImpl.getId())) { String message = NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerException_nodeExist", nodeDraftImpl.getId()); report.logIssue(new Issue(message, Level.WARNING)); return; } int index = nodeList.size(); nodeList.add(nodeDraftImpl); nodeMap.put(nodeDraftImpl.getId(), index); } @Override public NodeDraftImpl getNode(String id) { checkId(id); int index = nodeMap.getInt(id); NodeDraftImpl node = null; if (index == NULL_INDEX) { if (parameters.isAutoNode()) { //Creates the missing node node = factory.newNodeDraft(id); addNode(node); node.setCreatedAuto(true); if (!reportedUnknownNode) { String message = NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerException_AutoNodeCreated"); report.logIssue(new Issue(message, Level.INFO)); reportedUnknownNode = true; } } else { String message = NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerException_UnknowNodeId", id); report.logIssue(new Issue(message, Level.SEVERE)); } } else { node = nodeList.get(index); } return node; } @Override public boolean nodeExists(String id) { checkId(id); return nodeMap.containsKey(id); } @Override public boolean edgeExists(String source, String target) { checkId(source); checkId(target); NodeDraftImpl sourceNode = getNode(source); NodeDraftImpl targetNode = getNode(target); if (sourceNode != null && targetNode != null) { boolean undirected = edgeDefault.equals(EdgeDirectionDefault.UNDIRECTED) || (undirectedEdgesCount > 0 && directedEdgesCount == 0); long edgeId = getLongId(sourceNode, targetNode, !undirected); for (Long2ObjectMap l : edgeTypeSets) { if (l != null) { if (l.containsKey(edgeId)) { return true; } } } } return false; } @Override public void addEdge(EdgeDraft edgeDraft) { checkElementDraftImpl(edgeDraft); EdgeDraftImpl edgeDraftImpl = (EdgeDraftImpl) edgeDraft; if (edgeDraftImpl.getSource() == null) { String message = NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerException_MissingNodeSource"); report.logIssue(new Issue(message, Level.SEVERE)); return; } if (edgeDraftImpl.getTarget() == null) { String message = NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerException_MissingNodeTarget"); report.logIssue(new Issue(message, Level.SEVERE)); return; } //Check if already exists if (edgeMap.containsKey(edgeDraftImpl.getId())) { String message = NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerException_edgeExist", edgeDraftImpl.getId()); report.logIssue(new Issue(message, Level.WARNING)); return; } //Self loop if (edgeDraftImpl.isSelfLoop() && !parameters.isSelfLoops()) { String message = NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerException_SelfLoop"); report.logIssue(new Issue(message, Level.SEVERE)); return; } //Check direction and default type if (edgeDraftImpl.getDirection() != null) { //Test if the given type match with parameters switch (edgeDefault) { case DIRECTED: if (edgeDraftImpl.getDirection().equals(EdgeDirection.UNDIRECTED)) { report.logIssue(new Issue(NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerException_Bad_Edge_Type", edgeDefault, edgeDraftImpl.getId()), Level.SEVERE)); return; } break; case UNDIRECTED: if (edgeDraftImpl.getDirection().equals(EdgeDirection.DIRECTED)) { report.logIssue(new Issue(NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerException_Bad_Edge_Type", edgeDefault, edgeDraftImpl.getId()), Level.SEVERE)); return; } break; } } //Get index int index = edgeList.size(); //Type int edgeType = getEdgeType(edgeDraftImpl.getType()); long sourceTargetLong = getLongId(edgeDraftImpl); ensureLongSetArraySize(edgeType); Long2ObjectMap<int[]> edgeTypeSet = edgeTypeSets[edgeType]; if (edgeTypeSet.containsKey(sourceTargetLong)) { if (!parameters.isParallelEdges()) { report.logIssue(new Issue(NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerException_Parallel_Edge_Forbidden", edgeDraftImpl.getId()), Level.SEVERE)); return; } else { int[] edges = edgeTypeSet.get(sourceTargetLong); int[] newEdges = new int[edges.length + 1]; newEdges[edges.length] = index; System.arraycopy(edges, 0, newEdges, 0, edges.length); edgeTypeSet.put(sourceTargetLong, newEdges); if (!reportedParallelEdges) { report.logIssue(new Issue(NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerException_Parallel_Edge_Merged", edgeDraftImpl.getId()), Level.INFO)); reportedParallelEdges = true; } } } else { edgeTypeSet.put(sourceTargetLong, new int[]{index}); } //Self loop if (edgeDraftImpl.isSelfLoop()) { selfLoops++; } //Direction EdgeDirection direction = edgeDraftImpl.getDirection(); if (direction != null) { //Counting switch (direction) { case DIRECTED: directedEdgesCount++; break; case UNDIRECTED: undirectedEdgesCount++; break; } } //Adding edgeList.add(edgeDraftImpl); edgeMap.put(edgeDraft.getId(), index); } @Override public void removeEdge(EdgeDraft edgeDraft) { checkElementDraftImpl(edgeDraft); EdgeDraftImpl edgeDraftImpl = (EdgeDraftImpl) edgeDraft; String id = edgeDraftImpl.getId(); if (!edgeMap.containsKey(id)) { return; } if (edgeDraftImpl.getDirection() != null) { //UnCounting switch (edgeDraftImpl.getDirection()) { case DIRECTED: directedEdgesCount--; break; case UNDIRECTED: undirectedEdgesCount--; break; } } if (edgeDraftImpl.isSelfLoop()) { selfLoops--; } int edgeType = getEdgeType(edgeDraftImpl.getType()); long sourceTargetLong = getLongId(edgeDraftImpl); ensureLongSetArraySize(edgeType); Long2ObjectMap<int[]> edgeTypeSet = edgeTypeSets[edgeType]; //Get index int index = edgeMap.remove(id); //Update edgeType set int[] edges = edgeTypeSet.remove(sourceTargetLong); if (edges.length > 1) { int[] newEdges = new int[edges.length - 1]; int i = 0; for (int e : edges) { if (e != index) { newEdges[i++] = e; } } edgeTypeSet.put(sourceTargetLong, newEdges); } //Remove edge edgeList.set(index, null); } @Override public boolean edgeExists(String id) { checkId(id); return edgeMap.containsKey(id); } @Override public EdgeDraft getEdge(String id) { checkId(id); int index = edgeMap.getInt(id); if (index == NULL_INDEX) { return null; } return edgeList.get(index); } @Override public Iterable<NodeDraft> getNodes() { return new NullFilterIterable<>(nodeList); } @Override public int getNodeCount() { return nodeMap.size(); } @Override public Iterable<EdgeDraft> getEdges() { return new NullFilterIterable<>(edgeList); } @Override public int getEdgeCount() { return edgeMap.size(); } @Override public TimeFormat getTimeFormat() { return timeFormat; } @Override public void setTimeFormat(TimeFormat timeFormat) { this.timeFormat = timeFormat; } @Override public TimeRepresentation getTimeRepresentation() { return timeRepresentation; } @Override public void setTimeRepresentation(TimeRepresentation timeRepresentation) { this.timeRepresentation = timeRepresentation; } @Override public DateTimeZone getTimeZone() { return timeZone; } @Override public void setTimeZone(DateTimeZone timeZone) { this.timeZone = timeZone; } @Override public ColumnDraft addNodeColumn(String key, Class typeClass) { if (AttributeUtils.isDynamicType(typeClass)) { if (TimeSet.class.isAssignableFrom(typeClass)) { return addNodeColumn(key, typeClass, true); } else { return addNodeColumn(key, AttributeUtils.getStaticType(typeClass), true); } } else { return addNodeColumn(key, typeClass, false); } } @Override public ColumnDraft addNodeColumn(String key, Class typeClass, boolean dynamic) { key = key.toLowerCase().trim(); ColumnDraft column = nodeColumns.get(key); typeClass = AttributeUtils.getStandardizedType(typeClass); if (column == null) { int index = nodeColumns.size(); column = new ColumnDraftImpl(key, index, dynamic, typeClass); nodeColumns.put(key, column); if (dynamic) { report.log(NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerLog.AddDynamicNodeColumn", key, typeClass.getSimpleName())); } else { report.log(NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerLog.AddNodeColumn", key, typeClass.getSimpleName())); } } else if (!column.getTypeClass().equals(typeClass)) { report.logIssue(new Issue(NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerException_Column_Type_Mismatch", key, column.getTypeClass()), Level.SEVERE)); } return column; } @Override public ColumnDraft addEdgeColumn(String key, Class typeClass) { if (AttributeUtils.isDynamicType(typeClass)) { if (TimeSet.class.isAssignableFrom(typeClass)) { return addEdgeColumn(key, typeClass, true); } else { return addEdgeColumn(key, AttributeUtils.getStaticType(typeClass), true); } } else { return addEdgeColumn(key, typeClass, false); } } @Override public ColumnDraft addEdgeColumn(String key, Class typeClass, boolean dynamic) { key = key.toLowerCase().trim(); ColumnDraft column = edgeColumns.get(key); typeClass = AttributeUtils.getStandardizedType(typeClass); if (column == null) { int index = edgeColumns.size(); column = new ColumnDraftImpl(key, index, dynamic, typeClass); edgeColumns.put(key, column); if (dynamic) { report.log(NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerLog.AddDynamicEdgeColumn", key, typeClass.getSimpleName())); } else { report.log(NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerLog.AddEdgeColumn", key, typeClass.getSimpleName())); } } else if (!column.getTypeClass().equals(typeClass)) { report.logIssue(new Issue(NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerException_Column_Type_Mismatch", key, column.getTypeClass()), Level.SEVERE)); } return column; } @Override public ColumnDraft getNodeColumn(String key) { return nodeColumns.get(key.toLowerCase()); } @Override public boolean hasNodeColumn(String key) { return nodeColumns.containsKey(key.toLowerCase()); } @Override public ColumnDraft getEdgeColumn(String key) { return edgeColumns.get(key.toLowerCase()); } @Override public boolean hasEdgeColumn(String key) { return edgeColumns.containsKey(key.toLowerCase()); } @Override public Iterable<ColumnDraft> getNodeColumns() { return nodeColumns.values(); } @Override public Iterable<ColumnDraft> getEdgeColumns() { return edgeColumns.values(); } @Override public void setTimestamp(String timestamp) { try { double t = timeFormat.equals(TimeFormat.DOUBLE) ? Double.parseDouble(timestamp) : AttributeUtils.parseDateTime(timestamp); this.timestamp = t; } catch (Exception e) { report.logIssue(new Issue(NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerException_Timestamp_Parse_Error", timestamp), Level.SEVERE)); return; } report.log(NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerLog.GraphTimestamp", timestamp)); } @Override public void setInterval(String startDateTime, String endDateTime) { try { double start, end; if (startDateTime == null || startDateTime.trim().isEmpty() || "-inf".equalsIgnoreCase(startDateTime) || "-infinity".equalsIgnoreCase(startDateTime)) { start = Double.NEGATIVE_INFINITY; } else { start = timeFormat.equals(TimeFormat.DOUBLE) ? Double.parseDouble(startDateTime) : AttributeUtils.parseDateTime(startDateTime); } if (endDateTime == null || endDateTime.trim().isEmpty() || "inf".equalsIgnoreCase(endDateTime) || "infinity".equalsIgnoreCase(endDateTime)) { end = Double.POSITIVE_INFINITY; } else { end = timeFormat.equals(TimeFormat.DOUBLE) ? Double.parseDouble(endDateTime) : AttributeUtils.parseDateTime(endDateTime); } this.interval = new Interval(start, end); } catch (Exception e) { report.logIssue(new Issue(NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerException_Interval_Parse_Error", "[" + startDateTime + "," + endDateTime + "]"), Level.SEVERE)); return; } report.log(NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerLog.GraphInterval", "[" + startDateTime + "," + endDateTime + "]")); } @Override public Interval getInterval() { return interval; } @Override public Double getTimestamp() { return timestamp; } @Override public void setElementIdType(ElementIdType type) { if (this.elementIdType != type) { this.elementIdType = type; report.log(NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerLog.ElementIdType", elementIdType.toString())); } } @Override public ElementIdType getElementIdType() { return elementIdType; } @Override public boolean verify() { //Edge weight zero or negative for (EdgeDraftImpl edge : new NullFilterIterable<EdgeDraftImpl>(edgeList)) { String id = edge.getId(); if (edge.getWeight() < 0f) { report.logIssue(new Issue(NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerException_Negative_Weight", id), Level.WARNING)); } else if (edge.getWeight() == 0) { removeEdge(edge); report.logIssue(new Issue(NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerException_Weight_Zero_Ignored", id), Level.SEVERE)); } } //Graph EdgeDefault if (directedEdgesCount > 0 && undirectedEdgesCount == 0) { setEdgeDefault(EdgeDirectionDefault.DIRECTED); } else if (directedEdgesCount == 0 && undirectedEdgesCount > 0) { setEdgeDefault(EdgeDirectionDefault.UNDIRECTED); } else if (directedEdgesCount > 0 && undirectedEdgesCount > 0) { setEdgeDefault(EdgeDirectionDefault.MIXED); } //IdType if (elementIdType.equals(ElementIdType.INTEGER) || elementIdType.equals(ElementIdType.LONG)) { try { for (NodeDraftImpl node : nodeList) { if (elementIdType.equals(ElementIdType.INTEGER)) { Integer.parseInt(node.getId()); } else if (elementIdType.equals(ElementIdType.LONG)) { Long.parseLong(node.getId()); } } for (EdgeDraftImpl edge : edgeList) { if (elementIdType.equals(ElementIdType.INTEGER)) { Integer.parseInt(edge.getId()); } else if (elementIdType.equals(ElementIdType.LONG)) { Long.parseLong(edge.getId()); } } } catch (NumberFormatException e) { report.logIssue(new Issue(NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerException_ElementIdType_Parse_Error", elementIdType), Level.WARNING)); elementIdType = ElementIdType.STRING; } } //Is dynamic graph for (NodeDraftImpl node : nodeList) { if (node != null) { if (node.isDynamic()) { dynamicGraph = true; } if (node.hasDynamicAttributes()) { dynamicAttributes = true; } } } for (EdgeDraftImpl edge : edgeList) { if (edge != null) { if (edge.isDynamic()) { dynamicGraph = true; } if (edge.hasDynamicAttributes()) { dynamicAttributes = true; } } } //Print time interval values to report // if (timeIntervalMin != null || timeIntervalMax != null) { // if (timeFormat.equals(TimeFormat.DATE) || timeFormat.equals(TimeFormat.DATETIME)) { // try { // String message = "[" + (timeIntervalMin != null ? DynamicUtilities.getXMLDateStringFromDouble(timeIntervalMin) : "-inf") + ","; // message += (timeIntervalMax != null ? DynamicUtilities.getXMLDateStringFromDouble(timeIntervalMax) : "+inf") + "]"; // report.log(NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerLog.TimeInterval", message)); // } catch (Exception e) { // } // } else { // String message = "[" + (timeIntervalMin != null ? timeIntervalMin.toString() : "-inf") + ","; // message += (timeIntervalMax != null ? timeIntervalMax.toString() : "+inf") + "]"; // report.log(NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerLog.TimeInterval", message)); // } // } // //Print TimeFormat if (dynamicGraph) { report.log(NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerLog.TimeFormat", timeFormat.toString())); report.log(NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerLog.TimeRepresentation", timeRepresentation.toString())); report.log(NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerLog.TimeZone", timeZone.toString())); } //Print edge label type if (lastEdgeType != null) { report.log(NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerLog.EdgeLabelType", lastEdgeType.getSimpleName())); } //Print edge types if (isMultiGraph()) { report.log(NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerLog.MultiGraphCount", edgeTypeMap.size() - 1)); } return true; } @Override public void closeLoader() { //Remove self-loops if (!parameters.isSelfLoops() && selfLoops > 0) { List<EdgeDraftImpl> l = new ArrayList<>(); for (EdgeDraftImpl e : edgeList) { if (e != null && e.isSelfLoop()) { l.add(e); } } for (EdgeDraftImpl e : l) { removeEdge(e); } } if (directedEdgesCount > 0 && edgeDefault.equals(EdgeDirectionDefault.UNDIRECTED)) { //Force undirected for (EdgeDraftImpl edge : edgeList.toArray(new EdgeDraftImpl[0])) { if (edge != null && edge.getDirection().equals(EdgeDirection.DIRECTED)) { EdgeDraftImpl opposite = getOpposite(edge); if (opposite != null) { int oppositeIndex = edgeMap.getInt(opposite.getId()); mergeDirectedEdges(opposite, edge); edgeMap.removeInt(opposite.getId()); edgeList.set(oppositeIndex, null); } } } } //TODO check when mixed is forced //Clean autoNode if (!allowAutoNode()) { for (NodeDraftImpl node : nodeList) { if (node != null && node.isCreatedAuto()) { int index = nodeMap.removeInt(node.getId()); nodeList.set(index, null); } } for (EdgeDraftImpl edge : edgeList) { if (edge != null && (edge.getSource().isCreatedAuto() || edge.getTarget().isCreatedAuto())) { int index = edgeMap.remove(edge.getId()); edgeList.set(index, null); } } } //Sort nodes by height if (parameters.isSortNodesBySize()) { Collections.sort(nodeList, new Comparator<NodeDraftImpl>() { @Override public int compare(NodeDraftImpl o1, NodeDraftImpl o2) { return new Float(o2 != null ? o2.getSize() : 0f).compareTo(o1 != null ? o1.getSize() : 0f); } }); } //Set id as label for nodes that miss label if (parameters.isFillLabelWithId()) { for (NodeDraftImpl node : nodeList) { if (node != null && node.getLabel() == null) { node.setLabel(node.getId()); } } } //Set random position boolean customPosition = false; for (NodeDraftImpl node : nodeList) { if (node != null) { if (Float.isNaN(node.getX())) { node.setX(0); } if (Float.isNaN(node.getY())) { node.setY(0); } if (Float.isNaN(node.getZ())) { node.setZ(0); } if (node.getX() != 0f || node.getY() != 0f) { customPosition = true; } } } if (!customPosition) { for (NodeDraftImpl node : nodeList) { if (node != null) { node.setX((float) ((0.01 + Math.random()) * 1000) - 500); node.setY((float) ((0.01 + Math.random()) * 1000) - 500); } } } //MANAGEMENT } protected void mergeDirectedEdges(EdgeDraftImpl source, EdgeDraftImpl dest) { EdgeMergeStrategy mergeStrategy = parameters.getEdgesMergeStrategy(); double result = dest.getWeight(); switch (mergeStrategy) { case AVG: result = (source.getWeight() + dest.getWeight()) / 2.0; break; case MAX: result = Math.max(source.getWeight(), dest.getWeight()); break; case MIN: result = Math.min(source.getWeight(), dest.getWeight()); break; case SUM: result = source.getWeight() + dest.getWeight(); break; case FIRST: result = dest.getWeight(); break; case LAST: result = source.getWeight(); break; default: break; } dest.setWeight(result); } @Override public boolean isDynamicGraph() { return dynamicGraph; } @Override public boolean hasDynamicAttributes() { return dynamicAttributes; } //REPORT @Override public Report getReport() { return report; } @Override public void setReport(Report report) { this.report = report; } //PARAMS GETTER @Override public boolean allowAutoNode() { return parameters.isAutoNode(); } @Override public boolean allowParallelEdges() { return parameters.isParallelEdges(); } @Override public boolean allowSelfLoop() { return parameters.isSelfLoops(); } @Override public boolean isFillLabelWithId() { return parameters.isFillLabelWithId(); } @Override public EdgeMergeStrategy getEdgesMergeStrategy() { return parameters.getEdgesMergeStrategy(); } @Override public EdgeDirectionDefault getEdgeDefault() { return edgeDefault; } @Override public boolean isMultiGraph() { return edgeTypeMap.size() > 1; } @Override public boolean hasSelfLoops() { return selfLoops > 0; } //PARAMS @Override public void setAllowAutoNode(boolean value) { parameters.setAutoNode(value); } @Override public void setAllowParallelEdge(boolean value) { parameters.setParallelEdges(value); } @Override public void setAllowSelfLoop(boolean value) { parameters.setSelfLoops(value); } @Override public void setFillLabelWithId(boolean value) { parameters.setFillLabelWithId(value); } @Override public void setEdgeDefault(EdgeDirectionDefault edgeDefault) { if (this.edgeDefault != edgeDefault) { this.edgeDefault = edgeDefault; report.log(NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerException_Set_EdgeDefault", edgeDefault.toString())); } } @Override public boolean isAutoScale() { return parameters.isAutoScale(); } @Override public void setAutoScale(boolean autoscale) { parameters.setAutoScale(autoscale); } @Override public void setEdgesMergeStrategy(EdgeMergeStrategy edgesMergeStrategy) { parameters.setEdgesMergeStrategy(edgesMergeStrategy); } @Override public Class getEdgeTypeLabelClass() { return lastEdgeType; } //Utility private int getEdgeType(Object type) { //Verify if (type != null) { Class cl = type.getClass(); if (!(cl.equals(Integer.class) || cl.equals(String.class) || cl.equals(Float.class) || cl.equals(Double.class) || cl.equals(Short.class) || cl.equals(Byte.class) || cl.equals(Long.class) || cl.equals(Character.class) || cl.equals(Boolean.class))) { report.logIssue(new Issue(NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerException_Unsupported_Edge_type"), Level.SEVERE)); type = null; } if (type != null && lastEdgeType != null && !lastEdgeType.equals(type.getClass())) { report.logIssue(new Issue(NbBundle.getMessage(ImportContainerImpl.class, "ImportContainerException_Unsupported_Edge_type_Conflict", type.getClass().getSimpleName(), lastEdgeType.getSimpleName()), Level.SEVERE)); type = null; } } if (type != null) { lastEdgeType = type.getClass(); } if (edgeTypeMap.containsKey(type)) { return edgeTypeMap.getInt(type); } int id = edgeTypeMap.size(); edgeTypeMap.put(type, id); return id; } private void ensureLongSetArraySize(int type) { if (edgeTypeSets.length <= type) { Long2ObjectMap[] l = new Long2ObjectMap[type + 1]; System.arraycopy(edgeTypeSets, 0, l, 0, edgeTypeSets.length); edgeTypeSets = l; edgeTypeSets[type] = new Long2ObjectOpenHashMap<>(); } } private long getLongId(EdgeDraftImpl edge) { EdgeDirection direction = edge.getDirection(); boolean directed = edgeDefault.equals(EdgeDirectionDefault.DIRECTED) || (edgeDefault.equals(EdgeDirectionDefault.MIXED) && direction != EdgeDirection.UNDIRECTED); return getLongId(edge.getSource(), edge.getTarget(), directed); } private long getLongId(NodeDraftImpl source, NodeDraftImpl target, boolean directed) { if (directed) { long edgeId = ((long) source.hashCode()) << 32; edgeId = edgeId | (long) (target.hashCode()); return edgeId; } else { long edgeId = ((long) (source.hashCode() > target.hashCode() ? source.hashCode() : target.hashCode())) << 32; edgeId = edgeId | (long) (source.hashCode() > target.hashCode() ? target.hashCode() : source.hashCode()); return edgeId; } } private EdgeDraftImpl getOpposite(EdgeDraftImpl edge) { Long2ObjectMap<int[]> typeSet = edgeTypeSets[getEdgeType(edge.getType())]; long longId = getLongId(edge.getTarget(), edge.getSource(), true); int[] opposites = typeSet.get(longId); if (opposites != null && opposites.length > 0) { return edgeList.get(opposites[0]); } return null; } private void checkElementDraftImpl(ElementDraft elmt) { if (elmt == null) { throw new NullPointerException(); } if (!(elmt instanceof ElementDraftImpl)) { throw new ClassCastException(); } } private void checkId(String id) { if (id == null) { throw new NullPointerException(); } if (id.trim().isEmpty()) { throw new IllegalArgumentException("The id can't be empty"); } } //UTILITY ITERATOR private static class NullFilterIterable<T extends ElementDraft> implements Iterable<T> { private final Collection<T> collection; public NullFilterIterable(Collection elementCollection) { this.collection = elementCollection; } @Override public Iterator<T> iterator() { return new NullFilterIterator<>(collection); } } private static class NullFilterIterator<T extends ElementDraft> implements Iterator<T> { private T pointer; private final Iterator<T> itr; public NullFilterIterator(Collection<T> elementCollection) { this.itr = elementCollection.iterator(); } @Override public boolean hasNext() { while (itr.hasNext()) { pointer = itr.next(); if (pointer != null) { return true; } } return false; } @Override public T next() { return pointer; } @Override public void remove() { throw new UnsupportedOperationException("Not supported."); } } }