View Javadoc

1   /*
2   
3       dsh-graph-io  Directed graph readers and writers.
4       Copyright (c) 2008-2013 held jointly by the individual authors.
5   
6       This library is free software; you can redistribute it and/or modify it
7       under the terms of the GNU Lesser General Public License as published
8       by the Free Software Foundation; either version 3 of the License, or (at
9       your option) any later version.
10  
11      This library is distributed in the hope that it will be useful, but WITHOUT
12      ANY WARRANTY; with out even the implied warranty of MERCHANTABILITY or
13      FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14      License for more details.
15  
16      You should have received a copy of the GNU Lesser General Public License
17      along with this library;  if not, write to the Free Software Foundation,
18      Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA.
19  
20      > http://www.fsf.org/licensing/licenses/lgpl.html
21      > http://www.opensource.org/licenses/lgpl-license.php
22  
23  */
24  package org.dishevelled.graph.io.ygraphml;
25  
26  import java.io.File;
27  import java.io.InputStream;
28  import java.io.IOException;
29  
30  import java.net.URL;
31  
32  import javax.xml.parsers.SAXParserFactory;
33  import javax.xml.parsers.ParserConfigurationException;
34  
35  import net.sf.stax.StAXContentHandlerBase;
36  import net.sf.stax.StAXContext;
37  import net.sf.stax.StAXDelegationContext;
38  import net.sf.stax.StringElementHandler;
39  
40  import org.xml.sax.XMLReader;
41  import org.xml.sax.Attributes;
42  import org.xml.sax.SAXException;
43  
44  import org.dishevelled.graph.Graph;
45  
46  import org.dishevelled.graph.io.GraphReader;
47  
48  import org.dishevelled.graph.io.graphml.GraphMLReader;
49  
50  /**
51   * Graph reader for the yFiles extension to GraphML.  The XML schema is
52   * <a href="http://www.yworks.com/xml/schema/graphml/1.0/ygraphml.xsd">
53   * http://www.yworks.com/xml/schema/graphml/1.0/ygraphml.xsd</a>.
54   *
55   * @author  Michael Heuer
56   * @version $Revision$ $Date$
57   */
58  public final class YGraphMLReader
59      implements GraphReader<ShapeNode, PolyLineEdge>
60  {
61      /** GraphML reader to delegate to. */
62      private final GraphMLReader<ShapeNode, PolyLineEdge> reader;
63  
64  
65      /**
66       * Create a new YGraphML reader.
67       */
68      public YGraphMLReader()
69      {
70          XMLReader xmlReader = null;
71          try
72          {
73              xmlReader = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
74          }
75          catch (SAXException e)
76          {
77              // ...
78          }
79          catch (ParserConfigurationException e)
80          {
81              // ...
82          }
83          reader = new GraphMLReader<ShapeNode, PolyLineEdge>(xmlReader);
84          reader.setNodeValueHandler(new ShapeNodeHandler());
85          reader.setEdgeValueHandler(new PolyLineEdgeHandler());
86      }
87  
88  
89      /** {@inheritDoc} */
90      public Graph<ShapeNode, PolyLineEdge> read(final File file)
91          throws IOException
92      {
93          return reader.read(file);
94      }
95  
96      /** {@inheritDoc} */
97      public Graph<ShapeNode, PolyLineEdge> read(final InputStream inputStream)
98          throws IOException
99      {
100         return reader.read(inputStream);
101     }
102 
103     /** {@inheritDoc} */
104     public Graph<ShapeNode, PolyLineEdge> read(final URL url)
105         throws IOException
106     {
107         return reader.read(url);
108     }
109 
110     /**
111      * <code>&lt;y:ShapeNode&gt;</code> element handler.
112      */
113     private class ShapeNodeHandler
114         extends StAXContentHandlerBase
115     {
116         /** Fill. */
117         private Fill fill;
118 
119         /** Node label. */
120         private NodeLabel nodeLabel;
121 
122         /** Border style. */
123         private BorderStyle borderStyle;
124 
125         /** Shape. */
126         private Shape shape;
127 
128         /** Fill handler. */
129         private final FillHandler fillHandler = new FillHandler();
130 
131         /** Node label handler. */
132         private final NodeLabelHandler nodeLabelHandler = new NodeLabelHandler();
133 
134         /** Border style handler. */
135         private final BorderStyleHandler borderStyleHandler = new BorderStyleHandler();
136 
137         /** Shape handler. */
138         private final ShapeHandler shapeHandler = new ShapeHandler();
139 
140 
141         /** {@inheritDoc} */
142         public void startElement(final String nsURI,
143                                  final String localName,
144                                  final String qName,
145                                  final Attributes attrs,
146                                  final StAXDelegationContext dctx)
147             throws SAXException
148         {
149             // TODO:  this doesn't seem right, nsURI & localName should be populated
150             //    maybe namespace resolution isn't turned on in the default SAX parser?
151             if ("y:Fill".equals(qName))
152             {
153                 dctx.delegate(fillHandler);
154             }
155             else if ("y:NodeLabel".equals(qName))
156             {
157                 dctx.delegate(nodeLabelHandler);
158             }
159             else if ("y:BorderStyle".equals(qName))
160             {
161                 dctx.delegate(borderStyleHandler);
162             }
163             else if ("y:Shape".equals(qName))
164             {
165                 dctx.delegate(shapeHandler);
166             }
167         }
168 
169         /** {@inheritDoc} */
170         public void endElement(final String nsURI,
171                                final String localName,
172                                final String qName,
173                                final Object result,
174                                final StAXContext context)
175             throws SAXException
176         {
177             if ("y:Fill".equals(qName))
178             {
179                 fill = (Fill) result;
180             }
181             else if ("y:NodeLabel".equals(qName))
182             {
183                 nodeLabel = (NodeLabel) result;
184             }
185             else if ("y:BorderStyle".equals(qName))
186             {
187                 borderStyle = (BorderStyle) result;
188             }
189             else if ("y:Shape".equals(qName))
190             {
191                 shape = (Shape) result;
192             }
193         }
194 
195         /** {@inheritDoc} */
196         public Object endTree(final StAXContext context)
197             throws SAXException
198         {
199             return new ShapeNode(fill, nodeLabel, borderStyle, shape);
200         }
201 
202         /**
203          * <code>&lt;y:BorderStyle&gt;</code> element handler.
204          */
205         private class FillHandler
206             extends StAXContentHandlerBase
207         {
208             /** Color attribute. */
209             private String color;
210 
211             /** Transparent attribute. */
212             private boolean transparent;
213 
214 
215             /** {@inheritDoc} */
216             public void startElement(final String nsURI,
217                                      final String localName,
218                                      final String qName,
219                                      final Attributes attrs,
220                                      final StAXDelegationContext dctx)
221                 throws SAXException
222             {
223                 if ("y:Fill".equals(qName))
224                 {
225                     color = attrs.getValue("color");
226                     transparent = "true".equals(attrs.getValue("transparent"));
227                 }
228             }
229 
230             /** {@inheritDoc} */
231             public Object endTree(final StAXContext context)
232                 throws SAXException
233             {
234                 return new Fill(color, transparent);
235             }
236         }
237 
238         /**
239          * <code>&lt;y:BorderStyle&gt;</code> element handler.
240          */
241         private class NodeLabelHandler
242             extends StAXContentHandlerBase
243         {
244             /** Visible attribute. */
245             private boolean visible;
246 
247             /** Alignment attribute. */
248             private String alignment;
249 
250             /** Font family attribute. */
251             private String fontFamily;
252 
253             /** Font size attribute. */
254             private int fontSize;
255 
256             /** Font style attribute. */
257             private String fontStyle;
258 
259             /** Text color attribute. */
260             private String textColor;
261 
262             /** Model name attribute. */
263             private String modelName;
264 
265             /** Model position attribute. */
266             private String modelPosition;
267 
268             /** Auto size policy attribute. */
269             private String autoSizePolicy;
270 
271             /** Nested text element. */
272             private String text;
273 
274             /** Text handler. */
275             private StringElementHandler textHandler = new StringElementHandler();
276 
277 
278             /** {@inheritDoc} */
279             public void startElement(final String nsURI,
280                                      final String localName,
281                                      final String qName,
282                                      final Attributes attrs,
283                                      final StAXDelegationContext dctx)
284                 throws SAXException
285             {
286                 if ("y:NodeLabel".equals(qName))
287                 {
288                     visible = "true".equals(attrs.getValue("visible"));
289                     alignment = attrs.getValue("alignment");
290                     fontFamily = attrs.getValue("fontFamily");
291                     fontSize = Integer.valueOf(attrs.getValue("fontSize"));
292                     fontStyle = attrs.getValue("fontStyle");
293                     textColor = attrs.getValue("textColor");
294                     modelName = attrs.getValue("modelName");
295                     modelPosition = attrs.getValue("modelPosition");
296                     autoSizePolicy = attrs.getValue("autoSizePolicy");
297                     dctx.delegate(textHandler);
298                 }
299             }
300 
301             /** {@inheritDoc} */
302             public void endElement(final String nsURI,
303                                    final String localName,
304                                    final String qName,
305                                    final Object result,
306                                    final StAXContext context)
307                 throws SAXException
308             {
309                 if ("y:NodeLabel".equals(qName))
310                 {
311                     text = (String) result;
312                 }
313             }
314 
315             /** {@inheritDoc} */
316             public Object endTree(final StAXContext context)
317                 throws SAXException
318             {
319                 return new NodeLabel(visible, alignment, fontFamily, fontSize, fontStyle, textColor,
320                                      modelName, modelPosition, autoSizePolicy, text);
321             }
322         }
323 
324         /**
325          * <code>&lt;y:BorderStyle&gt;</code> element handler.
326          */
327         private class BorderStyleHandler
328             extends StAXContentHandlerBase
329         {
330             /** Type attribute. */
331             private String type;
332 
333             /** Width attribute. */
334             private double width;
335 
336             /** Color attribute. */
337             private String color;
338 
339 
340             /** {@inheritDoc} */
341             public void startElement(final String nsURI,
342                                      final String localName,
343                                      final String qName,
344                                      final Attributes attrs,
345                                      final StAXDelegationContext dctx)
346                 throws SAXException
347             {
348                 if ("y:BorderStyle".equals(qName))
349                 {
350                     type = attrs.getValue("type");
351                     width = Double.valueOf(attrs.getValue("width"));
352                     color = attrs.getValue("color");
353                 }
354             }
355 
356             /** {@inheritDoc} */
357             public Object endTree(final StAXContext context)
358                 throws SAXException
359             {
360                 return new BorderStyle(type, width, color);
361             }
362         }
363 
364         /**
365          * <code>&lt;y:Shape&gt;</code> element handler.
366          */
367         private class ShapeHandler
368             extends StAXContentHandlerBase
369         {
370             /** Type attribute. */
371             private String type;
372 
373 
374             /** {@inheritDoc} */
375             public void startElement(final String nsURI,
376                                      final String localName,
377                                      final String qName,
378                                      final Attributes attrs,
379                                      final StAXDelegationContext dctx)
380                 throws SAXException
381             {
382                 if ("y:Shape".equals(qName))
383                 {
384                     type = attrs.getValue("type");
385                 }
386             }
387 
388             /** {@inheritDoc} */
389             public Object endTree(final StAXContext context)
390                 throws SAXException
391             {
392                 return new Shape(type);
393             }
394         }
395     }
396 
397     /**
398      * <code>&lt;y:PolyLineEdge&gt;</code> element handler.
399      */
400     private class PolyLineEdgeHandler
401         extends StAXContentHandlerBase
402     {
403         /** Line style. */
404         private LineStyle lineStyle;
405 
406         /** Arrows. */
407         private Arrows arrows;
408 
409         /** Edge label. */
410         private EdgeLabel edgeLabel;
411 
412         /** Bend style. */
413         private BendStyle bendStyle;
414 
415         /** Line style handler. */
416         private final LineStyleHandler lineStyleHandler = new LineStyleHandler();
417 
418         /** Arrows handler. */
419         private final ArrowsHandler arrowsHandler = new ArrowsHandler();
420 
421         /** Edge label handler. */
422         private final EdgeLabelHandler edgeLabelHandler = new EdgeLabelHandler();
423 
424         /** Bend style handler. */
425         private final BendStyleHandler bendStyleHandler = new BendStyleHandler();
426 
427 
428         /** {@inheritDoc} */
429         public void startElement(final String nsURI,
430                                  final String localName,
431                                  final String qName,
432                                  final Attributes attrs,
433                                  final StAXDelegationContext dctx)
434             throws SAXException
435         {
436             if ("y:LineStyle".equals(qName))
437             {
438                 dctx.delegate(lineStyleHandler);
439             }
440             else if ("y:Arrows".equals(qName))
441             {
442                 dctx.delegate(arrowsHandler);
443             }
444             else if ("y:EdgeLabel".equals(qName))
445             {
446                 dctx.delegate(edgeLabelHandler);
447             }
448             else if ("y:BendStyle".equals(qName))
449             {
450                 dctx.delegate(bendStyleHandler);
451             }
452         }
453 
454         /** {@inheritDoc} */
455         public void endElement(final String nsURI,
456                                final String localName,
457                                final String qName,
458                                final Object result,
459                                final StAXContext context)
460             throws SAXException
461         {
462             if ("y:LineStyle".equals(qName))
463             {
464                 lineStyle = (LineStyle) result;
465             }
466             else if ("y:Arrows".equals(qName))
467             {
468                 arrows = (Arrows) result;
469             }
470             else if ("y:EdgeLabel".equals(qName))
471             {
472                 edgeLabel = (EdgeLabel) result;
473             }
474             else if ("y:BendStyle".equals(qName))
475             {
476                 bendStyle = (BendStyle) result;
477             }
478         }
479 
480         /** {@inheritDoc} */
481         public Object endTree(final StAXContext context)
482             throws SAXException
483         {
484             return new PolyLineEdge(lineStyle, arrows, edgeLabel, bendStyle);
485         }
486 
487         /**
488          * <code>&lt;y:LineStyle&gt;</code> element handler.
489          */
490         private class LineStyleHandler
491             extends StAXContentHandlerBase
492         {
493             /** Type attribute. */
494             private String type;
495 
496             /** Width attribute. */
497             private double width;
498 
499             /** Color attribute. */
500             private String color;
501 
502 
503             /** {@inheritDoc} */
504             public void startElement(final String nsURI,
505                                      final String localName,
506                                      final String qName,
507                                      final Attributes attrs,
508                                      final StAXDelegationContext dctx)
509                 throws SAXException
510             {
511                 if ("y:LineStyle".equals(qName))
512                 {
513                     type = attrs.getValue("type");
514                     width = Double.valueOf(attrs.getValue("width"));
515                     color = attrs.getValue("color");
516                 }
517             }
518 
519             /** {@inheritDoc} */
520             public Object endTree(final StAXContext context)
521                 throws SAXException
522             {
523                 return new LineStyle(type, width, color);
524             }
525         }
526 
527         /**
528          * <code>&lt;y:Arrows&gt;</code> element handler.
529          */
530         private class ArrowsHandler
531             extends StAXContentHandlerBase
532         {
533             /** Source attribute. */
534             private String source;
535 
536             /** Target attribute. */
537             private String target;
538 
539 
540             /** {@inheritDoc} */
541             public void startElement(final String nsURI,
542                                      final String localName,
543                                      final String qName,
544                                      final Attributes attrs,
545                                      final StAXDelegationContext dctx)
546                 throws SAXException
547             {
548                 if ("y:Arrows".equals(qName))
549                 {
550                     source = attrs.getValue("source");
551                     target = attrs.getValue("target");
552                 }
553             }
554 
555             /** {@inheritDoc} */
556             public Object endTree(final StAXContext context)
557                 throws SAXException
558             {
559                 return new Arrows(source, target);
560             }
561         }
562 
563         /**
564          * <code>&lt;y:EdgeLabel&gt;</code> element handler.
565          */
566         private class EdgeLabelHandler
567             extends StAXContentHandlerBase
568         {
569             /** Visible attribute. */
570             private boolean visible;
571 
572             /** Alignment attribute. */
573             private String alignment;
574 
575             /** Font family attribute. */
576             private String fontFamily;
577 
578             /** Font size attribute. */
579             private int fontSize;
580 
581             /** Font style attribute. */
582             private String fontStyle;
583 
584             /** Text color attribute. */
585             private String textColor;
586 
587             /** Model name attribute. */
588             private String modelName;
589 
590             /** Model position attribute. */
591             private String modelPosition;
592 
593             /** Preferred placement attribute. */
594             private String preferredPlacement;
595 
596             /** Distance attribute. */
597             private double distance;
598 
599             /** Ratio attribute. */
600             private double ratio;
601 
602             /** Nested text element. */
603             private String text;
604 
605             /** Text handler. */
606             private StringElementHandler textHandler = new StringElementHandler();
607 
608 
609             /** {@inheritDoc} */
610             public void startElement(final String nsURI,
611                                      final String localName,
612                                      final String qName,
613                                      final Attributes attrs,
614                                      final StAXDelegationContext dctx)
615                 throws SAXException
616             {
617                 if ("y:EdgeLabel".equals(qName))
618                 {
619                     visible = "true".equals(attrs.getValue("visible"));
620                     alignment = attrs.getValue("alignment");
621                     fontFamily = attrs.getValue("fontFamily");
622                     fontSize = Integer.valueOf(attrs.getValue("fontSize"));
623                     fontStyle = attrs.getValue("fontStyle");
624                     textColor = attrs.getValue("textColor");
625                     modelName = attrs.getValue("modelName");
626                     modelPosition = attrs.getValue("modelPosition");
627                     preferredPlacement = attrs.getValue("preferredPlacement");
628                     distance = Double.valueOf(attrs.getValue("distance"));
629                     ratio = Double.valueOf(attrs.getValue("ratio"));
630                     dctx.delegate(textHandler);
631                 }
632             }
633 
634             /** {@inheritDoc} */
635             public void endElement(final String nsURI,
636                                    final String localName,
637                                    final String qName,
638                                    final Object result,
639                                    final StAXContext context)
640                 throws SAXException
641             {
642                 if ("y:EdgeLabel".equals(qName))
643                 {
644                     text = (String) result;
645                 }
646             }
647 
648             /** {@inheritDoc} */
649             public Object endTree(final StAXContext context)
650                 throws SAXException
651             {
652                 return new EdgeLabel(visible, alignment, fontFamily, fontSize, fontStyle, textColor,
653                                      modelName, modelPosition, preferredPlacement, distance, ratio, text);
654             }
655         }
656 
657         /**
658          * <code>&lt;y:BendStyle&gt;</code> element handler.
659          */
660         private class BendStyleHandler
661             extends StAXContentHandlerBase
662         {
663             /** Smoothed attribute. */
664             private boolean smoothed;
665 
666 
667             /** {@inheritDoc} */
668             public void startElement(final String nsURI,
669                                      final String localName,
670                                      final String qName,
671                                      final Attributes attrs,
672                                      final StAXDelegationContext dctx)
673                 throws SAXException
674             {
675                 if ("y:BendStyle".equals(qName))
676                 {
677                     smoothed = "true".equals(attrs.getValue("smoothed"));
678                 }
679             }
680 
681             /** {@inheritDoc} */
682             public Object endTree(final StAXContext context)
683                 throws SAXException
684             {
685                 return new BendStyle(smoothed);
686             }
687         }
688     }
689 }