[Fix/MNT-24209] logging for download restapi (#3065)

* [fix/MNT-24209] Adding loggers in ACS download restApi

* [fix/MNT-24209] Adding loggers in ACS download restApi

* [fix/MNT-24209] Adding loggers in ACS download restApi

* Update ZipDownloadExporter.java

* [fix/MNT-24209-logging-for-download-restapi] Adding loggers in downloads RestAPI

* Revert "Update ZipDownloadExporter.java"

This reverts commit 2d97b34959.

* resolved Pre commit error

* resolved Pre commit error

* Bump io.swagger:swagger-parser from 1.0.71 to 1.0.72 (#3044)

Bumps [io.swagger:swagger-parser](https://github.com/swagger-api/swagger-parser) from 1.0.71 to 1.0.72.
- [Release notes](https://github.com/swagger-api/swagger-parser/releases)
- [Commits](https://github.com/swagger-api/swagger-parser/compare/v1.0.71...v1.0.72)

---
updated-dependencies:
- dependency-name: io.swagger:swagger-parser
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* [maven-release-plugin][skip ci] prepare release 25.1.0.4

* [maven-release-plugin][skip ci] prepare for next development iteration

* Update the SiteMembership Class

* Update the SiteMembership Class

* Update the SiteMembership Class

* Revert "Update the SiteMembership Class"

This reverts commit 15045f9612.

* Update the SiteMembership Class

* Update the SiteMembership Class

* Update the license i SiteMembership

* Revert "Update the license i SiteMembership"

This reverts commit ee8f3bec18.

* Update the license SiteMembership

* Fix Precommit

* Fix Precommit

* Fix Precommit

* Update the SiteMembership

* [maven-release-plugin][skip ci] prepare release 25.1.0.5

* [maven-release-plugin][skip ci] prepare for next development iteration

* Revert "Bump dependency.log4j.version from 2.23.1 to 2.24.2 (#3051)"

This reverts commit 748be1f4a0.

* [fix/MNT-24209-logging-for-download-restapi] Adding loggers in downloads RestAPI

* resolved Pre commit error

* resolved Pre commit error

* reformatting ZipDownloadExporter file

* [fix/MNT-24209-logging-for-download-restapi] Adding loggers in downloads RestAPI

* [fix/MNT-24209-logging-for-download-restapi] Adding loggers in downloads RestAPI

* [fix/MNT-24209-logging-for-download-restapi] Adding loggers in downloads RestAPI

* [fix/MNT-24209-logging-for-download-restapi] Adding loggers in downloads RestAPI

* [fix/MNT-24209-logging-for-download-restapi] Adding loggers in downloads RestAPI

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: mohit-singh4 <mohit.singh@contractors.hyland.com>
Co-authored-by: MohinishSah <88024811+MohinishSah@users.noreply.github.com>
Co-authored-by: Mohinish Sah <Mohinish.Sah@contractors.onbase.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: alfresco-build <8039454+alfresco-build@users.noreply.github.com>
Co-authored-by: varapathijanakiram <172787912+varapathijanakiram@users.noreply.github.com>
Co-authored-by: vjanakiram <varapathi.janakiram@hyland.com>
Co-authored-by: rrajoria <88024787+rrajoria@users.noreply.github.com>
Co-authored-by: Cezary Witkowski <cezary.witkowski@hyland.com>
This commit is contained in:
mohit-singh4
2024-12-04 14:24:43 +05:30
committed by GitHub
parent 00c36251d4
commit de0ba15a91

View File

@@ -1,329 +1,344 @@
/* /*
* #%L * #%L
* Alfresco Repository * Alfresco Repository
* %% * %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited * Copyright (C) 2005 - 2024 Alfresco Software Limited
* %% * %%
* This file is part of the Alfresco software. * This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of * If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is * the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms: * provided under the following open source license terms:
* *
* Alfresco is free software: you can redistribute it and/or modify * Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* Alfresco is distributed in the hope that it will be useful, * Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. * GNU Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L% * #L%
*/ */
package org.alfresco.repo.download; package org.alfresco.repo.download;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.file.attribute.FileTime; import java.nio.file.attribute.FileTime;
import java.util.Date; import java.util.Date;
import java.util.Deque; import java.util.Deque;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import org.alfresco.model.ContentModel; import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream.UnicodeExtraFieldPolicy;
import org.alfresco.service.cmr.coci.CheckOutCheckInService; import org.slf4j.Logger;
import org.alfresco.service.cmr.dictionary.DictionaryService; import org.slf4j.LoggerFactory;
import org.alfresco.service.cmr.download.DownloadStatus;
import org.alfresco.service.cmr.download.DownloadStatus.Status; import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.coci.CheckOutCheckInService;
import org.alfresco.service.cmr.view.ExporterContext; import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.view.ExporterException; import org.alfresco.service.cmr.download.DownloadStatus;
import org.alfresco.service.namespace.QName; import org.alfresco.service.cmr.download.DownloadStatus.Status;
import org.alfresco.util.Pair; import org.alfresco.service.cmr.repository.ContentData;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; import org.alfresco.service.cmr.repository.NodeRef;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; import org.alfresco.service.cmr.repository.NodeService;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream.UnicodeExtraFieldPolicy; import org.alfresco.service.cmr.view.ExporterContext;
import org.slf4j.Logger; import org.alfresco.service.cmr.view.ExporterException;
import org.slf4j.LoggerFactory; import org.alfresco.service.namespace.QName;
import org.alfresco.util.Pair;
/** /**
* Handler for exporting node content to a ZIP file * Handler for exporting node content to a ZIP file
* *
* @author Alex Miller * @author Alex Miller
*/ */
public class ZipDownloadExporter extends BaseExporter public class ZipDownloadExporter extends BaseExporter
{ {
private static Logger log = LoggerFactory.getLogger(ZipDownloadExporter.class); private static Logger log = LoggerFactory.getLogger(ZipDownloadExporter.class);
private static final String PATH_SEPARATOR = "/"; private static final String PATH_SEPARATOR = "/";
protected ZipArchiveOutputStream zipStream; protected ZipArchiveOutputStream zipStream;
private NodeRef downloadNodeRef; private NodeRef downloadNodeRef;
private int sequenceNumber = 1; private int sequenceNumber = 1;
private long total; private long total;
private long done; private long done;
private long totalFileCount; private long totalFileCount;
private long filesAddedCount; private long filesAddedCount;
private RetryingTransactionHelper transactionHelper; private RetryingTransactionHelper transactionHelper;
private DownloadStorage downloadStorage; private DownloadStorage downloadStorage;
private DictionaryService dictionaryService; private DictionaryService dictionaryService;
private DownloadStatusUpdateService updateService; private DownloadStatusUpdateService updateService;
private Deque<Pair<String, NodeRef>> path = new LinkedList<Pair<String, NodeRef>>(); private Deque<Pair<String, NodeRef>> path = new LinkedList<Pair<String, NodeRef>>();
private String currentName; private String currentName;
private OutputStream outputStream; private OutputStream outputStream;
private Date zipTimestampCreated; private Date zipTimestampCreated;
private Date zipTimestampModified; private Date zipTimestampModified;
/** /**
* Construct * Construct
* *
* @param zipFile File * @param zipFile
* @param checkOutCheckInService CheckOutCheckInService * File
* @param nodeService NodeService * @param checkOutCheckInService
* @param transactionHelper RetryingTransactionHelper * CheckOutCheckInService
* @param updateService DownloadStatusUpdateService * @param nodeService
* @param downloadStorage DownloadStorage * NodeService
* @param dictionaryService DictionaryService * @param transactionHelper
* @param downloadNodeRef NodeRef * RetryingTransactionHelper
* @param total long * @param updateService
* @param totalFileCount long * DownloadStatusUpdateService
*/ * @param downloadStorage
public ZipDownloadExporter(File zipFile, CheckOutCheckInService checkOutCheckInService, NodeService nodeService, RetryingTransactionHelper transactionHelper, DownloadStatusUpdateService updateService, DownloadStorage downloadStorage, DictionaryService dictionaryService, NodeRef downloadNodeRef, long total, long totalFileCount) * DownloadStorage
{ * @param dictionaryService
super(checkOutCheckInService, nodeService); * DictionaryService
try * @param downloadNodeRef
{ * NodeRef
this.outputStream = new FileOutputStream(zipFile); * @param total
this.updateService = updateService; * long
this.transactionHelper = transactionHelper; * @param totalFileCount
this.downloadStorage = downloadStorage; * long
this.dictionaryService = dictionaryService; */
public ZipDownloadExporter(File zipFile, CheckOutCheckInService checkOutCheckInService, NodeService nodeService,
this.downloadNodeRef = downloadNodeRef; RetryingTransactionHelper transactionHelper, DownloadStatusUpdateService updateService,
this.total = total; DownloadStorage downloadStorage, DictionaryService dictionaryService,
this.totalFileCount = totalFileCount; NodeRef downloadNodeRef, long total, long totalFileCount)
} {
catch (FileNotFoundException e) super(checkOutCheckInService, nodeService);
{ try
throw new ExporterException("Failed to create zip file", e); {
} this.outputStream = new FileOutputStream(zipFile);
} this.updateService = updateService;
this.transactionHelper = transactionHelper;
@Override this.downloadStorage = downloadStorage;
public void start(final ExporterContext context) this.dictionaryService = dictionaryService;
{
zipStream = new ZipArchiveOutputStream(outputStream); this.downloadNodeRef = downloadNodeRef;
// NOTE: This encoding allows us to workaround bug... this.total = total;
// http://bugs.sun.com/bugdatabase/view_bug.do;:WuuT?bug_id=4820807 this.totalFileCount = totalFileCount;
zipStream.setEncoding("UTF-8"); }
zipStream.setCreateUnicodeExtraFields(UnicodeExtraFieldPolicy.ALWAYS); catch (FileNotFoundException e)
zipStream.setUseLanguageEncodingFlag(true); {
zipStream.setFallbackToUTF8(true); throw new ExporterException("Failed to create zip file", e);
} }
}
@Override
public void startNode(NodeRef nodeRef) @Override
{ public void start(final ExporterContext context)
this.currentName = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_NAME); {
this.zipTimestampCreated = (Date)nodeService.getProperty(nodeRef, ContentModel.PROP_CREATED); zipStream = new ZipArchiveOutputStream(outputStream);
this.zipTimestampModified = (Date)nodeService.getProperty(nodeRef, ContentModel.PROP_MODIFIED); // NOTE: This encoding allows us to workaround bug...
path.push(new Pair<String, NodeRef>(currentName, nodeRef)); // http://bugs.sun.com/bugdatabase/view_bug.do;:WuuT?bug_id=4820807
if (dictionaryService.isSubClass(nodeService.getType(nodeRef), ContentModel.TYPE_FOLDER)) zipStream.setEncoding("UTF-8");
{ zipStream.setCreateUnicodeExtraFields(UnicodeExtraFieldPolicy.ALWAYS);
String path = getPath() + PATH_SEPARATOR; zipStream.setUseLanguageEncodingFlag(true);
ZipArchiveEntry archiveEntry = new ZipArchiveEntry(path); zipStream.setFallbackToUTF8(true);
try }
{
archiveEntry.setTime(zipTimestampCreated.getTime()); @Override
archiveEntry.setCreationTime(FileTime.fromMillis(zipTimestampCreated.getTime())); public void startNode(NodeRef nodeRef)
archiveEntry.setLastModifiedTime(FileTime.fromMillis(zipTimestampModified.getTime())); {
zipStream.putArchiveEntry(archiveEntry); this.currentName = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_NAME);
zipStream.closeArchiveEntry(); this.zipTimestampCreated = (Date) nodeService.getProperty(nodeRef, ContentModel.PROP_CREATED);
} this.zipTimestampModified = (Date) nodeService.getProperty(nodeRef, ContentModel.PROP_MODIFIED);
catch (IOException e) path.push(new Pair<String, NodeRef>(currentName, nodeRef));
{ if (dictionaryService.isSubClass(nodeService.getType(nodeRef), ContentModel.TYPE_FOLDER))
throw new ExporterException("Unexpected IOException adding folder entry", e); {
} String path = getPath() + PATH_SEPARATOR;
} ZipArchiveEntry archiveEntry = new ZipArchiveEntry(path);
} try
{
@Override archiveEntry.setTime(zipTimestampCreated.getTime());
public void contentImpl(NodeRef nodeRef, QName property, InputStream content, ContentData contentData, int index) archiveEntry.setCreationTime(FileTime.fromMillis(zipTimestampCreated.getTime()));
{ archiveEntry.setLastModifiedTime(FileTime.fromMillis(zipTimestampModified.getTime()));
// if the content stream to output is empty, then just return content descriptor as is zipStream.putArchiveEntry(archiveEntry);
if (content == null) zipStream.closeArchiveEntry();
{ }
return; catch (IOException e)
} {
throw new ExporterException("Unexpected IOException adding folder entry", e);
try }
{ }
if (log.isDebugEnabled()) }
{
log.debug("Archiving content for nodeRef: "+nodeRef+" with contentURL: "+contentData.getContentUrl()); @Override
} public void contentImpl(NodeRef nodeRef, QName property, InputStream content, ContentData contentData, int index)
// ALF-2016 {
ZipArchiveEntry zipEntry=new ZipArchiveEntry(getPath()); // if the content stream to output is empty, then just return content descriptor as is
zipEntry.setTime(zipTimestampCreated.getTime()); if (content == null)
zipEntry.setCreationTime(FileTime.fromMillis(zipTimestampCreated.getTime())); {
zipEntry.setLastModifiedTime(FileTime.fromMillis(zipTimestampModified.getTime())); log.info("Archiving content has been removed or modified for the specified NodeReference: " + nodeRef
zipStream.putArchiveEntry(zipEntry); + ", and the size of the content is " + contentData.getSize());
return;
// copy export stream to zip }
copyStream(zipStream, content);
try
zipStream.closeArchiveEntry(); {
filesAddedCount = filesAddedCount + 1; if (log.isDebugEnabled())
} {
catch (IOException e) log.debug("Archiving content for nodeRef: " + nodeRef + " with contentURL: "
{ + contentData.getContentUrl());
throw new ExporterException("Failed to zip export stream", e); }
} // ALF-2016
} ZipArchiveEntry zipEntry = new ZipArchiveEntry(getPath());
zipEntry.setTime(zipTimestampCreated.getTime());
@Override zipEntry.setCreationTime(FileTime.fromMillis(zipTimestampCreated.getTime()));
public void endNode(NodeRef nodeRef) zipEntry.setLastModifiedTime(FileTime.fromMillis(zipTimestampModified.getTime()));
{ zipStream.putArchiveEntry(zipEntry);
path.pop();
} // copy export stream to zip
copyStream(zipStream, content);
@Override
public void end() zipStream.closeArchiveEntry();
{ filesAddedCount = filesAddedCount + 1;
try }
{ catch (IOException e)
zipStream.close(); {
} throw new ExporterException("Failed to zip export stream", e);
catch (IOException error) }
{ }
throw new ExporterException("Unexpected error closing zip stream!", error);
} @Override
} public void endNode(NodeRef nodeRef)
{
private String getPath() path.pop();
{ }
if (path.size() < 1)
{ @Override
throw new IllegalStateException("No elements in path!"); public void end()
} {
try
Iterator<Pair<String, NodeRef>> iter = path.descendingIterator(); {
StringBuilder pathBuilder = new StringBuilder(); zipStream.close();
}
while (iter.hasNext()) catch (IOException error)
{ {
Pair<String, NodeRef> element = iter.next(); throw new ExporterException("Unexpected error closing zip stream!", error);
}
pathBuilder.append(element.getFirst()); }
if (iter.hasNext())
{ private String getPath()
pathBuilder.append(PATH_SEPARATOR); {
} if (path.size() < 1)
} {
throw new IllegalStateException("No elements in path!");
return pathBuilder.toString(); }
}
Iterator<Pair<String, NodeRef>> iter = path.descendingIterator();
/** StringBuilder pathBuilder = new StringBuilder();
* Copy input stream to output stream
* while (iter.hasNext())
* @param output output stream {
* @param in input stream Pair<String, NodeRef> element = iter.next();
* @throws IOException
*/ pathBuilder.append(element.getFirst());
private void copyStream(OutputStream output, InputStream in) if (iter.hasNext())
throws IOException {
{ pathBuilder.append(PATH_SEPARATOR);
byte[] buffer = new byte[2048 * 10]; }
int read = in.read(buffer, 0, 2048 *10); }
int i = 0;
while (read != -1) return pathBuilder.toString();
{ }
output.write(buffer, 0, read);
done = done + read; /**
* Copy input stream to output stream
// ALF-16289 - only update the status every 10MB *
if (i++%500 == 0) * @param output
{ * output stream
updateStatus(); * @param in
checkCancelled(); * input stream
} * @throws IOException
*/
read = in.read(buffer, 0, 2048 *10); private void copyStream(OutputStream output, InputStream in) throws IOException
} {
} byte[] buffer = new byte[2048 * 10];
int read = in.read(buffer, 0, 2048 * 10);
private void checkCancelled() int i = 0;
{ while (read != -1)
boolean downloadCancelled = transactionHelper.doInTransaction(new RetryingTransactionCallback<Boolean>() {
{ output.write(buffer, 0, read);
@Override done = done + read;
public Boolean execute() throws Throwable
{ // ALF-16289 - only update the status every 10MB
return downloadStorage.isCancelled(downloadNodeRef); if (i++ % 500 == 0)
} {
}, true, true); updateStatus();
checkCancelled();
if ( downloadCancelled == true) }
{
log.debug("Download cancelled"); read = in.read(buffer, 0, 2048 * 10);
throw new DownloadCancelledException(); }
} }
}
private void checkCancelled()
private void updateStatus() {
{ boolean downloadCancelled = transactionHelper.doInTransaction(new RetryingTransactionCallback<Boolean>() {
transactionHelper.doInTransaction(new RetryingTransactionCallback<Object>() @Override
{ public Boolean execute() throws Throwable
@Override {
public Object execute() throws Throwable return downloadStorage.isCancelled(downloadNodeRef);
{ }
DownloadStatus status = new DownloadStatus(Status.IN_PROGRESS, done, total, filesAddedCount, totalFileCount); }, true, true);
updateService.update(downloadNodeRef, status, getNextSequenceNumber()); if (downloadCancelled == true)
return null; {
} log.debug("Download cancelled");
}, false, true); throw new DownloadCancelledException();
} }
}
public int getNextSequenceNumber()
{ private void updateStatus()
return sequenceNumber++; {
} transactionHelper.doInTransaction(new RetryingTransactionCallback<Object>() {
@Override
public long getDone() public Object execute() throws Throwable
{ {
return done; DownloadStatus status = new DownloadStatus(Status.IN_PROGRESS, done, total, filesAddedCount, totalFileCount);
}
updateService.update(downloadNodeRef, status, getNextSequenceNumber());
public long getTotal() return null;
{ }
return total; }, false, true);
} }
public long getFilesAdded() public int getNextSequenceNumber()
{ {
return filesAddedCount; return sequenceNumber++;
} }
public long getTotalFiles() public long getDone()
{ {
return totalFileCount; return done;
} }
}
public long getTotal()
{
return total;
}
public long getFilesAdded()
{
return filesAddedCount;
}
public long getTotalFiles()
{
return totalFileCount;
}
}