Pdfcrowd - Client.java

raw code

  1 // Copyright (C) 2010-2013 pdfcrowd.com
  2 // 
  3 // Permission is hereby granted, free of charge, to any person
  4 // obtaining a copy of this software and associated documentation
  5 // files (the "Software"), to deal in the Software without
  6 // restriction, including without limitation the rights to use,
  7 // copy, modify, merge, publish, distribute, sublicense, and/or sell
  8 // copies of the Software, and to permit persons to whom the
  9 // Software is furnished to do so, subject to the following
 10 // conditions:
 11 // 
 12 // The above copyright notice and this permission notice shall be
 13 // included in all copies or substantial portions of the Software.
 14 // 
 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 17 // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 19 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 20 // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 22 // OTHER DEALINGS IN THE SOFTWARE.
 23 
 24 package com.pdfcrowd;
 25 
 26 import java.util.*;
 27 import java.io.*;
 28 import java.net.*;
 29 import javax.net.ssl.*;
 30 
 31 //
 32 // Pdfcrowd API client.
 33 // 
 34 public class Client {
 35     
 36     private HashMap<String,String> fields;
 37     private boolean m_useSSL = false;
 38 
 39     //
 40     // Client constructor.
 41     // 
 42     // username - your username at Pdfcrowd
 43     // apikey   - your API key
 44     // 
 45     public Client(String username, String apikey) {
 46         init(username, apikey, API_HOSTNAME);
 47     }
 48 
 49     //
 50     // Converts a web page.
 51     //
 52     // uri       - a web page URL
 53     // outStream - an output stream (java.io.OutputStream)
 54     // 
 55     public void convertURI(String uri, OutputStream outStream) {
 56         byte[] data = encodePostData(uri);
 57         callAPI(data, "pdf/convert/uri/", outStream, URLENCODED);
 58     }
 59 
 60     //
 61     // Converts an in-memory html document.
 62     //
 63     // html      - a string containing a html document
 64     // outStream - an output stream (java.io.OutputStream)
 65     // 
 66     public void convertHtml(String html, OutputStream outStream) {
 67         byte[] data = encodePostData(html);
 68         callAPI(data, "pdf/convert/html/", outStream, URLENCODED);
 69     }
 70 
 71     //
 72     // Converts an html file.
 73     //
 74     // path      - a path to an html file
 75     // outStream - an output stream (java.io.OutputStream)
 76     // 
 77     public void convertFile(String path, OutputStream outStream) {
 78         ByteArrayOutputStream data = encodeMultipartPostData(path);
 79         callAPI(data, "pdf/convert/html/", outStream, MULTIPART);
 80     }
 81 
 82     //
 83     // Returns the number of available conversion tokens.
 84     // 
 85     public int numTokens() {
 86         byte[] data = encodePostData(null);
 87         ByteArrayOutputStream tokens = new ByteArrayOutputStream();
 88         callAPI(data, "user/" + fields.get("username") + "/tokens/", tokens, URLENCODED);
 89         return Integer.parseInt(tokens.toString());
 90     }
 91 
 92     public void useSSL(boolean val) {
 93         m_useSSL = val;
 94     }
 95 
 96     public void setUsername(String username) {
 97         fields.put("username", username);
 98     }
 99     
100     public void setApiKey(String key) {
101         fields.put("key", key);
102     }
103 
104     public void setPageWidth(double value) {
105         fields.put("width", doubleToString(value));
106     }
107 
108     public void setPageWidth(String value) {
109         fields.put("width", value);
110     }
111     
112 
113     public void setPageHeight(double value) {
114         fields.put("height", doubleToString(value));
115     }
116 
117     public void setPageHeight(String value) {
118         fields.put("height", value);
119     }
120 
121     public void setHorizontalMargin(double value) {
122         fields.put("margin_right", doubleToString(value));
123         fields.put("margin_left", doubleToString(value));
124     }
125 
126     public void setHorizontalMargin(String value) {
127         fields.put("margin_right", value);
128         fields.put("margin_left", value);
129     }
130 
131     public void setVerticalMargin(double value) {
132         fields.put("margin_top", doubleToString(value));
133         fields.put("margin_bottom", doubleToString(value));
134     }
135 
136     public void setVerticalMargin(String value) {
137         fields.put("margin_top", value);
138         fields.put("margin_bottom", value);
139     }
140 
141     public void setPageMargins(String top, String right, String bottom, String left) {
142         fields.put("margin_top", top);
143         fields.put("margin_right", right);
144         fields.put("margin_bottom", bottom);
145         fields.put("margin_left", left);
146     }
147 
148 
149     public void setEncrypted() {
150         setEncrypted(true);
151     }
152 
153     public void setEncrypted(boolean value) {
154         fields.put("encrypted", value ? "true" : null);
155     }
156 
157     public void setUserPassword(String pwd) {
158         fields.put("user_pwd", pwd);
159     }
160 
161     public void setOwnerPassword(String pwd) {
162         fields.put("owner_pwd", pwd);
163     }
164 
165     public void setNoPrint() {
166         setNoPrint(true);
167     }
168 
169     public void setNoPrint(boolean val) {
170         fields.put("no_print", val ? "true" : null);
171     }
172 
173     public void setNoModify() {
174         setNoModify(true);
175     }
176 
177     public void setNoModify(boolean val) {
178         fields.put("no_modify", val ? "true" : null);
179     }
180 
181     public void setNoCopy() {
182         setNoCopy(true);
183     }
184 
185     public void setNoCopy(boolean val) {
186         fields.put("no_copy", val ? "true" : null);
187     }
188 
189     // constants for setPageLayout()
190     public static int SINGLE_PAGE = 1;
191     public static int CONTINUOUS = 2;
192     public static int CONTINUOUS_FACING = 3;
193     
194     public void setPageLayout(int value) {
195         assert value > 0 && value <= 3;
196         fields.put("page_layout", Integer.toString(value));
197     }
198 
199     // constants for setPageMode()
200     public static int NONE_VISIBLE = 1;
201     public static int THUMBNAILS_VISIBLE = 2;
202     public static int FULLSCREEN = 3;
203 
204     public void setPageMode(int value) {
205         assert value > 0 && value <= 3;
206         fields.put("page_mode", Integer.toString(value));
207     }
208     
209     public void setFooterText(String value) {
210         fields.put("footer_text", value);
211     }
212     
213     public void enableImages() {
214         enableImages(true);
215     }
216 
217     public void enableImages(boolean value) {
218         fields.put("no_images", value ? null : "true");
219     }
220 
221     public void enableBackgrounds() {
222         enableBackgrounds(true);
223     }
224     
225     public void enableBackgrounds(boolean value) {
226         fields.put("no_backgrounds", value ? null : "true");
227     }
228 
229     public void setHtmlZoom(double value) {
230         fields.put("html_zoom", Double.toString(value));
231     }
232 
233     public void enableJavaScript() {
234         enableJavaScript(true);
235     }
236     
237     public void enableJavaScript(boolean value) {
238         fields.put("no_javascript", value ? null : "true");
239     }
240 
241     public void enableHyperlinks() {
242         enableHyperlinks(true);
243     }
244 
245     public void enableHyperlinks(boolean value) {
246         fields.put("no_hyperlinks", value ? null : "true");
247     }
248     
249     public void setDefaultTextEncoding(String value) {
250         fields.put("text_encoding", value);
251     }
252 
253     public void usePrintMedia() {
254         usePrintMedia(true);
255     }
256     
257     public void usePrintMedia(boolean value) {
258         fields.put("use_print_media", value ? "true" : null);
259     }
260 
261     public void setMaxPages(int value) {
262         fields.put("max_pages", Integer.toString(value));
263     }
264 
265     public void enablePdfcrowdLogo() {
266         enablePdfcrowdLogo(true);
267     }
268 
269     public void enablePdfcrowdLogo(boolean value) {
270         fields.put("pdfcrowd_logo", value ? "true" : null);
271     }
272 
273     // constants for setInitialPdfZoomType()
274     public static int FIT_WIDTH = 1;
275     public static int FIT_HEIGHT = 2;
276     public static int FIT_PAGE = 3;
277 
278     public void setInitialPdfZoomType(int value) {
279         assert value>0 && value<=3;
280         fields.put("initial_pdf_zoom_type", Integer.toString(value));
281     }
282     
283     public void setInitialPdfExactZoom(double value) {
284         fields.put("initial_pdf_zoom_type", "4");
285         fields.put("initial_pdf_zoom", Double.toString(value));
286     }
287 
288     public Client(String username, String apikey, String api_hostname) {
289         init(username, apikey, api_hostname);
290     }
291 
292     public void setAuthor(String value) {
293         fields.put("author", value);
294     }
295 
296     public void setFailOnNon200(boolean value) {
297         fields.put("fail_on_non200", value ? "true" : null);
298     }
299 
300     public void setPdfScalingFactor(double value) {
301         fields.put("pdf_scaling_factor", doubleToString(value));
302     }
303 
304     public void setFooterHtml(String value) {
305         fields.put("footer_html", value);
306     }
307         
308     public void setFooterUrl(String value) {
309         fields.put("footer_url", value);
310     }
311         
312     public void setHeaderHtml(String value) {
313         fields.put("header_html", value);
314     }
315         
316     public void setHeaderUrl(String value) {
317         fields.put("header_url", value);
318     }
319 
320     public void setPageBackgroundColor(String value) {
321         fields.put("page_background_color", value);
322     }
323 
324     public void setTransparentBackground() {
325         setTransparentBackground(true);
326     }
327     
328     public void setTransparentBackground(boolean val) {
329         fields.put("transparent_background", val ? "true" : null);
330     }
331 
332     public void setPageNumberingOffset(int value) {
333         fields.put("page_numbering_offset", Integer.toString(value));
334     }
335 
336     public void setHeaderFooterPageExcludeList(String value) {
337         fields.put("header_footer_page_exclude_list", value);
338     }
339         
340     public void setWatermark(String url, double offset_x, double offset_y) {
341         fields.put("watermark_url", url);
342         fields.put("watermark_offset_x", Double.toString(offset_x));
343         fields.put("watermark_offset_y", Double.toString(offset_y));
344     }
345 
346     public void setWatermark(String url, String offset_x, String offset_y) {
347         fields.put("watermark_url", url);
348         fields.put("watermark_offset_x", offset_x);
349         fields.put("watermark_offset_y", offset_y);
350     }
351     
352     public void setWatermarkRotation(double angle) {
353         fields.put("watermark_rotation", Double.toString(angle));
354     }
355 
356     public void setWatermarkInBackground() {
357         setWatermarkInBackground(true);
358     }
359     
360     public void setWatermarkInBackground(boolean val) {
361         fields.put("watermark_in_background", val ? "true" : null);
362     }
363     
364     
365     
366 
367     // ----------------------------------------------------------------------
368     //                     Private stuff
369     //                     
370 
371     private static String URLENCODED = new String("application/x-www-form-urlencoded");
372     private static String MULTIPART_BOUNDARY = new String("----------ThIs_Is_tHe_bOUnDary_$");
373     private static String MULTIPART = new String("multipart/form-data; boundary=" + MULTIPART_BOUNDARY);
374 
375     public static String API_HOSTNAME = new String("pdfcrowd.com");
376     public static int API_HTTP_PORT = 80;
377     public static int API_HTTPS_PORT = 443;
378     private String api_hostname;
379 
380 
381     private final static HostnameVerifier HOSTNAME_VERIFIER = new HostnameVerifier() {
382         public boolean verify(String hostname, SSLSession session) {
383             return true;
384             //return "pdfcrowd.com".equals(hostname);
385         }
386     };
387 
388     private void init(String username, String apikey, String apihost) {
389         fields = new HashMap<String,String>();
390         fields.put("username", username);
391         fields.put("key", apikey);
392         fields.put("pdf_scaling_factor", "1.0");
393         fields.put("html_zoom", "200");
394         api_hostname = apihost;
395     }
396     
397 
398     private String doubleToString(double val) {
399         return String.format(Locale.US, "%.5f", val);
400     }
401 
402     private static void copyStream(InputStream in, OutputStream out) throws IOException {
403         byte[] buffer = new byte[8192];
404         while (true) {
405             int bytesRead = in.read(buffer, 0, 8192);
406             if (bytesRead == -1) break;
407             out.write(buffer, 0, bytesRead);
408         }
409     }
410 
411     private static String join(AbstractCollection<String> col, String delimiter) {
412         if (col.isEmpty()) return "";
413         Iterator<String> iter = col.iterator();
414         StringBuffer buffer = new StringBuffer(iter.next());
415         while(iter.hasNext()) buffer.append(delimiter).append(iter.next());
416         return buffer.toString();
417     }
418 
419     private String getBaseUri() {
420         if (m_useSSL)
421         {
422             return String.format("https://%s:%d/api/", api_hostname, API_HTTPS_PORT);
423         }
424         else
425         {
426             return String.format("http://%s:%d/api/", api_hostname, API_HTTP_PORT);
427         }
428     }
429 
430     private HttpURLConnection getConnection(String uriSuffix, String contentType) throws IOException {
431         try
432         {
433             URL url;
434             HttpURLConnection conn = (HttpURLConnection)new URL(
435                 getBaseUri() + uriSuffix).openConnection();
436 
437             if (m_useSSL)
438             {
439                 // BUG: sun-java6-bin: missing cacerts the trustAnchors parameter must be non-empty
440                 // http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=564903
441                 HttpsURLConnection ssl_conn = (HttpsURLConnection)conn;
442                 ssl_conn.setHostnameVerifier(HOSTNAME_VERIFIER);
443             }
444             conn.setRequestMethod("POST");
445             conn.setDoOutput(true);
446             conn.setRequestProperty("Content-Type", contentType);
447             conn.setConnectTimeout(120000);
448             return conn;
449         }
450         catch(MalformedURLException e)
451         {
452             throw new PdfcrowdError(e);
453         }
454     }
455 
456     private void callAPI(Object data, String uriSuffix,
457                          OutputStream outStream, String contentType) {
458         try
459         {
460             HttpURLConnection conn = getConnection(uriSuffix, contentType);
461             OutputStream wr = conn.getOutputStream();
462             if (data instanceof byte[]) {
463                 //System.out.println(new String((byte[])data));
464                 wr.write((byte[])data);
465             }
466             else {
467                 //System.out.println(((ByteArrayOutputStream)data).toString());
468                 ((ByteArrayOutputStream)data).writeTo(wr);
469             }
470             wr.flush();
471             
472             if (conn.getResponseCode() == 200) {
473                 InputStream rd = conn.getInputStream();
474                 copyStream(rd, outStream);
475                 rd.close();             
476             }
477             else {
478                 String errMsg;
479                 if (conn.getErrorStream() != null) {
480                     ByteArrayOutputStream errOut = new ByteArrayOutputStream();
481                     copyStream(conn.getErrorStream(), errOut);
482                     errMsg = errOut.toString();
483                 }
484                 else {
485                     errMsg = conn.getResponseMessage();
486                 }
487                 throw new PdfcrowdError(errMsg, conn.getResponseCode());
488             }
489             wr.close();
490         }
491         catch(IOException e)
492         {
493             throw new PdfcrowdError(e);
494         }
495     }
496     
497     private ByteArrayOutputStream encodeMultipartPostData(String filename) {
498         try
499         {
500             Vector<String> body = new Vector<String>();
501             Iterator<String> it = fields.keySet().iterator();
502             ByteArrayOutputStream retval = new ByteArrayOutputStream();
503             while(it.hasNext()) {
504                 String key = it.next();
505                 String val = fields.get(key);
506                 if (val != null)
507                 {
508                     body.add("--" + MULTIPART_BOUNDARY);
509                     body.add(String.format("Content-Disposition: form-data; name=\"%s\"", key));
510                     body.add("");
511                     body.add(val);
512                 }
513             }
514             // filename
515             body.add("--" + MULTIPART_BOUNDARY);
516             body.add(String.format("Content-Disposition: form-data; name=\"src\"; filename=\"%s\"", filename));
517             body.add("Content-Type: application/octet-stream");
518             body.add("");
519             body.add("");
520             retval.write(join(body, "\r\n").getBytes("UTF-8"));
521             body.clear();
522 
523             // read file
524             copyStream(new FileInputStream(filename), retval);
525 
526             body.add("");
527             body.add("--" + MULTIPART_BOUNDARY);
528             body.add("");
529             retval.write(join(body, "\r\n").getBytes("UTF-8"));
530 
531             return retval;
532         }
533         catch(UnsupportedEncodingException e) {
534             throw new PdfcrowdError(e);
535         }
536         catch(IOException e) {
537             throw new PdfcrowdError(e);
538         }
539     }
540 
541     
542     private byte[] encodePostData(String src) {
543 
544         Vector<String> body = new Vector<String>();
545         Iterator it = fields.keySet().iterator();
546         try
547         {
548             if (src != null)
549                 body.add(URLEncoder.encode("src", "UTF-8") + "=" +
550                          URLEncoder.encode(src, "UTF-8"));
551 
552             while(it.hasNext()) {
553                 Object key = it.next();
554                 Object val = fields.get(key);
555                 
556                 if (val != null)
557                 {
558                     body.add(URLEncoder.encode(key.toString(), "UTF-8") + "=" +
559                              URLEncoder.encode(val.toString(), "UTF-8"));
560                 }
561             }
562             return join(body, "&").getBytes("UTF-8");
563         }
564         catch(UnsupportedEncodingException e)
565         {
566             throw new PdfcrowdError(e);
567         }
568     }
569 }