1 /*******************************************************************************
2 * Copyright � Igor Barma, Alexandre Desoubeaux, Christian Martel, Eric Brun, Mathieu Amblard, Gwenael Gevet, Pierre Guillot, 2012
3 * Copyright Alexandre Desoubeaux, Christian Martel, Cedric Lecarpentier, Alexandre Lefevre, Marc Salvat 2014-2016
4 * Copyright Alexandre Desoubeaux, Christian Martel, Cedric Lecarpentier, Marc Salvat, Marc Suarez, Harifetra Ramamonjy 2017
6 * This file is part of the work and learning management system Pentila Nero.
8 * Pentila Nero is free software. You can redistribute it and/or modify since
9 * you respect the terms of either (at least one of the both license) :
10 * - under the terms of the GNU Affero General Public License as
11 * published by the Free Software Foundation, either version 3 of the
12 * License, or (at your option) any later version.
13 * - the CeCILL-C as published by CeCILL-C; either version 1 of the
14 * License, or any later version
15 * - the GNU Lesser General Public License as published by the
16 * Free Software Foundation, either version 3 of the license,
17 * or (at your option) any later version.
19 * There are special exceptions to the terms and conditions of the
20 * licenses as they are applied to this software. View the full text of
21 * the exception in file LICENSE-PROJECT.txt in the directory of this software
24 * Pentila Nero is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * Licenses for more details.
29 * You should have received a copy of the GNU Affero General Public License
30 * and the CeCILL-C and the GNU Lesser General Public License along with
31 * Pentila Nero. If not, see :
32 * <http://www.gnu.org/licenses/> and
33 * <http://www.cecill.info/licences.fr.html>.
34 ******************************************************************************/
35 package com.pentila.entSavoie.utils;
37 import java.io.BufferedInputStream;
38 import java.io.BufferedOutputStream;
39 import java.io.ByteArrayInputStream;
41 import java.io.FileInputStream;
42 import java.io.FileOutputStream;
43 import java.io.IOException;
44 import java.io.InputStream;
45 import java.io.OutputStream;
46 import java.text.DateFormat;
47 import java.text.SimpleDateFormat;
48 import java.util.ArrayList;
49 import java.util.HashSet;
50 import java.util.List;
51 import java.util.zip.Deflater;
52 import java.util.zip.ZipEntry;
53 import java.util.zip.ZipInputStream;
54 import java.util.zip.ZipOutputStream;
56 import javax.portlet.ResourceRequest;
58 import org.apache.commons.compress.archivers.ArchiveEntry;
59 import org.apache.commons.compress.archivers.ArchiveException;
60 import org.apache.commons.compress.archivers.ArchiveInputStream;
61 import org.apache.commons.compress.archivers.ArchiveStreamFactory;
62 import org.apache.commons.compress.archivers.sevenz.SevenZFile;
63 import org.apache.commons.logging.Log;
64 import org.apache.commons.logging.LogFactory;
66 import com.liferay.portal.kernel.dao.orm.QueryUtil;
67 import com.liferay.portal.kernel.exception.PortalException;
68 import com.liferay.portal.kernel.exception.SystemException;
69 import com.liferay.portal.kernel.io.FileCacheOutputStream;
70 import com.liferay.portal.kernel.repository.model.FileEntry;
71 import com.liferay.portal.kernel.repository.model.Folder;
72 import com.liferay.portal.kernel.util.ParamUtil;
73 import com.liferay.portal.model.Layout;
74 import com.liferay.portal.model.Organization;
75 import com.liferay.portal.model.User;
76 import com.liferay.portal.model.UserGroup;
77 import com.liferay.portal.security.permission.PermissionChecker;
78 import com.liferay.portal.security.permission.PermissionCheckerFactoryUtil;
79 import com.liferay.portal.service.LayoutLocalServiceUtil;
80 import com.liferay.portal.service.ServiceContext;
81 import com.liferay.portal.util.PortalUtil;
82 import com.liferay.portlet.documentlibrary.service.DLAppLocalServiceUtil;
83 import com.liferay.portlet.documentlibrary.service.DLFileEntryLocalServiceUtil;
84 import com.pentila.entSavoie.applicationManager.ApplicationManagerUtils;
85 import com.pentila.entSavoie.casier.Constants;
86 import com.pentila.entSavoie.directory.OrganizationFinderServiceUtil;
87 import com.pentila.entSavoie.gestionMenus.model.EntityMenu;
88 import com.pentila.entSavoie.gestionMenus.service.EntityMenuLocalServiceUtil;
90 public class ZipUtil {
92 private static Log logger = LogFactory.getLog(ZipUtil.class);
93 static DateFormat returnDF = new SimpleDateFormat("MM/dd/yyyy HH:mm");
96 * Get request parameters and unzip archive
98 * @param resourceRequest
100 * @throws PortalException
101 * @throws SystemException
102 * @throws IOException
103 * @throws ArchiveException
105 public static Folder unzipFile(ResourceRequest resourceRequest)
106 throws PortalException, SystemException, IOException, ArchiveException {
108 final User user = PortalUtil.getUser(resourceRequest);
109 final long fileEntryId = ParamUtil.getLong(resourceRequest, "fileEntryId");
110 final String title = ParamUtil.getString(resourceRequest, "title");
112 return unzipFile(user, fileEntryId, title);
122 * @throws SystemException
123 * @throws IOException
124 * @throws PortalException
125 * @throws ArchiveException
127 public static Folder unzipFile(User user, long fileEntryId, String title) throws SystemException, IOException, PortalException, ArchiveException {
129 FileEntry fileEntry = DLAppLocalServiceUtil.getFileEntry(fileEntryId);
130 InputStream is = fileEntry.getContentStream();
132 Folder rootFolder = DLAppUtil.addFolder(user.getUserId(), fileEntry.getGroupId(), fileEntry.getFolderId(),
135 if (rootFolder == null) {
139 unArchiveFileProccess(is, fileEntry.getGroupId(), rootFolder, user);
146 * Is it possible to unarchive this file ?
148 * @param fileExtension
149 * @return true if possible to unarchive
151 public static boolean canUnArchive(String fileExtension) {
152 return (fileExtension.equals("zip") || fileExtension.equals("tar") || fileExtension.equals("ar")
153 || fileExtension.equals("jar") || fileExtension.equals("dump") || fileExtension.equals("cpio")
154 || fileExtension.equals("7z"));
158 * The inner unarchiving process
161 * @param scopeGroupId
164 * @throws SystemException
165 * @throws PortalException
166 * @throws IOException
167 * @throws ArchiveException
169 private static void unArchiveFileProccess(InputStream is, long scopeGroupId, Folder rootFolder, User user)
170 throws SystemException, PortalException, IOException, ArchiveException {
171 BufferedInputStream bis = new BufferedInputStream(is);
172 ArchiveInputStream ais = null;
173 SevenZFile sevenZFile = null;
174 File tempFile = null;
176 if (ArchiveStreamFactory.detect(bis).equals(ArchiveStreamFactory.SEVEN_Z)) {
177 tempFile = File.createTempFile("archive", "7z");
179 OutputStream outputStream = new FileOutputStream(tempFile, false);
182 byte[] bytes = new byte[1024];
184 while ((read = bis.read(bytes)) != -1) {
185 outputStream.write(bytes, 0, read);
188 sevenZFile = new SevenZFile(tempFile);
189 outputStream.close();
192 ais = new ArchiveStreamFactory().createArchiveInputStream(bis);
195 ArchiveEntry entry = null;
197 // Loop over archive entries
198 while ((entry = sevenZFile != null ? sevenZFile.getNextEntry() : ais.getNextEntry()) != null) {
200 if (!entry.isDirectory()) {
201 String[] filePath = entry.getName().split("/");
202 List<String> filePathList = new ArrayList<String>();
203 for (int i = 0; i < filePath.length; i++) {
204 filePathList.add(filePath[i]);
207 // on recupere le dossier qui doit contenir le fichier
208 Folder targetFolder = getTargetFolder(filePathList.subList(0, filePathList.size() - 1), rootFolder,
211 String targetFileName = "";
212 targetFileName = filePathList.get(filePathList.size() - 1);
215 final int BUFFER = 2048;
217 FileCacheOutputStream myFile = new FileCacheOutputStream();
219 byte data[] = new byte[BUFFER];
220 if (sevenZFile != null) {
221 while ((count = sevenZFile.read(data, 0, BUFFER)) != -1) {
222 myFile.write(data, 0, count);
225 while ((count = ais.read(data, 0, BUFFER)) != -1) {
226 myFile.write(data, 0, count);
230 DLAppUtil.addFileEntry(user, targetFolder, targetFileName, myFile.getBytes());
233 if (tempFile != null) {
239 if (sevenZFile != null) {
245 private static Folder getTargetFolder(List<String> filePathList, Folder rootFolder, User user, long scopeGroupId)
246 throws SystemException, PortalException {
247 if (filePathList.isEmpty()) {
250 for (Folder f : DLAppLocalServiceUtil.getFolders(scopeGroupId, rootFolder.getFolderId())) {
251 if (f.getName().equals(filePathList.get(0))) {
252 return getTargetFolder(filePathList.subList(1, filePathList.size()), f, user, scopeGroupId);
256 Folder newFolder = DLAppLocalServiceUtil.addFolder(user.getUserId(), scopeGroupId, rootFolder.getFolderId(),
257 filePathList.get(0), "", new ServiceContext());
258 PermissionsUtils.setParentPermissionToFolder(newFolder);
260 return getTargetFolder(filePathList.subList(1, filePathList.size()), newFolder, user, scopeGroupId);
265 * Loop over files of folder to add them into zip archive
268 * @param folderEntries
271 * @param permissionChecker
272 * @throws SystemException
273 * @throws PortalException
275 public static void addFolderToZip(User user, List<Folder> folderEntries, String directory, ZipOutputStream out,
276 PermissionChecker permissionChecker) throws SystemException, PortalException {
277 for (Folder dlfo : folderEntries) {
278 if (PermissionsUtils.checkFolderPermission(permissionChecker, dlfo, "VIEW")) {
280 List<FileEntry> ldlfe = DLAppLocalServiceUtil.getFileEntries(dlfo.getGroupId(), dlfo.getFolderId(),
281 QueryUtil.ALL_POS, QueryUtil.ALL_POS);
283 // Rename '._CASIER_' and "Mes documents" folder
284 String folderName = "";
285 if (dlfo.getName().equals(Constants.DROP_BOX_FOLDER_NAME)) {
286 folderName = "Casier";
287 } else if (dlfo.getName().equals(Constants.SCHOOL_BAG_FOLDER_NAME)) {
288 folderName = getDocumentsFolderName(user);
290 folderName = dlfo.getName();
293 addFileEntriesToZip(user, ldlfe, directory + folderName + "/", out, permissionChecker);
296 List<Folder> ldlfo = DLAppLocalServiceUtil.getFolders(dlfo.getGroupId(), dlfo.getFolderId());
297 addFolderToZip(user, ldlfo, directory + folderName + "/", out, permissionChecker);
303 * Add a list of file entries into a zip archive
309 * @param permissionChecker
311 public static void addFileEntriesToZip(User user, List<FileEntry> fileEntries, String folderPath,
312 ZipOutputStream out, PermissionChecker permissionChecker) {
313 for (FileEntry dlfe : fileEntries) {
314 logger.info("Adding file " + dlfe.getTitle() + " (id "+dlfe.getFileEntryId()+") into zip with folderPath=" + folderPath);
316 if (PermissionsUtils.checkFilePermission(permissionChecker, dlfe, "VIEW")) {
318 InputStream inputStream = DLFileEntryLocalServiceUtil.getFileAsStream(user.getUserId(),
319 dlfe.getFileEntryId(), dlfe.getVersion());
321 // Add ZIP entry to output stream.
322 out.putNextEntry(new ZipEntry(folderPath + dlfe.getTitle()));
324 byte buf[] = new byte[1024];
326 while ((len = inputStream.read(buf)) > 0) {
327 out.write(buf, 0, len);
332 } catch (Exception e) {
333 logger.error("Error while adding file entry into zip archive", e);
341 * Get the personal document folder from the menu
346 private static String getDocumentsFolderName(User user) {
350 Organization org = OrganizationFinderServiceUtil.getEtabRatachement(user);
355 HashSet<UserGroup> allAppliUserGroup = ApplicationManagerUtils.getUserApplicationRoles(user);
356 // We do not take the management(gestion) portlets and we put a
357 // clean label for each portlet
358 for (UserGroup a : allAppliUserGroup) {
359 for (Layout l : LayoutLocalServiceUtil.getLayouts(a.getGroup().getGroupId(), true)) {
360 // If the layout is the workspace one we get the label
361 if (l.getTypeSettings().contains(PortletConstant.CARTABLE_PORTLET_ID)) {
362 for (EntityMenu em : EntityMenuLocalServiceUtil
363 .getEntityMenusByEtabId(org.getOrganizationId())) {
364 if (em.getAppRoleId() == a.getUserGroupId()) {
365 return em.getEntityName();
371 } catch (Exception e) {
372 logger.error("Could not ranslate the personnal document folder name", e);
375 return Constants.SCHOOL_BAG_FOLDER_NAME;
379 * A file as a string into a zip archive
386 public static void addStringFileToZip(String fileString, String fileName, String folderPath, ZipOutputStream out) {
388 InputStream inputStream = new ByteArrayInputStream(fileString.getBytes());
390 // Add ZIP entry to output stream.
391 out.putNextEntry(new ZipEntry(folderPath + fileName));
393 byte buf[] = new byte[1024];
395 while ((len = inputStream.read(buf)) > 0)
396 out.write(buf, 0, len);
400 } catch (Exception e) {
401 logger.error("Erreur lors de la creation des fichiers pour l'archive zip", e);
407 * Add a file as a byte array into a zip archive
414 public static void addByteArrayFileToZip(byte[] file, String fileName, String folderPath, ZipOutputStream out) {
417 InputStream inputStream = new ByteArrayInputStream(file);
419 // Add ZIP entry to output stream.
420 out.putNextEntry(new ZipEntry(folderPath + fileName));
422 byte buf[] = new byte[1024];
424 while ((len = inputStream.read(buf)) > 0)
425 out.write(buf, 0, len);
429 } catch (Exception e) {
430 logger.error("Erreur lors de la creation des fichiers pour l'archive zip", e);
439 * @param folderIdArray
442 * @throws PortalException
443 * @throws SystemException
444 * @throws IOException
446 public static FileCacheOutputStream createZipStream(User user, long[] folderIdArray, long[] fileIdArray)
447 throws PortalException, SystemException, IOException {
449 PermissionChecker permissionChecker = null;
451 permissionChecker = PermissionCheckerFactoryUtil.create(user);
452 } catch (Exception e) {
456 FileCacheOutputStream fcos = new FileCacheOutputStream();
457 ZipOutputStream zipOut = new ZipOutputStream(fcos);
458 zipOut.setLevel(Deflater.BEST_COMPRESSION);
461 List<FileEntry> fileEntries = new ArrayList<FileEntry>();
462 for (long fileEntryId : fileIdArray) {
463 if (fileEntryId != 0) {
464 FileEntry dlfe = DLAppLocalServiceUtil.getFileEntry(fileEntryId);
465 fileEntries.add(dlfe);
468 addFileEntriesToZip(user, fileEntries, "", zipOut, permissionChecker);
471 List<Folder> folderEntries = new ArrayList<Folder>();
472 for (long folderId : folderIdArray) {
474 Folder dlfo = DLAppLocalServiceUtil.getFolder(folderId);
475 folderEntries.add(dlfo);
478 addFolderToZip(user, folderEntries, "", zipOut, permissionChecker);
486 * Unzip file to given folder and recreate full hierarchy
488 public static void unzipFileToDir(File zipFile, File outputDir) {
490 ZipInputStream zin = new ZipInputStream(new FileInputStream(zipFile.getAbsolutePath()));
493 while ((entry = zin.getNextEntry()) != null) {
494 name = entry.getName();
495 if (entry.isDirectory()) {
496 mkdirs(outputDir, name);
502 mkdirs(outputDir, dir);
504 extractFile(zin, outputDir, name);
507 } catch (IOException e) {
512 private static final int BUFFER_SIZE = 4096;
514 private static void extractFile(ZipInputStream in, File outdir, String name) throws IOException {
515 System.out.println("In extract file : " + name + ", outDir=" + outdir.getAbsolutePath());
516 byte[] buffer = new byte[BUFFER_SIZE];
517 BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(new File(outdir, name)));
519 while ((count = in.read(buffer)) != -1)
520 out.write(buffer, 0, count);
524 private static void mkdirs(File outdir, String path) {
525 File d = new File(outdir, path);
530 private static String dirpart(String name) {
531 int s = name.lastIndexOf(File.separatorChar);
532 return s == -1 ? null : name.substring(0, s);