001 package org.mycore.frontend.fileupload;
002
003 import java.io.BufferedInputStream;
004 import java.io.ByteArrayInputStream;
005 import java.io.DataInputStream;
006 import java.io.DataOutputStream;
007 import java.io.File;
008 import java.io.FileNotFoundException;
009 import java.io.IOException;
010 import java.io.InputStream;
011 import java.io.UnsupportedEncodingException;
012 import java.net.MalformedURLException;
013 import java.net.Socket;
014 import java.net.URL;
015 import java.net.URLConnection;
016 import java.net.URLEncoder;
017 import java.security.DigestInputStream;
018 import java.security.MessageDigest;
019 import java.util.Enumeration;
020 import java.util.Hashtable;
021 import java.util.Stack;
022 import java.util.StringTokenizer;
023 import java.util.Vector;
024 import java.util.zip.Deflater;
025 import java.util.zip.ZipEntry;
026 import java.util.zip.ZipOutputStream;
027
028
029 public class MCRMetsModsCommunicator{
030
031 protected String url;
032 protected String uid;
033 protected final static int bufferSize = 65536; // 64 KByte
034
035 public MCRMetsModsCommunicator(String url, String uploadId)
036 {
037 this.url = url;
038 this.uid = uploadId;
039 }
040
041 public void uploadMets(String mets_string) {
042 try{
043 startUploadSession(mets_string.length());
044 uploadFile("mets.xml", mets_string);
045 endUploadSession();
046 }catch(Exception e)
047 {
048 e.printStackTrace(System.out);
049 }
050 }
051
052
053
054 protected long countTotalBytes(Vector files) {
055 long total = 0;
056
057 for (int i = 0; i < files.size(); i++)
058 total += ((File) files.get(i)).length();
059
060 return total;
061 }
062
063
064
065 public void uploadFile(String path, String mets) throws Exception {
066 System.out.println("--- Starting filetransfer ---");
067 String md5 = buildMD5StringByString(mets);
068 System.out.println("MD5 checksum is " + md5);
069
070 // TODO: Refactor method names in communication
071 Hashtable request = new Hashtable();
072 request.put("md5", md5);
073 request.put("method", "uploadFile");
074 request.put("path", path);
075 request.put("length", String.valueOf(mets.length()) );
076
077 System.out.println("Sending filename to server: " + path);
078
079 String reply = (String) (send(request));
080 System.out.println("Received reply from server.");
081
082 if ("skip file".equals(reply)) {
083 System.out.println("File skipped.");
084 return;
085 }
086
087 StringTokenizer st = new StringTokenizer(reply, ":");
088 String host = st.nextToken();
089 int port = Integer.parseInt(st.nextToken());
090 System.out.println("Server says we should connect to " + host + ":" + port);
091
092 System.out.println("Trying to create client socket...");
093
094
095 Socket socket = new Socket(host, port);
096 socket.setReceiveBufferSize(Math.max(socket.getReceiveBufferSize(),bufferSize));
097 socket.setSendBufferSize(Math.max(socket.getSendBufferSize(),bufferSize));
098
099 System.out.println("Socket created, connected to server.");
100 System.out.println("Socket send buffer size is " + socket.getSendBufferSize() );
101
102 ZipOutputStream zos = new ZipOutputStream(socket.getOutputStream());
103 DataInputStream din = new DataInputStream(socket.getInputStream());
104
105 // Large files like video already are compressed somehow
106 zos.setLevel(Deflater.NO_COMPRESSION);
107
108 ZipEntry ze = new ZipEntry(java.net.URLEncoder.encode(path, "UTF-8"));
109 StringBuffer extra = new StringBuffer();
110 extra.append(md5).append(" ").append(mets.length()).append(" ").append(uid);
111 ze.setExtra(extra.toString().getBytes("UTF-8"));
112 zos.putNextEntry(ze);
113
114 int num = 0;
115 long sended = 0;
116 byte[] buffer = new byte[bufferSize];
117
118 System.out.println("Starting to send file content...");
119
120 ByteArrayInputStream bais = new ByteArrayInputStream(mets.getBytes());
121
122 InputStream source = new BufferedInputStream(bais,buffer.length);
123
124 long lastPing = System.currentTimeMillis();
125 while ((num = source.read(buffer)) != -1) {
126
127 zos.write(buffer, 0, num);
128 sended += num;
129
130
131 // Send a "ping" to MCRUploadServlet so that server keeps HTTP Session alive
132 if( ( System.currentTimeMillis() - lastPing ) > 10000 )
133 {
134 lastPing = System.currentTimeMillis();
135 Hashtable ping = new Hashtable();
136 ping.put("method", "ping");
137 System.out.println( "Sending ping to servlet..." );
138 String pong = (String)( send(ping) );
139 System.out.println( "Server responded with " + pong );
140 }
141 }
142
143 zos.closeEntry();
144 zos.flush();
145 System.out.println("Releasing file: mets.xml");
146 source.close();
147 System.out.println("Finished sending file content.");
148
149 long numBytesStored = din.readLong();
150 System.out.println("Server reports that " + numBytesStored + " bytes have been stored." );
151
152 socket.close();
153
154 System.out.println("Socket closed, file transfer successfully completed.");
155 }
156
157
158
159 /**
160 * Creates a list of all files in the given directories
161 *
162 * @param selectedFiles
163 * list of selected files or directories from filechooser
164 */
165 protected Vector[] listFiles(File[] selectedFiles) throws Exception {
166 Vector[] list = new Vector[2];
167 list[0] = new Vector();
168 list[1] = new Vector();
169
170 if ((null == selectedFiles) || (0 == selectedFiles.length)) {
171 return list;
172 }
173
174 for (int i = 0; i < selectedFiles.length; i++) {
175 File f = selectedFiles[i];
176
177 if (!f.exists()) {
178 throw new FileNotFoundException("Datei oder Verzeichnis " + f.getPath() + " nicht gefunden!");
179 }
180
181 if (!f.canRead()) {
182 throw new IOException("Datei oder Verzeichnis " + f.getPath() + " nicht lesbar!");
183 }
184
185 if (f.isFile()) {
186 list[0].addElement(f);
187 list[1].addElement(f.getName());
188 } else {
189 Stack dirStack = new Stack();
190 Stack baseStack = new Stack();
191
192 dirStack.push(f);
193 baseStack.push(f.getName() + "/");
194
195 while (!dirStack.empty()) {
196 File dir = (File) (dirStack.pop());
197 String base = (String) (baseStack.pop());
198
199 String[] files = dir.list();
200
201 for (int j = 0; j < files.length; j++) {
202 f = new File(dir, files[j]);
203
204 if (f.isFile()) {
205 list[0].addElement(f);
206 list[1].addElement(base + files[j]);
207 } else {
208 dirStack.push(f);
209 baseStack.push(base + files[j] + "/");
210 }
211 }
212 }
213 }
214 }
215
216 return list;
217 }
218
219 protected void startUploadSession(int numFiles) throws IOException, MCRUploadException {
220 Hashtable request = new Hashtable();
221 request.put("method", "startUploadSession");
222 request.put("numFiles", String.valueOf(numFiles));
223 send(request);
224 }
225
226 protected void endUploadSession() throws IOException, MCRUploadException {
227 Hashtable request = new Hashtable();
228 request.put("method", "endUploadSession");
229 send(request);
230 }
231
232 protected void cancelUploadSession() throws IOException, MCRUploadException {
233 Hashtable request = new Hashtable();
234 request.put("method", "cancelUploadSession");
235 send(request);
236 }
237
238 protected Object send(Hashtable parameters) throws IOException, MCRUploadException {
239 parameters.put("uploadId", uid);
240 Hashtable response = getResponse(doPost(parameters));
241 return response.get("return");
242 }
243
244 protected InputStream doPost(Hashtable parameters) throws IOException {
245 String data = encodeParameters(parameters);
246 String mime = "application/x-www-form-urlencoded";
247
248 URLConnection connection = null;
249
250 try {
251 connection = new URL(url).openConnection();
252 } catch (MalformedURLException ignored) {
253 } // will never happen if base URL is ok
254
255 connection.setDoInput(true);
256 connection.setDoOutput(true);
257 connection.setUseCaches(false);
258 connection.setDefaultUseCaches(false);
259 connection.setRequestProperty("Content-type", mime);
260 connection.setRequestProperty("Content-length", String.valueOf(data.length()));
261
262 DataOutputStream out = new DataOutputStream(connection.getOutputStream());
263 out.writeBytes(data);
264 out.flush();
265 out.close();
266
267 return connection.getInputStream();
268 }
269
270 protected String encodeParameters(Hashtable parameters) {
271 StringBuffer data = new StringBuffer();
272 Enumeration e = parameters.keys();
273
274 while (e.hasMoreElements()) {
275 String name = (String) e.nextElement();
276 String value = (String) parameters.get(name);
277
278 try {
279 data.append(URLEncoder.encode(name, "UTF-8")).append("=").append(URLEncoder.encode(value, "UTF-8")).append("&");
280 } catch (UnsupportedEncodingException ex) {
281 System.out.println(ex.getClass().getName());
282 System.out.println(ex.getMessage());
283 throw new RuntimeException("Could not encode parameters");
284 }
285 }
286
287 data.setLength(data.length() - 1);
288
289 return data.toString();
290 }
291
292 protected Hashtable getResponse(InputStream is) throws IOException, MCRUploadException {
293 DataInputStream dis = new DataInputStream(is);
294 String mime = dis.readUTF();
295 byte[] dummy = new byte[0];
296
297 Hashtable response = new Hashtable();
298
299 while (dis.read(dummy, 0, 0) != -1) {
300 String key = dis.readUTF();
301 String clname = dis.readUTF();
302 Object value = null;
303
304 if (clname.equals(String.class.getName())) {
305 value = dis.readUTF();
306 } else if (clname.equals(Integer.class.getName())) {
307 value = new Integer(dis.readInt());
308 } else {
309 value = dis.readUTF();
310 }
311
312 response.put(key, value);
313 }
314
315 if (mime.equals("upload/exception")) {
316 String clname = (String) (response.get("clname"));
317 String message = (String) (response.get("message"));
318 String strace = (String) (response.get("strace"));
319 throw new MCRUploadException(clname, message, strace);
320 }
321
322 return response;
323 }
324 /** Calculates the MD5 checksum of the given mets file * */
325 protected String buildMD5StringByString(String mets) throws Exception {
326 MessageDigest digest = MessageDigest.getInstance("MD5");
327
328 ByteArrayInputStream bais = new ByteArrayInputStream(mets.getBytes());
329
330 InputStream fis = bais;
331 BufferedInputStream bis = new BufferedInputStream(fis, bufferSize);
332 DigestInputStream in = new DigestInputStream(bis, digest);
333
334 byte[] buffer = new byte[bufferSize];
335
336 while (in.read(buffer, 0, buffer.length) != -1)
337 ;
338
339 in.close();
340
341 byte[] bytes = digest.digest();
342 StringBuffer sb = new StringBuffer();
343
344 for (int i = 0; i < bytes.length; i++) {
345 String sValue = "0" + Integer.toHexString(bytes[i]);
346 sb.append(sValue.substring(sValue.length() - 2));
347 }
348
349 return sb.toString();
350 }
351
352 }