1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.neo4j.server.rest.domain;
21
22 import java.util.Collection;
23 import java.util.Map;
24
25
26
27
28 public class HtmlHelper
29 {
30 private final static String STYLE_LOCATION = "http://resources.neo4j.org/style/";
31 private final static String HTML_JAVASCRIPT_LOCATION = "/webadmin/htmlbrowse.js";
32
33 public static String from( final Object object, final ObjectType objectType )
34 {
35 StringBuilder builder = start( objectType, null );
36 append( builder, object, objectType );
37 return end( builder );
38 }
39
40 public static StringBuilder start( final ObjectType objectType, final String additionalCodeInHead )
41 {
42 return start( objectType.getCaption(), additionalCodeInHead );
43 }
44
45 public static StringBuilder start( final String title, final String additionalCodeInHead )
46 {
47 StringBuilder builder = new StringBuilder();
48 builder.append( "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n" );
49 builder.append( "<html><head><title>" + title + "</title>" );
50 if ( additionalCodeInHead != null )
51 {
52 builder.append( additionalCodeInHead );
53 }
54 builder.append( "<meta content=\"text/html; charset=utf-8\" http-equiv=\"Content-Type\">\n"
55 + "<link href='"
56 + STYLE_LOCATION
57 + "rest.css' rel='stylesheet' type='text/css'>\n"
58 + "<script type='text/javascript' src='"
59 + HTML_JAVASCRIPT_LOCATION
60 + "'></script>\n"
61 + "</head>\n<body onload='javascript:neo4jHtmlBrowse.start();' id='"
62 + title.toLowerCase()
63 + "'>\n"
64 + "<div id='content'>"
65 + "<div id='header'>"
66 + "<h1><a title='Neo4j REST interface' href='/'><span>Neo4j REST interface</span></a></h1>"
67 + "</div>" + "\n<div id='page-body'>\n" );
68 return builder;
69 }
70
71 public static String end( final StringBuilder builder )
72 {
73 builder.append( "<div class='break'> </div>"
74 + "</div></div></body></html>" );
75 return builder.toString();
76 }
77
78 public static void appendMessage( final StringBuilder builder, final String message )
79 {
80 builder.append( "<p class=\"message\">" + message + "</p>" );
81 }
82
83 public static void append( final StringBuilder builder, final Object object, final ObjectType objectType )
84 {
85 if ( object instanceof Collection )
86 {
87 builder.append( "<ul>\n" );
88 for ( Object item : (Collection<?>) object )
89 {
90 builder.append( "<li>" );
91 append( builder, item, objectType );
92 builder.append( "</li>\n" );
93 }
94 builder.append( "</ul>\n" );
95 }
96 else if ( object instanceof Map )
97 {
98 Map<?, ?> map = (Map<?, ?>) object;
99 String htmlClass = objectType.getHtmlClass();
100 String caption = objectType.getCaption();
101 if ( !map.isEmpty() )
102 {
103 boolean isNodeOrRelationship = ObjectType.NODE.equals( objectType )
104 || ObjectType.RELATIONSHIP.equals( objectType );
105 if ( isNodeOrRelationship )
106 {
107 builder.append( "<h2>" + caption + "</h2>\n" );
108 append( builder, map.get( "data" ), ObjectType.PROPERTIES );
109 htmlClass = "meta";
110 caption += " info";
111 }
112 if ( ObjectType.NODE.equals( objectType ) && map.size() == 1 )
113 {
114
115 return;
116 }
117 builder.append( "<table class=\"" + htmlClass + "\"><caption>" );
118 builder.append( caption );
119 builder.append( "</caption>\n" );
120 boolean odd = true;
121 for ( Map.Entry<?, ?> entry : map.entrySet() )
122 {
123 if ( isNodeOrRelationship && "data".equals( entry.getKey() ) )
124 {
125 continue;
126 }
127 builder.append( "<tr" + ( odd ? " class='odd'" : "" ) + ">" );
128 odd = !odd;
129 builder.append( "<th>" + entry.getKey() + "</th><td>" );
130
131
132 append( builder, entry.getValue(), ObjectType.PROPERTIES );
133 builder.append( "</td></tr>\n" );
134 }
135 builder.append( "</table>\n" );
136 }
137 else
138 {
139 builder.append( "<table class=\"" + htmlClass + "\"><caption>" );
140 builder.append( caption );
141 builder.append( "</caption>" );
142 builder.append( "<tr><td></td></tr>" );
143 builder.append( "</table>" );
144 }
145 }
146 else
147 {
148 builder.append( object != null ? embedInLinkIfClickable( object.toString() )
149 : "" );
150 }
151 }
152
153 private static String embedInLinkIfClickable( String string )
154 {
155
156 if ( string.startsWith( "http://" ) || string.startsWith( "https://" ) )
157 {
158 String anchoredString = "<a href=\"" + string + "\"";
159
160
161 String anchorClass = null;
162 if ( string.contains( "/node/" ) )
163 {
164 anchorClass = "node";
165 }
166 else if ( string.contains( "/relationship/" ) )
167 {
168 anchorClass = "relationship";
169 }
170 if ( anchorClass != null )
171 {
172 anchoredString += " class=\"" + anchorClass + "\"";
173 }
174 anchoredString += ">" + escapeHtml( string ) + "</a>";
175 string = anchoredString;
176 }
177 else
178 {
179 string = escapeHtml( string );
180 }
181 return string;
182 }
183
184 private static String escapeHtml( final String string )
185 {
186 if ( string == null )
187 {
188 return null;
189 }
190 String res = string.replace( "&", "&" );
191 res = res.replace( "\"", """ );
192 res = res.replace( "<", "<" );
193 res = res.replace( ">", ">" );
194 return res;
195 }
196
197 public static enum ObjectType
198 {
199 NODE,
200 RELATIONSHIP,
201 PROPERTIES,
202 ROOT,
203 INDEX_ROOT,
204
205 ;
206
207 String getCaption()
208 {
209 return name().substring( 0, 1 ).toUpperCase() +
210 name().substring( 1 ).toLowerCase();
211 }
212
213 String getHtmlClass()
214 {
215 return getCaption().toLowerCase();
216 }
217 }
218 }