View Javadoc

1   /**
2    * Copyright (c) 2002-2011 "Neo Technology,"
3    * Network Engine for Objects in Lund AB [http://neotechnology.com]
4    *
5    * This file is part of Neo4j.
6    *
7    * Neo4j is free software: you can redistribute it and/or modify
8    * it under the terms of the GNU General Public License as published by
9    * the Free Software Foundation, either version 3 of the License, or
10   * (at your option) any later version.
11   *
12   * This program is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Public License for more details.
16   *
17   * You should have received a copy of the GNU General Public License
18   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19   */
20  package org.neo4j.server.rest.domain;
21  
22  import java.util.Collection;
23  import java.util.Map;
24  
25  /**
26   * This is just a simple test of how a HTML renderer could be like
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'>&nbsp;</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                     // there's only properties, so we're finished here
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                     // TODO We always assume that an inner map is for
131                     // properties, correct?
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         // TODO Hardcode "http://" string?
156         if ( string.startsWith( "http://" ) || string.startsWith( "https://" ) )
157         {
158             String anchoredString = "<a href=\"" + string + "\"";
159 
160             // TODO Hardcoded /node/, /relationship/ string?
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( "&", "&amp;" );
191         res = res.replace( "\"", "&quot;" );
192         res = res.replace( "<", "&lt;" );
193         res = res.replace( ">", "&gt;" );
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 }