001    /**
002     * 
003     */
004    package de.jw.cloud42.webapp;
005    
006    import java.io.File;
007    
008    import java.util.ArrayList;
009    import java.util.List;
010    import java.util.logging.Logger;
011    
012    import javax.faces.application.FacesMessage;
013    import javax.faces.context.ExternalContext;
014    import javax.servlet.ServletOutputStream;
015    import javax.servlet.http.HttpServletResponse;
016    
017    
018    import org.jboss.seam.ScopeType;
019    import org.jboss.seam.annotations.In;
020    import org.jboss.seam.annotations.Name;
021    import org.jboss.seam.annotations.Out;
022    
023    import org.jboss.seam.annotations.Scope;
024    import org.jboss.seam.annotations.Synchronized;
025    
026    import org.jboss.seam.faces.FacesMessages;
027    import org.richfaces.event.UploadEvent;
028    import org.richfaces.model.UploadItem;
029    
030    
031    import de.jw.cloud42.core.domain.RemoteResult;
032    import de.jw.cloud42.core.remoting.RemoteControl;
033    import de.jw.cloud42.webapp.utils.FileUtils;
034    
035    /**
036     * Seam component wrapper around file transfer functions of Cloud42.
037     * 
038     * @author fbitzer
039     *
040     */
041    @Name("filetransferManager")
042    @Scope(ScopeType.SESSION)
043    @Synchronized(timeout=1000000000)
044    public class FiletransferManager {
045    
046            @In
047            UserManager userManager;
048            
049            /**
050             * Inject faces messages to trigger error and success messages.
051             */
052            @In 
053            FacesMessages facesMessages;
054            
055            
056            //Inject FacesContext and externalContext to be able to create custom responses for file download
057            @In(value="#{facesContext.externalContext}")
058            private ExternalContext extCtx;
059            @In(value="#{facesContext}")
060            javax.faces.context.FacesContext facesContext;
061    
062            
063            //input fields used in the view (filetransfer dialog)
064            private String targetDirContent;
065            private String targetDir;
066            private boolean uploadFromURL;
067            private String uploadURL;
068            
069            private List<UploadItem> files = new ArrayList<UploadItem>();
070            
071    
072            private String targetFilename = "";
073            
074            
075            
076            private String downloadDirContent;
077            private String downloadFilename;
078            
079            
080            /**
081             * Uploads a file to an AMI instance.
082             * @param dnsName Hostname of instance.
083             * @param keyName Name of keypair to use. Actual key is retreived from stored private keys, if existing. 
084             */
085            public void uploadFile(String dnsName, String keyName){
086                    
087                    //check input first
088                    if (!uploadFromURL) {
089                            if (this.files.size()<1){
090                                    facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_ERROR, "msg_invalidInput", "No file.");
091                                    return;
092                            }
093                    } else {
094                            if (this.uploadURL.equals("")){
095                                    facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_ERROR, "msg_invalidInput", "No URL.");
096                                    return;
097                            }
098                            
099                            
100                            if (this.targetFilename.equals("")){
101                                    facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_ERROR, "msg_invalidInput", "No target file.");
102                                    return;
103                            }
104                    }
105                    
106                    RemoteControl c = new RemoteControl();
107                    
108                    //get the private key for the keyname
109                    String privateKey = userManager.getKeyForName(keyName);
110                    
111                    RemoteResult r = new RemoteResult();
112                    
113                    boolean success = false;
114                    
115                    //decide whether to upload a local file or a file from an URL
116                    if (this.uploadFromURL) {
117                            
118                            //adjust the target directory
119                            if (!targetDir.startsWith("/")) {
120                                    targetDir = "~/" + targetDir;
121                            }
122                            
123                            r = c.uploadFileFromURL(dnsName, privateKey, targetDir, targetFilename, uploadURL);
124                            
125                            if (r.getExceptionMessage() == null && r.getExitCode() == 0) success = true;
126                    
127                    } else {
128                            
129                            //iterate through uploaded files
130                            
131                            for (UploadItem item : files){
132                                    
133                                    String filename = FileUtils.extractFilename(item.getFileName());
134                                    
135                                    try {
136                                            byte[] filedata = FileUtils.getBytesFromFile(item.getFile());
137                                            
138                                            r = c.uploadFile(dnsName, privateKey, targetDir, filename, filedata);
139                                            
140                                            if (r.getExceptionMessage() == null && (r.getExitCode() == 0)){
141                                                    success = true;
142                                            } else {
143                                                    success = false;
144                                                    break;
145                                            }
146                                    } catch (Exception ex){
147                                            success = false;
148                                            break;
149                                    }
150                                    
151                            }
152                            
153                            
154                    }
155                    
156                    if (!success){
157                            facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_ERROR, "msg_fileNotUploaded");
158                            Logger.getAnonymousLogger().severe("Error uploading file: " + r.getExceptionMessage());
159                    } else {
160                            facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_INFO, "msg_fileUploaded");
161            
162                    }
163    
164                    //reset file after upload (the directory is kept in case the user wants to upload another file
165                    //to the same dir)
166                    this.files = new ArrayList<UploadItem>();
167                    targetFilename="";
168                    
169            }
170            
171            /**
172             * List the contents of a folder by remotely executing a ls -a.
173             * Stores the result in the corresponding member variable in order to provide access from the Facelets view.
174             * @param dnsName Hostname of instance.
175             * @param keyName Name of keypair to use.
176             * @param download boolean flag indicating whether the listing should be for file download or
177             * file upload area. In case of file download, a wildcard is inserted into the command (ls -a xyz*).
178             */
179            public void listFolder(String dnsName, String keyName, boolean download){
180                    
181                    //get the private key for the keyname
182                    String privateKey = userManager.getKeyForName(keyName);
183                    
184                    String result = "";
185                    
186                    String dir="";
187                    if (!download){
188                            dir = targetDir;
189                    } else {
190                            dir = downloadFilename + "*";
191                    }
192                    
193                    if (privateKey != null){
194                            
195                            RemoteControl c = new RemoteControl();
196                            
197                            RemoteResult r = c.executeCommand(dnsName, privateKey, "ls -a " + dir);
198                            
199                            if (r.getExceptionMessage() != null){
200                                    result =  "Exception: " + r.getExceptionMessage();
201                            } else if (!r.getStdErr().equals("")){
202                                    result = "Error: " + r.getStdErr();
203                            } else {
204                                    result =  r.getStdOut();
205                            }
206                    }
207                    
208                    if (!download){
209                            targetDirContent = result;
210                    } else {
211                            downloadDirContent = result;
212                    }
213                    
214            }
215            
216            /**
217             * Resets the file dialog by resetting the member variables for displayment in the UI.
218             */
219            public void resetFileDialog(){
220                    
221                    this.targetDirContent = "";
222                    targetDir = "";
223                    targetFilename = "";
224                    
225                    uploadFromURL = false;
226                    uploadURL = "";
227                    
228                    
229                    this.downloadDirContent="";
230                    downloadFilename="";
231                    
232                    this.clearUpload();
233                    
234                    
235            }
236            /**
237             * Resets the list of uploaded files.
238             */
239            public void clearUpload(){
240                    files =  new ArrayList<UploadItem>();
241            }
242            
243            
244            /**
245             * Download a file from an AMI instance and send it to the client using HTTP.
246             * @param dnsName Hostname of instance.
247             * @param keyName Name of keypair to use.
248             */
249            public void downloadFile(String dnsName, String keyName){
250                    
251    
252                    //check input first
253                    if (this.downloadFilename.equals("")) {
254                            
255                            facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_ERROR, "msg_invalidInput", "No file.");
256                            return;
257                            
258                    }
259                    
260                    RemoteControl c = new RemoteControl();
261                    
262                    //get the private key for the keyname
263                    String privateKey = userManager.getKeyForName(keyName);
264                    
265                    byte[] file = c.downloadFile(dnsName, privateKey, downloadFilename);
266                    
267                    if (file != null){
268                            //Create a HTTPResponse and send it back skipping the usual JSF lifecycle
269                            HttpServletResponse response = (HttpServletResponse)extCtx.getResponse();
270                            
271                            //response.setContentType(?);//content-type is unknown
272                            
273                            //the Header Content-Disposition causes a browser to display a download dialog instead
274                            //of trying to display the file directly. This way, content-type becomes irrelevant.
275                            //Use original filename as proposed filename for download dialog.
276                    String fname = downloadFilename.split("/")[downloadFilename.split("/").length - 1];
277                            response.setHeader( "Content-Disposition", "attachment; filename=\""
278                                            + fname + "\";");
279            
280                            //write file into response stream.
281                            try {
282                                    ServletOutputStream os = response.getOutputStream();
283                                    os.write(file);
284                                    os.flush();
285                                    os.close();
286                                    facesContext.responseComplete();
287                            } catch(Exception e) {
288                                    Logger.getAnonymousLogger().severe("Error serving downloaded file: " + e.getMessage());
289                            }
290                    } else {
291                            facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_ERROR, "msg_fileNotDownloaded");
292                            Logger.getAnonymousLogger().severe("Error downloading file.");
293                    }
294    
295            }
296    
297            
298            
299            //getters and setters for bean properties...
300            
301            /**
302             * @return the targetDirContent
303             */
304            public String getTargetDirContent() {
305                    return targetDirContent;
306            }
307    
308            /**
309             * @param targetDirContent the targetDirContent to set
310             */
311            public void setTargetDirContent(String targetDirContent) {
312                    this.targetDirContent = targetDirContent;
313            }
314    
315            /**
316             * @return the userManager
317             */
318            public UserManager getUserManager() {
319                    return userManager;
320            }
321    
322            /**
323             * @param userManager the userManager to set
324             */
325            public void setUserManager(UserManager userManager) {
326                    this.userManager = userManager;
327            }
328    
329            /**
330             * @return the targetDir
331             */
332            public String getTargetDir() {
333                    return targetDir;
334            }
335    
336            /**
337             * @param targetDir the targetDir to set
338             */
339            public void setTargetDir(String targetDir) {
340                    this.targetDir = targetDir;
341            }
342    
343            /**
344             * @return the targetFilename
345             */
346            public String getTargetFilename() {
347            
348                    return targetFilename;
349            }
350    
351            /**
352             * @param targetFilename the targetFilename to set
353             */
354            public void setTargetFilename(String targetFilename) {
355                    
356                    this.targetFilename = targetFilename;
357            }
358    
359            /**
360             * @return the uploadFromURL
361             */
362            public boolean isUploadFromURL() {
363                    return uploadFromURL;
364            }
365    
366            /**
367             * @param uploadFromURL the uploadFromURL to set
368             */
369            public void setUploadFromURL(boolean uploadFromURL) {
370                    this.uploadFromURL = uploadFromURL;
371            }
372    
373    
374    
375    
376            /**
377             * @return the uploadURL
378             */
379            public String getUploadURL() {
380                    return uploadURL;
381            }
382    
383            /**
384             * @param uploadURL the uploadURL to set
385             */
386            public void setUploadURL(String uploadURL) {
387                    this.uploadURL = uploadURL;
388            }
389    
390            /**
391             * @return the downloadFilename
392             */
393            public String getDownloadFilename() {
394                    return downloadFilename;
395            }
396    
397            /**
398             * @param downloadFilename the downloadFilename to set
399             */
400            public void setDownloadFilename(String downloadFilename) {
401                    this.downloadFilename = downloadFilename;
402            }
403    
404            /**
405             * @return the downloadDirContent
406             */
407            public String getDownloadDirContent() {
408                    return downloadDirContent;
409            }
410    
411            /**
412             * @param downloadDirContent the downloadDirContent to set
413             */
414            public void setDownloadDirContent(String downloadDirContent) {
415                    this.downloadDirContent = downloadDirContent;
416            }
417    
418            public List<UploadItem> getFiles() {
419                    return files;
420            }
421    
422            public void setFiles(List<UploadItem> files) {
423                    this.files = files;
424            }
425    }