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; 033 034import org.graphstream.stream.SourceBase.ElementType; 035 036import java.lang.annotation.Documented; 037import java.lang.annotation.Retention; 038import java.lang.annotation.RetentionPolicy; 039import java.lang.annotation.Target; 040import java.lang.reflect.InvocationTargetException; 041import java.lang.reflect.Method; 042import java.util.EnumMap; 043import java.util.HashMap; 044 045/** 046 * A sink easily allowing a bind between attribute modifications and method 047 * calls. 048 * 049 * <pre> 050 * public class MyObject extends AnnotatedSink { 051 * String a1; 052 * double a2; 053 * 054 * @Bind("myobject.set.a1") 055 * public void setA1(String eventId, Object value) { 056 * a1 = (String) value; 057 * } 058 * 059 * @Bind("myobject.set.a2") 060 * public void setA2(String eventId, Object value) { 061 * a2 = (Double) value; 062 * } 063 * 064 * public static void main(String ... args) { 065 * Graph g = ...; 066 * MyObject obj = new MyObject(); 067 * 068 * g.addSink(obj); 069 * 070 * g.addAttribute("myobject.set.a1", "MyObject A1"); 071 * g.addAttribute("myobject.set.a2", 100.0); 072 * } 073 * } 074 * </pre> 075 */ 076public abstract class AnnotatedSink implements Sink { 077 /** 078 * Annotation used to bind an event to a method. This bind is composed of a 079 * name (the attribute key) and an element type. For example, the annotation 080 * 081 * <pre> 082 * @Bind(value = "test", type = ElementType.NODE) 083 * </pre> 084 * 085 * will be triggered the annotated method when receiving 086 * 'nodeAttributeXXX()' methods. 087 */ 088 @Documented 089 @Retention(RetentionPolicy.RUNTIME) 090 @Target(java.lang.annotation.ElementType.METHOD) 091 public static @interface Bind { 092 /** 093 * Name of the attribute key that triggered the annotated method. 094 * 095 * @return an attribute key 096 */ 097 String value(); 098 099 /** 100 * Type of element that triggered the annotated method. Default is 101 * GRAPH. 102 * 103 * @return type of element in GRAPH, NODE or EDGE 104 */ 105 ElementType type() default ElementType.GRAPH; 106 } 107 108 private final EnumMap<ElementType, MethodMap> methods; 109 110 protected AnnotatedSink() { 111 methods = new EnumMap<ElementType, MethodMap>(ElementType.class); 112 methods.put(ElementType.GRAPH, new MethodMap()); 113 methods.put(ElementType.EDGE, new MethodMap()); 114 methods.put(ElementType.NODE, new MethodMap()); 115 116 Method[] ms = getClass().getMethods(); 117 118 if (ms != null) { 119 for (int i = 0; i < ms.length; i++) { 120 Method m = ms[i]; 121 Bind b = m.getAnnotation(Bind.class); 122 123 if (b != null) 124 methods.get(b.type()).put(b.value(), m); 125 } 126 } 127 } 128 129 private void invoke(Method m, Object... args) { 130 try { 131 m.invoke(this, args); 132 } catch (IllegalArgumentException e) { 133 e.printStackTrace(); 134 } catch (IllegalAccessException e) { 135 e.printStackTrace(); 136 } catch (InvocationTargetException e) { 137 e.printStackTrace(); 138 } 139 } 140 141 /* 142 * (non-Javadoc) 143 * @see org.graphstream.stream.AttributeSink#edgeAttributeAdded(java.lang.String, long, java.lang.String, java.lang.String, java.lang.Object) 144 */ 145 public void edgeAttributeAdded(String sourceId, long timeId, String edgeId, 146 String attribute, Object value) { 147 Method m = methods.get(ElementType.EDGE).get(attribute); 148 149 if (m != null) 150 invoke(m, edgeId, attribute, value); 151 } 152 153 /* 154 * (non-Javadoc) 155 * @see org.graphstream.stream.AttributeSink#edgeAttributeChanged(java.lang.String, long, java.lang.String, java.lang.String, java.lang.Object, java.lang.Object) 156 */ 157 public void edgeAttributeChanged(String sourceId, long timeId, 158 String edgeId, String attribute, Object oldValue, Object newValue) { 159 Method m = methods.get(ElementType.EDGE).get(attribute); 160 161 if (m != null) 162 invoke(m, edgeId, attribute, newValue); 163 } 164 165 /* 166 * (non-Javadoc) 167 * @see org.graphstream.stream.AttributeSink#edgeAttributeRemoved(java.lang.String, long, java.lang.String, java.lang.String) 168 */ 169 public void edgeAttributeRemoved(String sourceId, long timeId, 170 String edgeId, String attribute) { 171 Method m = methods.get(ElementType.EDGE).get(attribute); 172 173 if (m != null) 174 invoke(m, edgeId, attribute, null); 175 } 176 177 /* 178 * (non-Javadoc) 179 * @see org.graphstream.stream.AttributeSink#graphAttributeAdded(java.lang.String, long, java.lang.String, java.lang.Object) 180 */ 181 public void graphAttributeAdded(String sourceId, long timeId, 182 String attribute, Object value) { 183 Method m = methods.get(ElementType.GRAPH).get(attribute); 184 185 if (m != null) 186 invoke(m, attribute, value); 187 } 188 189 /* 190 * (non-Javadoc) 191 * @see org.graphstream.stream.AttributeSink#graphAttributeChanged(java.lang.String, long, java.lang.String, java.lang.Object, java.lang.Object) 192 */ 193 public void graphAttributeChanged(String sourceId, long timeId, 194 String attribute, Object oldValue, Object newValue) { 195 Method m = methods.get(ElementType.GRAPH).get(attribute); 196 197 if (m != null) 198 invoke(m, attribute, newValue); 199 } 200 201 /* 202 * (non-Javadoc) 203 * @see org.graphstream.stream.AttributeSink#graphAttributeRemoved(java.lang.String, long, java.lang.String) 204 */ 205 public void graphAttributeRemoved(String sourceId, long timeId, 206 String attribute) { 207 Method m = methods.get(ElementType.GRAPH).get(attribute); 208 209 if (m != null) 210 invoke(m, attribute, null); 211 } 212 213 /* 214 * (non-Javadoc) 215 * @see org.graphstream.stream.AttributeSink#nodeAttributeAdded(java.lang.String, long, java.lang.String, java.lang.String, java.lang.Object) 216 */ 217 public void nodeAttributeAdded(String sourceId, long timeId, String nodeId, 218 String attribute, Object value) { 219 Method m = methods.get(ElementType.NODE).get(attribute); 220 221 if (m != null) 222 invoke(m, nodeId, attribute, value); 223 } 224 225 /* 226 * (non-Javadoc) 227 * @see org.graphstream.stream.AttributeSink#nodeAttributeChanged(java.lang.String, long, java.lang.String, java.lang.String, java.lang.Object, java.lang.Object) 228 */ 229 public void nodeAttributeChanged(String sourceId, long timeId, 230 String nodeId, String attribute, Object oldValue, Object newValue) { 231 Method m = methods.get(ElementType.NODE).get(attribute); 232 233 if (m != null) 234 invoke(m, nodeId, attribute, newValue); 235 } 236 237 /* 238 * (non-Javadoc) 239 * @see org.graphstream.stream.AttributeSink#nodeAttributeRemoved(java.lang.String, long, java.lang.String, java.lang.String) 240 */ 241 public void nodeAttributeRemoved(String sourceId, long timeId, 242 String nodeId, String attribute) { 243 Method m = methods.get(ElementType.NODE).get(attribute); 244 245 if (m != null) 246 invoke(m, nodeId, attribute, null); 247 } 248 249 /* 250 * (non-Javadoc) 251 * @see org.graphstream.stream.ElementSink#edgeAdded(java.lang.String, long, java.lang.String, java.lang.String, java.lang.String, boolean) 252 */ 253 public void edgeAdded(String sourceId, long timeId, String edgeId, 254 String fromNodeId, String toNodeId, boolean directed) { 255 } 256 257 /* 258 * (non-Javadoc) 259 * @see org.graphstream.stream.ElementSink#edgeRemoved(java.lang.String, long, java.lang.String) 260 */ 261 public void edgeRemoved(String sourceId, long timeId, String edgeId) { 262 } 263 264 /* 265 * (non-Javadoc) 266 * @see org.graphstream.stream.ElementSink#graphCleared(java.lang.String, long) 267 */ 268 public void graphCleared(String sourceId, long timeId) { 269 } 270 271 /* 272 * (non-Javadoc) 273 * @see org.graphstream.stream.ElementSink#nodeAdded(java.lang.String, long, java.lang.String) 274 */ 275 public void nodeAdded(String sourceId, long timeId, String nodeId) { 276 } 277 278 /* 279 * (non-Javadoc) 280 * @see org.graphstream.stream.ElementSink#nodeRemoved(java.lang.String, long, java.lang.String) 281 */ 282 public void nodeRemoved(String sourceId, long timeId, String nodeId) { 283 } 284 285 /* 286 * (non-Javadoc) 287 * @see org.graphstream.stream.ElementSink#stepBegins(java.lang.String, long, double) 288 */ 289 public void stepBegins(String sourceId, long timeId, double step) { 290 } 291 292 private static class MethodMap extends HashMap<String, Method> { 293 private static final long serialVersionUID = 1664854698109523697L; 294 } 295}