001/* 002 * Copyright 2006 - 2013 003 * Stefan Balev <stefan.balev@graphstream-project.org> 004 * Julien Baudry <julien.baudry@graphstream-project.org> 005 * Antoine Dutot <antoine.dutot@graphstream-project.org> 006 * Yoann Pigné <yoann.pigne@graphstream-project.org> 007 * Guilhelm Savin <guilhelm.savin@graphstream-project.org> 008 * 009 * This file is part of GraphStream <http://graphstream-project.org>. 010 * 011 * GraphStream is a library whose purpose is to handle static or dynamic 012 * graph, create them from scratch, file or any source and display them. 013 * 014 * This program is free software distributed under the terms of two licenses, the 015 * CeCILL-C license that fits European law, and the GNU Lesser General Public 016 * License. You can use, modify and/ or redistribute the software under the terms 017 * of the CeCILL-C license as circulated by CEA, CNRS and INRIA at the following 018 * URL <http://www.cecill.info> or under the terms of the GNU LGPL as published by 019 * the Free Software Foundation, either version 3 of the License, or (at your 020 * option) any later version. 021 * 022 * This program is distributed in the hope that it will be useful, but WITHOUT ANY 023 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 024 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 025 * 026 * You should have received a copy of the GNU Lesser General Public License 027 * along with this program. If not, see <http://www.gnu.org/licenses/>. 028 * 029 * The fact that you are presently reading this means that you have had 030 * knowledge of the CeCILL-C and LGPL licenses and that you accept their terms. 031 */ 032package org.graphstream.stream.file; 033 034import java.awt.Color; 035import java.io.IOException; 036import java.io.PrintWriter; 037import java.lang.reflect.Array; 038import java.util.HashMap; 039import java.util.Locale; 040 041import org.graphstream.graph.CompoundAttribute; 042 043/** 044 * File output for the DGS (Dynamic Graph Stream) file format. 045 */ 046public class FileSinkDGS extends FileSinkBase { 047 // Attribute 048 049 /** 050 * A shortcut to the output. 051 */ 052 protected PrintWriter out; 053 054 protected String graphName = ""; 055 056 // Command 057 058 @Override 059 protected void outputHeader() throws IOException { 060 out = (PrintWriter) output; 061 062 out.printf("DGS004%n"); 063 064 if (graphName.length() <= 0) 065 out.printf("null 0 0%n"); 066 else 067 out.printf("\"%s\" 0 0%n", formatStringForQuoting(graphName)); 068 } 069 070 @Override 071 protected void outputEndOfFile() throws IOException { 072 // NOP 073 } 074 075 public void edgeAttributeAdded(String graphId, long timeId, String edgeId, 076 String attribute, Object value) { 077 edgeAttributeChanged(graphId, timeId, edgeId, attribute, null, value); 078 } 079 080 public void edgeAttributeChanged(String graphId, long timeId, 081 String edgeId, String attribute, Object oldValue, Object newValue) { 082 out.printf("ce \"%s\" %s%n", formatStringForQuoting(edgeId), 083 attributeString(attribute, newValue, false)); 084 } 085 086 public void edgeAttributeRemoved(String graphId, long timeId, 087 String edgeId, String attribute) { 088 out.printf("ce \"%s\" %s%n", formatStringForQuoting(edgeId), 089 attributeString(attribute, null, true)); 090 } 091 092 public void graphAttributeAdded(String graphId, long timeId, 093 String attribute, Object value) { 094 graphAttributeChanged(graphId, timeId, attribute, null, value); 095 } 096 097 public void graphAttributeChanged(String graphId, long timeId, 098 String attribute, Object oldValue, Object newValue) { 099 out.printf("cg %s%n", attributeString(attribute, newValue, false)); 100 } 101 102 public void graphAttributeRemoved(String graphId, long timeId, 103 String attribute) { 104 out.printf("cg %s%n", attributeString(attribute, null, true)); 105 } 106 107 public void nodeAttributeAdded(String graphId, long timeId, String nodeId, 108 String attribute, Object value) { 109 nodeAttributeChanged(graphId, timeId, nodeId, attribute, null, value); 110 } 111 112 public void nodeAttributeChanged(String graphId, long timeId, 113 String nodeId, String attribute, Object oldValue, Object newValue) { 114 out.printf("cn \"%s\" %s%n", formatStringForQuoting(nodeId), 115 attributeString(attribute, newValue, false)); 116 } 117 118 public void nodeAttributeRemoved(String graphId, long timeId, 119 String nodeId, String attribute) { 120 out.printf("cn \"%s\" %s%n", formatStringForQuoting(nodeId), 121 attributeString(attribute, null, true)); 122 } 123 124 public void edgeAdded(String graphId, long timeId, String edgeId, 125 String fromNodeId, String toNodeId, boolean directed) { 126 edgeId = formatStringForQuoting(edgeId); 127 fromNodeId = formatStringForQuoting(fromNodeId); 128 toNodeId = formatStringForQuoting(toNodeId); 129 130 out.printf("ae \"%s\" \"%s\" %s \"%s\"%n", edgeId, fromNodeId, 131 directed ? ">" : "", toNodeId); 132 } 133 134 public void edgeRemoved(String graphId, long timeId, String edgeId) { 135 out.printf("de \"%s\"%n", formatStringForQuoting(edgeId)); 136 } 137 138 public void graphCleared(String graphId, long timeId) { 139 out.printf("cl%n"); 140 } 141 142 public void nodeAdded(String graphId, long timeId, String nodeId) { 143 out.printf("an \"%s\"%n", formatStringForQuoting(nodeId)); 144 } 145 146 public void nodeRemoved(String graphId, long timeId, String nodeId) { 147 out.printf("dn \"%s\"%n", formatStringForQuoting(nodeId)); 148 } 149 150 public void stepBegins(String graphId, long timeId, double step) { 151 out.printf(Locale.US, "st %f%n", step); 152 } 153 154 // Utility 155 156 protected String formatStringForQuoting(String str) { 157 return str.replaceAll("(^|[^\\\\])\"", "$1\\\\\""); 158 } 159 160 protected String attributeString(String key, Object value, boolean remove) { 161 if (key == null || key.length() == 0) 162 return null; 163 164 if (remove) { 165 return String.format(" -\"%s\"", key); 166 } else { 167 if (value != null && value.getClass().isArray()) 168 return String.format(" \"%s\":%s", key, arrayString(value)); 169 else 170 return String.format(" \"%s\":%s", key, valueString(value)); 171 } 172 } 173 174 protected String arrayString(Object value) { 175 if (value != null && value.getClass().isArray()) { 176 StringBuilder sb = new StringBuilder(); 177 sb.append("{"); 178 179 if (Array.getLength(value) == 0) 180 sb.append("\"\""); 181 else 182 sb.append(arrayString(Array.get(value, 0))); 183 184 for (int i = 1; i < Array.getLength(value); ++i) 185 sb.append(String 186 .format(",%s", arrayString(Array.get(value, i)))); 187 188 sb.append("}"); 189 return sb.toString(); 190 } else { 191 return valueString(value); 192 } 193 } 194 195 protected String valueString(Object value) { 196 if (value == null) 197 return "\"\""; 198 199 if (value instanceof CharSequence) { 200 if (value instanceof String) 201 return String.format("\"%s\"", 202 formatStringForQuoting((String) value)); 203 else 204 return String.format("\"%s\"", (CharSequence) value); 205 } else if (value instanceof Number) { 206 Number nval = (Number) value; 207 208 if (value instanceof Integer || value instanceof Short 209 || value instanceof Byte || value instanceof Long) 210 return String.format(Locale.US, "%d", nval.longValue()); 211 else 212 return String.format(Locale.US, "%f", nval.doubleValue()); 213 } else if (value instanceof Boolean) { 214 return String.format(Locale.US, "%b", ((Boolean) value)); 215 } else if (value instanceof Character) { 216 return String.format("\"%c\"", ((Character) value).charValue()); 217 } else if (value instanceof Object[]) { 218 Object array[] = (Object[]) value; 219 int n = array.length; 220 StringBuffer sb = new StringBuffer(); 221 222 if (array.length > 0) 223 sb.append(valueString(array[0])); 224 225 for (int i = 1; i < n; i++) { 226 sb.append(","); 227 sb.append(valueString(array[i])); 228 } 229 230 return sb.toString(); 231 } else if (value instanceof HashMap<?, ?> 232 || value instanceof CompoundAttribute) { 233 HashMap<?, ?> hash; 234 235 if (value instanceof CompoundAttribute) 236 hash = ((CompoundAttribute) value).toHashMap(); 237 else 238 hash = (HashMap<?, ?>) value; 239 240 return hashToString(hash); 241 } else if (value instanceof Color) { 242 Color c = (Color) value; 243 return String.format("#%02X%02X%02X%02X", c.getRed(), c.getGreen(), 244 c.getBlue(), c.getAlpha()); 245 } else { 246 return String.format("\"%s\"", value.toString()); 247 } 248 } 249 250 protected String hashToString(HashMap<?, ?> hash) { 251 StringBuilder sb = new StringBuilder(); 252 253 sb.append("[ "); 254 255 for (Object key : hash.keySet()) { 256 sb.append(attributeString(key.toString(), hash.get(key), false)); 257 sb.append(","); 258 } 259 260 sb.append(']'); 261 262 return sb.toString(); 263 } 264}