package er.directtoweb.components.misc; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import org.apache.log4j.Logger; import com.webobjects.appserver.WOActionResults; import com.webobjects.appserver.WOComponent; import com.webobjects.appserver.WOContext; import com.webobjects.appserver.WORequest; import com.webobjects.foundation.NSData; import com.webobjects.foundation.NSDictionary; import com.webobjects.foundation.NSPathUtilities; import com.webobjects.foundation.NSValidation; import er.directtoweb.components.ERDCustomEditComponent; import er.extensions.foundation.ERXSimpleTemplateParser; import er.extensions.foundation.ERXValueUtilities; import er.extensions.localization.ERXLocalizer; import er.extensions.validation.ERXValidationException; import er.extensions.validation.ERXValidationFactory; /** * Allows you to handle a file name on the server as a property. * You can upload and delete the contents. * @author ak * */ public class ERDEditFile extends ERDCustomEditComponent { /** * Do I need to update serialVersionUID? * See section 5.6 <cite>Type Changes Affecting Serialization</cite> on page 51 of the * <a href="http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf">Java Object Serialization Spec</a> */ private static final long serialVersionUID = 1L; static final Logger log = Logger.getLogger(ERDEditFile.class); // Instance variables for the name and contents of the upload public String fileName; public String uploadDirectory; public NSData fileContents; public NSDictionary extraBindings; public boolean shouldRaise = false; public boolean didUpload = false; public ERDEditFile(WOContext context) { super(context); } private String localizedValueForBinding(String binding) { String result = (String)valueForBinding(binding); if(result == null) { result = ERXLocalizer.currentLocalizer().localizedStringForKeyWithDefault("ERDEditFile." + binding); } return result; } public String selectMessage() { String result = localizedValueForBinding("selectMessage"); return result; } public String uploadMessage() { String result = localizedValueForBinding("uploadMessage"); return result; } public String selectButton() { String result = localizedValueForBinding("selectButton"); return result; } public String uploadButton() { String result = localizedValueForBinding("uploadButton"); return result; } public String deleteButton() { String result = localizedValueForBinding("deleteButton"); return result; } void extract(InputStream in, String[] files) throws IOException { ZipInputStream zis = new ZipInputStream(in); ZipEntry e; while ((e = zis.getNextEntry()) != null) { if (files == null) extractFile(zis, e); else { String name = e.getName(); for (int i = 0; i < files.length; i++) { String file = files[i].replace(File.separatorChar, '/'); if (name.startsWith(file)) { extractFile(zis, e); break; } } } } } void extractFile(ZipInputStream zis, ZipEntry e) throws IOException { String name = e.getName(); File f = new File(uploadDirectory() + File.separatorChar + e.getName().replace('/', File.separatorChar)); if (e.isDirectory()) { if (!f.exists() && !f.mkdirs() || !f.isDirectory()) throw new IOException("Can't create " + f.getPath()); if (log.isDebugEnabled()) log.debug("Processing: " + name); } else { if (f.getParent() != null) { File d = new File(f.getParent()); if (!d.exists() && !d.mkdirs() || !d.isDirectory()) throw new IOException("Can't create " + d.getPath()); } OutputStream os = new FileOutputStream(f); byte[] b = new byte[512]; int len; while ((len = zis.read(b, 0, b.length)) != -1) os.write(b, 0, len); zis.closeEntry(); os.close(); if (log.isDebugEnabled()) { if (e.getMethod() == 8) log.debug("Extracted: " + name); else log.debug("Inflated: " + name); } } } public String uploadDirectory() { if(uploadDirectory == null) { uploadDirectory = (String)valueForBinding("uploadDirectory"); if(uploadDirectory == null) { uploadDirectory = "/tmp"; } uploadDirectory = ERXSimpleTemplateParser.sharedInstance().parseTemplateWithObject(uploadDirectory, null, this, object()); } return uploadDirectory; } @Override public WOActionResults invokeAction(WORequest worequest, WOContext wocontext) { WOActionResults results = super.invokeAction(worequest, wocontext); return results; } @Override public void takeValuesFromRequest(WORequest q, WOContext c) throws NSValidation.ValidationException { super.takeValuesFromRequest(q,c); uploadFile(); try { // allow for uploads that don't end up in the object if(key().charAt(0) != '#') object().validateTakeValueForKeyPath(objectKeyPathValue(),key()); } catch(Throwable e) { validationFailedWithException (e, objectKeyPathValue(), key()); } } /* public void awake() { super.awake(); if(!synchronizesVariablesWithBindings()) reset(); } */ @Override public void sleep() { if(!synchronizesVariablesWithBindings()) reset(); super.sleep(); } @Override public void reset() { fileName = null; fileContents = null; uploadDirectory = null; extraBindings = null; shouldRaise = false; didUpload = false; } @Override public boolean isStateless() { return false; } @Override public boolean synchronizesVariablesWithBindings() { return false; } public String fileName() { if(fileName == null) { fileName = (String)valueForBinding("fileName"); } if(fileName != null) { fileName = fileName.replace('\\', '/'); fileName = fileName.replace(':', '/'); fileName = NSPathUtilities.lastPathComponent(fileName); } return fileName; } public String realPath() { String fileName = fileName(); if(fileName == null || fileName().length() == 0) return null; File tmpPath = new File(uploadDirectory()); tmpPath.mkdirs(); String filePath = ( tmpPath.exists() ) ? tmpPath.getAbsolutePath() : System.getProperty( "user.dir" ); // Create the output path for the file on the application server return filePath + File.separator + lastPartOfFileName(); } public NSData fileContentz() { if(fileContents == null) { // fileContents = (NSData)valueForBinding("fileContentz"); } return fileContents; } public void setFileContentz(NSData data) { fileContents = data; } public boolean haveData() { if (fileContentz() != null && fileContentz().length() > 0 ) { return true; } return false; } @Override public void setObjectKeyPathValue(Object value) { if(key().charAt(0) != '#') super.setObjectKeyPathValue(value); } @Override public Object objectKeyPathValue() { if(key().charAt(0) != '#') return super.objectKeyPathValue(); return null; } /* */ public void deleteFile() { // Create the output path for the file on the application server if (fileExists()) { File file = new File(uploadDirectory() + File.separator + objectKeyPathValue()); file.delete(); log.debug( "Deleted file from '" + file + "'" ); } else { log.debug( "No File Deleted" ); } setObjectKeyPathValue(null); } public boolean shouldUnpack() { return ERXValueUtilities.booleanValueWithDefault(valueForBinding("shouldUnpack"), false); } public boolean fileExists() { if(uploadDirectory() != null && objectKeyPathValue() != null) return (new File(uploadDirectory() + File.separator + objectKeyPathValue())).exists(); return false; } public String lastPartOfFileName() { if(fileName() != null) { return NSPathUtilities.lastPathComponent(fileName()); } return null; } public void uploadFile() { // Create the output path for the file on the application server if(didUpload) return; if(fileContentz() == null || fileContentz().length() <= 0 ) { return; } String outputFilePath = realPath(); if (outputFilePath != null) { log.info("fileName: " + outputFilePath); if(new File(outputFilePath).exists()) { ERXValidationException ex = ERXValidationFactory.defaultFactory().createException(object(), key(), fileName(), "fileexists"); validationFailedWithException(ex, fileName(), key()); } else { try { FileOutputStream fileOutputStream = new FileOutputStream(outputFilePath); fileContentz().writeToStream(fileOutputStream); fileOutputStream.close(); log.debug( "Wrote file to '" + outputFilePath + "'" + shouldUnpack()); if(shouldUnpack()) { try { extract(new BufferedInputStream(new FileInputStream(outputFilePath)), null); } catch(IOException ex) { log.warn("Unpacking error: " + ex); } } setObjectKeyPathValue(lastPartOfFileName()); didUpload = true; } catch (IOException e) { log.error("Error writing file: " + e); } } } else { log.debug( "No File Uploaded" ); } } public WOComponent deleteAction() { deleteFile(); return context().page(); } public WOComponent uploadAction() { uploadFile(); return context().page(); } }