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 }