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    }