mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
ACS-1773 APPS-986 Refactor on TempOutputStream, BufferedRequest, BufferedResponse & RepositoryContainer (#584)
- remove the `TempOutputStream.deleteTempFileOnClose` capability - separate the `.close()` and the `.destroy()` methods in **TempOutputStream** (only the latter deletes the temp file) - made `BufferedRequest`&`BufferedResponse` **AutoClosable**; their `.close()` methods always calls `.destroy()` on the underlying _TempOutputStream_ object (thus triggering the removal of their temp files) - remove the `.destroy()` call from the `BufferedResponse.writeResponse()` method - use `BufferedRequest`&`BufferedResponse` in try-with-resources blocks (thus calling their `.close()` methods, which calls `.destroy()` on _TempOutputStream_, tiggering the removal of the temp files) - both in **RepositoryContainer** and in **ApiWebScripts** - replace the `TempOutputStreamFactory` class with a simple `Supplier<TempOutputStream>` - remove the `TempByteArrayOutputStream` inner class (replaced with `ByteArrayOutputStream`) - simplified the decision tree in some methods with the help of the IDE - other small improvements and changes
This commit is contained in:
@@ -29,6 +29,7 @@ import java.io.BufferedReader;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.springframework.extensions.surf.util.Content;
|
import org.springframework.extensions.surf.util.Content;
|
||||||
import org.springframework.extensions.webscripts.Description.FormatStyle;
|
import org.springframework.extensions.webscripts.Description.FormatStyle;
|
||||||
@@ -38,15 +39,15 @@ import org.springframework.extensions.webscripts.WebScriptRequest;
|
|||||||
import org.springframework.extensions.webscripts.WrappingWebScriptRequest;
|
import org.springframework.extensions.webscripts.WrappingWebScriptRequest;
|
||||||
import org.springframework.util.FileCopyUtils;
|
import org.springframework.util.FileCopyUtils;
|
||||||
|
|
||||||
public class BufferedRequest implements WrappingWebScriptRequest
|
public class BufferedRequest implements WrappingWebScriptRequest, AutoCloseable
|
||||||
{
|
{
|
||||||
private TempOutputStreamFactory streamFactory;
|
private final Supplier<TempOutputStream> streamFactory;
|
||||||
private WebScriptRequest req;
|
private final WebScriptRequest req;
|
||||||
private TempOutputStream bufferStream;
|
private TempOutputStream bufferStream;
|
||||||
private InputStream contentStream;
|
private InputStream contentStream;
|
||||||
private BufferedReader contentReader;
|
private BufferedReader contentReader;
|
||||||
|
|
||||||
public BufferedRequest(WebScriptRequest req, TempOutputStreamFactory streamFactory)
|
public BufferedRequest(WebScriptRequest req, Supplier<TempOutputStream> streamFactory)
|
||||||
{
|
{
|
||||||
this.req = req;
|
this.req = req;
|
||||||
this.streamFactory = streamFactory;
|
this.streamFactory = streamFactory;
|
||||||
@@ -56,7 +57,7 @@ public class BufferedRequest implements WrappingWebScriptRequest
|
|||||||
{
|
{
|
||||||
if (bufferStream == null)
|
if (bufferStream == null)
|
||||||
{
|
{
|
||||||
bufferStream = streamFactory.createOutputStream();
|
bufferStream = streamFactory.get();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -81,7 +82,7 @@ public class BufferedRequest implements WrappingWebScriptRequest
|
|||||||
}
|
}
|
||||||
if (contentStream == null)
|
if (contentStream == null)
|
||||||
{
|
{
|
||||||
contentStream = getBufferedBodyAsTempStream().getInputStream();
|
contentStream = getBufferedBodyAsTempStream().toNewInputStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
return contentStream;
|
return contentStream;
|
||||||
@@ -95,7 +96,7 @@ public class BufferedRequest implements WrappingWebScriptRequest
|
|||||||
{
|
{
|
||||||
contentStream.close();
|
contentStream.close();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception ignore)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
contentStream = null;
|
contentStream = null;
|
||||||
@@ -106,13 +107,14 @@ public class BufferedRequest implements WrappingWebScriptRequest
|
|||||||
{
|
{
|
||||||
contentReader.close();
|
contentReader.close();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception ignore)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
contentReader = null;
|
contentReader = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void close()
|
public void close()
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
@@ -122,7 +124,7 @@ public class BufferedRequest implements WrappingWebScriptRequest
|
|||||||
{
|
{
|
||||||
bufferStream.destroy();
|
bufferStream.destroy();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception ignore)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
bufferStream = null;
|
bufferStream = null;
|
||||||
|
@@ -28,6 +28,7 @@ package org.alfresco.repo.web.scripts;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.alfresco.error.AlfrescoRuntimeException;
|
import org.alfresco.error.AlfrescoRuntimeException;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
@@ -42,25 +43,24 @@ import org.springframework.util.FileCopyUtils;
|
|||||||
/**
|
/**
|
||||||
* Transactional Buffered Response
|
* Transactional Buffered Response
|
||||||
*/
|
*/
|
||||||
public class BufferedResponse implements WrappingWebScriptResponse
|
public class BufferedResponse implements WrappingWebScriptResponse, AutoCloseable
|
||||||
{
|
{
|
||||||
// Logger
|
// Logger
|
||||||
protected static final Log logger = LogFactory.getLog(BufferedResponse.class);
|
protected static final Log logger = LogFactory.getLog(BufferedResponse.class);
|
||||||
|
|
||||||
private TempOutputStreamFactory streamFactory;
|
private final Supplier<TempOutputStream> streamFactory;
|
||||||
private WebScriptResponse res;
|
private final WebScriptResponse res;
|
||||||
private int bufferSize;
|
private final int bufferSize;
|
||||||
private TempOutputStream outputStream = null;
|
private TempOutputStream outputStream;
|
||||||
private StringBuilderWriter outputWriter = null;
|
private StringBuilderWriter outputWriter;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct
|
* Construct
|
||||||
*
|
*
|
||||||
* @param res WebScriptResponse
|
* @param res WebScriptResponse
|
||||||
* @param bufferSize int
|
* @param bufferSize int
|
||||||
*/
|
*/
|
||||||
public BufferedResponse(WebScriptResponse res, int bufferSize, TempOutputStreamFactory streamFactory)
|
public BufferedResponse(WebScriptResponse res, int bufferSize, Supplier<TempOutputStream> streamFactory)
|
||||||
{
|
{
|
||||||
this.res = res;
|
this.res = res;
|
||||||
this.bufferSize = bufferSize;
|
this.bufferSize = bufferSize;
|
||||||
@@ -71,6 +71,7 @@ public class BufferedResponse implements WrappingWebScriptResponse
|
|||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.alfresco.web.scripts.WrappingWebScriptResponse#getNext()
|
* @see org.alfresco.web.scripts.WrappingWebScriptResponse#getNext()
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public WebScriptResponse getNext()
|
public WebScriptResponse getNext()
|
||||||
{
|
{
|
||||||
return res;
|
return res;
|
||||||
@@ -123,16 +124,18 @@ public class BufferedResponse implements WrappingWebScriptResponse
|
|||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.alfresco.web.scripts.WebScriptResponse#getOutputStream()
|
* @see org.alfresco.web.scripts.WebScriptResponse#getOutputStream()
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public OutputStream getOutputStream() throws IOException
|
public OutputStream getOutputStream() throws IOException
|
||||||
{
|
{
|
||||||
if (outputStream == null)
|
if (outputStream != null)
|
||||||
{
|
{
|
||||||
if (outputWriter != null)
|
return outputStream;
|
||||||
{
|
|
||||||
throw new AlfrescoRuntimeException("Already buffering output writer");
|
|
||||||
}
|
|
||||||
outputStream = streamFactory.createOutputStream();
|
|
||||||
}
|
}
|
||||||
|
if (outputWriter != null)
|
||||||
|
{
|
||||||
|
throw new AlfrescoRuntimeException("Already buffering output writer");
|
||||||
|
}
|
||||||
|
outputStream = streamFactory.get();
|
||||||
return outputStream;
|
return outputStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,14 +154,15 @@ public class BufferedResponse implements WrappingWebScriptResponse
|
|||||||
*/
|
*/
|
||||||
public Writer getWriter() throws IOException
|
public Writer getWriter() throws IOException
|
||||||
{
|
{
|
||||||
if (outputWriter == null)
|
if (outputWriter != null)
|
||||||
{
|
{
|
||||||
if (outputStream != null)
|
return outputWriter;
|
||||||
{
|
|
||||||
throw new AlfrescoRuntimeException("Already buffering output stream");
|
|
||||||
}
|
|
||||||
outputWriter = new StringBuilderWriter(bufferSize);
|
|
||||||
}
|
}
|
||||||
|
if (outputStream != null)
|
||||||
|
{
|
||||||
|
throw new AlfrescoRuntimeException("Already buffering output stream");
|
||||||
|
}
|
||||||
|
outputWriter = new StringBuilderWriter(bufferSize);
|
||||||
return outputWriter;
|
return outputWriter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,15 +266,7 @@ public class BufferedResponse implements WrappingWebScriptResponse
|
|||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
logger.debug("Writing Transactional response: size=" + outputStream.getLength());
|
logger.debug("Writing Transactional response: size=" + outputStream.getLength());
|
||||||
|
|
||||||
try
|
FileCopyUtils.copy(outputStream.toNewInputStream(), res.getOutputStream());
|
||||||
{
|
|
||||||
outputStream.flush();
|
|
||||||
FileCopyUtils.copy(outputStream.getInputStream(), res.getOutputStream());
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
outputStream.destroy();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
@@ -278,4 +274,20 @@ public class BufferedResponse implements WrappingWebScriptResponse
|
|||||||
throw new AlfrescoRuntimeException("Failed to commit buffered response", e);
|
throw new AlfrescoRuntimeException("Failed to commit buffered response", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close()
|
||||||
|
{
|
||||||
|
if (outputStream != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
outputStream.destroy();
|
||||||
|
}
|
||||||
|
catch (Exception ignore)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
outputStream = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -25,12 +25,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.alfresco.repo.web.scripts;
|
package org.alfresco.repo.web.scripts;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import javax.transaction.Status;
|
import javax.transaction.Status;
|
||||||
@@ -40,7 +40,6 @@ import org.alfresco.error.AlfrescoRuntimeException;
|
|||||||
import org.alfresco.error.ExceptionStackUtil;
|
import org.alfresco.error.ExceptionStackUtil;
|
||||||
import org.alfresco.repo.model.Repository;
|
import org.alfresco.repo.model.Repository;
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
|
||||||
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
|
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
|
||||||
import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState;
|
import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState;
|
||||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||||
@@ -95,8 +94,7 @@ public class RepositoryContainer extends AbstractRuntimeContainer
|
|||||||
private String tempDirectoryName = null;
|
private String tempDirectoryName = null;
|
||||||
private int memoryThreshold = 4 * 1024 * 1024; // 4mb
|
private int memoryThreshold = 4 * 1024 * 1024; // 4mb
|
||||||
private long maxContentSize = (long) 4 * 1024 * 1024 * 1024; // 4gb
|
private long maxContentSize = (long) 4 * 1024 * 1024 * 1024; // 4gb
|
||||||
private TempOutputStreamFactory streamFactory = null;
|
private Supplier<TempOutputStream> streamFactory = null;
|
||||||
private TempOutputStreamFactory responseStreamFactory = null;
|
|
||||||
private String preserveHeadersPattern = null;
|
private String preserveHeadersPattern = null;
|
||||||
|
|
||||||
private Class<?>[] notPublicExceptions = new Class<?>[] {};
|
private Class<?>[] notPublicExceptions = new Class<?>[] {};
|
||||||
@@ -107,17 +105,16 @@ public class RepositoryContainer extends AbstractRuntimeContainer
|
|||||||
*/
|
*/
|
||||||
public void setup()
|
public void setup()
|
||||||
{
|
{
|
||||||
File tempDirectory = TempFileProvider.getTempDir(tempDirectoryName);
|
streamFactory = TempOutputStream.factory(
|
||||||
this.streamFactory = new TempOutputStreamFactory(tempDirectory, memoryThreshold, maxContentSize, encryptTempFiles, false);
|
TempFileProvider.getTempDir(tempDirectoryName),
|
||||||
this.responseStreamFactory = new TempOutputStreamFactory(tempDirectory, memoryThreshold, maxContentSize,
|
memoryThreshold, maxContentSize, encryptTempFiles);
|
||||||
encryptTempFiles, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setEncryptTempFiles(Boolean encryptTempFiles)
|
public void setEncryptTempFiles(Boolean encryptTempFiles)
|
||||||
{
|
{
|
||||||
if(encryptTempFiles != null)
|
if(encryptTempFiles != null)
|
||||||
{
|
{
|
||||||
this.encryptTempFiles = encryptTempFiles.booleanValue();
|
this.encryptTempFiles = encryptTempFiles;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,7 +127,7 @@ public class RepositoryContainer extends AbstractRuntimeContainer
|
|||||||
{
|
{
|
||||||
if(memoryThreshold != null)
|
if(memoryThreshold != null)
|
||||||
{
|
{
|
||||||
this.memoryThreshold = memoryThreshold.intValue();
|
this.memoryThreshold = memoryThreshold;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,7 +135,7 @@ public class RepositoryContainer extends AbstractRuntimeContainer
|
|||||||
{
|
{
|
||||||
if(maxContentSize != null)
|
if(maxContentSize != null)
|
||||||
{
|
{
|
||||||
this.maxContentSize = maxContentSize.longValue();
|
this.maxContentSize = maxContentSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,8 +243,7 @@ public class RepositoryContainer extends AbstractRuntimeContainer
|
|||||||
*/
|
*/
|
||||||
public Map<String, Object> getScriptParameters()
|
public Map<String, Object> getScriptParameters()
|
||||||
{
|
{
|
||||||
Map<String, Object> params = new HashMap<String, Object>();
|
Map<String, Object> params = new HashMap<>(super.getScriptParameters());
|
||||||
params.putAll(super.getScriptParameters());
|
|
||||||
addRepoParameters(params);
|
addRepoParameters(params);
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
@@ -259,16 +255,11 @@ public class RepositoryContainer extends AbstractRuntimeContainer
|
|||||||
public Map<String, Object> getTemplateParameters()
|
public Map<String, Object> getTemplateParameters()
|
||||||
{
|
{
|
||||||
// Ensure we have a transaction - we might be generating the status template after the main transaction failed
|
// Ensure we have a transaction - we might be generating the status template after the main transaction failed
|
||||||
return fallbackTransactionHelper.doInTransaction(new RetryingTransactionCallback<Map<String, Object>>()
|
return fallbackTransactionHelper.doInTransaction(() -> {
|
||||||
{
|
Map<String, Object> params = new HashMap<>(RepositoryContainer.super.getTemplateParameters());
|
||||||
public Map<String, Object> execute() throws Throwable
|
params.put(TemplateService.KEY_IMAGE_RESOLVER, imageResolver.getImageResolver());
|
||||||
{
|
addRepoParameters(params);
|
||||||
Map<String, Object> params = new HashMap<String, Object>();
|
return params;
|
||||||
params.putAll(RepositoryContainer.super.getTemplateParameters());
|
|
||||||
params.put(TemplateService.KEY_IMAGE_RESOLVER, imageResolver.getImageResolver());
|
|
||||||
addRepoParameters(params);
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
}, true);
|
}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,7 +312,7 @@ public class RepositoryContainer extends AbstractRuntimeContainer
|
|||||||
Throwable displayCause = ExceptionStackUtil.getCause(e, publicExceptions);
|
Throwable displayCause = ExceptionStackUtil.getCause(e, publicExceptions);
|
||||||
if (displayCause == null && hideCause != null)
|
if (displayCause == null && hideCause != null)
|
||||||
{
|
{
|
||||||
AlfrescoRuntimeException alf = null;
|
final AlfrescoRuntimeException alf;
|
||||||
if (e instanceof AlfrescoRuntimeException)
|
if (e instanceof AlfrescoRuntimeException)
|
||||||
{
|
{
|
||||||
alf = (AlfrescoRuntimeException) e;
|
alf = (AlfrescoRuntimeException) e;
|
||||||
@@ -342,116 +333,110 @@ public class RepositoryContainer extends AbstractRuntimeContainer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void executeScriptInternal(WebScriptRequest scriptReq, WebScriptResponse scriptRes, final Authenticator auth)
|
protected void executeScriptInternal(final WebScriptRequest scriptReq, final WebScriptResponse scriptRes, final Authenticator auth)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
final WebScript script = scriptReq.getServiceMatch().getWebScript();
|
final WebScript script = scriptReq.getServiceMatch().getWebScript();
|
||||||
final Description desc = script.getDescription();
|
final Description desc = script.getDescription();
|
||||||
final boolean debug = logger.isDebugEnabled();
|
final boolean debug = logger.isDebugEnabled();
|
||||||
|
|
||||||
// Escalate the webscript declared level of authentication to the container required authentication
|
// Escalate the webscript declared level of authentication to the container required authentication
|
||||||
// eg. must be guest if MT is enabled unless credentials are empty
|
// eg. must be guest if MT is enabled unless credentials are empty
|
||||||
RequiredAuthentication containerRequiredAuthentication = getRequiredAuthentication();
|
final RequiredAuthentication containerRequiredAuthentication = getRequiredAuthentication();
|
||||||
final RequiredAuthentication required = (desc.getRequiredAuthentication().compareTo(containerRequiredAuthentication) < 0 && !auth.emptyCredentials() ? containerRequiredAuthentication : desc.getRequiredAuthentication());
|
final RequiredAuthentication required = (desc.getRequiredAuthentication().compareTo(containerRequiredAuthentication) < 0 && !auth.emptyCredentials() ? containerRequiredAuthentication : desc.getRequiredAuthentication());
|
||||||
final boolean isGuest = scriptReq.isGuest();
|
final boolean isGuest = scriptReq.isGuest();
|
||||||
|
|
||||||
if (required == RequiredAuthentication.none)
|
if (required == RequiredAuthentication.none)
|
||||||
{
|
{
|
||||||
// TODO revisit - cleared here, in-lieu of WebClient clear
|
// TODO revisit - cleared here, in-lieu of WebClient clear
|
||||||
//AuthenticationUtil.clearCurrentSecurityContext();
|
//AuthenticationUtil.clearCurrentSecurityContext();
|
||||||
|
|
||||||
transactionedExecuteAs(script, scriptReq, scriptRes);
|
transactionedExecuteAs(script, scriptReq, scriptRes);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else if ((required == RequiredAuthentication.user || required == RequiredAuthentication.admin) && isGuest)
|
|
||||||
|
if ((required == RequiredAuthentication.user || required == RequiredAuthentication.admin) && isGuest)
|
||||||
{
|
{
|
||||||
throw new WebScriptException(HttpServletResponse.SC_UNAUTHORIZED, "Web Script " + desc.getId() + " requires user authentication; however, a guest has attempted access.");
|
throw new WebScriptException(HttpServletResponse.SC_UNAUTHORIZED, "Web Script " + desc.getId() + " requires user authentication; however, a guest has attempted access.");
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
try
|
AuthenticationUtil.pushAuthentication();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Determine if user already authenticated
|
||||||
|
//
|
||||||
|
if (debug)
|
||||||
{
|
{
|
||||||
AuthenticationUtil.pushAuthentication();
|
String currentUser = AuthenticationUtil.getFullyAuthenticatedUser();
|
||||||
|
logger.debug("Current authentication: " + (currentUser == null ? "unauthenticated" : "authenticated as " + currentUser));
|
||||||
//
|
logger.debug("Authentication required: " + required);
|
||||||
// Determine if user already authenticated
|
logger.debug("Guest login requested: " + isGuest);
|
||||||
//
|
|
||||||
if (debug)
|
|
||||||
{
|
|
||||||
String currentUser = AuthenticationUtil.getFullyAuthenticatedUser();
|
|
||||||
logger.debug("Current authentication: " + (currentUser == null ? "unauthenticated" : "authenticated as " + currentUser));
|
|
||||||
logger.debug("Authentication required: " + required);
|
|
||||||
logger.debug("Guest login requested: " + isGuest);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Apply appropriate authentication to Web Script invocation
|
|
||||||
//
|
|
||||||
RetryingTransactionCallback<Boolean> authWork = new RetryingTransactionCallback<Boolean>()
|
|
||||||
{
|
|
||||||
public Boolean execute() throws Exception
|
|
||||||
{
|
|
||||||
if (auth == null || auth.authenticate(required, isGuest))
|
|
||||||
{
|
|
||||||
// The user will now have been authenticated, based on HTTP Auth, Ticket etc
|
|
||||||
// Check that the user they authenticated as has appropriate access to the script
|
|
||||||
|
|
||||||
// Check to see if they supplied HTTP Auth or Ticket as guest, on a script that needs more
|
|
||||||
if (required == RequiredAuthentication.user || required == RequiredAuthentication.admin)
|
|
||||||
{
|
|
||||||
String authenticatedUser = AuthenticationUtil.getFullyAuthenticatedUser();
|
|
||||||
String runAsUser = AuthenticationUtil.getRunAsUser();
|
|
||||||
|
|
||||||
if ( (authenticatedUser == null) ||
|
|
||||||
(authenticatedUser.equals(runAsUser) && authorityService.hasGuestAuthority()) ||
|
|
||||||
(!authenticatedUser.equals(runAsUser) && authorityService.isGuestAuthority(authenticatedUser)) )
|
|
||||||
{
|
|
||||||
throw new WebScriptException(HttpServletResponse.SC_UNAUTHORIZED, "Web Script " + desc.getId() + " requires user authentication; however, a guest has attempted access.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check to see if they're admin or system on an Admin only script
|
|
||||||
if (required == RequiredAuthentication.admin && !(authorityService.hasAdminAuthority() || AuthenticationUtil.getFullyAuthenticatedUser().equals(AuthenticationUtil.getSystemUserName())))
|
|
||||||
{
|
|
||||||
throw new WebScriptException(HttpServletResponse.SC_UNAUTHORIZED, "Web Script " + desc.getId() + " requires admin authentication; however, a non-admin has attempted access.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (debug)
|
|
||||||
{
|
|
||||||
String currentUser = AuthenticationUtil.getFullyAuthenticatedUser();
|
|
||||||
logger.debug("Authentication: " + (currentUser == null ? "unauthenticated" : "authenticated as " + currentUser));
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
boolean readOnly = transactionService.isReadOnly();
|
|
||||||
boolean requiresNew = !readOnly && AlfrescoTransactionSupport.getTransactionReadState() == TxnReadState.TXN_READ_ONLY;
|
|
||||||
if (transactionService.getRetryingTransactionHelper().doInTransaction(authWork, readOnly, requiresNew))
|
|
||||||
{
|
|
||||||
// Execute Web Script if authentication passed
|
|
||||||
// The Web Script has its own txn management with potential runAs() user
|
|
||||||
transactionedExecuteAs(script, scriptReq, scriptRes);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new WebScriptException(HttpServletResponse.SC_UNAUTHORIZED, "Authentication failed for Web Script " + desc.getId());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
{
|
//
|
||||||
//
|
// Apply appropriate authentication to Web Script invocation
|
||||||
// Reset authentication for current thread
|
//
|
||||||
//
|
final RetryingTransactionCallback<Boolean> authWork = () -> {
|
||||||
AuthenticationUtil.popAuthentication();
|
if (auth != null && !auth.authenticate(required, isGuest))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// The user will now have been authenticated, based on HTTP Auth, Ticket etc
|
||||||
|
// Check that the user they authenticated as has appropriate access to the script
|
||||||
|
|
||||||
|
// Check to see if they supplied HTTP Auth or Ticket as guest, on a script that needs more
|
||||||
|
if (required == RequiredAuthentication.user || required == RequiredAuthentication.admin)
|
||||||
|
{
|
||||||
|
final String authenticatedUser = AuthenticationUtil.getFullyAuthenticatedUser();
|
||||||
|
final String runAsUser = AuthenticationUtil.getRunAsUser();
|
||||||
|
|
||||||
|
if ( (authenticatedUser == null) ||
|
||||||
|
(authenticatedUser.equals(runAsUser) && authorityService.hasGuestAuthority()) ||
|
||||||
|
(!authenticatedUser.equals(runAsUser) && authorityService.isGuestAuthority(authenticatedUser)) )
|
||||||
|
{
|
||||||
|
throw new WebScriptException(HttpServletResponse.SC_UNAUTHORIZED, "Web Script " + desc.getId() + " requires user authentication; however, a guest has attempted access.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check to see if they're admin or system on an Admin only script
|
||||||
|
if (required == RequiredAuthentication.admin && !(authorityService.hasAdminAuthority() || AuthenticationUtil.getFullyAuthenticatedUser().equals(AuthenticationUtil.getSystemUserName())))
|
||||||
|
{
|
||||||
|
throw new WebScriptException(HttpServletResponse.SC_UNAUTHORIZED, "Web Script " + desc.getId() + " requires admin authentication; however, a non-admin has attempted access.");
|
||||||
|
}
|
||||||
|
|
||||||
if (debug)
|
if (debug)
|
||||||
{
|
{
|
||||||
String currentUser = AuthenticationUtil.getFullyAuthenticatedUser();
|
String currentUser = AuthenticationUtil.getFullyAuthenticatedUser();
|
||||||
logger.debug("Authentication reset: " + (currentUser == null ? "unauthenticated" : "authenticated as " + currentUser));
|
logger.debug("Authentication: " + (currentUser == null ? "unauthenticated" : "authenticated as " + currentUser));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
final boolean readOnly = transactionService.isReadOnly();
|
||||||
|
final boolean requiresNew = !readOnly && AlfrescoTransactionSupport.getTransactionReadState() == TxnReadState.TXN_READ_ONLY;
|
||||||
|
if (!transactionService.getRetryingTransactionHelper().doInTransaction(authWork, readOnly, requiresNew))
|
||||||
|
{
|
||||||
|
throw new WebScriptException(HttpServletResponse.SC_UNAUTHORIZED, "Authentication failed for Web Script " + desc.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute Web Script if authentication passed
|
||||||
|
// The Web Script has its own txn management with potential runAs() user
|
||||||
|
transactionedExecuteAs(script, scriptReq, scriptRes);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Reset authentication for current thread
|
||||||
|
//
|
||||||
|
AuthenticationUtil.popAuthentication();
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
{
|
||||||
|
String currentUser = AuthenticationUtil.getFullyAuthenticatedUser();
|
||||||
|
logger.debug("Authentication reset: " + (currentUser == null ? "unauthenticated" : "authenticated as " + currentUser));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -467,191 +452,160 @@ public class RepositoryContainer extends AbstractRuntimeContainer
|
|||||||
protected void transactionedExecute(final WebScript script, final WebScriptRequest scriptReq, final WebScriptResponse scriptRes)
|
protected void transactionedExecute(final WebScript script, final WebScriptRequest scriptReq, final WebScriptResponse scriptRes)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
|
final Description description = script.getDescription();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
final Description description = script.getDescription();
|
|
||||||
if (description.getRequiredTransaction() == RequiredTransaction.none)
|
if (description.getRequiredTransaction() == RequiredTransaction.none)
|
||||||
{
|
{
|
||||||
script.execute(scriptReq, scriptRes);
|
script.execute(scriptReq, scriptRes);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
handleIOException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
final RequiredTransactionParameters trxParams = description.getRequiredTransactionParameters();
|
||||||
|
|
||||||
|
try (final BufferedRequest bufferedReq = newBufferedRequest(trxParams, scriptReq, streamFactory);
|
||||||
|
final BufferedResponse bufferedRes = newBufferedResponse(trxParams, scriptRes, streamFactory))
|
||||||
|
{
|
||||||
|
boolean readonly = description.getRequiredTransactionParameters().getCapability() == TransactionCapability.readonly;
|
||||||
|
boolean requiresNew = description.getRequiredTransaction() == RequiredTransaction.requiresnew;
|
||||||
|
|
||||||
|
// log a warning if we detect a GET webscript being run in a readwrite transaction, GET calls should
|
||||||
|
// NOT have any side effects so this scenario as a warning sign something maybe amiss, see ALF-10179.
|
||||||
|
if (logger.isDebugEnabled() && !readonly && "GET".equalsIgnoreCase(
|
||||||
|
description.getMethod()))
|
||||||
{
|
{
|
||||||
final BufferedRequest bufferedReq;
|
logger.debug("Webscript with URL '" + scriptReq.getURL() +
|
||||||
final BufferedResponse bufferedRes;
|
"' is a GET request but it's descriptor has declared a readwrite transaction is required");
|
||||||
RequiredTransactionParameters trxParams = description.getRequiredTransactionParameters();
|
}
|
||||||
if (trxParams.getCapability() == TransactionCapability.readwrite)
|
|
||||||
{
|
|
||||||
if (trxParams.getBufferSize() > 0)
|
|
||||||
{
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
logger.debug("Creating Transactional Response for ReadWrite transaction; buffersize=" + trxParams.getBufferSize());
|
|
||||||
|
|
||||||
// create buffered request and response that allow transaction retrying
|
try
|
||||||
bufferedReq = new BufferedRequest(scriptReq, streamFactory);
|
{
|
||||||
bufferedRes = new BufferedResponse(scriptRes, trxParams.getBufferSize(), responseStreamFactory);
|
final RetryingTransactionHelper transactionHelper = transactionService.getRetryingTransactionHelper();
|
||||||
}
|
if (script instanceof LoginPost)
|
||||||
else
|
{
|
||||||
|
//login script requires read-write transaction because of authorization interceptor
|
||||||
|
transactionHelper.setForceWritable(true);
|
||||||
|
}
|
||||||
|
transactionHelper.doInTransaction(() -> {
|
||||||
|
try
|
||||||
{
|
{
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
logger.debug("Transactional Response bypassed for ReadWrite - buffersize=0");
|
logger.debug("Begin retry transaction block: " + description.getRequiredTransaction() + ","
|
||||||
bufferedReq = null;
|
+ description.getRequiredTransactionParameters().getCapability());
|
||||||
bufferedRes = null;
|
|
||||||
}
|
if (bufferedReq == null || bufferedRes == null)
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bufferedReq = null;
|
|
||||||
bufferedRes = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// encapsulate script within transaction
|
|
||||||
RetryingTransactionCallback<Object> work = new RetryingTransactionCallback<Object>()
|
|
||||||
{
|
|
||||||
public Object execute() throws Exception
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
if (logger.isDebugEnabled())
|
script.execute(scriptReq, scriptRes);
|
||||||
logger.debug("Begin retry transaction block: " + description.getRequiredTransaction() + ","
|
|
||||||
+ description.getRequiredTransactionParameters().getCapability());
|
|
||||||
|
|
||||||
if (bufferedRes == null)
|
|
||||||
{
|
|
||||||
script.execute(scriptReq, scriptRes);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Reset the request and response in case of a transaction retry
|
|
||||||
bufferedReq.reset();
|
|
||||||
// REPO-4388 don't reset specified headers
|
|
||||||
bufferedRes.reset(preserveHeadersPattern);
|
|
||||||
script.execute(bufferedReq, bufferedRes);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
else
|
||||||
{
|
{
|
||||||
if (logger.isDebugEnabled())
|
// Reset the request and response in case of a transaction retry
|
||||||
{
|
bufferedReq.reset();
|
||||||
logger.debug("Transaction exception: " + description.getRequiredTransaction() + ": " + e.getMessage());
|
// REPO-4388 don't reset specified headers
|
||||||
// Note: user transaction shouldn't be null, but just in case inside this exception handler
|
bufferedRes.reset(preserveHeadersPattern);
|
||||||
UserTransaction userTrx = RetryingTransactionHelper.getActiveUserTransaction();
|
script.execute(bufferedReq, bufferedRes);
|
||||||
if (userTrx != null)
|
}
|
||||||
{
|
}
|
||||||
logger.debug("Transaction status: " + userTrx.getStatus());
|
catch (Exception e)
|
||||||
}
|
{
|
||||||
}
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("Transaction exception: " + description.getRequiredTransaction() + ": " + e.getMessage());
|
||||||
|
// Note: user transaction shouldn't be null, but just in case inside this exception handler
|
||||||
UserTransaction userTrx = RetryingTransactionHelper.getActiveUserTransaction();
|
UserTransaction userTrx = RetryingTransactionHelper.getActiveUserTransaction();
|
||||||
if (userTrx != null)
|
if (userTrx != null)
|
||||||
{
|
{
|
||||||
if (userTrx.getStatus() != Status.STATUS_MARKED_ROLLBACK)
|
logger.debug("Transaction status: " + userTrx.getStatus());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final UserTransaction userTrx = RetryingTransactionHelper.getActiveUserTransaction();
|
||||||
|
if (userTrx != null)
|
||||||
|
{
|
||||||
|
if (userTrx.getStatus() != Status.STATUS_MARKED_ROLLBACK)
|
||||||
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
logger.debug("Marking web script transaction for rollback");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
userTrx.setRollbackOnly();
|
||||||
|
}
|
||||||
|
catch (Throwable re)
|
||||||
{
|
{
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
logger.debug("Marking web script transaction for rollback");
|
logger.debug("Caught and ignoring exception during marking for rollback: " + re.getMessage());
|
||||||
try
|
|
||||||
{
|
|
||||||
userTrx.setRollbackOnly();
|
|
||||||
}
|
|
||||||
catch(Throwable re)
|
|
||||||
{
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
logger.debug("Caught and ignoring exception during marking for rollback: " + re.getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// re-throw original exception for retry
|
|
||||||
throw e;
|
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
logger.debug("End retry transaction block: " + description.getRequiredTransaction() + ","
|
|
||||||
+ description.getRequiredTransactionParameters().getCapability());
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
boolean readonly = description.getRequiredTransactionParameters().getCapability() == TransactionCapability.readonly;
|
|
||||||
boolean requiresNew = description.getRequiredTransaction() == RequiredTransaction.requiresnew;
|
|
||||||
|
|
||||||
// log a warning if we detect a GET webscript being run in a readwrite transaction, GET calls should
|
|
||||||
// NOT have any side effects so this scenario as a warning sign something maybe amiss, see ALF-10179.
|
|
||||||
if (logger.isDebugEnabled() && !readonly && "GET".equalsIgnoreCase(description.getMethod()))
|
|
||||||
{
|
|
||||||
logger.debug("Webscript with URL '" + scriptReq.getURL() +
|
|
||||||
"' is a GET request but it's descriptor has declared a readwrite transaction is required");
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
RetryingTransactionHelper transactionHelper = transactionService.getRetryingTransactionHelper();
|
|
||||||
if(script instanceof LoginPost)
|
|
||||||
{
|
|
||||||
//login script requires read-write transaction because of authorization intercepter
|
|
||||||
transactionHelper.setForceWritable(true);
|
|
||||||
}
|
|
||||||
transactionHelper.doInTransaction(work, readonly, requiresNew);
|
|
||||||
}
|
|
||||||
catch (TooBusyException e)
|
|
||||||
{
|
|
||||||
// Map TooBusyException to a 503 status code
|
|
||||||
throw new WebScriptException(HttpServletResponse.SC_SERVICE_UNAVAILABLE, e.getMessage(), e);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
// Get rid of any temporary files
|
|
||||||
if (bufferedReq != null)
|
|
||||||
{
|
|
||||||
bufferedReq.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure a response is always flushed after successful execution
|
// re-throw original exception for retry
|
||||||
if (bufferedRes != null)
|
throw e;
|
||||||
{
|
}
|
||||||
bufferedRes.writeResponse();
|
finally
|
||||||
}
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
logger.debug("End retry transaction block: " + description.getRequiredTransaction() + ","
|
||||||
|
+ description.getRequiredTransactionParameters().getCapability());
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}, readonly, requiresNew);
|
||||||
}
|
}
|
||||||
}
|
catch (TooBusyException e)
|
||||||
catch (IOException ioe)
|
|
||||||
{
|
|
||||||
Throwable socketException = ExceptionStackUtil.getCause(ioe, SocketException.class);
|
|
||||||
Class<?> clientAbortException = null;
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
clientAbortException = Class.forName("org.apache.catalina.connector.ClientAbortException");
|
// Map TooBusyException to a 503 status code
|
||||||
|
throw new WebScriptException(HttpServletResponse.SC_SERVICE_UNAVAILABLE, e.getMessage(), e);
|
||||||
}
|
}
|
||||||
catch (ClassNotFoundException e)
|
|
||||||
|
// Ensure a response is always flushed after successful execution
|
||||||
|
if (bufferedRes != null)
|
||||||
{
|
{
|
||||||
// do nothing
|
bufferedRes.writeResponse();
|
||||||
}
|
|
||||||
// Note: if you need to look for more exceptions in the stack, then create a static array and pass it in
|
|
||||||
if ((socketException != null && socketException.getMessage().contains("Broken pipe")) || (clientAbortException != null && ExceptionStackUtil.getCause(ioe, clientAbortException) != null))
|
|
||||||
{
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
{
|
|
||||||
logger.warn("Client has cut off communication", ioe);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
logger.info("Client has cut off communication");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw ioe;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void handleIOException(final IOException ioe) throws IOException
|
||||||
|
{
|
||||||
|
Throwable socketException = ExceptionStackUtil.getCause(ioe, SocketException.class);
|
||||||
|
Class<?> clientAbortException = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
clientAbortException = Class.forName("org.apache.catalina.connector.ClientAbortException");
|
||||||
|
}
|
||||||
|
catch (ClassNotFoundException e)
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
// Note: if you need to look for more exceptions in the stack, then create a static array and pass it in
|
||||||
|
if ((socketException != null && socketException.getMessage().contains("Broken pipe")) ||
|
||||||
|
(clientAbortException != null && ExceptionStackUtil.getCause(ioe, clientAbortException) != null))
|
||||||
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.warn("Client has cut off communication", ioe);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.info("Client has cut off communication");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw ioe;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute script within required level of transaction as required effective user.
|
* Execute script within required level of transaction as required effective user.
|
||||||
*
|
*
|
||||||
* @param script WebScript
|
* @param script WebScript
|
||||||
* @param scriptReq WebScriptRequest
|
* @param scriptReq WebScriptRequest
|
||||||
* @param scriptRes WebScriptResponse
|
* @param scriptRes WebScriptResponse
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
@@ -659,22 +613,17 @@ public class RepositoryContainer extends AbstractRuntimeContainer
|
|||||||
private void transactionedExecuteAs(final WebScript script, final WebScriptRequest scriptReq,
|
private void transactionedExecuteAs(final WebScript script, final WebScriptRequest scriptReq,
|
||||||
final WebScriptResponse scriptRes) throws IOException
|
final WebScriptResponse scriptRes) throws IOException
|
||||||
{
|
{
|
||||||
String runAs = script.getDescription().getRunAs();
|
final String runAs = script.getDescription().getRunAs();
|
||||||
if (runAs == null)
|
if (runAs == null)
|
||||||
{
|
{
|
||||||
transactionedExecute(script, scriptReq, scriptRes);
|
transactionedExecute(script, scriptReq, scriptRes);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
RunAsWork<Object> work = new RunAsWork<Object>()
|
AuthenticationUtil.runAs(() -> {
|
||||||
{
|
transactionedExecute(script, scriptReq, scriptRes);
|
||||||
public Object doWork() throws Exception
|
return null;
|
||||||
{
|
}, runAs);
|
||||||
transactionedExecute(script, scriptReq, scriptRes);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
AuthenticationUtil.runAs(work, runAs);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -688,17 +637,12 @@ public class RepositoryContainer extends AbstractRuntimeContainer
|
|||||||
{
|
{
|
||||||
ContextRefreshedEvent refreshEvent = (ContextRefreshedEvent)event;
|
ContextRefreshedEvent refreshEvent = (ContextRefreshedEvent)event;
|
||||||
ApplicationContext refreshContext = refreshEvent.getApplicationContext();
|
ApplicationContext refreshContext = refreshEvent.getApplicationContext();
|
||||||
if (refreshContext != null && refreshContext.equals(applicationContext))
|
if (refreshContext.equals(applicationContext))
|
||||||
{
|
{
|
||||||
RunAsWork<Object> work = new RunAsWork<Object>()
|
AuthenticationUtil.runAs(() -> {
|
||||||
{
|
reset();
|
||||||
public Object doWork() throws Exception
|
return null;
|
||||||
{
|
}, AuthenticationUtil.getSystemUserName());
|
||||||
reset();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
AuthenticationUtil.runAs(work, AuthenticationUtil.getSystemUserName());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -739,18 +683,54 @@ public class RepositoryContainer extends AbstractRuntimeContainer
|
|||||||
@Override
|
@Override
|
||||||
public void reset()
|
public void reset()
|
||||||
{
|
{
|
||||||
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Object>()
|
transactionService.getRetryingTransactionHelper().doInTransaction(() -> {
|
||||||
{
|
internalReset();
|
||||||
public Object execute() throws Exception
|
return null;
|
||||||
{
|
|
||||||
internalReset();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}, true, false);
|
}, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void internalReset()
|
private void internalReset()
|
||||||
{
|
{
|
||||||
super.reset();
|
super.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static BufferedRequest newBufferedRequest(
|
||||||
|
final RequiredTransactionParameters trxParams,
|
||||||
|
final WebScriptRequest scriptReq,
|
||||||
|
final Supplier<TempOutputStream> streamFactory)
|
||||||
|
{
|
||||||
|
if (trxParams.getCapability() != TransactionCapability.readwrite)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (trxParams.getBufferSize() <= 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create buffered request that allow transaction retrying
|
||||||
|
return new BufferedRequest(scriptReq, streamFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BufferedResponse newBufferedResponse(
|
||||||
|
final RequiredTransactionParameters trxParams,
|
||||||
|
final WebScriptResponse scriptRes,
|
||||||
|
final Supplier<TempOutputStream> streamFactory)
|
||||||
|
{
|
||||||
|
if (trxParams.getCapability() != TransactionCapability.readwrite)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (trxParams.getBufferSize() <= 0)
|
||||||
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
logger.debug("Transactional Response bypassed for ReadWrite - buffersize=0");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
logger.debug("Creating Transactional Response for ReadWrite transaction; buffersize=" + trxParams.getBufferSize());
|
||||||
|
|
||||||
|
// create buffered response that allow transaction retrying
|
||||||
|
return new BufferedResponse(scriptRes, trxParams.getBufferSize(), streamFactory);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -36,6 +36,7 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.security.Key;
|
import java.security.Key;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import javax.crypto.Cipher;
|
import javax.crypto.Cipher;
|
||||||
import javax.crypto.CipherInputStream;
|
import javax.crypto.CipherInputStream;
|
||||||
@@ -88,13 +89,11 @@ public class TempOutputStream extends OutputStream
|
|||||||
private final File tempDir;
|
private final File tempDir;
|
||||||
private final int memoryThreshold;
|
private final int memoryThreshold;
|
||||||
private final long maxContentSize;
|
private final long maxContentSize;
|
||||||
private boolean encrypt;
|
private final boolean encrypt;
|
||||||
private boolean deleteTempFileOnClose;
|
|
||||||
|
|
||||||
private long length = 0;
|
private long length = 0;
|
||||||
private OutputStream outputStream;
|
private OutputStream outputStream;
|
||||||
private File tempFile;
|
private File tempFile;
|
||||||
private TempByteArrayOutputStream tempStream;
|
|
||||||
|
|
||||||
private Key symKey;
|
private Key symKey;
|
||||||
private byte[] iv;
|
private byte[] iv;
|
||||||
@@ -112,58 +111,49 @@ public class TempOutputStream extends OutputStream
|
|||||||
* the max content size in B
|
* the max content size in B
|
||||||
* @param encrypt
|
* @param encrypt
|
||||||
* true if temp files should be encrypted
|
* true if temp files should be encrypted
|
||||||
* @param deleteTempFileOnClose
|
|
||||||
* true if temp files should be deleted on output stream close
|
|
||||||
* (useful if we need to cache the content for further reads). If
|
|
||||||
* this is false then we need to make sure we call
|
|
||||||
* {@link TempOutputStream}.destroy to clean up properly.
|
|
||||||
*/
|
*/
|
||||||
public TempOutputStream(File tempDir, int memoryThreshold, long maxContentSize, boolean encrypt, boolean deleteTempFileOnClose)
|
public TempOutputStream(File tempDir, int memoryThreshold, long maxContentSize, boolean encrypt)
|
||||||
{
|
{
|
||||||
this.tempDir = tempDir;
|
this.tempDir = tempDir;
|
||||||
this.memoryThreshold = (memoryThreshold < 0) ? DEFAULT_MEMORY_THRESHOLD : memoryThreshold;
|
this.memoryThreshold = (memoryThreshold < 0) ? DEFAULT_MEMORY_THRESHOLD : memoryThreshold;
|
||||||
this.maxContentSize = maxContentSize;
|
this.maxContentSize = maxContentSize;
|
||||||
this.encrypt = encrypt;
|
this.encrypt = encrypt;
|
||||||
this.deleteTempFileOnClose = deleteTempFileOnClose;
|
|
||||||
|
|
||||||
this.tempStream = new TempByteArrayOutputStream();
|
this.outputStream = new ByteArrayOutputStream();
|
||||||
this.outputStream = this.tempStream;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the data as an InputStream
|
* Returns the data as an InputStream
|
||||||
*/
|
*/
|
||||||
public InputStream getInputStream() throws IOException
|
public InputStream toNewInputStream() throws IOException
|
||||||
{
|
{
|
||||||
if (tempFile != null)
|
closeOutputStream();
|
||||||
|
|
||||||
|
if (tempFile == null)
|
||||||
|
{
|
||||||
|
return new ByteArrayInputStream(((ByteArrayOutputStream) outputStream).toByteArray());
|
||||||
|
}
|
||||||
|
if (!encrypt)
|
||||||
{
|
{
|
||||||
if (encrypt)
|
|
||||||
{
|
|
||||||
final Cipher cipher;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
cipher = Cipher.getInstance(TRANSFORMATION);
|
|
||||||
cipher.init(Cipher.DECRYPT_MODE, symKey, new IvParameterSpec(iv));
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
destroy();
|
|
||||||
|
|
||||||
if (logger.isErrorEnabled())
|
|
||||||
{
|
|
||||||
logger.error("Cannot initialize decryption cipher", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IOException("Cannot initialize decryption cipher", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new BufferedInputStream(new CipherInputStream(new FileInputStream(tempFile), cipher));
|
|
||||||
}
|
|
||||||
return new BufferedInputStream(new FileInputStream(tempFile));
|
return new BufferedInputStream(new FileInputStream(tempFile));
|
||||||
}
|
}
|
||||||
else
|
try
|
||||||
{
|
{
|
||||||
return new ByteArrayInputStream(tempStream.getBuffer(), 0, tempStream.getCount());
|
final Cipher cipher = Cipher.getInstance(TRANSFORMATION);
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, symKey, new IvParameterSpec(iv));
|
||||||
|
|
||||||
|
return new BufferedInputStream(new CipherInputStream(new FileInputStream(tempFile), cipher));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
destroy();
|
||||||
|
|
||||||
|
if (logger.isErrorEnabled())
|
||||||
|
{
|
||||||
|
logger.error("Cannot initialize decryption cipher", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IOException("Cannot initialize decryption cipher", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,7 +180,7 @@ public class TempOutputStream extends OutputStream
|
|||||||
@Override
|
@Override
|
||||||
public void close() throws IOException
|
public void close() throws IOException
|
||||||
{
|
{
|
||||||
close(deleteTempFileOnClose);
|
closeOutputStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -215,7 +205,9 @@ public class TempOutputStream extends OutputStream
|
|||||||
*/
|
*/
|
||||||
public void destroy() throws IOException
|
public void destroy() throws IOException
|
||||||
{
|
{
|
||||||
close(true);
|
closeOutputStream();
|
||||||
|
|
||||||
|
deleteTempFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getLength()
|
public long getLength()
|
||||||
@@ -282,102 +274,95 @@ public class TempOutputStream extends OutputStream
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void close(boolean deleteTempFileOnClose)
|
private BufferedOutputStream createFileOutputStream(final File file) throws IOException
|
||||||
{
|
{
|
||||||
closeOutputStream();
|
if (!encrypt)
|
||||||
|
|
||||||
if (deleteTempFileOnClose)
|
|
||||||
{
|
{
|
||||||
deleteTempFile();
|
return new BufferedOutputStream(new FileOutputStream(file));
|
||||||
}
|
}
|
||||||
}
|
try
|
||||||
|
|
||||||
private BufferedOutputStream createOutputStream(File file) throws IOException
|
|
||||||
{
|
|
||||||
BufferedOutputStream fileOutputStream;
|
|
||||||
if (encrypt)
|
|
||||||
{
|
{
|
||||||
try
|
// Generate a symmetric key
|
||||||
|
final KeyGenerator keyGen = KeyGenerator.getInstance(ALGORITHM);
|
||||||
|
keyGen.init(KEY_SIZE);
|
||||||
|
symKey = keyGen.generateKey();
|
||||||
|
|
||||||
|
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, symKey);
|
||||||
|
|
||||||
|
iv = cipher.getIV();
|
||||||
|
|
||||||
|
return new BufferedOutputStream(new CipherOutputStream(new FileOutputStream(file), cipher));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
if (logger.isErrorEnabled())
|
||||||
{
|
{
|
||||||
// Generate a symmetric key
|
logger.error("Cannot initialize encryption cipher", e);
|
||||||
final KeyGenerator keyGen = KeyGenerator.getInstance(ALGORITHM);
|
|
||||||
keyGen.init(KEY_SIZE);
|
|
||||||
symKey = keyGen.generateKey();
|
|
||||||
|
|
||||||
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
|
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, symKey);
|
|
||||||
|
|
||||||
iv = cipher.getIV();
|
|
||||||
|
|
||||||
fileOutputStream = new BufferedOutputStream(new CipherOutputStream(new FileOutputStream(file), cipher));
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
if (logger.isErrorEnabled())
|
|
||||||
{
|
|
||||||
logger.error("Cannot initialize encryption cipher", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IOException("Cannot initialize encryption cipher", e);
|
throw new IOException("Cannot initialize encryption cipher", e);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
fileOutputStream = new BufferedOutputStream(new FileOutputStream(file));
|
|
||||||
}
|
|
||||||
|
|
||||||
return fileOutputStream;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void update(int len) throws IOException
|
private void update(int len) throws IOException
|
||||||
{
|
{
|
||||||
if (maxContentSize > -1 && length + len > maxContentSize)
|
if (surpassesMaxContentSize(len))
|
||||||
{
|
{
|
||||||
destroy();
|
destroy();
|
||||||
throw new ContentLimitViolationException("Content size violation, limit = " + maxContentSize);
|
throw new ContentLimitViolationException("Content size violation, limit = " + maxContentSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tempFile == null && (tempStream.getCount() + len) > memoryThreshold)
|
if (surpassesThreshold(len))
|
||||||
{
|
{
|
||||||
File file = TempFileProvider.createTempFile(TEMP_FILE_PREFIX, ".bin", tempDir);
|
tempFile = TempFileProvider.createTempFile(TEMP_FILE_PREFIX, ".bin", tempDir);
|
||||||
|
|
||||||
BufferedOutputStream fileOutputStream = createOutputStream(file);
|
final BufferedOutputStream fileOutputStream = createFileOutputStream(tempFile);
|
||||||
fileOutputStream.write(this.tempStream.getBuffer(), 0, this.tempStream.getCount());
|
fileOutputStream.write(((ByteArrayOutputStream) outputStream).toByteArray());
|
||||||
fileOutputStream.flush();
|
fileOutputStream.flush();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
tempStream.close();
|
outputStream.close();
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (IOException ignore)
|
||||||
{
|
{
|
||||||
// Ignore exception
|
// Ignore exception
|
||||||
}
|
}
|
||||||
tempStream = null;
|
|
||||||
|
|
||||||
tempFile = file;
|
|
||||||
outputStream = fileOutputStream;
|
outputStream = fileOutputStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
length += len;
|
length += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class TempByteArrayOutputStream extends ByteArrayOutputStream
|
private boolean surpassesMaxContentSize(final int len)
|
||||||
{
|
{
|
||||||
/**
|
return maxContentSize >= 0 && length + len > maxContentSize;
|
||||||
* @return The internal buffer where data is stored
|
}
|
||||||
*/
|
|
||||||
public byte[] getBuffer()
|
|
||||||
{
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
private boolean surpassesThreshold(final int len)
|
||||||
* @return The number of valid bytes in the buffer.
|
{
|
||||||
*/
|
return tempFile == null && length + len > memoryThreshold;
|
||||||
public int getCount()
|
}
|
||||||
{
|
|
||||||
return count;
|
/**
|
||||||
}
|
* Creates a {@link TempOutputStream} factory/supplier.
|
||||||
|
*
|
||||||
|
* @param tempDir
|
||||||
|
* the temporary directory, i.e. <code>isDir == true</code>, that
|
||||||
|
* will be used as * parent directory for creating temp file backed
|
||||||
|
* streams
|
||||||
|
* @param memoryThreshold
|
||||||
|
* the memory threshold in B
|
||||||
|
* @param maxContentSize
|
||||||
|
* the max content size in B
|
||||||
|
* @param encrypt
|
||||||
|
* true if temp files should be encrypted
|
||||||
|
*/
|
||||||
|
public static Supplier<TempOutputStream> factory(final File tempDir, final int memoryThreshold,
|
||||||
|
final long maxContentSize, final boolean encrypt)
|
||||||
|
{
|
||||||
|
return () -> new TempOutputStream(tempDir, memoryThreshold, maxContentSize, encrypt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,105 +0,0 @@
|
|||||||
/*
|
|
||||||
* #%L
|
|
||||||
* Alfresco Remote API
|
|
||||||
* %%
|
|
||||||
* Copyright (C) 2005 - 2019 Alfresco Software Limited
|
|
||||||
* %%
|
|
||||||
* This file is part of the Alfresco software.
|
|
||||||
* If the software was purchased under a paid Alfresco license, the terms of
|
|
||||||
* the paid license agreement will prevail. Otherwise, the software is
|
|
||||||
* provided under the following open source license terms:
|
|
||||||
*
|
|
||||||
* 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
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* Alfresco is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
* #L%
|
|
||||||
*/
|
|
||||||
package org.alfresco.repo.web.scripts;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory for {@link TempOutputStream}
|
|
||||||
*/
|
|
||||||
public class TempOutputStreamFactory
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* A temporary directory, i.e. <code>isDir == true</code>, that will be used as
|
|
||||||
* parent directory for creating temp file backed streams.
|
|
||||||
*/
|
|
||||||
private final File tempDir;
|
|
||||||
private int memoryThreshold;
|
|
||||||
private long maxContentSize;
|
|
||||||
private boolean encrypt;
|
|
||||||
private boolean deleteTempFileOnClose;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a {@link TempOutputStream} factory.
|
|
||||||
*
|
|
||||||
* @param tempDir
|
|
||||||
* the temporary directory, i.e. <code>isDir == true</code>, that
|
|
||||||
* will be used as * parent directory for creating temp file backed
|
|
||||||
* streams
|
|
||||||
* @param memoryThreshold
|
|
||||||
* the memory threshold in B
|
|
||||||
* @param maxContentSize
|
|
||||||
* the max content size in B
|
|
||||||
* @param encrypt
|
|
||||||
* true if temp files should be encrypted
|
|
||||||
* @param deleteTempFileOnClose
|
|
||||||
* true if temp files should be deleted on output stream close
|
|
||||||
* (useful if we need to cache the content for further reads). If
|
|
||||||
* this is false then we need to make sure we call
|
|
||||||
* {@link TempOutputStream}.destroy to clean up properly.
|
|
||||||
*/
|
|
||||||
public TempOutputStreamFactory(File tempDir, int memoryThreshold, long maxContentSize, boolean encrypt, boolean deleteTempFileOnClose)
|
|
||||||
{
|
|
||||||
this.tempDir = tempDir;
|
|
||||||
this.memoryThreshold = memoryThreshold;
|
|
||||||
this.maxContentSize = maxContentSize;
|
|
||||||
this.encrypt = encrypt;
|
|
||||||
this.deleteTempFileOnClose = deleteTempFileOnClose;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new {@link TempOutputStream} object
|
|
||||||
*/
|
|
||||||
public TempOutputStream createOutputStream()
|
|
||||||
{
|
|
||||||
return new TempOutputStream(tempDir, memoryThreshold, maxContentSize, encrypt, deleteTempFileOnClose);
|
|
||||||
}
|
|
||||||
|
|
||||||
public File getTempDir()
|
|
||||||
{
|
|
||||||
return tempDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getMemoryThreshold()
|
|
||||||
{
|
|
||||||
return memoryThreshold;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getMaxContentSize()
|
|
||||||
{
|
|
||||||
return maxContentSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEncrypt()
|
|
||||||
{
|
|
||||||
return encrypt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isDeleteTempFileOnClose()
|
|
||||||
{
|
|
||||||
return deleteTempFileOnClose;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -23,149 +23,144 @@
|
|||||||
* 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.web.scripts.model.filefolder;
|
package org.alfresco.repo.web.scripts.model.filefolder;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
import org.alfresco.repo.model.filefolder.FileFolderLoader;
|
import org.alfresco.repo.model.filefolder.FileFolderLoader;
|
||||||
import org.alfresco.service.cmr.model.FileNotFoundException;
|
import org.alfresco.service.cmr.model.FileNotFoundException;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import org.json.JSONTokener;
|
import org.json.JSONTokener;
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.ApplicationContextAware;
|
import org.springframework.context.ApplicationContextAware;
|
||||||
import org.springframework.extensions.webscripts.AbstractWebScript;
|
import org.springframework.extensions.webscripts.AbstractWebScript;
|
||||||
import org.springframework.extensions.webscripts.Status;
|
import org.springframework.extensions.webscripts.Status;
|
||||||
import org.springframework.extensions.webscripts.WebScriptException;
|
import org.springframework.extensions.webscripts.WebScriptException;
|
||||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||||
import org.springframework.extensions.webscripts.WebScriptResponse;
|
import org.springframework.extensions.webscripts.WebScriptResponse;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Link to {@link FileFolderLoader}
|
* Link to {@link FileFolderLoader}
|
||||||
*/
|
*/
|
||||||
public class FileFolderLoaderPost extends AbstractWebScript implements ApplicationContextAware
|
public class FileFolderLoaderPost extends AbstractWebScript implements ApplicationContextAware
|
||||||
{
|
{
|
||||||
public static final String KEY_FOLDER_PATH = "folderPath";
|
public static final String KEY_FOLDER_PATH = "folderPath";
|
||||||
public static final String KEY_FILE_COUNT = "fileCount";
|
public static final String KEY_FILE_COUNT = "fileCount";
|
||||||
public static final String KEY_FILES_PER_TXN = "filesPerTxn";
|
public static final String KEY_FILES_PER_TXN = "filesPerTxn";
|
||||||
public static final String KEY_MIN_FILE_SIZE = "minFileSize";
|
public static final String KEY_MIN_FILE_SIZE = "minFileSize";
|
||||||
public static final String KEY_MAX_FILE_SIZE = "maxFileSize";
|
public static final String KEY_MAX_FILE_SIZE = "maxFileSize";
|
||||||
public static final String KEY_MAX_UNIQUE_DOCUMENTS = "maxUniqueDocuments";
|
public static final String KEY_MAX_UNIQUE_DOCUMENTS = "maxUniqueDocuments";
|
||||||
public static final String KEY_FORCE_BINARY_STORAGE = "forceBinaryStorage";
|
public static final String KEY_FORCE_BINARY_STORAGE = "forceBinaryStorage";
|
||||||
public static final String KEY_DESCRIPTION_COUNT = "descriptionCount";
|
public static final String KEY_DESCRIPTION_COUNT = "descriptionCount";
|
||||||
public static final String KEY_DESCRIPTION_SIZE = "descriptionSize";
|
public static final String KEY_DESCRIPTION_SIZE = "descriptionSize";
|
||||||
public static final String KEY_COUNT = "count";
|
public static final String KEY_COUNT = "count";
|
||||||
|
|
||||||
public static final int DEFAULT_FILE_COUNT = 100;
|
public static final int DEFAULT_FILE_COUNT = 100;
|
||||||
public static final int DEFAULT_FILES_PER_TXN = 100;
|
public static final int DEFAULT_FILES_PER_TXN = 100;
|
||||||
public static final long DEFAULT_MIN_FILE_SIZE = 80*1024L;
|
public static final long DEFAULT_MIN_FILE_SIZE = 80*1024L;
|
||||||
public static final long DEFAULT_MAX_FILE_SIZE = 120*1024L;
|
public static final long DEFAULT_MAX_FILE_SIZE = 120*1024L;
|
||||||
public static final long DEFAULT_MAX_UNIQUE_DOCUMENTS = Long.MAX_VALUE;
|
public static final long DEFAULT_MAX_UNIQUE_DOCUMENTS = Long.MAX_VALUE;
|
||||||
public static final int DEFAULT_DESCRIPTION_COUNT = 1;
|
public static final int DEFAULT_DESCRIPTION_COUNT = 1;
|
||||||
public static final long DEFAULT_DESCRIPTION_SIZE = 128L;
|
public static final long DEFAULT_DESCRIPTION_SIZE = 128L;
|
||||||
public static final boolean DEFAULT_FORCE_BINARY_STORAGE = false;
|
public static final boolean DEFAULT_FORCE_BINARY_STORAGE = false;
|
||||||
|
|
||||||
private ApplicationContext applicationContext;
|
private ApplicationContext applicationContext;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
|
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
|
||||||
{
|
{
|
||||||
this.applicationContext = applicationContext;
|
this.applicationContext = applicationContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void execute(WebScriptRequest req, WebScriptResponse res) throws IOException
|
public void execute(WebScriptRequest req, WebScriptResponse res) throws IOException
|
||||||
{
|
{
|
||||||
FileFolderLoader loader = (FileFolderLoader) applicationContext.getBean("fileFolderLoader");
|
FileFolderLoader loader = (FileFolderLoader) applicationContext.getBean("fileFolderLoader");
|
||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
String folderPath = "";
|
String folderPath = "";
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
JSONObject json = new JSONObject(new JSONTokener(req.getContent().getContent()));
|
JSONObject json = new JSONObject(new JSONTokener(req.getContent().getContent()));
|
||||||
folderPath = json.getString(KEY_FOLDER_PATH);
|
folderPath = json.getString(KEY_FOLDER_PATH);
|
||||||
if (folderPath == null)
|
if (folderPath == null)
|
||||||
{
|
{
|
||||||
throw new WebScriptException(Status.STATUS_BAD_REQUEST, KEY_FOLDER_PATH + " not supplied.");
|
throw new WebScriptException(Status.STATUS_BAD_REQUEST, KEY_FOLDER_PATH + " not supplied.");
|
||||||
}
|
}
|
||||||
int fileCount = 100;
|
int fileCount = 100;
|
||||||
if (json.has(KEY_FILE_COUNT))
|
if (json.has(KEY_FILE_COUNT))
|
||||||
{
|
{
|
||||||
fileCount = json.getInt(KEY_FILE_COUNT);
|
fileCount = json.getInt(KEY_FILE_COUNT);
|
||||||
}
|
}
|
||||||
int filesPerTxn = DEFAULT_FILES_PER_TXN;
|
int filesPerTxn = DEFAULT_FILES_PER_TXN;
|
||||||
if (json.has(KEY_FILES_PER_TXN))
|
if (json.has(KEY_FILES_PER_TXN))
|
||||||
{
|
{
|
||||||
filesPerTxn = json.getInt(KEY_FILES_PER_TXN);
|
filesPerTxn = json.getInt(KEY_FILES_PER_TXN);
|
||||||
}
|
}
|
||||||
long minFileSize = DEFAULT_MIN_FILE_SIZE;
|
long minFileSize = DEFAULT_MIN_FILE_SIZE;
|
||||||
if (json.has(KEY_MIN_FILE_SIZE))
|
if (json.has(KEY_MIN_FILE_SIZE))
|
||||||
{
|
{
|
||||||
minFileSize = json.getInt(KEY_MIN_FILE_SIZE);
|
minFileSize = json.getInt(KEY_MIN_FILE_SIZE);
|
||||||
}
|
}
|
||||||
long maxFileSize = DEFAULT_MAX_FILE_SIZE;
|
long maxFileSize = DEFAULT_MAX_FILE_SIZE;
|
||||||
if (json.has(KEY_MAX_FILE_SIZE))
|
if (json.has(KEY_MAX_FILE_SIZE))
|
||||||
{
|
{
|
||||||
maxFileSize = json.getInt(KEY_MAX_FILE_SIZE);
|
maxFileSize = json.getInt(KEY_MAX_FILE_SIZE);
|
||||||
}
|
}
|
||||||
long maxUniqueDocuments = DEFAULT_MAX_UNIQUE_DOCUMENTS;
|
long maxUniqueDocuments = DEFAULT_MAX_UNIQUE_DOCUMENTS;
|
||||||
if (json.has(KEY_MAX_UNIQUE_DOCUMENTS))
|
if (json.has(KEY_MAX_UNIQUE_DOCUMENTS))
|
||||||
{
|
{
|
||||||
maxUniqueDocuments = json.getInt(KEY_MAX_UNIQUE_DOCUMENTS);
|
maxUniqueDocuments = json.getInt(KEY_MAX_UNIQUE_DOCUMENTS);
|
||||||
}
|
}
|
||||||
boolean forceBinaryStorage = DEFAULT_FORCE_BINARY_STORAGE;
|
boolean forceBinaryStorage = DEFAULT_FORCE_BINARY_STORAGE;
|
||||||
if (json.has(KEY_FORCE_BINARY_STORAGE))
|
if (json.has(KEY_FORCE_BINARY_STORAGE))
|
||||||
{
|
{
|
||||||
forceBinaryStorage = json.getBoolean(KEY_FORCE_BINARY_STORAGE);
|
forceBinaryStorage = json.getBoolean(KEY_FORCE_BINARY_STORAGE);
|
||||||
}
|
}
|
||||||
int descriptionCount = DEFAULT_DESCRIPTION_COUNT;
|
int descriptionCount = DEFAULT_DESCRIPTION_COUNT;
|
||||||
if (json.has(KEY_DESCRIPTION_COUNT))
|
if (json.has(KEY_DESCRIPTION_COUNT))
|
||||||
{
|
{
|
||||||
descriptionCount = json.getInt(KEY_DESCRIPTION_COUNT);
|
descriptionCount = json.getInt(KEY_DESCRIPTION_COUNT);
|
||||||
}
|
}
|
||||||
long descriptionSize = DEFAULT_DESCRIPTION_SIZE;
|
long descriptionSize = DEFAULT_DESCRIPTION_SIZE;
|
||||||
if (json.has(KEY_DESCRIPTION_SIZE))
|
if (json.has(KEY_DESCRIPTION_SIZE))
|
||||||
{
|
{
|
||||||
descriptionSize = json.getLong(KEY_DESCRIPTION_SIZE);
|
descriptionSize = json.getLong(KEY_DESCRIPTION_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform the load
|
// Perform the load
|
||||||
count = loader.createFiles(
|
count = loader.createFiles(
|
||||||
folderPath,
|
folderPath,
|
||||||
fileCount, filesPerTxn,
|
fileCount, filesPerTxn,
|
||||||
minFileSize, maxFileSize,
|
minFileSize, maxFileSize,
|
||||||
maxUniqueDocuments,
|
maxUniqueDocuments,
|
||||||
forceBinaryStorage,
|
forceBinaryStorage,
|
||||||
descriptionCount, descriptionSize);
|
descriptionCount, descriptionSize);
|
||||||
}
|
}
|
||||||
catch (FileNotFoundException e)
|
catch (FileNotFoundException e)
|
||||||
{
|
{
|
||||||
throw new WebScriptException(Status.STATUS_NOT_FOUND, "Folder not found: ", folderPath);
|
throw new WebScriptException(Status.STATUS_NOT_FOUND, "Folder not found: ", folderPath);
|
||||||
}
|
}
|
||||||
catch (IOException iox)
|
catch (IOException iox)
|
||||||
{
|
{
|
||||||
throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Could not read content from req.", iox);
|
throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Could not read content from req.", iox);
|
||||||
}
|
}
|
||||||
catch (JSONException je)
|
catch (JSONException je)
|
||||||
{
|
{
|
||||||
throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Could not parse JSON from req.", je);
|
throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Could not parse JSON from req.", je);
|
||||||
}
|
}
|
||||||
// Write the response
|
// Write the response
|
||||||
OutputStream os = res.getOutputStream();
|
try (OutputStream os = res.getOutputStream())
|
||||||
try
|
{
|
||||||
{
|
JSONObject json = new JSONObject();
|
||||||
JSONObject json = new JSONObject();
|
json.put(KEY_COUNT, count);
|
||||||
json.put(KEY_COUNT, count);
|
os.write(json.toString().getBytes("UTF-8"));
|
||||||
os.write(json.toString().getBytes("UTF-8"));
|
}
|
||||||
}
|
catch (JSONException e)
|
||||||
catch (JSONException e)
|
{
|
||||||
{
|
throw new WebScriptException(Status.STATUS_INTERNAL_SERVER_ERROR, "Failed to write JSON", e);
|
||||||
throw new WebScriptException(Status.STATUS_INTERNAL_SERVER_ERROR, "Failed to write JSON", e);
|
}
|
||||||
}
|
}
|
||||||
finally
|
}
|
||||||
{
|
|
||||||
os.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -125,16 +125,15 @@ public class PostSnapshotCommandProcessor implements CommandProcessor
|
|||||||
|
|
||||||
logger.debug("success");
|
logger.debug("success");
|
||||||
resp.setStatus(Status.STATUS_OK);
|
resp.setStatus(Status.STATUS_OK);
|
||||||
|
|
||||||
OutputStream out = resp.getOutputStream();
|
try (OutputStream out = resp.getOutputStream())
|
||||||
resp.setContentType("text/xml");
|
{
|
||||||
resp.setContentEncoding("utf-8");
|
resp.setContentType("text/xml");
|
||||||
|
resp.setContentEncoding("utf-8");
|
||||||
receiver.generateRequsite(transferId, out);
|
|
||||||
|
receiver.generateRequsite(transferId, out);
|
||||||
out.close();
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
logger.debug("exception caught", ex);
|
logger.debug("exception caught", ex);
|
||||||
|
@@ -28,10 +28,11 @@ package org.alfresco.rest.framework.webscripts;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.alfresco.repo.web.scripts.BufferedRequest;
|
import org.alfresco.repo.web.scripts.BufferedRequest;
|
||||||
import org.alfresco.repo.web.scripts.BufferedResponse;
|
import org.alfresco.repo.web.scripts.BufferedResponse;
|
||||||
import org.alfresco.repo.web.scripts.TempOutputStreamFactory;
|
import org.alfresco.repo.web.scripts.TempOutputStream;
|
||||||
import org.alfresco.rest.framework.Api;
|
import org.alfresco.rest.framework.Api;
|
||||||
import org.alfresco.rest.framework.tools.ApiAssistant;
|
import org.alfresco.rest.framework.tools.ApiAssistant;
|
||||||
import org.alfresco.service.transaction.TransactionService;
|
import org.alfresco.service.transaction.TransactionService;
|
||||||
@@ -56,7 +57,7 @@ public abstract class ApiWebScript extends AbstractWebScript
|
|||||||
protected String tempDirectoryName = null;
|
protected String tempDirectoryName = null;
|
||||||
protected int memoryThreshold = 4 * 1024 * 1024; // 4mb
|
protected int memoryThreshold = 4 * 1024 * 1024; // 4mb
|
||||||
protected long maxContentSize = (long) 4 * 1024 * 1024 * 1024; // 4gb
|
protected long maxContentSize = (long) 4 * 1024 * 1024 * 1024; // 4gb
|
||||||
protected TempOutputStreamFactory streamFactory = null;
|
protected Supplier<TempOutputStream> streamFactory = null;
|
||||||
protected TransactionService transactionService;
|
protected TransactionService transactionService;
|
||||||
|
|
||||||
public void setTransactionService(TransactionService transactionService)
|
public void setTransactionService(TransactionService transactionService)
|
||||||
@@ -88,7 +89,7 @@ public abstract class ApiWebScript extends AbstractWebScript
|
|||||||
this.maxContentSize = maxContentSize;
|
this.maxContentSize = maxContentSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStreamFactory(TempOutputStreamFactory streamFactory)
|
public void setStreamFactory(Supplier<TempOutputStream> streamFactory)
|
||||||
{
|
{
|
||||||
this.streamFactory = streamFactory;
|
this.streamFactory = streamFactory;
|
||||||
}
|
}
|
||||||
@@ -96,50 +97,38 @@ public abstract class ApiWebScript extends AbstractWebScript
|
|||||||
public void init()
|
public void init()
|
||||||
{
|
{
|
||||||
File tempDirectory = TempFileProvider.getTempDir(tempDirectoryName);
|
File tempDirectory = TempFileProvider.getTempDir(tempDirectoryName);
|
||||||
this.streamFactory = new TempOutputStreamFactory(tempDirectory, memoryThreshold, maxContentSize, false, false);
|
streamFactory = TempOutputStream.factory(tempDirectory, memoryThreshold, maxContentSize, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(final WebScriptRequest req, final WebScriptResponse res) throws IOException
|
public void execute(final WebScriptRequest req, final WebScriptResponse res) throws IOException
|
||||||
{
|
{
|
||||||
Map<String, String> templateVars = req.getServiceMatch().getTemplateVars();
|
final Map<String, String> templateVars = req.getServiceMatch().getTemplateVars();
|
||||||
Api api = assistant.determineApi(templateVars);
|
final Api api = ApiAssistant.determineApi(templateVars);
|
||||||
|
|
||||||
final BufferedRequest bufferedReq = getRequest(req);
|
|
||||||
final BufferedResponse bufferedRes = getResponse(res);
|
|
||||||
|
|
||||||
try
|
try (final BufferedRequest bufferedReq = getRequest(req);
|
||||||
{
|
final BufferedResponse bufferedRes = getResponse(res))
|
||||||
execute(api, bufferedReq, bufferedRes);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
// Get rid of any temporary files
|
|
||||||
if (bufferedReq != null)
|
|
||||||
{
|
|
||||||
bufferedReq.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure a response is always flushed after successful execution
|
|
||||||
if (bufferedRes != null)
|
|
||||||
{
|
{
|
||||||
bufferedRes.writeResponse();
|
execute(api, bufferedReq, bufferedRes);
|
||||||
|
|
||||||
|
// Ensure a response is always flushed after successful execution
|
||||||
|
if (bufferedRes != null)
|
||||||
|
{
|
||||||
|
bufferedRes.writeResponse();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected BufferedRequest getRequest(final WebScriptRequest req)
|
protected BufferedRequest getRequest(final WebScriptRequest req)
|
||||||
{
|
{
|
||||||
// create buffered request and response that allow transaction retrying
|
// create buffered request and response that allow transaction retrying
|
||||||
final BufferedRequest bufferedReq = new BufferedRequest(req, streamFactory);
|
return new BufferedRequest(req, streamFactory);
|
||||||
return bufferedReq;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected BufferedResponse getResponse(final WebScriptResponse resp)
|
protected BufferedResponse getResponse(final WebScriptResponse resp)
|
||||||
{
|
{
|
||||||
// create buffered request and response that allow transaction retrying
|
// create buffered request and response that allow transaction retrying
|
||||||
final BufferedResponse bufferedRes = new BufferedResponse(resp, memoryThreshold, streamFactory);
|
return new BufferedResponse(resp, memoryThreshold, streamFactory);
|
||||||
return bufferedRes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void execute(final Api api, WebScriptRequest req, WebScriptResponse res) throws IOException;
|
public abstract void execute(final Api api, WebScriptRequest req, WebScriptResponse res) throws IOException;
|
||||||
|
@@ -23,110 +23,110 @@
|
|||||||
* 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.web.scripts;
|
package org.alfresco.web.scripts;
|
||||||
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.alfresco.repo.jscript.ScriptUtils;
|
import org.alfresco.repo.jscript.ScriptUtils;
|
||||||
import org.alfresco.repo.web.scripts.RepositoryContainer;
|
import org.alfresco.repo.web.scripts.RepositoryContainer;
|
||||||
import org.alfresco.service.cmr.admin.RepoUsage;
|
import org.alfresco.service.cmr.admin.RepoUsage;
|
||||||
import org.alfresco.service.cmr.repository.StoreRef;
|
import org.alfresco.service.cmr.repository.StoreRef;
|
||||||
import org.springframework.extensions.webscripts.WebScript;
|
import org.springframework.extensions.webscripts.WebScript;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override of the JavaScript API ScriptUtils bean "utilsScript" to provide additional
|
* Override of the JavaScript API ScriptUtils bean "utilsScript" to provide additional
|
||||||
* Remote API methods using objects not available to base Repository project.
|
* Remote API methods using objects not available to base Repository project.
|
||||||
* <p>
|
* <p>
|
||||||
* See "web-scripts-application-context.xml" for bean definition.
|
* See "web-scripts-application-context.xml" for bean definition.
|
||||||
*
|
*
|
||||||
* @since 4.2.0
|
* @since 4.2.0
|
||||||
* @since 5.1 (Moved to Remote API project)
|
* @since 5.1 (Moved to Remote API project)
|
||||||
* @author Kevin Roast
|
* @author Kevin Roast
|
||||||
*/
|
*/
|
||||||
public class WebScriptUtils extends ScriptUtils
|
public class WebScriptUtils extends ScriptUtils
|
||||||
{
|
{
|
||||||
protected RepositoryContainer repositoryContainer;
|
protected RepositoryContainer repositoryContainer;
|
||||||
|
|
||||||
public void setRepositoryContainer(RepositoryContainer repositoryContainer)
|
public void setRepositoryContainer(RepositoryContainer repositoryContainer)
|
||||||
{
|
{
|
||||||
this.repositoryContainer = repositoryContainer;
|
this.repositoryContainer = repositoryContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Searches for webscript components with the given family name.
|
* Searches for webscript components with the given family name.
|
||||||
*
|
*
|
||||||
* @param family the family
|
* @param family the family
|
||||||
*
|
*
|
||||||
* @return An array of webscripts that match the given family name
|
* @return An array of webscripts that match the given family name
|
||||||
*/
|
*/
|
||||||
public Object[] findWebScripts(String family)
|
public Object[] findWebScripts(String family)
|
||||||
{
|
{
|
||||||
List<Object> values = new ArrayList<Object>();
|
List<Object> values = new ArrayList<Object>();
|
||||||
|
|
||||||
for (WebScript webscript : this.repositoryContainer.getRegistry().getWebScripts())
|
for (WebScript webscript : this.repositoryContainer.getRegistry().getWebScripts())
|
||||||
{
|
{
|
||||||
if (family != null)
|
if (family != null)
|
||||||
{
|
{
|
||||||
Set<String> familys = webscript.getDescription().getFamilys();
|
Set<String> familys = webscript.getDescription().getFamilys();
|
||||||
if (familys != null && familys.contains(family))
|
if (familys != null && familys.contains(family))
|
||||||
{
|
{
|
||||||
values.add(webscript.getDescription());
|
values.add(webscript.getDescription());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
values.add(webscript.getDescription());
|
values.add(webscript.getDescription());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return values.toArray(new Object[values.size()]);
|
return values.toArray(new Object[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getHostAddress()
|
public String getHostAddress()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return InetAddress.getLocalHost().getHostAddress();
|
return InetAddress.getLocalHost().getHostAddress();
|
||||||
}
|
}
|
||||||
catch (UnknownHostException e)
|
catch (UnknownHostException e)
|
||||||
{
|
{
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getHostName()
|
public String getHostName()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return InetAddress.getLocalHost().getHostName();
|
return InetAddress.getLocalHost().getHostName();
|
||||||
}
|
}
|
||||||
catch (UnknownHostException e)
|
catch (UnknownHostException e)
|
||||||
{
|
{
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public RepoUsage getRestrictions()
|
public RepoUsage getRestrictions()
|
||||||
{
|
{
|
||||||
return this.services.getRepoAdminService().getRestrictions();
|
return this.services.getRepoAdminService().getRestrictions();
|
||||||
}
|
}
|
||||||
|
|
||||||
public RepoUsage getUsage()
|
public RepoUsage getUsage()
|
||||||
{
|
{
|
||||||
return this.services.getRepoAdminService().getUsage();
|
return this.services.getRepoAdminService().getUsage();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the list of repository stores
|
* Gets the list of repository stores
|
||||||
*
|
*
|
||||||
* @return stores
|
* @return stores
|
||||||
*/
|
*/
|
||||||
public List<StoreRef> getStores()
|
public List<StoreRef> getStores()
|
||||||
{
|
{
|
||||||
return this.services.getNodeService().getStores();
|
return this.services.getNodeService().getStores();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -26,23 +26,23 @@
|
|||||||
*/
|
*/
|
||||||
package org.alfresco.rest.api.tests;
|
package org.alfresco.rest.api.tests;
|
||||||
|
|
||||||
import org.alfresco.repo.web.scripts.BufferedResponse;
|
|
||||||
import org.alfresco.repo.web.scripts.TempOutputStream;
|
|
||||||
import org.alfresco.repo.web.scripts.TempOutputStreamFactory;
|
|
||||||
import org.alfresco.util.TempFileProvider;
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.RandomAccessFile;
|
import java.io.RandomAccessFile;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import org.alfresco.repo.web.scripts.BufferedResponse;
|
||||||
|
import org.alfresco.repo.web.scripts.TempOutputStream;
|
||||||
|
import org.alfresco.util.TempFileProvider;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that BufferedResponse uses a temp file instead of buffering the entire output stream in memory
|
* Test that BufferedResponse uses a temp file instead of buffering the entire output stream in memory
|
||||||
*
|
*
|
||||||
@@ -82,17 +82,25 @@ public class BufferedResponseTest
|
|||||||
public void testOutputStream() throws IOException
|
public void testOutputStream() throws IOException
|
||||||
{
|
{
|
||||||
File bufferTempDirectory = TempFileProvider.getTempDir(TEMP_DIRECTORY_NAME);
|
File bufferTempDirectory = TempFileProvider.getTempDir(TEMP_DIRECTORY_NAME);
|
||||||
TempOutputStreamFactory streamFactory = new TempOutputStreamFactory(bufferTempDirectory, MEMORY_THRESHOLD, MAX_CONTENT_SIZE, false,true);
|
Supplier<TempOutputStream> streamFactory = TempOutputStream.factory(bufferTempDirectory,
|
||||||
BufferedResponse response = new BufferedResponse(null, 0, streamFactory);
|
MEMORY_THRESHOLD, MAX_CONTENT_SIZE, false);
|
||||||
|
|
||||||
long countBefore = countFilesInDirectoryWithPrefix(bufferTempDirectory, FILE_PREFIX );
|
final long countBefore = countFilesInDirectoryWithPrefix(bufferTempDirectory, FILE_PREFIX);
|
||||||
copyFileToOutputStream(response);
|
|
||||||
long countAfter = countFilesInDirectoryWithPrefix(bufferTempDirectory, FILE_PREFIX);
|
|
||||||
|
|
||||||
response.getOutputStream().close();
|
|
||||||
|
|
||||||
Assert.assertEquals(countBefore + 1, countAfter);
|
try (BufferedResponse response = new BufferedResponse(null, 0, streamFactory))
|
||||||
|
{
|
||||||
|
copyFileToOutputStream(response);
|
||||||
|
final long countBeforeClose = countFilesInDirectoryWithPrefix(bufferTempDirectory, FILE_PREFIX);
|
||||||
|
|
||||||
|
response.getOutputStream().close();
|
||||||
|
final long countAfterClose = countFilesInDirectoryWithPrefix(bufferTempDirectory, FILE_PREFIX);
|
||||||
|
|
||||||
|
Assert.assertEquals(countBefore + 1, countBeforeClose);
|
||||||
|
Assert.assertEquals(countBefore + 1, countAfterClose);
|
||||||
|
}
|
||||||
|
|
||||||
|
final long countAfterDestroy = countFilesInDirectoryWithPrefix(bufferTempDirectory, FILE_PREFIX);
|
||||||
|
Assert.assertEquals(countBefore, countAfterDestroy);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void copyFileToOutputStream(BufferedResponse response) throws IOException
|
private void copyFileToOutputStream(BufferedResponse response) throws IOException
|
||||||
|
@@ -33,11 +33,11 @@ import java.io.IOException;
|
|||||||
import java.io.RandomAccessFile;
|
import java.io.RandomAccessFile;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.alfresco.repo.content.ContentLimitViolationException;
|
import org.alfresco.repo.content.ContentLimitViolationException;
|
||||||
import org.alfresco.repo.web.scripts.TempOutputStream;
|
import org.alfresco.repo.web.scripts.TempOutputStream;
|
||||||
import org.alfresco.repo.web.scripts.TempOutputStreamFactory;
|
|
||||||
import org.alfresco.util.TempFileProvider;
|
import org.alfresco.util.TempFileProvider;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -57,11 +57,12 @@ public class TempOutputStreamTest
|
|||||||
@Test
|
@Test
|
||||||
public void testInMemoryStream() throws IOException
|
public void testInMemoryStream() throws IOException
|
||||||
{
|
{
|
||||||
TempOutputStreamFactory streamFactory = new TempOutputStreamFactory(bufferTempDirectory, MEMORY_THRESHOLD, MAX_CONTENT_SIZE, false, false);
|
Supplier<TempOutputStream> streamFactory = TempOutputStream.factory(bufferTempDirectory,
|
||||||
|
MEMORY_THRESHOLD, MAX_CONTENT_SIZE, false);
|
||||||
|
|
||||||
File file = createTextFileWithRandomContent(MEMORY_THRESHOLD - 1024L);
|
File file = createTextFileWithRandomContent(MEMORY_THRESHOLD - 1024L);
|
||||||
{
|
{
|
||||||
TempOutputStream outputStream = streamFactory.createOutputStream();
|
TempOutputStream outputStream = streamFactory.get();
|
||||||
|
|
||||||
long countBefore = countFilesInDirectoryWithPrefix(bufferTempDirectory);
|
long countBefore = countFilesInDirectoryWithPrefix(bufferTempDirectory);
|
||||||
|
|
||||||
@@ -83,8 +84,8 @@ public class TempOutputStreamTest
|
|||||||
|
|
||||||
{
|
{
|
||||||
// Create stream factory that doesn't delete temp file on stream close
|
// Create stream factory that doesn't delete temp file on stream close
|
||||||
TempOutputStreamFactory streamFactory = new TempOutputStreamFactory(bufferTempDirectory, MEMORY_THRESHOLD, MAX_CONTENT_SIZE, false, false);
|
Supplier<TempOutputStream> streamFactory = TempOutputStream.factory(bufferTempDirectory, MEMORY_THRESHOLD, MAX_CONTENT_SIZE, false);
|
||||||
TempOutputStream outputStream = streamFactory.createOutputStream();
|
TempOutputStream outputStream = streamFactory.get();
|
||||||
|
|
||||||
long countBefore = countFilesInDirectoryWithPrefix(bufferTempDirectory);
|
long countBefore = countFilesInDirectoryWithPrefix(bufferTempDirectory);
|
||||||
|
|
||||||
@@ -107,26 +108,6 @@ public class TempOutputStreamTest
|
|||||||
Assert.assertEquals(countBefore, countAfter);
|
Assert.assertEquals(countBefore, countAfter);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
// Create stream factory that deletes temp file on stream close
|
|
||||||
TempOutputStreamFactory streamFactory = new TempOutputStreamFactory(bufferTempDirectory, MEMORY_THRESHOLD, MAX_CONTENT_SIZE, false, true);
|
|
||||||
TempOutputStream outputStream = streamFactory.createOutputStream();
|
|
||||||
|
|
||||||
long countBefore = countFilesInDirectoryWithPrefix(bufferTempDirectory);
|
|
||||||
|
|
||||||
StreamUtils.copy(new BufferedInputStream(new FileInputStream(file)), outputStream);
|
|
||||||
|
|
||||||
// Check that temp file was created
|
|
||||||
long countAfter = countFilesInDirectoryWithPrefix(bufferTempDirectory);
|
|
||||||
Assert.assertEquals(countBefore + 1, countAfter);
|
|
||||||
|
|
||||||
outputStream.close();
|
|
||||||
|
|
||||||
// Check that file was deleted on close
|
|
||||||
countAfter = countFilesInDirectoryWithPrefix(bufferTempDirectory);
|
|
||||||
Assert.assertEquals(countBefore, countAfter);
|
|
||||||
}
|
|
||||||
|
|
||||||
file.delete();
|
file.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,9 +121,9 @@ public class TempOutputStreamTest
|
|||||||
|
|
||||||
File file = createTextFileWithRandomContent(contentSize);
|
File file = createTextFileWithRandomContent(contentSize);
|
||||||
|
|
||||||
// Create stream factory that deletes temp file on stream close
|
// Create stream factory that deletes the temp file when the max Size is reached
|
||||||
TempOutputStreamFactory streamFactory = new TempOutputStreamFactory(bufferTempDirectory, MEMORY_THRESHOLD, maxContentSize, false, true);
|
Supplier<TempOutputStream> streamFactory = TempOutputStream.factory(bufferTempDirectory, MEMORY_THRESHOLD, maxContentSize, false);
|
||||||
TempOutputStream outputStream = streamFactory.createOutputStream();
|
TempOutputStream outputStream = streamFactory.get();
|
||||||
|
|
||||||
long countBefore = countFilesInDirectoryWithPrefix(bufferTempDirectory);
|
long countBefore = countFilesInDirectoryWithPrefix(bufferTempDirectory);
|
||||||
|
|
||||||
@@ -156,7 +137,7 @@ public class TempOutputStreamTest
|
|||||||
// Expected
|
// Expected
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that file was already deleted on close
|
// Check that file was already deleted on error
|
||||||
long countAfter = countFilesInDirectoryWithPrefix(bufferTempDirectory);
|
long countAfter = countFilesInDirectoryWithPrefix(bufferTempDirectory);
|
||||||
Assert.assertEquals(countBefore, countAfter);
|
Assert.assertEquals(countBefore, countAfter);
|
||||||
|
|
||||||
@@ -170,9 +151,9 @@ public class TempOutputStreamTest
|
|||||||
|
|
||||||
File file = createTextFileWithRandomContent(contentSize);
|
File file = createTextFileWithRandomContent(contentSize);
|
||||||
|
|
||||||
// Create stream factory that deletes temp file on stream close
|
// Create stream factory that deletes the temp file when the max Size is reached
|
||||||
TempOutputStreamFactory streamFactory = new TempOutputStreamFactory(bufferTempDirectory, MEMORY_THRESHOLD, maxContentSize, false, true);
|
Supplier<TempOutputStream> streamFactory = TempOutputStream.factory(bufferTempDirectory, MEMORY_THRESHOLD, maxContentSize, false);
|
||||||
TempOutputStream outputStream = streamFactory.createOutputStream();
|
TempOutputStream outputStream = streamFactory.get();
|
||||||
|
|
||||||
long countBefore = countFilesInDirectoryWithPrefix(bufferTempDirectory);
|
long countBefore = countFilesInDirectoryWithPrefix(bufferTempDirectory);
|
||||||
|
|
||||||
@@ -186,7 +167,7 @@ public class TempOutputStreamTest
|
|||||||
// Expected
|
// Expected
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that file was already deleted on close
|
// Check that file was already deleted on error
|
||||||
long countAfter = countFilesInDirectoryWithPrefix(bufferTempDirectory);
|
long countAfter = countFilesInDirectoryWithPrefix(bufferTempDirectory);
|
||||||
Assert.assertEquals(countBefore, countAfter);
|
Assert.assertEquals(countBefore, countAfter);
|
||||||
|
|
||||||
@@ -200,9 +181,9 @@ public class TempOutputStreamTest
|
|||||||
File file = createTextFileWithRandomContent(MEMORY_THRESHOLD + 1024L);
|
File file = createTextFileWithRandomContent(MEMORY_THRESHOLD + 1024L);
|
||||||
|
|
||||||
// Create stream factory that doesn't delete temp file on stream close
|
// Create stream factory that doesn't delete temp file on stream close
|
||||||
TempOutputStreamFactory streamFactory = new TempOutputStreamFactory(bufferTempDirectory, MEMORY_THRESHOLD, MAX_CONTENT_SIZE, true, false);
|
Supplier<TempOutputStream> streamFactory = TempOutputStream.factory(bufferTempDirectory, MEMORY_THRESHOLD, MAX_CONTENT_SIZE, true);
|
||||||
|
|
||||||
TempOutputStream outputStream = streamFactory.createOutputStream();
|
TempOutputStream outputStream = streamFactory.get();
|
||||||
|
|
||||||
long countBefore = countFilesInDirectoryWithPrefix(bufferTempDirectory);
|
long countBefore = countFilesInDirectoryWithPrefix(bufferTempDirectory);
|
||||||
|
|
||||||
@@ -220,7 +201,7 @@ public class TempOutputStreamTest
|
|||||||
|
|
||||||
// Compare content
|
// Compare content
|
||||||
String contentWriten = StreamUtils.copyToString(new BufferedInputStream(new FileInputStream(file)), Charset.defaultCharset());
|
String contentWriten = StreamUtils.copyToString(new BufferedInputStream(new FileInputStream(file)), Charset.defaultCharset());
|
||||||
String contentRead = StreamUtils.copyToString(outputStream.getInputStream(), Charset.defaultCharset());
|
String contentRead = StreamUtils.copyToString(outputStream.toNewInputStream(), Charset.defaultCharset());
|
||||||
Assert.assertEquals(contentWriten, contentRead);
|
Assert.assertEquals(contentWriten, contentRead);
|
||||||
|
|
||||||
outputStream.destroy();
|
outputStream.destroy();
|
||||||
|
Reference in New Issue
Block a user