1   package eu.fbk.knowledgestore.internal.rdf;
2   
3   import java.io.IOException;
4   import java.io.OutputStream;
5   import java.io.OutputStreamWriter;
6   import java.io.Writer;
7   import java.util.List;
8   import java.util.Map;
9   
10  import com.google.common.base.Charsets;
11  import com.google.common.collect.ImmutableList;
12  import com.google.common.collect.Maps;
13  
14  import org.openrdf.model.impl.BooleanLiteralImpl;
15  import org.openrdf.query.BindingSet;
16  import org.openrdf.query.QueryResultHandlerException;
17  import org.openrdf.query.TupleQueryResultHandlerException;
18  import org.openrdf.query.resultio.BooleanQueryResultFormat;
19  import org.openrdf.query.resultio.BooleanQueryResultWriter;
20  import org.openrdf.query.resultio.BooleanQueryResultWriterFactory;
21  import org.openrdf.query.resultio.QueryResultFormat;
22  import org.openrdf.query.resultio.QueryResultWriterBase;
23  import org.openrdf.query.resultio.TupleQueryResultFormat;
24  import org.openrdf.query.resultio.TupleQueryResultWriter;
25  import org.openrdf.query.resultio.TupleQueryResultWriterFactory;
26  
27  public class HtmlSparql implements BooleanQueryResultWriterFactory, TupleQueryResultWriterFactory {
28  
29      public static final TupleQueryResultFormat TUPLE_FORMAT = new TupleQueryResultFormat(
30              "HTML/TUPLE", "text/html", Charsets.UTF_8, "html");
31  
32      public static final BooleanQueryResultFormat BOOLEAN_FORMAT = new BooleanQueryResultFormat(
33              "HTML/BOOLEAN", "text/html", Charsets.UTF_8, "html");
34  
35      static {
36          TupleQueryResultFormat.register(TUPLE_FORMAT);
37          BooleanQueryResultFormat.register(BOOLEAN_FORMAT);
38      }
39  
40      public static void register() {
41          // calling this method will cause the static initializer to run once
42      }
43  
44      @Override
45      public TupleQueryResultFormat getTupleQueryResultFormat() {
46          return TUPLE_FORMAT;
47      }
48  
49      @Override
50      public BooleanQueryResultFormat getBooleanQueryResultFormat() {
51          return BOOLEAN_FORMAT;
52      }
53  
54      @Override
55      public HtmlWriter getWriter(final OutputStream out) {
56          return new HtmlWriter(new OutputStreamWriter(out, Charsets.UTF_8));
57      }
58  
59      private static final class HtmlWriter extends QueryResultWriterBase implements
60              BooleanQueryResultWriter, TupleQueryResultWriter {
61  
62          private final Writer writer;
63  
64          private final Map<String, String> prefixes;
65  
66          private List<String> variables;
67  
68          HtmlWriter(final Writer writer) {
69              this.writer = writer;
70              this.prefixes = Maps.newHashMap();
71              this.variables = null;
72          }
73  
74          @Override
75          public QueryResultFormat getQueryResultFormat() {
76              return TUPLE_FORMAT;
77          }
78  
79          @Override
80          public TupleQueryResultFormat getTupleQueryResultFormat() {
81              return TUPLE_FORMAT;
82          }
83  
84          @Override
85          public BooleanQueryResultFormat getBooleanQueryResultFormat() {
86              return BOOLEAN_FORMAT;
87          }
88  
89          @Override
90          public void handleNamespace(final String prefix, final String uri) {
91              this.prefixes.put(uri, prefix);
92          }
93  
94          @Override
95          public void startDocument() throws QueryResultHandlerException {
96              try {
97                  this.writer.append("<html>\n<head>\n<meta http-equiv=\"Content-type\" "
98                          + "content=\"text/html;charset=UTF-8\"/>\n");
99              } catch (final IOException ex) {
100                 throw new QueryResultHandlerException(ex);
101             }
102         }
103 
104         @Override
105         public void handleStylesheet(final String stylesheetUrl) {
106         }
107 
108         @Override
109         public void startHeader() {
110         }
111 
112         @Override
113         public void handleLinks(final List<String> linkURLs) throws QueryResultHandlerException {
114             try {
115                 for (final String linkURL : linkURLs) {
116                     this.writer.append("<link rel=\"nofollow\" href=\"" + linkURL + "\">\n");
117                 }
118             } catch (final IOException ex) {
119                 throw new QueryResultHandlerException(ex);
120             }
121         }
122 
123         @Override
124         public void endHeader() {
125         }
126 
127         @Override
128         public void write(final boolean value) {
129             throw new UnsupportedOperationException();
130         }
131 
132         @Override
133         public void handleBoolean(final boolean value) throws QueryResultHandlerException {
134             try {
135                 this.writer.append("</head>\n<body>\n"//
136                         + "<table class=\"sparql\">\n<thead>\n" //
137                         + "<tr><th>boolean</th></tr>\n" //
138                         + "</thead>\n<tbody>\n" //
139                         + "<tr><td>");
140                 RDFUtil.toHtml(value ? BooleanLiteralImpl.TRUE : BooleanLiteralImpl.FALSE,
141                         this.prefixes, this.writer);
142                 this.writer.append("</td></tr>\n" //
143                         + "</tbody>\n</table>\n" //
144                         + "</body>\n</html>\n");
145                 this.writer.flush();
146             } catch (final IOException ex) {
147                 throw new TupleQueryResultHandlerException(ex);
148             }
149         }
150 
151         @Override
152         public void startQueryResult(final List<String> variables)
153                 throws TupleQueryResultHandlerException {
154             try {
155                 this.variables = ImmutableList.copyOf(variables);
156                 this.writer.append("</head>\n<body>\n" //
157                         + "<table class=\"sparql\">\n<thead>\n<tr>");
158                 for (final String variable : variables) {
159                     this.writer.append("<th>").append(variable).append("</th>");
160                 }
161                 this.writer.append("</tr>\n</thead>\n<tbody>\n");
162             } catch (final IOException ex) {
163                 throw new TupleQueryResultHandlerException(ex);
164             }
165         }
166 
167         @Override
168         public void handleSolution(final BindingSet bindings)
169                 throws TupleQueryResultHandlerException {
170             try {
171                 this.writer.append("<tr>");
172                 for (final String variable : this.variables) {
173                     this.writer.append("<td>");
174                     RDFUtil.toHtml(bindings.getValue(variable), this.prefixes, this.writer);
175                     this.writer.append("</td>");
176                 }
177                 this.writer.append("</tr>\n");
178             } catch (final IOException ex) {
179                 throw new TupleQueryResultHandlerException(ex);
180             }
181         }
182 
183         @Override
184         public void endQueryResult() throws TupleQueryResultHandlerException {
185             try {
186                 this.writer.append("</tbody>\n</table>\n" //
187                         + "</body>\n</html>\n");
188                 this.writer.flush();
189             } catch (final IOException ex) {
190                 throw new TupleQueryResultHandlerException(ex);
191             }
192         }
193 
194     }
195 
196 }