Woodstox sample: Typed Access API, binary
Message format
Here is the simple xml message format we will be using:
<files> <file name="test.jpg" checksumType="SHA">... base64 encoded content ... </file> <checksum value="...base64 encoded hash of content..." /> <!-- ... and more files (with checksums), if need be... --> </files>
That is, a single message contains one or more files, each with associated checksum. Checksum is used to verify that contents were passed unmodified (as opposed to being corrupted by transfer).
Client implementation
1 import java.io.*;
2 import java.net.URL;
3 import java.net.URLConnection;
4 import java.security.MessageDigest;
5 import java.util.*;
6 import javax.xml.stream.*;
7
8 import org.codehaus.stax2.XMLStreamReader2;
9
10 /// Simple example of a client that downloads a set of files from a server.
11 public class BinaryClient
12 {
13 final XMLInputFactory _xmlInputFactory = XMLInputFactory.newInstance();
14
15 /**
16 * @param urlStr Full URL (including query parameters if any)
17 * used to access web service for downloading files.
18 */
19 public List<File> fetchFiles(URL serviceURL) throws Exception
20 {
21 List<File> files = new ArrayList<File>();
22 URLConnection conn = serviceURL.openConnection();
23 conn.setDoOutput(false); // only true when POSTing
24 conn.connect();
25 // note, should check 'if (conn.getResponseCode() != 200) ...'
26
27 // Ok, let's read it then... (note: StaxMate could simplify a lot!)
28 InputStream in = conn.getInputStream();
29 XMLStreamReader2 sr = (XMLStreamReader2) _xmlInputFactory.createXMLStreamReader(in);
30 sr.nextTag(); // to "files"
31 File dir = new File("/tmp"); // for linux...
32 byte[] buffer = new byte[4000];
33
34 while (sr.nextTag() != XMLStreamConstants.END_ELEMENT) { // one more 'file'
35 String filename = sr.getAttributeValue("", "name");
36 String csumType = sr.getAttributeValue("", "checksumType");
37 File outputFile = new File(dir, filename);
38 FileOutputStream out = new FileOutputStream(outputFile);
39 files.add(outputFile);
40 MessageDigest md = MessageDigest.getInstance(csumType);
41
42 int count;
43 // Read binary contents of the file, calc checksum and write
44 while ((count = sr.readElementAsBinary(buffer, 0, buffer.length)) != -1) {
45 md.update(buffer, 0, count);
46 out.write(buffer, 0, count);
47 }
48 out.close();
49 // Then verify checksum
50 sr.nextTag();
51 byte[] expectedCsum = sr.getAttributeAsBinary(sr.getAttributeIndex("", "value"));
52 byte[] actualCsum = md.digest();
53 if (!Arrays.equals(expectedCsum, actualCsum)) {
54 throw new IllegalArgumentException("File '"+filename+"' corrupt: content checksum does not match expected");
55 }
56 sr.nextTag(); // to match closing "checksum"
57 }
58 return files;
59 }
60
61 // Call with arg like "localhost:8080/downloadServlet"
62 public static void main(String[] args) throws Exception {
63 if (args.length != 1) {
64 System.err.println("Usage: java BinaryClient [URL]");
65 System.exit(1);
66 }
67 URL serviceURL = new URL(args[0]);
68 System.out.println("Fetching files from '"+serviceURL.toExternalForm()+"'...");
69 List<File> files = new BinaryClient().fetchFiles(serviceURL);
70 System.out.println("OK: Fetched "+files.size()+" files with correct checksums:");
71 for (File f : files) {
72 System.out.println(" File '"+f.getAbsolutePath()+"'");
73 }
74 System.out.println("Done.");
75 }
76 }
Service implementation
1 // TO BE WRITTEN
Authoritative source code
The original source code is included with Woodstox distribution, and is stored in Woodstox SVN Repository under src/samples (files BinaryService.java and BinaryClient.java.
