mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-14 17:58:59 +00:00
Web Script Framework enhancements: ReadOnly transactions, Buffered Responses
- additional 'allow' attribute on <transaction> element in web script descriptor - values: readonly, readwrite (default) - readonly means that the whole web script executes in read transaction - readonly lighter weight; no flushing, no cache checks/updates - transaction aware web script response buffers - only commits to response when trx is committed - fixes ALFCOM-2497 - CMIS: createFolder & immediately add document can fail - also means errors half-way thru response result in clean response with error contents only - readonly transactions are not buffered - WebScript RepoStore now uses ReadOnly transaction for gets - CMIS getter Web Scripts set to ReadOnly transaction - Fix up Web Script pattern that checks for WebScriptServletResponse using instanceof - no longer the case, as it may be wrapped in BufferedResponse - use getRuntime() instanceof WebScriptServletRuntime and/or - WebScriptServletRuntime.getHttpServletResponse/Request(WebScriptReponse r) - returns null, if none Tests: - Run CMIS Tests - Run CMIS BulkCreateSystemTest (now working) - Run Share Suggestion: - Update your 'read' web script descriptors to include <transaction allow="readonly">. This will improve repo performance significantly. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@14670 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -31,6 +31,7 @@ It is recommended that “includeAllowableActions” be used with query statemen
|
||||
</description>
|
||||
<url>/api/query</url>
|
||||
<authentication>user</authentication>
|
||||
<transaction allow="readonly"/>
|
||||
<format default="atomfeed"/>
|
||||
<family>CMIS</family>
|
||||
</webscript>
|
@@ -4,6 +4,7 @@
|
||||
<url>/api/node/{store_type}/{store_id}/{id}/permissions</url>
|
||||
<url>/api/path/{store_type}/{store_id}/{id}/permissions</url>
|
||||
<authentication>guest</authentication>
|
||||
<transaction allow="readonly"/>
|
||||
<format default="cmisallowableactions">argument</format>
|
||||
<family>CMIS</family>
|
||||
</webscript>
|
@@ -30,6 +30,7 @@ If no “maxItems” value is provided, then the Repository will determine an ap
|
||||
</description>
|
||||
<url>/api/checkedout?folderId={folderId?}&includeDescendants={includeDescendants?}&filter={filter?}&skipCount={skipCount?}&maxItems={maxItems?}&includeAllowableActions={includeAllowableActions?}</url>
|
||||
<authentication>user</authentication>
|
||||
<transaction allow="readonly"/>
|
||||
<format default="atomfeed"/>
|
||||
<family>CMIS</family>
|
||||
</webscript>
|
@@ -37,6 +37,7 @@ If no “maxItems” value is provided, then the Repository will determine an ap
|
||||
<url>/api/node/{store_type}/{store_id}/{id}/children?types={types}&filter={filter?}&skipCount={skipCount?}&maxItems={maxItems?}&includeAllowableActions={includeAllowableActions?}</url>
|
||||
<url>/api/path/{store_type}/{store_id}/{id}/children?types={types}&filter={filter?}&skipCount={skipCount?}&maxItems={maxItems?}&includeAllowableActions={includeAllowableActions?}</url>
|
||||
<authentication>guest</authentication>
|
||||
<transaction allow="readonly"/>
|
||||
<format default="atomfeed">argument</format>
|
||||
<family>CMIS</family>
|
||||
</webscript>
|
@@ -26,6 +26,7 @@ Each CMIS protocol binding will provide a way for fetching a sub-range within a
|
||||
<url>/api/node/{store_type}/{store_id}/{id}/content{property}?a={attach?}</url>
|
||||
<url>/api/path/{store_type}/{store_id}/{id}/content{property}?a={attach?}</url>
|
||||
<authentication>guest</authentication>
|
||||
<transaction allow="readonly"/>
|
||||
<format default="">argument</format>
|
||||
<family>CMIS</family>
|
||||
<lifecycle>public_api</lifecycle>
|
||||
|
@@ -35,6 +35,7 @@ If “includeAllowableActions” is TRUE, the repository will return the allowab
|
||||
<url>/api/node/{store_type}/{store_id}/{id}/descendants?types={types}&filter={filter?}&depth={depth?}&includeAllowableActions={includeAllowableActions?}</url>
|
||||
<url>/api/path/{store_type}/{store_id}/{id}/descendants?types={types}&filter={filter?}&depth={depth?}&includeAllowableActions={includeAllowableActions?}</url>
|
||||
<authentication>guest</authentication>
|
||||
<transaction allow="readonly"/>
|
||||
<format default="atomfeed">argument</format>
|
||||
<family>CMIS</family>
|
||||
</webscript>
|
@@ -30,6 +30,7 @@ PropertyCollection includes changeToken (if applicable to repository)<br>
|
||||
<url>/api/path/{store_type}/{store_id}/{id}?filter={filter?}&returnVersion={returnVersion?}&filter={filter?}&includeAllowableActions={includeAllowableActions?}</url>
|
||||
<!-- TODO: consider /api/node/{store_type}/{store_id}/{id}/{child_node} for atom relative paths -->
|
||||
<authentication>guest</authentication>
|
||||
<transaction allow="readonly"/>
|
||||
<format default="atomentry">argument</format>
|
||||
<family>CMIS</family>
|
||||
</webscript>
|
@@ -29,6 +29,7 @@ If “includeAllowableActions” is TRUE, the repository will return the allowab
|
||||
<url>/api/node/{store_type}/{store_id}/{id}/parent?returnToRoot={returnToRoot}&filter={filter?}&includeAllowableActions={includeAllowableActions?}</url>
|
||||
<url>/api/path/{store_type}/{store_id}/{id}/parent?returnToRoot={returnToRoot}&filter={filter?}&includeAllowableActions={includeAllowableActions?}</url>
|
||||
<authentication>guest</authentication>
|
||||
<transaction allow="readonly"/>
|
||||
<format default="atomfeed">argument</format>
|
||||
<family>CMIS</family>
|
||||
</webscript>
|
@@ -27,6 +27,7 @@ If “includeAllowableActions” is TRUE, the repository will return the allowab
|
||||
<url>/api/node/{store_type}/{store_id}/{id}/parents?filter={filter?}&includeAllowableActions={includeAllowableActions?}</url>
|
||||
<url>/api/path/{store_type}/{store_id}/{id}/parents?filter={filter?}&includeAllowableActions={includeAllowableActions?}</url>
|
||||
<authentication>guest</authentication>
|
||||
<transaction allow="readonly"/>
|
||||
<format default="atomfeed">argument</format>
|
||||
<family>CMIS</family>
|
||||
</webscript>
|
@@ -3,6 +3,7 @@
|
||||
<description>Retrieves the properties of a private working copy</description>
|
||||
<url>/api/pwc/{store_type}/{store_id}/{id}?filter={filter?}</url>
|
||||
<authentication>user</authentication>
|
||||
<transaction allow="readonly"/>
|
||||
<format default="atomentry">argument</format>
|
||||
<family>CMIS</family>
|
||||
</webscript>
|
@@ -4,6 +4,7 @@
|
||||
</description>
|
||||
<url>/api/rel/{store_type}/{store_id}/{id}/type/{rel_type}/target/{target_store_type}/{target_store_id}/{target_id}?filter={filter?}&includeAllowableActions={includeAllowableActions?}</url>
|
||||
<authentication>guest</authentication>
|
||||
<transaction allow="readonly"/>
|
||||
<format default="atomentry">argument</format>
|
||||
<family>CMIS</family>
|
||||
</webscript>
|
@@ -21,6 +21,7 @@ When includeInheritedProperties is true, the repository SHOULD return all proper
|
||||
</description>
|
||||
<url>/api/type/{typeId}?includeInheritedProperties={includeInheritedProperties?}</url>
|
||||
<authentication>user</authentication>
|
||||
<transaction allow="readonly"/>
|
||||
<format default="atomentry"/>
|
||||
<family>CMIS</family>
|
||||
</webscript>
|
@@ -3,6 +3,7 @@
|
||||
<description>Retrieve list of all child Types</description>
|
||||
<url>/api/type/{typeId}/children?includePropertyDefinitions={includePropertyDefinitions?}&skipCount={skipCount?}&maxItems={maxItems?}</url>
|
||||
<authentication>user</authentication>
|
||||
<transaction allow="readonly"/>
|
||||
<format default="atomfeed"/>
|
||||
<family>CMIS</family>
|
||||
</webscript>
|
@@ -3,6 +3,7 @@
|
||||
<description>Retrieve list of all descendant Types</description>
|
||||
<url>/api/type/{typeId}/descendants?includePropertyDefinitions={includePropertyDefinitions?}&skipCount={skipCount?}&maxItems={maxItems?}</url>
|
||||
<authentication>user</authentication>
|
||||
<transaction allow="readonly"/>
|
||||
<format default="atomfeed"/>
|
||||
<family>CMIS</family>
|
||||
</webscript>
|
@@ -28,6 +28,7 @@ If “returnPropertyDefinitions” is False, then the Repository will return onl
|
||||
</description>
|
||||
<url>/api/types?type={type?}&includePropertyDefinitions={includePropertyDefinitions?}&skipCount={skipCount?}&maxItems={maxItems?}</url>
|
||||
<authentication>user</authentication>
|
||||
<transaction allow="readonly"/>
|
||||
<format default="atomfeed"/>
|
||||
<family>CMIS</family>
|
||||
</webscript>
|
@@ -3,6 +3,7 @@
|
||||
<description>Retrieve list of documents that are not in any folder</description>
|
||||
<url>/api/unfiled</url>
|
||||
<authentication>guest</authentication>
|
||||
<transaction allow="readonly"/>
|
||||
<format default="atomfeed"/>
|
||||
<family>CMIS</family>
|
||||
</webscript>
|
@@ -21,6 +21,7 @@ Returns all versions the user can access including checked-out version and priva
|
||||
<url>/api/node/{store_type}/{store_id}/{id}/versions?filter={filter?}</url>
|
||||
<url>/api/path/{store_type}/{store_id}/{id}/versions?filter={filter?}</url>
|
||||
<authentication>user</authentication>
|
||||
<transaction allow="readonly"/>
|
||||
<format default="atomfeed">argument</format>
|
||||
<family>CMIS</family>
|
||||
</webscript>
|
@@ -57,13 +57,12 @@ public class BulkCreateSystemTest
|
||||
abdera.getFactory().registerExtension(new CMISExtensionFactory());
|
||||
|
||||
AbderaClient client = new AbderaClient(abdera);
|
||||
client.setMaxConnectionsTotal(1);
|
||||
client.usePreemptiveAuthentication(true);
|
||||
client.addCredentials("http://localhost:8080", null, "basic", new UsernamePasswordCredentials("admin", "admin"));
|
||||
|
||||
String root = createFolder(client,
|
||||
"http://localhost:8080/alfresco/service/api/path/workspace/SpacesStore/Company%20Home/children",
|
||||
"testfolder7");
|
||||
"testfolder14");
|
||||
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
|
@@ -243,7 +243,7 @@ public class RepoStore implements Store, TenantDeployer
|
||||
"Web Script Store " + repoStore.toString() + repoPath + " must exist; it was not found");
|
||||
}
|
||||
}
|
||||
});
|
||||
}, true, false);
|
||||
}
|
||||
}, AuthenticationUtil.getSystemUserName());
|
||||
|
||||
@@ -364,7 +364,7 @@ public class RepoStore implements Store, TenantDeployer
|
||||
|
||||
return documentPaths != null ? documentPaths.toArray(new String[documentPaths.size()]) : new String[0];
|
||||
}
|
||||
});
|
||||
}, true, false);
|
||||
}
|
||||
}, AuthenticationUtil.getSystemUserName());
|
||||
}
|
||||
@@ -423,7 +423,7 @@ public class RepoStore implements Store, TenantDeployer
|
||||
}
|
||||
return documentPaths.toArray(new String[documentPaths.size()]);
|
||||
}
|
||||
});
|
||||
}, true, false);
|
||||
}
|
||||
}, AuthenticationUtil.getSystemUserName());
|
||||
}
|
||||
@@ -499,7 +499,7 @@ public class RepoStore implements Store, TenantDeployer
|
||||
|
||||
return documentPaths.toArray(new String[documentPaths.size()]);
|
||||
}
|
||||
});
|
||||
}, true, false);
|
||||
}
|
||||
}, AuthenticationUtil.getSystemUserName());
|
||||
}
|
||||
@@ -521,7 +521,7 @@ public class RepoStore implements Store, TenantDeployer
|
||||
findNodeRef(documentPath), ContentModel.PROP_CONTENT);
|
||||
return reader.getLastModified();
|
||||
}
|
||||
});
|
||||
}, true, false);
|
||||
}
|
||||
}, AuthenticationUtil.getSystemUserName());
|
||||
}
|
||||
@@ -542,7 +542,7 @@ public class RepoStore implements Store, TenantDeployer
|
||||
NodeRef nodeRef = findNodeRef(documentPath);
|
||||
return (nodeRef != null);
|
||||
}
|
||||
});
|
||||
}, true, false);
|
||||
}
|
||||
}, AuthenticationUtil.getSystemUserName());
|
||||
}
|
||||
@@ -573,7 +573,7 @@ public class RepoStore implements Store, TenantDeployer
|
||||
}
|
||||
return reader.getContentInputStream();
|
||||
}
|
||||
});
|
||||
}, true, false);
|
||||
}
|
||||
}, AuthenticationUtil.getSystemUserName());
|
||||
}
|
||||
@@ -867,7 +867,7 @@ public class RepoStore implements Store, TenantDeployer
|
||||
}
|
||||
return location;
|
||||
}
|
||||
});
|
||||
}, true, false);
|
||||
}
|
||||
}, AuthenticationUtil.getSystemUserName());
|
||||
}
|
||||
|
@@ -24,7 +24,12 @@
|
||||
*/
|
||||
package org.alfresco.repo.web.scripts;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.io.Writer;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -32,6 +37,7 @@ import javax.servlet.http.HttpServletResponse;
|
||||
import javax.transaction.Status;
|
||||
import javax.transaction.UserTransaction;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.repo.cache.SimpleCache;
|
||||
import org.alfresco.repo.model.Repository;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
@@ -40,6 +46,7 @@ import org.alfresco.repo.tenant.TenantAdminService;
|
||||
import org.alfresco.repo.tenant.TenantDeployer;
|
||||
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.repo.transaction.TransactionListener;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.TemplateService;
|
||||
@@ -47,15 +54,19 @@ import org.alfresco.service.cmr.security.AuthorityService;
|
||||
import org.alfresco.service.descriptor.DescriptorService;
|
||||
import org.alfresco.web.scripts.AbstractRuntimeContainer;
|
||||
import org.alfresco.web.scripts.Authenticator;
|
||||
import org.alfresco.web.scripts.Cache;
|
||||
import org.alfresco.web.scripts.Description;
|
||||
import org.alfresco.web.scripts.Registry;
|
||||
import org.alfresco.web.scripts.Runtime;
|
||||
import org.alfresco.web.scripts.ServerModel;
|
||||
import org.alfresco.web.scripts.WebScript;
|
||||
import org.alfresco.web.scripts.WebScriptException;
|
||||
import org.alfresco.web.scripts.WebScriptRequest;
|
||||
import org.alfresco.web.scripts.WebScriptResponse;
|
||||
import org.alfresco.web.scripts.WrappingWebScriptResponse;
|
||||
import org.alfresco.web.scripts.Description.RequiredAuthentication;
|
||||
import org.alfresco.web.scripts.Description.RequiredTransaction;
|
||||
import org.alfresco.web.scripts.Description.TransactionCapability;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
@@ -71,6 +82,9 @@ public class RepositoryContainer extends AbstractRuntimeContainer implements Ten
|
||||
// Logger
|
||||
protected static final Log logger = LogFactory.getLog(RepositoryContainer.class);
|
||||
|
||||
// Transaction key for buffered response
|
||||
private static String BUFFERED_RESPONSE_KEY = RepositoryContainer.class.getName() + ".bufferedresponse";
|
||||
|
||||
/** Component Dependencies */
|
||||
private Repository repository;
|
||||
private RepositoryImageResolver imageResolver;
|
||||
@@ -92,7 +106,8 @@ public class RepositoryContainer extends AbstractRuntimeContainer implements Ten
|
||||
/**
|
||||
* @param registryFactory
|
||||
*/
|
||||
public void setRegistryFactory(ObjectFactory registryFactory) {
|
||||
public void setRegistryFactory(ObjectFactory registryFactory)
|
||||
{
|
||||
this.registryFactory = registryFactory;
|
||||
}
|
||||
|
||||
@@ -314,9 +329,22 @@ public class RepositoryContainer extends AbstractRuntimeContainer implements Ten
|
||||
try
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Begin retry transaction block: " + description.getRequiredTransaction());
|
||||
logger.debug("Begin retry transaction block: " + description.getRequiredTransaction() + "," + description.getTransactionCapability());
|
||||
|
||||
script.execute(scriptReq, scriptRes);
|
||||
WebScriptResponse redirectedRes = scriptRes;
|
||||
if (description.getTransactionCapability() == TransactionCapability.readwrite)
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Creating Transactional Response for ReadWrite transaction");
|
||||
|
||||
// create buffered response that's sensitive transaction boundary
|
||||
BufferedResponse bufferedRes = new BufferedResponse(scriptRes);
|
||||
AlfrescoTransactionSupport.bindResource(BUFFERED_RESPONSE_KEY, bufferedRes);
|
||||
AlfrescoTransactionSupport.bindListener(bufferedRes);
|
||||
redirectedRes = bufferedRes;
|
||||
}
|
||||
|
||||
script.execute(scriptReq, redirectedRes);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
@@ -356,21 +384,16 @@ public class RepositoryContainer extends AbstractRuntimeContainer implements Ten
|
||||
finally
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("End retry transaction block: " + description.getRequiredTransaction());
|
||||
logger.debug("End retry transaction block: " + description.getRequiredTransaction() + "," + description.getTransactionCapability());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
if (description.getRequiredTransaction() == RequiredTransaction.required)
|
||||
{
|
||||
retryingTransactionHelper.doInTransaction(work);
|
||||
}
|
||||
else
|
||||
{
|
||||
retryingTransactionHelper.doInTransaction(work, false, true);
|
||||
}
|
||||
boolean readonly = description.getTransactionCapability() == TransactionCapability.readonly;
|
||||
boolean requiresNew = description.getRequiredTransaction() == RequiredTransaction.requiresnew;
|
||||
retryingTransactionHelper.doInTransaction(work, readonly, requiresNew);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -465,4 +488,213 @@ public class RepositoryContainer extends AbstractRuntimeContainer implements Ten
|
||||
{
|
||||
webScriptsRegistryCache.remove(tenantAdminService.getCurrentUserDomain());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Transactional Buffered Response
|
||||
*/
|
||||
private static class BufferedResponse implements TransactionListener, WrappingWebScriptResponse
|
||||
{
|
||||
private WebScriptResponse res;
|
||||
private ByteArrayOutputStream outputStream;
|
||||
private OutputStreamWriter outputWriter;
|
||||
|
||||
/**
|
||||
* Construct
|
||||
*
|
||||
* @param res
|
||||
*/
|
||||
public BufferedResponse(WebScriptResponse res)
|
||||
{
|
||||
this.res = res;
|
||||
this.outputStream = new ByteArrayOutputStream(4096);
|
||||
try
|
||||
{
|
||||
this.outputWriter = new OutputStreamWriter(outputStream, "UTF-8");
|
||||
}
|
||||
catch (UnsupportedEncodingException e)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Failed to create buffered response", e);
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.web.scripts.WrappingWebScriptResponse#getNext()
|
||||
*/
|
||||
public WebScriptResponse getNext()
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.web.scripts.WebScriptResponse#addHeader(java.lang.String, java.lang.String)
|
||||
*/
|
||||
public void addHeader(String name, String value)
|
||||
{
|
||||
res.addHeader(name, value);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.web.scripts.WebScriptResponse#encodeScriptUrl(java.lang.String)
|
||||
*/
|
||||
public String encodeScriptUrl(String url)
|
||||
{
|
||||
return res.encodeScriptUrl(url);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.web.scripts.WebScriptResponse#getEncodeScriptUrlFunction(java.lang.String)
|
||||
*/
|
||||
public String getEncodeScriptUrlFunction(String name)
|
||||
{
|
||||
return res.getEncodeScriptUrlFunction(name);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.web.scripts.WebScriptResponse#getOutputStream()
|
||||
*/
|
||||
public OutputStream getOutputStream() throws IOException
|
||||
{
|
||||
return outputStream;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.web.scripts.WebScriptResponse#getRuntime()
|
||||
*/
|
||||
public Runtime getRuntime()
|
||||
{
|
||||
return res.getRuntime();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.web.scripts.WebScriptResponse#getWriter()
|
||||
*/
|
||||
public Writer getWriter() throws IOException
|
||||
{
|
||||
return outputWriter;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.web.scripts.WebScriptResponse#reset()
|
||||
*/
|
||||
public void reset()
|
||||
{
|
||||
outputStream.reset();
|
||||
res.reset();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.web.scripts.WebScriptResponse#setCache(org.alfresco.web.scripts.Cache)
|
||||
*/
|
||||
public void setCache(Cache cache)
|
||||
{
|
||||
res.setCache(cache);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.web.scripts.WebScriptResponse#setContentType(java.lang.String)
|
||||
*/
|
||||
public void setContentType(String contentType)
|
||||
{
|
||||
res.setContentType(contentType);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.web.scripts.WebScriptResponse#setContentEncoding(java.lang.String)
|
||||
*/
|
||||
public void setContentEncoding(String contentEncoding)
|
||||
{
|
||||
res.setContentEncoding(contentEncoding);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.web.scripts.WebScriptResponse#setHeader(java.lang.String, java.lang.String)
|
||||
*/
|
||||
public void setHeader(String name, String value)
|
||||
{
|
||||
res.setHeader(name, value);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.web.scripts.WebScriptResponse#setStatus(int)
|
||||
*/
|
||||
public void setStatus(int status)
|
||||
{
|
||||
res.setStatus(status);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.transaction.TransactionListener#afterCommit()
|
||||
*/
|
||||
public void afterCommit()
|
||||
{
|
||||
writeResponse();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.transaction.TransactionListener#afterRollback()
|
||||
*/
|
||||
public void afterRollback()
|
||||
{
|
||||
writeResponse();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.transaction.TransactionListener#beforeCommit(boolean)
|
||||
*/
|
||||
public void beforeCommit(boolean readOnly)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.transaction.TransactionListener#beforeCompletion()
|
||||
*/
|
||||
public void beforeCompletion()
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.transaction.TransactionListener#flush()
|
||||
*/
|
||||
public void flush()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Write buffered response to underlying response
|
||||
*/
|
||||
private void writeResponse()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Writing Transactional response: size=" + outputStream.size());
|
||||
|
||||
outputStream.flush();
|
||||
outputStream.writeTo(res.getOutputStream());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Failed to commit buffered response", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -46,7 +46,6 @@ import org.alfresco.service.cmr.search.SearchService;
|
||||
import org.alfresco.web.scripts.Status;
|
||||
import org.alfresco.web.scripts.WebScriptException;
|
||||
import org.alfresco.web.scripts.WebScriptResponse;
|
||||
import org.alfresco.web.scripts.servlet.WebScriptServletResponse;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
@@ -167,11 +166,10 @@ public class AVMRemoteStore extends BaseRemoteStore
|
||||
}
|
||||
|
||||
// set mimetype for the content and the character encoding + length for the stream
|
||||
WebScriptServletResponse httpRes = (WebScriptServletResponse)res;
|
||||
httpRes.setContentType(mimetype);
|
||||
httpRes.getHttpServletResponse().setCharacterEncoding(reader.getEncoding());
|
||||
httpRes.getHttpServletResponse().setDateHeader("Last-Modified", desc.getModDate());
|
||||
httpRes.setHeader("Content-Length", Long.toString(reader.getSize()));
|
||||
res.setContentType(mimetype);
|
||||
res.setContentEncoding(reader.getEncoding());
|
||||
res.setHeader("Last-Modified", Long.toString(desc.getModDate()));
|
||||
res.setHeader("Content-Length", Long.toString(reader.getSize()));
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("AVMRemoteStore.getDocument() " + mimetype + " of size: " + reader.getSize());
|
||||
|
@@ -47,7 +47,7 @@ import org.alfresco.web.scripts.WebScriptException;
|
||||
import org.alfresco.web.scripts.WebScriptRequest;
|
||||
import org.alfresco.web.scripts.WebScriptResponse;
|
||||
import org.alfresco.web.scripts.servlet.HTTPProxy;
|
||||
import org.alfresco.web.scripts.servlet.WebScriptServletResponse;
|
||||
import org.alfresco.web.scripts.servlet.WebScriptServletRuntime;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.dom4j.Attribute;
|
||||
@@ -166,11 +166,12 @@ public class SearchProxy extends AbstractWebScript implements InitializingBean
|
||||
|
||||
// issue request against search engine
|
||||
// NOTE: This web script must be executed in a HTTP servlet environment
|
||||
if (!(res instanceof WebScriptServletResponse))
|
||||
if (!(res.getRuntime() instanceof WebScriptServletRuntime))
|
||||
{
|
||||
throw new WebScriptException("Search Proxy must be executed in HTTP Servlet environment");
|
||||
}
|
||||
HttpServletResponse servletRes = ((WebScriptServletResponse)res).getHttpServletResponse();
|
||||
|
||||
HttpServletResponse servletRes = WebScriptServletRuntime.getHttpServletResponse(res);
|
||||
SearchEngineHttpProxy proxy = new SearchEngineHttpProxy(req.getServicePath() + "/" + req.getContextPath(), engine, engineUrl, servletRes);
|
||||
proxy.service();
|
||||
}
|
||||
|
@@ -35,7 +35,6 @@ import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
@@ -58,8 +57,6 @@ import org.alfresco.web.scripts.WebScriptException;
|
||||
import org.alfresco.web.scripts.WebScriptRequest;
|
||||
import org.alfresco.web.scripts.WebScriptResponse;
|
||||
import org.alfresco.web.scripts.WebScriptStatus;
|
||||
import org.alfresco.web.scripts.servlet.WebScriptServletRequest;
|
||||
import org.alfresco.web.scripts.servlet.WebScriptServletResponse;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
@@ -298,14 +295,6 @@ public class StreamContent extends AbstractWebScript
|
||||
protected void streamContent(WebScriptRequest req, WebScriptResponse res, NodeRef nodeRef, QName propertyQName, boolean attach)
|
||||
throws IOException
|
||||
{
|
||||
// NOTE: This web script must be executed in a HTTP Servlet environment
|
||||
if (!(req instanceof WebScriptServletRequest))
|
||||
{
|
||||
throw new WebScriptException("Content retrieval must be executed in HTTP Servlet environment");
|
||||
}
|
||||
HttpServletRequest httpReq = ((WebScriptServletRequest)req).getHttpServletRequest();
|
||||
HttpServletResponse httpRes = ((WebScriptServletResponse)res).getHttpServletResponse();
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Retrieving content from node ref " + nodeRef.toString() + " (property: " + propertyQName.toString() + ") (attach: " + attach + ")");
|
||||
|
||||
@@ -317,14 +306,19 @@ public class StreamContent extends AbstractWebScript
|
||||
|
||||
// check If-Modified-Since header and set Last-Modified header as appropriate
|
||||
Date modified = (Date)nodeService.getProperty(nodeRef, ContentModel.PROP_MODIFIED);
|
||||
long modifiedSince = httpReq.getDateHeader("If-Modified-Since");
|
||||
String modifiedSinceStr = req.getHeader("If-Modified-Since");
|
||||
if (modifiedSinceStr == null)
|
||||
{
|
||||
modifiedSinceStr = "-1";
|
||||
}
|
||||
long modifiedSince = new Long(modifiedSinceStr);
|
||||
if (modifiedSince > 0L)
|
||||
{
|
||||
// round the date to the ignore millisecond value which is not supplied by header
|
||||
long modDate = (modified.getTime() / 1000L) * 1000L;
|
||||
if (modDate <= modifiedSince)
|
||||
{
|
||||
httpRes.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
|
||||
res.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -398,15 +392,12 @@ public class StreamContent extends AbstractWebScript
|
||||
protected void streamContentImpl(WebScriptRequest req, WebScriptResponse res, ContentReader reader, boolean attach, Date modified, String eTag)
|
||||
throws IOException
|
||||
{
|
||||
HttpServletRequest httpReq = ((WebScriptServletRequest)req).getHttpServletRequest();
|
||||
HttpServletResponse httpRes = ((WebScriptServletResponse)res).getHttpServletResponse();
|
||||
|
||||
// handle attachment
|
||||
if (attach == true)
|
||||
{
|
||||
// set header based on filename - will force a Save As from the browse if it doesn't recognize it
|
||||
// this is better than the default response of the browser trying to display the contents
|
||||
httpRes.setHeader("Content-Disposition", "attachment");
|
||||
res.setHeader("Content-Disposition", "attachment");
|
||||
}
|
||||
|
||||
// establish mimetype
|
||||
@@ -428,9 +419,9 @@ public class StreamContent extends AbstractWebScript
|
||||
}
|
||||
|
||||
// set mimetype for the content and the character encoding + length for the stream
|
||||
httpRes.setContentType(mimetype);
|
||||
httpRes.setCharacterEncoding(reader.getEncoding());
|
||||
httpRes.setHeader("Content-Length", Long.toString(reader.getSize()));
|
||||
res.setContentType(mimetype);
|
||||
res.setContentEncoding(reader.getEncoding());
|
||||
res.setHeader("Content-Length", Long.toString(reader.getSize()));
|
||||
|
||||
// set caching
|
||||
Cache cache = new Cache();
|
||||
|
Reference in New Issue
Block a user