package com.openkm.servlet.frontend;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.openkm.api.OKMAuth;
import com.openkm.api.OKMDocument;
import com.openkm.api.OKMFolder;
import com.openkm.api.OKMNotification;
import com.openkm.api.OKMProperty;
import com.openkm.bean.Document;
import com.openkm.bean.Folder;
import com.openkm.core.AccessDeniedException;
import com.openkm.core.Config;
import com.openkm.core.DatabaseException;
import com.openkm.core.FileSizeExceededException;
import com.openkm.core.ItemExistsException;
import com.openkm.core.PathNotFoundException;
import com.openkm.core.RepositoryException;
import com.openkm.core.UnsupportedMimeTypeException;
import com.openkm.core.VersionException;
import com.openkm.core.VirusDetectedException;
import com.openkm.extension.core.ExtensionException;
import com.openkm.frontend.client.contants.service.ErrorCode;
import com.openkm.frontend.client.contants.ui.UIFileUploadConstants;
import com.openkm.jcr.JCRUtils;
import com.openkm.util.FileUtils;
import com.openkm.util.SecureStore;
import com.openkm.util.impexp.ImpExpStats;
import com.openkm.util.impexp.RepositoryImporter;
import com.openkm.util.impexp.TextInfoDecorator;
import de.schlichtherle.io.File;
import de.schlichtherle.io.FileOutputStream;
/**
* FileUploadServlet
*
* @author pavila
*/
public class FileUploadServlet extends OKMHttpServlet {
private static Logger log = LoggerFactory.getLogger(FileUploadServlet.class);
private static final long serialVersionUID = 1L;
public static final int INSERT = 0;
public static final int UPDATE = 1;
private final String returnOKMessage = "OKM_OK";
public static final String FILE_UPLOAD_STATUS = "file_upload_status";
@SuppressWarnings("unchecked")
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
log.debug("doPost({}, {})", request, response);
String fileName = null;
InputStream is = null;
String path = null;
int action = 0;
boolean notify = false;
boolean importZip = false;
String users = null;
String roles = null;
String message = null;
String comment = null;
String folder = null;
String cipherName = null;
String rename = null;
PrintWriter out = null;
String uploadedDocPath = null;
java.io.File tmp = null;
updateSessionManager(request);
try {
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
response.setContentType("text/plain");
out = response.getWriter();
log.debug("isMultipart: {}", isMultipart);
// Create a factory for disk-based file items
if (isMultipart) {
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
FileUploadListener listener = new FileUploadListener();
// Saving listener to session
request.getSession().setAttribute(FILE_UPLOAD_STATUS, listener);
upload.setHeaderEncoding("UTF-8");
// upload servlet allows to set upload listener
upload.setProgressListener(listener);
List<FileItem> items = upload.parseRequest(request);
// Parse the request and get all parameters and the uploaded file
for (Iterator<FileItem> it = items.iterator(); it.hasNext();) {
FileItem item = it.next();
if (item.isFormField()) {
if (item.getFieldName().equals("path")) { path = item.getString("UTF-8"); }
if (item.getFieldName().equals("action")) { action = Integer.parseInt(item.getString("UTF-8")); }
if (item.getFieldName().equals("users")) { users = item.getString("UTF-8"); }
if (item.getFieldName().equals("roles")) { roles = item.getString("UTF-8"); }
if (item.getFieldName().equals("notify")) { notify = true; }
if (item.getFieldName().equals("importZip")) { importZip = true; }
if (item.getFieldName().equals("message")) { message = item.getString("UTF-8"); }
if (item.getFieldName().equals("comment")) { comment = item.getString("UTF-8"); }
if (item.getFieldName().equals("folder")) { folder = item.getString("UTF-8"); }
if (item.getFieldName().equals("cipherName")) { cipherName = item.getString("UTF-8"); }
if (item.getFieldName().equals("rename")) { rename = item.getString("UTF-8"); }
} else {
fileName = item.getName();
is = item.getInputStream();
}
}
// Save document with different name than uploading
if (rename!=null && !rename.equals("")) {
if (rename.contains(".")) {
fileName = rename;
} else {
// here rename not contains .
if (fileName.contains(".")) {
fileName = fileName.substring(fileName.indexOf("."));
fileName = rename + fileName;
}
}
}
// Now, we have read all parameters and the uploaded file
if (action == UIFileUploadConstants.ACTION_INSERT) {
if (fileName != null && !fileName.equals("")) {
if (importZip && FilenameUtils.getExtension(fileName).equalsIgnoreCase("zip")) {
log.info("Import zip file '{}' into '{}'", fileName, path);
String erroMsg = importZip(path, is);
if (erroMsg == null) {
out.print(returnOKMessage);
} else {
log.warn("erroMsg: {}", erroMsg);
out.print(erroMsg);
}
} else if (importZip && FilenameUtils.getExtension(fileName).equalsIgnoreCase("jar")) {
log.info("Import jar file '{}' into '{}'", fileName, path);
String erroMsg = importJar(path, is);
if (erroMsg == null) {
out.print(returnOKMessage);
} else {
log.warn("erroMsg: {}", erroMsg);
out.print(erroMsg);
}
} else {
fileName = FilenameUtils.getName(fileName);
log.info("Upload file '{}' into '{}'", fileName, path);
Document doc = new Document();
doc.setPath(path + "/" + fileName);
uploadedDocPath = OKMDocument.getInstance().create(null, doc, is).getPath();
// Case is uploaded a encrypted document
if (cipherName!=null && !cipherName.equals("")) {
OKMProperty.getInstance().setEncryption(null, doc.getPath(), cipherName);
}
// Return the path of the inserted document in response
out.print(returnOKMessage + " path["+URLEncoder.encode(uploadedDocPath,"UTF-8")+"]path");
}
}
} else if (action == UIFileUploadConstants.ACTION_UPDATE) {
log.info("File updated: {}", path);
// http://en.wikipedia.org/wiki/Truth_table#Applications => ¬p ∨ q
if (!Config.SYSTEM_DOCUMENT_NAME_MISMATCH_CHECK || JCRUtils.getName(path).equals(fileName)) {
OKMDocument document = OKMDocument.getInstance();
//added by vissu feb13
System.out.println("path= "+path);
Document doc = document.getProperties(null, path);
document.setContent(null, path, is);
document.checkin(null, path, comment);
uploadedDocPath = path;
// Case is uploaded a encrypted document
if (cipherName != null && !cipherName.equals("")) {
// Case updated document was not encripted yet
if (doc.getCipherName() == null) {
OKMProperty.getInstance().setEncryption(null, path, cipherName);
// In that case is mandatory compact the history
document.purgeVersionHistory(null, path);
}
} else {
// Case us uploaded a decrypt document
if (doc.getCipherName() != null && !doc.getCipherName().equals("")) {
OKMProperty.getInstance().unsetEncryption(null, path);
// In that case is mandatory compact the history too
document.purgeVersionHistory(null, path);
}
}
// Return the path of the inserted document in response
out.print(returnOKMessage + " path["+URLEncoder.encode(uploadedDocPath,"UTF-8")+"]path");
} else {
out.print(ErrorCode.get(ErrorCode.ORIGIN_OKMUploadService, ErrorCode.CAUSE_DocumentNameMismatch));
}
} else if (action == UIFileUploadConstants.ACTION_FOLDER) {
log.info("Folder create: {}", path);
Folder fld = new Folder();
fld.setPath(path + "/" + folder);
OKMFolder.getInstance().create(null, fld);
out.print(returnOKMessage);
}
listener.setUploadFinish(true); // Mark uploading operation has finished
// If the document have been added to the repository, perform user notification
if ((action == UIFileUploadConstants.ACTION_INSERT || action == UIFileUploadConstants.ACTION_UPDATE) & notify) {
List<String> userNames = new ArrayList<String>(Arrays.asList(users.split(",")));
List<String> roleNames = Arrays.asList(roles.split(","));
for (String role : roleNames) {
List<String> usersInRole = OKMAuth.getInstance().getUsersByRole(null, role);
for (String user : usersInRole) {
if (!userNames.contains(user)) {
userNames.add(user);
}
}
}
OKMNotification.getInstance().notify(null, uploadedDocPath, userNames, message, false);
}
} else {
// Used only when document is digital signed ( form in that case is not multiplart it's a normal post )
action = (request.getParameter("action")!=null?Integer.parseInt(request.getParameter("action")):-1);
if (action == UIFileUploadConstants.ACTION_DIGITAL_SIGNATURE_INSERT ||
action == UIFileUploadConstants.ACTION_DIGITAL_SIGNATURE_UPDATE) {
path = request.getParameter("path");
String data = request.getParameter("data");
tmp = java.io.File.createTempFile("okm", ".tmp");
FileOutputStream fos = new FileOutputStream(tmp);
BufferedOutputStream bos = new BufferedOutputStream(fos);
bos.write(SecureStore.b64Decode(data));
bos.flush();
bos.close();
fos.flush();
fos.close();
FileInputStream fis = new FileInputStream(tmp);
switch (action) {
case UIFileUploadConstants.ACTION_DIGITAL_SIGNATURE_INSERT:
Document newDoc = new Document();
path = path.substring(0,path.lastIndexOf(".")+1) + "pdf";
newDoc.setPath(path);
OKMDocument.getInstance().create(null, newDoc, fis);
break;
case UIFileUploadConstants.ACTION_DIGITAL_SIGNATURE_UPDATE:
OKMDocument.getInstance().checkout(null, path);
OKMDocument.getInstance().setContent(null, path, fis);
OKMDocument.getInstance().checkin(null, path, "Signed");
break;
}
}
}
} catch (AccessDeniedException e) {
log.warn(e.getMessage(), e);
out.print(ErrorCode.get(ErrorCode.ORIGIN_OKMUploadService, ErrorCode.CAUSE_AccessDenied));
} catch (PathNotFoundException e) {
log.warn(e.getMessage(), e);
out.print(ErrorCode.get(ErrorCode.ORIGIN_OKMUploadService, ErrorCode.CAUSE_PathNotFound));
} catch (ItemExistsException e) {
log.warn(e.getMessage(), e);
out.print(ErrorCode.get(ErrorCode.ORIGIN_OKMUploadService, ErrorCode.CAUSE_ItemExists));
} catch (UnsupportedMimeTypeException e) {
log.warn(e.getMessage(), e);
out.print(ErrorCode.get(ErrorCode.ORIGIN_OKMUploadService, ErrorCode.CAUSE_UnsupportedMimeType));
} catch (FileSizeExceededException e) {
log.warn(e.getMessage(), e);
out.print(ErrorCode.get(ErrorCode.ORIGIN_OKMUploadService, ErrorCode.CAUSE_FileSizeExceeded));
} catch (VirusDetectedException e) {
log.warn(e.getMessage(), e);
out.print(VirusDetectedException.class.getSimpleName() + " : "+ e.getMessage());
} catch (VersionException e) {
log.error(e.getMessage(), e);
out.print(ErrorCode.get(ErrorCode.ORIGIN_OKMUploadService, ErrorCode.CAUSE_Version));
} catch (RepositoryException e) {
log.error(e.getMessage(), e);
out.print(ErrorCode.get(ErrorCode.ORIGIN_OKMUploadService, ErrorCode.CAUSE_Repository));
} catch (DatabaseException e) {
log.error(e.getMessage(), e);
out.print(ErrorCode.get(ErrorCode.ORIGIN_OKMUploadService, ErrorCode.CAUSE_Database));
} catch (IOException e) {
log.error(e.getMessage(), e);
out.print(ErrorCode.get(ErrorCode.ORIGIN_OKMUploadService, ErrorCode.CAUSE_IO));
} catch (Exception e) {
log.error(e.getMessage(), e);
out.print(e.toString());
} finally {
if (tmp != null) {
tmp.delete();
}
IOUtils.closeQuietly(is);
out.flush();
IOUtils.closeQuietly(out);
System.gc();
}
}
/**
* Import zipped documents
*
* @param path Where import into the repository.
* @param is The zip file to import.
*/
private synchronized String importZip(String path, InputStream is) throws PathNotFoundException,
ItemExistsException, AccessDeniedException, RepositoryException, IOException,
DatabaseException, ExtensionException {
log.debug("importZip({}, {})", path, is);
java.io.File tmpIn = null;
java.io.File tmpOut = null;
String errorMsg = null;
try {
// Create temporal
tmpIn = File.createTempFile("okm", ".zip");
tmpOut = FileUtils.createTempDir();
FileOutputStream fos = new FileOutputStream(tmpIn);
IOUtils.copy(is, fos);
fos.close();
// Unzip files
File fileTmpIn = new File(tmpIn);
fileTmpIn.archiveCopyAllTo(tmpOut);
File.umount();
// Import files
StringWriter out = new StringWriter();
ImpExpStats stats = RepositoryImporter.importDocuments(null, tmpOut, path, false, out, new TextInfoDecorator(tmpOut));
if (!stats.isOk()) {
errorMsg = out.toString();
}
out.close();
} catch (IOException e) {
log.error("Error importing zip", e);
throw e;
} finally {
if (tmpIn != null) {
org.apache.commons.io.FileUtils.deleteQuietly(tmpIn);
}
if (tmpOut != null) {
org.apache.commons.io.FileUtils.deleteQuietly(tmpOut);
}
if (is != null) {
try {
is.close();
} catch (IOException e) {
log.error("Error closing zip input stream", e);
throw e;
}
}
}
log.debug("importZip: {}", errorMsg);
return errorMsg;
}
/**
* Import jarred documents
*
* @param path Where import into the repository.
* @param is The jar file to import.
*/
private String importJar(String path, InputStream is) throws PathNotFoundException,
ItemExistsException, AccessDeniedException, RepositoryException, IOException,
DatabaseException, ExtensionException {
log.debug("importJar({}, {})", path, is);
java.io.File tmpIn = null;
java.io.File tmpOut = null;
String errorMsg = null;
try {
// Create temporal
tmpIn = File.createTempFile("okm", ".jar");
tmpOut = FileUtils.createTempDir();
FileOutputStream fos = new FileOutputStream(tmpIn);
IOUtils.copy(is, fos);
fos.close();
// Unzip files
File fileTmpIn = new File(tmpIn);
fileTmpIn.archiveCopyAllTo(tmpOut);
// Import files
StringWriter out = new StringWriter();
ImpExpStats stats = RepositoryImporter.importDocuments(null, tmpOut, path, false, out, new TextInfoDecorator(tmpOut));
if (!stats.isOk()) {
errorMsg = out.toString();
}
out.close();
} catch (IOException e) {
log.error("Error importing jar", e);
throw e;
} finally {
if (tmpIn != null) {
File.umount();
org.apache.commons.io.FileUtils.deleteQuietly(tmpIn);
}
if (tmpOut != null) {
org.apache.commons.io.FileUtils.deleteQuietly(tmpOut);
}
if (is != null) {
try {
is.close();
} catch (IOException e) {
log.error("Error closing zip input stream", e);
throw e;
}
}
}
log.debug("importJar: {}", errorMsg);
return errorMsg;
}
}