mirror of
				https://github.com/Alfresco/alfresco-community-repo.git
				synced 2025-10-29 15:21:53 +00:00 
			
		
		
		
	Compare commits
	
		
			21 Commits
		
	
	
		
			22.13
			...
			APPS-1821-
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 06871bce8a | ||
|  | 58e595ce13 | ||
|  | 333a7dca98 | ||
|  | 0c810f5e80 | ||
|  | 4d930a6f18 | ||
|  | ff68f92455 | ||
|  | c88353ccb7 | ||
|  | 6b94ee41d4 | ||
|  | a414aa3064 | ||
|  | 7914e87f77 | ||
|  | 4f63b3871e | ||
|  | 876962db57 | ||
|  | 5e2ff120ae | ||
|  | 2d95ccc754 | ||
|  | 3de741a78e | ||
|  | 8993ec9d5c | ||
|  | 428a82c195 | ||
|  | 519ef19c83 | ||
|  | f19849b547 | ||
|  | d956a4f4aa | ||
|  | 71f649d1bd | 
| @@ -7,7 +7,7 @@ | ||||
|    <parent> | ||||
|       <groupId>org.alfresco</groupId> | ||||
|       <artifactId>alfresco-community-repo-amps</artifactId> | ||||
|       <version>17.183</version> | ||||
|       <version>18.8-SNAPSHOT</version> | ||||
|    </parent> | ||||
|  | ||||
|    <modules> | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|    <parent> | ||||
|       <groupId>org.alfresco</groupId> | ||||
|       <artifactId>alfresco-governance-services-community-parent</artifactId> | ||||
|       <version>17.183</version> | ||||
|       <version>18.8-SNAPSHOT</version> | ||||
|    </parent> | ||||
|  | ||||
|    <modules> | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|    <parent> | ||||
|       <groupId>org.alfresco</groupId> | ||||
|       <artifactId>alfresco-governance-services-automation-community-repo</artifactId> | ||||
|       <version>17.183</version> | ||||
|       <version>18.8-SNAPSHOT</version> | ||||
|    </parent> | ||||
|  | ||||
|    <build> | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|    <parent> | ||||
|       <groupId>org.alfresco</groupId> | ||||
|       <artifactId>alfresco-governance-services-community-parent</artifactId> | ||||
|       <version>17.183</version> | ||||
|       <version>18.8-SNAPSHOT</version> | ||||
|    </parent> | ||||
|  | ||||
|    <modules> | ||||
|   | ||||
| @@ -8,7 +8,7 @@ | ||||
|    <parent> | ||||
|       <groupId>org.alfresco</groupId> | ||||
|       <artifactId>alfresco-governance-services-community-repo-parent</artifactId> | ||||
|       <version>17.183</version> | ||||
|       <version>18.8-SNAPSHOT</version> | ||||
|    </parent> | ||||
|  | ||||
|    <properties> | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
| # Version label | ||||
| version.major=7 | ||||
| version.minor=3 | ||||
| version.revision=0 | ||||
| version.revision=1 | ||||
| version.label= | ||||
|  | ||||
| # Edition label | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|     <parent> | ||||
|         <groupId>org.alfresco</groupId> | ||||
|         <artifactId>alfresco-governance-services-community-repo-parent</artifactId> | ||||
|         <version>17.183</version> | ||||
|         <version>18.8-SNAPSHOT</version> | ||||
|     </parent> | ||||
|  | ||||
|     <build> | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|     <parent> | ||||
|         <groupId>org.alfresco</groupId> | ||||
|         <artifactId>alfresco-community-repo</artifactId> | ||||
|         <version>17.183</version> | ||||
|         <version>18.8-SNAPSHOT</version> | ||||
|     </parent> | ||||
|  | ||||
|     <modules> | ||||
|   | ||||
| @@ -8,7 +8,7 @@ | ||||
|     <parent> | ||||
|         <groupId>org.alfresco</groupId> | ||||
|         <artifactId>alfresco-community-repo-amps</artifactId> | ||||
|         <version>17.183</version> | ||||
|         <version>18.8-SNAPSHOT</version> | ||||
|     </parent> | ||||
|  | ||||
|     <properties> | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|    <parent> | ||||
|       <groupId>org.alfresco</groupId> | ||||
|       <artifactId>alfresco-community-repo</artifactId> | ||||
|       <version>17.183</version> | ||||
|       <version>18.8-SNAPSHOT</version> | ||||
|    </parent> | ||||
|  | ||||
|    <dependencies> | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|     <parent> | ||||
|         <groupId>org.alfresco</groupId> | ||||
|         <artifactId>alfresco-community-repo</artifactId> | ||||
|         <version>17.183</version> | ||||
|         <version>18.8-SNAPSHOT</version> | ||||
|     </parent> | ||||
|  | ||||
|     <properties> | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|     <parent> | ||||
|         <groupId>org.alfresco</groupId> | ||||
|         <artifactId>alfresco-community-repo</artifactId> | ||||
|         <version>17.183</version> | ||||
|         <version>18.8-SNAPSHOT</version> | ||||
|     </parent> | ||||
|  | ||||
|     <dependencies> | ||||
|   | ||||
| @@ -9,6 +9,6 @@ | ||||
|     <parent> | ||||
|         <groupId>org.alfresco</groupId> | ||||
|         <artifactId>alfresco-community-repo-packaging</artifactId> | ||||
|         <version>17.183</version> | ||||
|         <version>18.8-SNAPSHOT</version> | ||||
|     </parent> | ||||
| </project> | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|     <parent> | ||||
|         <groupId>org.alfresco</groupId> | ||||
|         <artifactId>alfresco-community-repo-packaging</artifactId> | ||||
|         <version>17.183</version> | ||||
|         <version>18.8-SNAPSHOT</version> | ||||
|     </parent> | ||||
|  | ||||
|     <properties> | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|     <parent> | ||||
|         <groupId>org.alfresco</groupId> | ||||
|         <artifactId>alfresco-community-repo</artifactId> | ||||
|         <version>17.183</version> | ||||
|         <version>18.8-SNAPSHOT</version> | ||||
|     </parent> | ||||
|  | ||||
|     <modules> | ||||
|   | ||||
| @@ -6,7 +6,7 @@ | ||||
|     <parent> | ||||
|         <groupId>org.alfresco</groupId> | ||||
|         <artifactId>alfresco-community-repo-packaging</artifactId> | ||||
|         <version>17.183</version> | ||||
|         <version>18.8-SNAPSHOT</version> | ||||
|     </parent> | ||||
|  | ||||
|     <modules> | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|     <parent> | ||||
|         <groupId>org.alfresco</groupId> | ||||
|         <artifactId>alfresco-community-repo-tests</artifactId> | ||||
|         <version>17.183</version> | ||||
|         <version>18.8-SNAPSHOT</version> | ||||
|     </parent> | ||||
|  | ||||
|     <organization> | ||||
|   | ||||
| @@ -9,7 +9,7 @@ | ||||
|     <parent> | ||||
|         <groupId>org.alfresco</groupId> | ||||
|         <artifactId>alfresco-community-repo-tests</artifactId> | ||||
|         <version>17.183</version> | ||||
|         <version>18.8-SNAPSHOT</version> | ||||
|     </parent> | ||||
|  | ||||
|     <developers> | ||||
|   | ||||
| @@ -9,7 +9,7 @@ | ||||
|     <parent> | ||||
|         <groupId>org.alfresco</groupId> | ||||
|         <artifactId>alfresco-community-repo-tests</artifactId> | ||||
|         <version>17.183</version> | ||||
|         <version>18.8-SNAPSHOT</version> | ||||
|     </parent> | ||||
|  | ||||
|     <developers> | ||||
|   | ||||
| @@ -9,7 +9,7 @@ | ||||
|     <parent> | ||||
|         <groupId>org.alfresco</groupId> | ||||
|         <artifactId>alfresco-community-repo-tests</artifactId> | ||||
|         <version>17.183</version> | ||||
|         <version>18.8-SNAPSHOT</version> | ||||
|     </parent> | ||||
|  | ||||
|     <developers> | ||||
|   | ||||
| @@ -9,7 +9,7 @@ | ||||
|     <parent> | ||||
|         <groupId>org.alfresco</groupId> | ||||
|         <artifactId>alfresco-community-repo-tests</artifactId> | ||||
|         <version>17.183</version> | ||||
|         <version>18.8-SNAPSHOT</version> | ||||
|     </parent> | ||||
|  | ||||
|     <developers> | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|     <parent> | ||||
|         <groupId>org.alfresco</groupId> | ||||
|         <artifactId>alfresco-community-repo-packaging</artifactId> | ||||
|         <version>17.183</version> | ||||
|         <version>18.8-SNAPSHOT</version> | ||||
|     </parent> | ||||
|  | ||||
|     <properties> | ||||
|   | ||||
| @@ -71,7 +71,7 @@ ModuleDetails shareServicesModule = moduleService.getModule("alfresco-share-serv | ||||
|          </div> | ||||
|  | ||||
|          <div class="index-list"> | ||||
|             <h4><%=descriptorService.getServerDescriptor().getEdition()%> - <%=descriptorService.getServerDescriptor().getVersion()%></h4> | ||||
|             <h4><%=descriptorService.getServerDescriptor().getEdition()%></h4> | ||||
|             <p></p> | ||||
|             <p><a href="http://docs.alfresco.com/">Online Documentation</a></p> | ||||
|             <p></p> | ||||
|   | ||||
							
								
								
									
										8
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								pom.xml
									
									
									
									
									
								
							| @@ -2,7 +2,7 @@ | ||||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||||
|     <modelVersion>4.0.0</modelVersion> | ||||
|     <artifactId>alfresco-community-repo</artifactId> | ||||
|     <version>17.183</version> | ||||
|     <version>18.8-SNAPSHOT</version> | ||||
|     <packaging>pom</packaging> | ||||
|     <name>Alfresco Community Repo Parent</name> | ||||
|  | ||||
| @@ -25,7 +25,7 @@ | ||||
|     <properties> | ||||
|         <acs.version.major>7</acs.version.major> | ||||
|         <acs.version.minor>3</acs.version.minor> | ||||
|         <acs.version.revision>0</acs.version.revision> | ||||
|         <acs.version.revision>1</acs.version.revision> | ||||
|         <acs.version.label /> | ||||
|         <amp.min.version>${acs.version.major}.0.0</amp.min.version> | ||||
|  | ||||
| @@ -61,7 +61,7 @@ | ||||
|         <dependency.jackson.version>2.14.0-rc1</dependency.jackson.version> | ||||
|         <dependency.cxf.version>3.5.3</dependency.cxf.version> | ||||
|         <dependency.opencmis.version>1.0.0</dependency.opencmis.version> | ||||
|         <dependency.webscripts.version>8.32</dependency.webscripts.version> | ||||
|         <dependency.webscripts.version>8.33</dependency.webscripts.version> | ||||
|         <dependency.bouncycastle.version>1.70</dependency.bouncycastle.version> | ||||
|         <dependency.mockito-core.version>4.6.1</dependency.mockito-core.version> | ||||
|         <dependency.assertj.version>3.23.1</dependency.assertj.version> | ||||
| @@ -149,7 +149,7 @@ | ||||
|         <connection>scm:git:https://github.com/Alfresco/alfresco-community-repo.git</connection> | ||||
|         <developerConnection>scm:git:https://github.com/Alfresco/alfresco-community-repo.git</developerConnection> | ||||
|         <url>https://github.com/Alfresco/alfresco-community-repo</url> | ||||
|         <tag>17.183</tag> | ||||
|         <tag>HEAD</tag> | ||||
|     </scm> | ||||
|  | ||||
|     <distributionManagement> | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|     <parent> | ||||
|         <groupId>org.alfresco</groupId> | ||||
|         <artifactId>alfresco-community-repo</artifactId> | ||||
|         <version>17.183</version> | ||||
|         <version>18.8-SNAPSHOT</version> | ||||
|     </parent> | ||||
|  | ||||
|     <dependencies> | ||||
|   | ||||
| @@ -295,7 +295,18 @@ public class AuditImpl implements Audit | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             totalItems = hasMoreItems ? getAuditEntriesCountByApp(auditApplication) : totalRetrievedItems; | ||||
|             if (hasMoreItems) { | ||||
|                 if (q != null) { | ||||
|                     // filtering via "where" clause | ||||
|                     AuditEntryQueryWalker propertyWalker = new AuditEntryQueryWalker(); | ||||
|                     QueryHelper.walk(q, propertyWalker); | ||||
|                     totalItems = getAuditEntriesCountByAppAndProperties(auditApplication, propertyWalker); | ||||
|                 } else { | ||||
|                     totalItems = getAuditEntriesCountByApp(auditApplication); | ||||
|                 } | ||||
|             } else { | ||||
|                 totalItems = totalRetrievedItems; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         entriesAudit = (skipCount >= totalRetrievedItems) | ||||
| @@ -895,4 +906,19 @@ public class AuditImpl implements Audit | ||||
|         final String applicationName = auditApplication.getKey().substring(1); | ||||
|         return auditService.getAuditEntriesCountByApp(applicationName); | ||||
|     } | ||||
|  | ||||
|     public int getAuditEntriesCountByAppAndProperties(AuditService.AuditApplication auditApplication, AuditEntryQueryWalker propertyWalker) | ||||
|     { | ||||
|         final String applicationName = auditApplication.getKey().substring(1); | ||||
|  | ||||
|         AuditQueryParameters parameters = new AuditQueryParameters(); | ||||
|         parameters.setApplicationName(applicationName); | ||||
|         parameters.setFromTime(propertyWalker.getFromTime()); | ||||
|         parameters.setToTime(propertyWalker.getToTime()); | ||||
|         parameters.setFromId(propertyWalker.getFromId()); | ||||
|         parameters.setToId(propertyWalker.getToId()); | ||||
|         parameters.setUser(propertyWalker.getCreatedByUser()); | ||||
|  | ||||
|         return auditService.getAuditEntriesCountByAppAndProperties(applicationName, parameters); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -3,12 +3,13 @@ function main() | ||||
|    // Get the args | ||||
|    var siteShortName = url.templateArgs.shortname, | ||||
|       site = siteService.getSite(siteShortName), | ||||
|       filter = ((args.filter != null) ? args.filter : (args.shortNameFilter != null) ? args.shortNameFilter : "" )+ " [hint:useCQ]", | ||||
|       maxResults = (args.maxResults == null) ? 10 : parseInt(args.maxResults, 10), | ||||
|       authorityType = args.authorityType, | ||||
|       zone = args.zone, | ||||
|       sortBy = args.sortBy, | ||||
|       sortAsc = args.dir != "desc"; | ||||
|     | ||||
|   var filter; | ||||
|  | ||||
|  | ||||
|    if (authorityType != null) | ||||
| @@ -28,6 +29,7 @@ function main() | ||||
|  | ||||
|    if (authorityType == null || authorityType == "USER") | ||||
|    { | ||||
|       filter = ((args.filter != null) ? args.filter : (args.shortNameFilter != null) ? args.shortNameFilter : "" )+ " [hint:useCQ]"; | ||||
|       // Get the collection of people | ||||
|       peopleFound = sortBy != null ? people.getPeople(filter, maxResults, sortBy, sortAsc) : people.getPeople(filter, maxResults); | ||||
|  | ||||
| @@ -67,6 +69,7 @@ function main() | ||||
|  | ||||
|    if (authorityType == null || authorityType == "GROUP") | ||||
|    { | ||||
|       filter = (args.filter != null) ? args.filter : (args.shortNameFilter != null) ? args.shortNameFilter : ""; | ||||
|       // Get the collection of groups | ||||
|       paging = utils.createPaging(maxResults, -1); | ||||
|       groupsFound = groups.getGroupsInZone(filter, zone, paging, "displayName"); | ||||
| @@ -96,4 +99,4 @@ function contains(arr, value) { | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| main(); | ||||
| main(); | ||||
|   | ||||
| @@ -34,6 +34,9 @@ import static org.junit.Assert.assertTrue; | ||||
| import static org.junit.Assert.fail; | ||||
|  | ||||
| import java.net.URL; | ||||
| import java.time.ZonedDateTime; | ||||
| import java.time.format.DateTimeFormatter; | ||||
| import java.time.temporal.ChronoUnit; | ||||
| import java.util.Date; | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| @@ -386,6 +389,7 @@ public class AuditAppTest extends AbstractSingleNetworkSiteTest | ||||
|         AuditApp auditApp = auditAppsProxy.getAuditApp("alfresco-access"); | ||||
|  | ||||
|         testGetAuditEntries(auditAppsProxy, auditApp); | ||||
|         testGetAuditEntriesWhereCreatedAt(auditAppsProxy, auditApp); | ||||
|         testAuditEntriesSorting(auditAppsProxy, auditApp); | ||||
|         testAuditEntriesWhereDate(auditAppsProxy, auditApp); | ||||
|         testAuditEntriesWhereId(auditAppsProxy, auditApp); | ||||
| @@ -396,6 +400,30 @@ public class AuditAppTest extends AbstractSingleNetworkSiteTest | ||||
|         testDeleteAuditEntries(auditAppsProxy, auditApp); | ||||
|     } | ||||
|  | ||||
|     private void testGetAuditEntriesWhereCreatedAt(AuditApps auditAppsProxy, AuditApp auditApp) throws Exception | ||||
|     { | ||||
|         // get "totalItems" for a specific time interval | ||||
|         Map<String, String> params = new HashMap<>(); | ||||
|  | ||||
|         final ZonedDateTime beginDate = ZonedDateTime.now().minusHours(1).truncatedTo(ChronoUnit.MINUTES); | ||||
|         final ZonedDateTime endDate = ZonedDateTime.now().truncatedTo(ChronoUnit.MINUTES); | ||||
|         params.put("where","(createdAt BETWEEN ('"+beginDate.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)+"' , '"+endDate.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)+"'))"); | ||||
|  | ||||
|         ListResponse<AuditEntry> auditEntries = auditAppsProxy.getAuditAppEntries(auditApp.getId(), params, | ||||
|                 HttpServletResponse.SC_OK); | ||||
|         int totalItemsWithDefaultMaxSize = auditEntries.getPaging().getTotalItems(); | ||||
|         assertTrue( totalItemsWithDefaultMaxSize > 1 ); | ||||
|  | ||||
|         // get "totalItems" for a specific time internal (with maxSize=1) | ||||
|         params.put("maxSize","1"); | ||||
|         auditEntries = auditAppsProxy.getAuditAppEntries(auditApp.getId(), params, | ||||
|                 HttpServletResponse.SC_OK); | ||||
|         int totalItemsWithMaxSize1 = auditEntries.getPaging().getTotalItems(); | ||||
|  | ||||
|         // number of "totalItems" must be the same, regardless maxSize | ||||
|         assertEquals(totalItemsWithMaxSize1, totalItemsWithDefaultMaxSize); | ||||
|     } | ||||
|  | ||||
|     private void testGetAuditEntries(AuditApps auditAppsProxy, AuditApp auditApp) throws Exception  | ||||
|     { | ||||
|         // Positive tests | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|     <parent> | ||||
|         <groupId>org.alfresco</groupId> | ||||
|         <artifactId>alfresco-community-repo</artifactId> | ||||
|         <version>17.183</version> | ||||
|         <version>18.8-SNAPSHOT</version> | ||||
|     </parent> | ||||
|  | ||||
|     <dependencies> | ||||
|   | ||||
| @@ -272,4 +272,16 @@ public interface AuditComponent | ||||
|     { | ||||
|         return -1; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Issue an audit query to retrieve count of records for a given application and properties | ||||
|      * | ||||
|      * @param applicationName             the name of the application | ||||
|      * @param parameters                  audit parameters provided by the <code>where</code> clause on the ReST API | ||||
|      * @return                            a map containing min/max and the associated value | ||||
|      */ | ||||
|     default int getAuditEntriesCountByAppAndProperties(String applicationName, AuditQueryParameters parameters) | ||||
|     { | ||||
|         return -1; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -955,4 +955,11 @@ public class AuditComponentImpl implements AuditComponent | ||||
|  | ||||
|         return auditDAO.getAuditEntriesCountByApp(applicationId); | ||||
|     } | ||||
|  | ||||
|     @Override public int getAuditEntriesCountByAppAndProperties(String applicationName, AuditQueryParameters parameters) | ||||
|     { | ||||
|         org.alfresco.repo.domain.audit.AuditQueryParameters dbParameters = new org.alfresco.repo.domain.audit.AuditQueryParameters(); | ||||
|  | ||||
|         return auditDAO.getAuditEntriesCountByAppAndProperties(applicationName, parameters); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -186,4 +186,12 @@ public class AuditServiceImpl implements AuditService | ||||
|     { | ||||
|         return auditComponent.getAuditEntriesCountByApp(applicationName); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritDoc} | ||||
|      */ | ||||
|     @Override public int getAuditEntriesCountByAppAndProperties(String applicationName, AuditQueryParameters parameters) | ||||
|     { | ||||
|         return auditComponent.getAuditEntriesCountByAppAndProperties(applicationName, parameters); | ||||
|     } | ||||
| } | ||||
| @@ -25,6 +25,10 @@ | ||||
|  */ | ||||
| package org.alfresco.repo.content.transform; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.util.StringJoiner; | ||||
|  | ||||
| import org.alfresco.error.AlfrescoRuntimeException; | ||||
| import org.alfresco.service.cmr.repository.ContentReader; | ||||
| import org.alfresco.service.cmr.repository.ContentWriter; | ||||
| @@ -44,9 +48,6 @@ import org.apache.http.impl.client.CloseableHttpClient; | ||||
| import org.apache.http.impl.client.HttpClients; | ||||
| import org.apache.http.util.EntityUtils; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.util.StringJoiner; | ||||
|  | ||||
| /** | ||||
|  * Client class that transfers content (from a ContentReader) to a remote transformation agent together with | ||||
|  * request parameters that will be used to transform the content. The transformed content is then returned and | ||||
| @@ -86,44 +87,33 @@ public class RemoteTransformerClient | ||||
|     } | ||||
|  | ||||
|     public void request(ContentReader reader, ContentWriter writer, String sourceMimetype, String sourceExtension, | ||||
|                         String targetExtension, long timeoutMs, Log logger, String... args) | ||||
|             String targetExtension, long timeoutMs, Log logger, String... args) | ||||
|     { | ||||
|  | ||||
|         if (args.length % 2 != 0) | ||||
|         { | ||||
|             throw new IllegalArgumentException("There should be a value for each request property"); | ||||
|         } | ||||
|  | ||||
|         StringJoiner sj = new StringJoiner(" "); | ||||
|         HttpEntity reqEntity = getRequestEntity(reader, sourceMimetype, sourceExtension, targetExtension, timeoutMs, args, sj); | ||||
|  | ||||
|         request(logger, sourceExtension, targetExtension, reqEntity, writer, sj.toString()); | ||||
|         try (InputStream contentStream = reader.getContentInputStream()) | ||||
|         { | ||||
|             HttpEntity reqEntity = getRequestEntity(contentStream, sourceMimetype, sourceExtension, targetExtension, timeoutMs, | ||||
|                     args, sj); | ||||
|  | ||||
|             request(logger, sourceExtension, targetExtension, reqEntity, writer, sj.toString()); | ||||
|         } | ||||
|         catch (IOException e) | ||||
|         { | ||||
|             throw new AlfrescoRuntimeException("Failed to read content from reader", e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     HttpEntity getRequestEntity(ContentReader reader, String sourceMimetype, String sourceExtension, | ||||
|                                         String targetExtension, long timeoutMs, String[] args, StringJoiner sj) | ||||
|     HttpEntity getRequestEntity(ContentReader reader, String sourceMimetype, String sourceExtension, String targetExtension, | ||||
|             long timeoutMs, String[] args, StringJoiner sj) | ||||
|     { | ||||
|         MultipartEntityBuilder builder = MultipartEntityBuilder.create(); | ||||
|         ContentType contentType = ContentType.create(sourceMimetype); | ||||
|         builder.addBinaryBody("file", reader.getContentInputStream(), contentType, "tmp."+sourceExtension); | ||||
|         builder.addTextBody("targetExtension", targetExtension); | ||||
|         sj.add("targetExtension" + '=' + targetExtension); | ||||
|         for (int i=0; i< args.length; i+=2) | ||||
|         { | ||||
|             if (args[i+1] != null) | ||||
|             { | ||||
|                 builder.addTextBody(args[i], args[i + 1]); | ||||
|  | ||||
|                 sj.add(args[i] + '=' + args[i + 1]); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (timeoutMs > 0) | ||||
|         { | ||||
|             String timeoutMsString = Long.toString(timeoutMs); | ||||
|             builder.addTextBody("timeout", timeoutMsString); | ||||
|             sj.add("timeout=" + timeoutMsString); | ||||
|         } | ||||
|         return builder.build(); | ||||
|         return getRequestEntity(reader.getContentInputStream(), sourceMimetype, sourceExtension, targetExtension, timeoutMs, args, sj); | ||||
|     } | ||||
|  | ||||
|     void request(Log logger, String sourceExtension, String targetExtension, HttpEntity reqEntity, ContentWriter writer, String args) | ||||
| @@ -331,6 +321,33 @@ public class RemoteTransformerClient | ||||
|         return httpclient.execute(httpGet); | ||||
|     } | ||||
|  | ||||
|     private HttpEntity getRequestEntity(InputStream contentStream, String sourceMimetype, String sourceExtension, | ||||
|             String targetExtension, long timeoutMs, String[] args, StringJoiner sj) | ||||
|     { | ||||
|         MultipartEntityBuilder builder = MultipartEntityBuilder.create(); | ||||
|         ContentType contentType = ContentType.create(sourceMimetype); | ||||
|         builder.addBinaryBody("file", contentStream, contentType, "tmp." + sourceExtension); | ||||
|         builder.addTextBody("targetExtension", targetExtension); | ||||
|         sj.add("targetExtension" + '=' + targetExtension); | ||||
|         for (int i = 0; i < args.length; i += 2) | ||||
|         { | ||||
|             if (args[i + 1] != null) | ||||
|             { | ||||
|                 builder.addTextBody(args[i], args[i + 1]); | ||||
|  | ||||
|                 sj.add(args[i] + '=' + args[i + 1]); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (timeoutMs > 0) | ||||
|         { | ||||
|             String timeoutMsString = Long.toString(timeoutMs); | ||||
|             builder.addTextBody("timeout", timeoutMsString); | ||||
|             sj.add("timeout=" + timeoutMsString); | ||||
|         } | ||||
|         return builder.build(); | ||||
|     } | ||||
|  | ||||
|     // Strip out just the error message in the response | ||||
|     private String getErrorMessage(HttpEntity resEntity) throws IOException | ||||
|     { | ||||
|   | ||||
| @@ -1,28 +1,28 @@ | ||||
| /* | ||||
|  * #%L | ||||
|  * Alfresco Repository | ||||
|  * %% | ||||
|  * Copyright (C) 2005 - 2016 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% | ||||
|  */ | ||||
| /* | ||||
|  * #%L | ||||
|  * Alfresco Repository | ||||
|  * %% | ||||
|  * Copyright (C) 2005 - 2016 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.domain.audit; | ||||
|  | ||||
| import java.io.IOException; | ||||
| @@ -452,37 +452,86 @@ public abstract class AbstractAuditDAOImpl implements AuditDAO | ||||
|             org.alfresco.service.cmr.audit.AuditQueryParameters parameters, | ||||
|             int maxResults) | ||||
|     { | ||||
|         String searchKey = null; | ||||
|         Serializable searchValue = null; | ||||
|         if (parameters.getSearchKeyValues().size() > 0) | ||||
|         { | ||||
|             // Only handle one pair for now | ||||
|             Pair<String, Serializable> searchKeyValue = parameters.getSearchKeyValues().get(0); | ||||
|             searchKey = searchKeyValue.getFirst(); | ||||
|             searchValue = searchKeyValue.getSecond(); | ||||
|         } | ||||
|          | ||||
|         AuditQueryRowHandler rowHandler = new AuditQueryRowHandler(callback); | ||||
|         findAuditEntries( | ||||
|                 rowHandler, | ||||
|                 parameters.isForward(), | ||||
|                 parameters.getApplicationName(), | ||||
|                 parameters.getUser(), | ||||
|                 parameters.getFromId(), | ||||
|                 parameters.getToId(), | ||||
|                 parameters.getFromTime(), | ||||
|                 parameters.getToTime(), | ||||
|                 maxResults, | ||||
|                 searchKey, | ||||
|                 searchValue); | ||||
|                 parameters); | ||||
|     } | ||||
|      | ||||
|     protected abstract void findAuditEntries( | ||||
|             AuditQueryRowHandler rowHandler, | ||||
|             boolean forward, | ||||
|             String applicationName, String user, | ||||
|             Long fromId, Long toId, | ||||
|             Long fromTime, Long toTime, | ||||
|             int maxResults, | ||||
|             String searchKey, Serializable searchValue); | ||||
|             org.alfresco.service.cmr.audit.AuditQueryParameters restParameters); | ||||
|  | ||||
|     protected AuditQueryParameters convertFromRestAuditQueryParameters(org.alfresco.service.cmr.audit.AuditQueryParameters restParameters) | ||||
|     { | ||||
|         AuditQueryParameters dbParameters = new AuditQueryParameters(); | ||||
|  | ||||
|         String appName = restParameters.getApplicationName(); | ||||
|         if (appName != null) | ||||
|         { | ||||
|             // Look up the application's ID (this is unique) | ||||
|             Pair<Long, Serializable> appNamePair = propertyValueDAO.getPropertyValue(appName); | ||||
|             if (appNamePair == null) | ||||
|             { | ||||
|                 // No such value | ||||
|                 return null; | ||||
|             } | ||||
|             dbParameters.setAuditAppNameId(appNamePair.getFirst()); | ||||
|         } | ||||
|  | ||||
|         String user = restParameters.getUser(); | ||||
|         if (user != null) | ||||
|         { | ||||
|             // Look up the application's ID (this is unique) | ||||
|             Pair<Long, Serializable> userPair = propertyValueDAO.getPropertyValue(user); | ||||
|             if (userPair == null) | ||||
|             { | ||||
|                 // No such value | ||||
|                 return null; | ||||
|             } | ||||
|             dbParameters.setAuditUserId(userPair.getFirst()); | ||||
|         } | ||||
|  | ||||
|         dbParameters.setAuditFromId(restParameters.getFromId()); | ||||
|         dbParameters.setAuditToId(restParameters.getToId()); | ||||
|         dbParameters.setAuditFromTime(restParameters.getFromTime()); | ||||
|         dbParameters.setAuditToTime(restParameters.getToTime()); | ||||
|  | ||||
|         String searchKey = null; | ||||
|         Serializable searchValue = null; | ||||
|         if (restParameters.getSearchKeyValues().size() > 0) | ||||
|         { | ||||
|             // Only handle one pair for now | ||||
|             Pair<String, Serializable> searchKeyValue = restParameters.getSearchKeyValues().get(0); | ||||
|             searchKey = searchKeyValue.getFirst(); | ||||
|             searchValue = searchKeyValue.getSecond(); | ||||
|         } | ||||
|         if (searchKey != null) | ||||
|         { | ||||
|             // Look up the ID of the search key | ||||
|             Pair<Long, Serializable> searchKeyPair = propertyValueDAO.getPropertyValue(searchKey); | ||||
|             if (searchKeyPair == null) | ||||
|             { | ||||
|                 // No such value | ||||
|                 return null; | ||||
|             } | ||||
|             dbParameters.setSearchKeyId(searchKeyPair.getFirst()); | ||||
|         } | ||||
|         if (searchValue != null) | ||||
|         { | ||||
|             // Look up the ID of the search key | ||||
|             Pair<Long, Serializable> searchValuePair = propertyValueDAO.getPropertyValue(searchValue); | ||||
|             if (searchValuePair == null) | ||||
|             { | ||||
|                 // No such value | ||||
|                 return null; | ||||
|             } | ||||
|             dbParameters.setSearchValueId(searchValuePair.getFirst()); | ||||
|         } | ||||
|         dbParameters.setForward(restParameters.isForward()); | ||||
|  | ||||
|         return dbParameters; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -244,4 +244,16 @@ public interface AuditDAO | ||||
|     { | ||||
|         return -1; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Issue an audit query to retrieve count of records for a given application and properties | ||||
|      * | ||||
|      * @param applicationName   name of the application to be queried | ||||
|      * @param parameters        audit parameters provided by the <code>where</code> clause on the ReST API | ||||
|      * @return                  a map containing min/max and the associated value | ||||
|      */ | ||||
|     default int getAuditEntriesCountByAppAndProperties(String applicationName, org.alfresco.service.cmr.audit.AuditQueryParameters parameters) | ||||
|     { | ||||
|         return -1; | ||||
|     } | ||||
| } | ||||
| @@ -66,6 +66,7 @@ public class AuditDAOImpl extends AbstractAuditDAOImpl | ||||
|     private static final String INSERT_ENTRY = "alfresco.audit.insert.insert_AuditEntry"; | ||||
|     private static final String SELECT_MINMAX_ENTRY_FOR_APP = "alfresco.audit.select_MinMaxAuditEntryId"; | ||||
|     private static final String SELECT_COUNT_ENTRIES_FOR_APP = "alfresco.audit.select_CountAuditEntryId"; | ||||
|     private static final String SELECT_COUNT_ENTRIES_FOR_APP_WITH_PROPERTIES = "select_CountAuditEntryIdWithWhereClause"; | ||||
|      | ||||
|     @SuppressWarnings("unused") | ||||
|     private static final String SELECT_ENTRIES_SIMPLE = "alfresco.audit.select_AuditEntriesSimple"; | ||||
| @@ -235,68 +236,29 @@ public class AuditDAOImpl extends AbstractAuditDAOImpl | ||||
|         return result; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int getAuditEntriesCountByAppAndProperties(String applicationName, org.alfresco.service.cmr.audit.AuditQueryParameters parameters) | ||||
|     { | ||||
|         AuditQueryParameters dbParameters = convertFromRestAuditQueryParameters(parameters); | ||||
|  | ||||
|         int result = template.selectOne(SELECT_COUNT_ENTRIES_FOR_APP_WITH_PROPERTIES, dbParameters); | ||||
|  | ||||
|         return result; | ||||
|     } | ||||
|  | ||||
|     @SuppressWarnings("unchecked") | ||||
|     @Override | ||||
|     protected void findAuditEntries( | ||||
|             final AuditQueryRowHandler rowHandler, | ||||
|             boolean forward, | ||||
|             String appName, String user, | ||||
|             Long fromId, Long toId, | ||||
|             Long fromTime, Long toTime, | ||||
|             int maxResults, | ||||
|             String searchKey, Serializable searchValue) | ||||
|             org.alfresco.service.cmr.audit.AuditQueryParameters restParameters) | ||||
|     { | ||||
|         AuditQueryParameters params = new AuditQueryParameters(); | ||||
|         if (appName != null) | ||||
|         AuditQueryParameters params = convertFromRestAuditQueryParameters(restParameters); | ||||
|         if (params==null) | ||||
|         { | ||||
|             // Look up the application's ID (this is unique) | ||||
|             Pair<Long, Serializable> appNamePair = propertyValueDAO.getPropertyValue(appName); | ||||
|             if (appNamePair == null) | ||||
|             { | ||||
|                 // No such value | ||||
|                 return; | ||||
|             } | ||||
|             params.setAuditAppNameId(appNamePair.getFirst()); | ||||
|             return; | ||||
|         } | ||||
|         if (user != null) | ||||
|         { | ||||
|             // Look up the application's ID (this is unique) | ||||
|             Pair<Long, Serializable> userPair = propertyValueDAO.getPropertyValue(user); | ||||
|             if (userPair == null) | ||||
|             { | ||||
|                 // No such value | ||||
|                 return; | ||||
|             } | ||||
|             params.setAuditUserId(userPair.getFirst()); | ||||
|         } | ||||
|         params.setAuditFromId(fromId); | ||||
|         params.setAuditToId(toId); | ||||
|         params.setAuditFromTime(fromTime); | ||||
|         params.setAuditToTime(toTime); | ||||
|         if (searchKey != null) | ||||
|         { | ||||
|             // Look up the ID of the search key | ||||
|             Pair<Long, Serializable> searchKeyPair = propertyValueDAO.getPropertyValue(searchKey); | ||||
|             if (searchKeyPair == null) | ||||
|             { | ||||
|                 // No such value | ||||
|                 return; | ||||
|             } | ||||
|             params.setSearchKeyId(searchKeyPair.getFirst()); | ||||
|         } | ||||
|         if (searchValue != null) | ||||
|         { | ||||
|             // Look up the ID of the search key | ||||
|             Pair<Long, Serializable> searchValuePair = propertyValueDAO.getPropertyValue(searchValue); | ||||
|             if (searchValuePair == null) | ||||
|             { | ||||
|                 // No such value | ||||
|                 return; | ||||
|             } | ||||
|             params.setSearchValueId(searchValuePair.getFirst()); | ||||
|         } | ||||
|         params.setForward(forward); | ||||
|          | ||||
|  | ||||
|         if (maxResults > 0) | ||||
|         { | ||||
|             // Query without getting the values.  We gather all the results and batch-fetch the audited | ||||
|   | ||||
| @@ -0,0 +1,201 @@ | ||||
| /* | ||||
|  * #%L | ||||
|  * Alfresco Repository | ||||
|  * %% | ||||
|  * Copyright (C) 2005 - 2022 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.jscript; | ||||
|  | ||||
| import org.apache.commons.logging.Log; | ||||
| import org.apache.commons.logging.LogFactory; | ||||
| import org.mozilla.javascript.Callable; | ||||
| import org.mozilla.javascript.Context; | ||||
| import org.mozilla.javascript.ContextFactory; | ||||
| import org.mozilla.javascript.Scriptable; | ||||
|  | ||||
| /** | ||||
|  * Custom factory that allows to apply configured limits during script executions | ||||
|  *  | ||||
|  * @see ContextFactory | ||||
|  */ | ||||
| public class AlfrescoContextFactory extends ContextFactory | ||||
| { | ||||
|     private static final Log LOGGER = LogFactory.getLog(AlfrescoContextFactory.class); | ||||
|  | ||||
|     private int optimizationLevel = -1; | ||||
|     private int maxScriptExecutionSeconds = -1; | ||||
|     private int maxStackDepth = -1; | ||||
|     private long maxMemoryUsedInBytes = -1L; | ||||
|     private int observeInstructionCount = -1; | ||||
|  | ||||
|     private AlfrescoScriptThreadMxBeanWrapper threadMxBeanWrapper; | ||||
|  | ||||
|     private final int INTERPRETIVE_MODE = -1; | ||||
|  | ||||
|     @Override | ||||
|     protected Context makeContext() | ||||
|     { | ||||
|         AlfrescoScriptContext context = new AlfrescoScriptContext(); | ||||
|  | ||||
|         context.setOptimizationLevel(optimizationLevel); | ||||
|  | ||||
|         // Needed for both time and memory measurement | ||||
|         if (maxScriptExecutionSeconds > 0 || maxMemoryUsedInBytes > 0L) | ||||
|         { | ||||
|             if (observeInstructionCount > 0) | ||||
|             { | ||||
|                 LOGGER.info("Enabling observer count..."); | ||||
|                 context.setGenerateObserverCount(true); | ||||
|                 context.setInstructionObserverThreshold(observeInstructionCount); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 LOGGER.info("Disabling observer count..."); | ||||
|                 context.setGenerateObserverCount(false); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Memory limit | ||||
|         if (maxMemoryUsedInBytes > 0) | ||||
|         { | ||||
|             context.setThreadId(Thread.currentThread().getId()); | ||||
|         } | ||||
|  | ||||
|         // Max stack depth | ||||
|         if (maxStackDepth > 0) | ||||
|         { | ||||
|             if (optimizationLevel != INTERPRETIVE_MODE) | ||||
|             { | ||||
|                 LOGGER.warn("Changing optimization level from " + optimizationLevel + " to " + INTERPRETIVE_MODE); | ||||
|             } | ||||
|             // stack depth can only be set when no optimizations are applied | ||||
|             context.setOptimizationLevel(INTERPRETIVE_MODE); | ||||
|             context.setMaximumInterpreterStackDepth(maxStackDepth); | ||||
|         } | ||||
|  | ||||
|         return context; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void observeInstructionCount(Context cx, int instructionCount) | ||||
|     { | ||||
|         AlfrescoScriptContext acx = (AlfrescoScriptContext) cx; | ||||
|  | ||||
|         if (acx.isLimitsEnabled()) | ||||
|         { | ||||
|             // Time limit | ||||
|             if (maxScriptExecutionSeconds > 0) | ||||
|             { | ||||
|                 long currentTime = System.currentTimeMillis(); | ||||
|                 if (currentTime - acx.getStartTime() > maxScriptExecutionSeconds * 1000) | ||||
|                 { | ||||
|                     throw new Error("Maximum script time of " + maxScriptExecutionSeconds + " seconds exceeded"); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             // Memory | ||||
|             if (maxMemoryUsedInBytes > 0 && threadMxBeanWrapper != null && threadMxBeanWrapper.isThreadAllocatedMemorySupported()) | ||||
|             { | ||||
|  | ||||
|                 if (acx.getStartMemory() <= 0) | ||||
|                 { | ||||
|                     acx.setStartMemory(threadMxBeanWrapper.getThreadAllocatedBytes(acx.getThreadId())); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     long currentAllocatedBytes = threadMxBeanWrapper.getThreadAllocatedBytes(acx.getThreadId()); | ||||
|                     if (currentAllocatedBytes - acx.getStartMemory() >= maxMemoryUsedInBytes) | ||||
|                     { | ||||
|                         throw new Error("Memory limit of " + maxMemoryUsedInBytes + " bytes reached"); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected Object doTopCall(Callable callable, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) | ||||
|     { | ||||
|         AlfrescoScriptContext acx = (AlfrescoScriptContext) cx; | ||||
|         acx.setStartTime(System.currentTimeMillis()); | ||||
|         return super.doTopCall(callable, cx, scope, thisObj, args); | ||||
|     } | ||||
|  | ||||
|     public int getOptimizationLevel() | ||||
|     { | ||||
|         return optimizationLevel; | ||||
|     } | ||||
|  | ||||
|     public void setOptimizationLevel(int optimizationLevel) | ||||
|     { | ||||
|         this.optimizationLevel = optimizationLevel; | ||||
|     } | ||||
|  | ||||
|     public int getMaxScriptExecutionSeconds() | ||||
|     { | ||||
|         return maxScriptExecutionSeconds; | ||||
|     } | ||||
|  | ||||
|     public void setMaxScriptExecutionSeconds(int maxScriptExecutionSeconds) | ||||
|     { | ||||
|         this.maxScriptExecutionSeconds = maxScriptExecutionSeconds; | ||||
|     } | ||||
|  | ||||
|     public int getMaxStackDepth() | ||||
|     { | ||||
|         return maxStackDepth; | ||||
|     } | ||||
|  | ||||
|     public void setMaxStackDepth(int maxStackDepth) | ||||
|     { | ||||
|         this.maxStackDepth = maxStackDepth; | ||||
|     } | ||||
|  | ||||
|     public long getMaxMemoryUsedInBytes() | ||||
|     { | ||||
|         return maxMemoryUsedInBytes; | ||||
|     } | ||||
|  | ||||
|     public void setMaxMemoryUsedInBytes(long maxMemoryUsedInBytes) | ||||
|     { | ||||
|         this.maxMemoryUsedInBytes = maxMemoryUsedInBytes; | ||||
|         if (maxMemoryUsedInBytes > 0) | ||||
|         { | ||||
|             this.threadMxBeanWrapper = new AlfrescoScriptThreadMxBeanWrapper(); | ||||
|             if (!threadMxBeanWrapper.isThreadAllocatedMemorySupported()) | ||||
|             { | ||||
|                 LOGGER.warn("com.sun.management.ThreadMXBean was not found on the classpath. " | ||||
|                         + "This means that the limiting the memory usage for a script will NOT work."); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public int getObserveInstructionCount() | ||||
|     { | ||||
|         return observeInstructionCount; | ||||
|     } | ||||
|  | ||||
|     public void setObserveInstructionCount(int observeInstructionCount) | ||||
|     { | ||||
|         this.observeInstructionCount = observeInstructionCount; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,81 @@ | ||||
| /* | ||||
|  * #%L | ||||
|  * Alfresco Repository | ||||
|  * %% | ||||
|  * Copyright (C) 2005 - 2022 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.jscript; | ||||
|  | ||||
| import org.mozilla.javascript.Context; | ||||
|  | ||||
| /** | ||||
|  * Custom Rhino context that holds data as start time and memory | ||||
|  *  | ||||
|  * @see Context | ||||
|  */ | ||||
| public class AlfrescoScriptContext extends Context | ||||
| { | ||||
|     private long startTime; | ||||
|     private long threadId; | ||||
|     private long startMemory; | ||||
|     private boolean limitsEnabled = false; | ||||
|  | ||||
|     public long getStartTime() | ||||
|     { | ||||
|         return startTime; | ||||
|     } | ||||
|  | ||||
|     public void setStartTime(long startTime) | ||||
|     { | ||||
|         this.startTime = startTime; | ||||
|     } | ||||
|  | ||||
|     public long getThreadId() | ||||
|     { | ||||
|         return threadId; | ||||
|     } | ||||
|  | ||||
|     public void setThreadId(long threadId) | ||||
|     { | ||||
|         this.threadId = threadId; | ||||
|     } | ||||
|  | ||||
|     public long getStartMemory() | ||||
|     { | ||||
|         return startMemory; | ||||
|     } | ||||
|  | ||||
|     public void setStartMemory(long startMemory) | ||||
|     { | ||||
|         this.startMemory = startMemory; | ||||
|     } | ||||
|  | ||||
|     public boolean isLimitsEnabled() | ||||
|     { | ||||
|         return limitsEnabled; | ||||
|     } | ||||
|  | ||||
|     public void setLimitsEnabled(boolean limitsEnabled) | ||||
|     { | ||||
|         this.limitsEnabled = limitsEnabled; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,78 @@ | ||||
| /* | ||||
|  * #%L | ||||
|  * Alfresco Repository | ||||
|  * %% | ||||
|  * Copyright (C) 2005 - 2022 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.jscript; | ||||
|  | ||||
| import java.lang.management.ManagementFactory; | ||||
| import java.lang.management.ThreadMXBean; | ||||
|  | ||||
| /** | ||||
|  * Allows to monitor memory usage | ||||
|  */ | ||||
| public class AlfrescoScriptThreadMxBeanWrapper | ||||
| { | ||||
|  | ||||
|     private ThreadMXBean threadMXBean = null; | ||||
|     private boolean threadAllocatedMemorySupported = false; | ||||
|  | ||||
|     private final String THREAD_MX_BEAN_SUN = "com.sun.management.ThreadMXBean"; | ||||
|  | ||||
|     public AlfrescoScriptThreadMxBeanWrapper() | ||||
|     { | ||||
|         checkThreadAllocatedMemory(); | ||||
|     } | ||||
|  | ||||
|     public long getThreadAllocatedBytes(long threadId) | ||||
|     { | ||||
|         if (threadMXBean != null && threadAllocatedMemorySupported) | ||||
|         { | ||||
|             return ((com.sun.management.ThreadMXBean) threadMXBean).getThreadAllocatedBytes(threadId); | ||||
|         } | ||||
|  | ||||
|         return -1; | ||||
|     } | ||||
|  | ||||
|     public void checkThreadAllocatedMemory() | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             Class<?> clazz = Class.forName(THREAD_MX_BEAN_SUN); | ||||
|             if (clazz != null) | ||||
|             { | ||||
|                 this.threadAllocatedMemorySupported = true; | ||||
|                 this.threadMXBean = (com.sun.management.ThreadMXBean) ManagementFactory.getThreadMXBean(); | ||||
|             } | ||||
|         } | ||||
|         catch (Exception e) | ||||
|         { | ||||
|             this.threadAllocatedMemorySupported = false; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public boolean isThreadAllocatedMemorySupported() | ||||
|     { | ||||
|         return threadAllocatedMemorySupported; | ||||
|     } | ||||
| } | ||||
| @@ -57,10 +57,12 @@ import org.alfresco.service.namespace.QName; | ||||
| import org.apache.commons.logging.Log; | ||||
| import org.apache.commons.logging.LogFactory; | ||||
| import org.mozilla.javascript.Context; | ||||
| import org.mozilla.javascript.ContextFactory; | ||||
| import org.mozilla.javascript.ImporterTopLevel; | ||||
| import org.mozilla.javascript.Script; | ||||
| import org.mozilla.javascript.Scriptable; | ||||
| import org.mozilla.javascript.ScriptableObject; | ||||
| import org.mozilla.javascript.ScriptableObject; | ||||
| import org.mozilla.javascript.Undefined; | ||||
| import org.mozilla.javascript.WrapFactory; | ||||
| import org.mozilla.javascript.WrappedException; | ||||
| import org.springframework.beans.factory.InitializingBean; | ||||
| @@ -108,7 +110,24 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess | ||||
|     /** Cache of runtime compiled script instances */ | ||||
|     private final Map<String, Script> scriptCache = new ConcurrentHashMap<String, Script>(256); | ||||
|      | ||||
|      | ||||
|     /** Rhino optimization level */ | ||||
|     private int optimizationLevel = -1; | ||||
|  | ||||
|     /** Maximum seconds a script is allowed to run */ | ||||
|     private int maxScriptExecutionSeconds = -1; | ||||
|  | ||||
|     /** Maximum of call stack depth (in terms of number of call frames) */ | ||||
|     private int maxStackDepth = -1; | ||||
|  | ||||
|     /** Maximum memory (bytes) a script can use */ | ||||
|     private long maxMemoryUsedInBytes = -1L; | ||||
|  | ||||
|     /** Number of (bytecode) instructions that will trigger the observer */ | ||||
|     private int observerInstructionCount = 100; | ||||
|  | ||||
|     /** Custom context factory */ | ||||
|     public static AlfrescoContextFactory contextFactory; | ||||
|  | ||||
|     /** | ||||
|      * Set the default store reference | ||||
|      *  | ||||
| @@ -143,6 +162,51 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess | ||||
|     { | ||||
|         this.shareSealedScopes = shareSealedScopes; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param optimizationLevel | ||||
|      *            -1 interpretive mode, 0 no optimizations, 1-9 optimizations performed | ||||
|      */ | ||||
|     public void setOptimizationLevel(int optimizationLevel) | ||||
|     { | ||||
|         this.optimizationLevel = optimizationLevel; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param maxScriptExecutionSeconds | ||||
|      *            the number of seconds a script is allowed to run | ||||
|      */ | ||||
|     public void setMaxScriptExecutionSeconds(int maxScriptExecutionSeconds) | ||||
|     { | ||||
|         this.maxScriptExecutionSeconds = maxScriptExecutionSeconds; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param maxStackDepth | ||||
|      *            the number of call stack depth allowed | ||||
|      */ | ||||
|     public void setMaxStackDepth(int maxStackDepth) | ||||
|     { | ||||
|         this.maxStackDepth = maxStackDepth; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param maxMemoryUsedInBytes | ||||
|      *            the number of memory a script can use | ||||
|      */ | ||||
|     public void setMaxMemoryUsedInBytes(long maxMemoryUsedInBytes) | ||||
|     { | ||||
|         this.maxMemoryUsedInBytes = maxMemoryUsedInBytes; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param observerInstructionCount | ||||
|      *            the number of instructions that will trigger {@link ContextFactory#observeInstructionCount} | ||||
|      */ | ||||
|     public void setObserverInstructionCount(int observerInstructionCount) | ||||
|     { | ||||
|         this.observerInstructionCount = observerInstructionCount; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @see org.alfresco.service.cmr.repository.ScriptProcessor#reset() | ||||
| @@ -449,6 +513,8 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess | ||||
|     private Object executeScriptImpl(Script script, Map<String, Object> model, boolean secure, String debugScriptName) | ||||
|         throws AlfrescoRuntimeException | ||||
|     { | ||||
|         Scriptable scope = null; | ||||
|  | ||||
|         long startTime = 0; | ||||
|         if (callLogger.isDebugEnabled()) | ||||
|         { | ||||
| @@ -465,14 +531,16 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess | ||||
|             // Create a thread-specific scope from one of the shared scopes. | ||||
|             // See http://www.mozilla.org/rhino/scopes.html | ||||
|             cx.setWrapFactory(secure ? wrapFactory : sandboxFactory); | ||||
|             Scriptable scope; | ||||
|  | ||||
|             // Enables or disables execution limits based on secure flag | ||||
|             enableLimits(cx, secure); | ||||
|  | ||||
|             if (this.shareSealedScopes) | ||||
|             { | ||||
|                 Scriptable sharedScope = secure ? this.nonSecureScope : this.secureScope; | ||||
|                 scope = cx.newObject(sharedScope); | ||||
|                 scope.setPrototype(sharedScope); | ||||
|                 scope.setParentScope(null); | ||||
|  | ||||
|             } | ||||
|             else | ||||
|             { | ||||
| @@ -545,7 +613,8 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess | ||||
|             throw new AlfrescoRuntimeException(err.getMessage(), err); | ||||
|         } | ||||
|         finally | ||||
|         { | ||||
|         { | ||||
|             unsetScope(model, scope); | ||||
|             Context.exit(); | ||||
|              | ||||
|             if (callLogger.isDebugEnabled()) | ||||
| @@ -638,6 +707,9 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess | ||||
|      */ | ||||
|     public void afterPropertiesSet() throws Exception | ||||
|     { | ||||
|         // Initialize context factory | ||||
|         initContextFactory(); | ||||
|  | ||||
|         // Initialize the secure scope | ||||
|         Context cx = Context.enter(); | ||||
|         try | ||||
| @@ -695,4 +767,129 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess | ||||
|         } | ||||
|         return scope; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Clean supplied scope and unset it from any model instance where it has been injected before | ||||
|      * | ||||
|      * @param model | ||||
|      *            Data model containing objects from where scope will be unset | ||||
|      * @param scope | ||||
|      *            The scope to clean | ||||
|      */ | ||||
|     private void unsetScope(Map<String, Object> model, Scriptable scope) | ||||
|     { | ||||
|         if (scope != null) | ||||
|         { | ||||
|             Object[] ids = scope.getIds(); | ||||
|             if (ids != null) | ||||
|             { | ||||
|                 for (Object id : ids) | ||||
|                 { | ||||
|                     try | ||||
|                     { | ||||
|                         deleteProperty(scope, id.toString()); | ||||
|                     } | ||||
|                     catch (Exception e) | ||||
|                     { | ||||
|                         logger.info("Unable to delete id: " + id, e); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (model != null) | ||||
|         { | ||||
|             for (String key : model.keySet()) | ||||
|             { | ||||
|                 try | ||||
|                 { | ||||
|                     deleteProperty(scope, key); | ||||
|  | ||||
|                     Object obj = model.get(key); | ||||
|                     if (obj instanceof Scopeable) | ||||
|                     { | ||||
|                         ((Scopeable) obj).setScope(null); | ||||
|                     } | ||||
|                 } | ||||
|                 catch (Exception e) | ||||
|                 { | ||||
|                     logger.info("Unable to unset model object " + key + " : ", e); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Deletes a property from the supplied scope, if property is not removable, then is set to null | ||||
|      * | ||||
|      * @param scope | ||||
|      *            the scope object from where property will be removed | ||||
|      * @param name | ||||
|      *            the property name to delete | ||||
|      */ | ||||
|     private void deleteProperty(Scriptable scope, String name) | ||||
|     { | ||||
|         if (scope != null && name != null) | ||||
|         { | ||||
|             if (!ScriptableObject.deleteProperty(scope, name)) | ||||
|             { | ||||
|                 ScriptableObject.putProperty(scope, name, null); | ||||
|             } | ||||
|             scope.delete(name); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Initializes the context factory with limits configuration | ||||
|      */ | ||||
|     private synchronized void initContextFactory() | ||||
|     { | ||||
|         if (contextFactory == null) | ||||
|         { | ||||
|             contextFactory = new AlfrescoContextFactory(); | ||||
|             contextFactory.setOptimizationLevel(optimizationLevel); | ||||
|  | ||||
|             if (maxScriptExecutionSeconds > 0) | ||||
|             { | ||||
|                 contextFactory.setMaxScriptExecutionSeconds(maxScriptExecutionSeconds); | ||||
|             } | ||||
|  | ||||
|             if (maxMemoryUsedInBytes > 0L) | ||||
|             { | ||||
|                 contextFactory.setMaxMemoryUsedInBytes(maxMemoryUsedInBytes); | ||||
|             } | ||||
|  | ||||
|             if (maxStackDepth > 0) | ||||
|             { | ||||
|                 contextFactory.setMaxStackDepth(maxStackDepth); | ||||
|             } | ||||
|  | ||||
|             if (maxScriptExecutionSeconds > 0 || maxMemoryUsedInBytes > 0L) | ||||
|             { | ||||
|                 contextFactory.setObserveInstructionCount(observerInstructionCount); | ||||
|             } | ||||
|  | ||||
|             ContextFactory.initGlobal(contextFactory); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * If script is considered secure no limits will be applied, otherwise, the limits are enabled and the script can be | ||||
|      * interrupted in case a limit has been reached. | ||||
|      * | ||||
|      * @param cx | ||||
|      *            the Rhino scope | ||||
|      * @param secure | ||||
|      *            true if script execution is considered secure (e.g, deployed at classpath level) | ||||
|      */ | ||||
|     private void enableLimits(Context cx, boolean secure) | ||||
|     { | ||||
|         if (cx != null) | ||||
|         { | ||||
|             if (cx instanceof AlfrescoScriptContext) | ||||
|             { | ||||
|                 ((AlfrescoScriptContext) cx).setLimitsEnabled(!secure); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -267,7 +267,11 @@ public class SolrJSONResultSet implements SearchEngineResultSet { | ||||
|                         ArrayList<Pair<String, Integer>> facetValues = new ArrayList<Pair<String, Integer>>(facetArraySize/2); | ||||
|                         for(int i = 0; i < facetArraySize; i+=2) | ||||
|                         { | ||||
|                             String facetEntryName = facets.getString(i); | ||||
|                             String facetEntryName = "Null"; | ||||
|                             if(!facets.isNull(i)) | ||||
|                             { | ||||
|                                 facetEntryName = facets.getString(i); | ||||
|                             } | ||||
|                             Integer facetEntryCount = Integer.valueOf(facets.getInt(i+1)); | ||||
|                             Pair<String, Integer> pair = new Pair<String, Integer>(facetEntryName, facetEntryCount); | ||||
|                             facetValues.add(pair); | ||||
|   | ||||
| @@ -252,4 +252,16 @@ public interface AuditService | ||||
|     { | ||||
|         return -1; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Issue an audit query to retrieve min / max audit record id for a given application and properties | ||||
|      * | ||||
|      * @param applicationName               the name of the application | ||||
|      * @param parameters                    audit parameters provided by the <code>where</code> clause on the ReST API | ||||
|      * @return                              a map containing min/max and the associated value | ||||
|      */ | ||||
|     default int getAuditEntriesCountByAppAndProperties(String applicationName, AuditQueryParameters parameters) | ||||
|     { | ||||
|         return -1; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -50,6 +50,15 @@ | ||||
|     <!-- Parameter Maps --> | ||||
|     <!--                --> | ||||
|  | ||||
|     <parameterMap id="parameter_AuditAppId_WhereClauseMap" type="map"> | ||||
|         <parameter property="auditAppNameId" jdbcType="BIGINT" javaType="Long"/> | ||||
|         <parameter property="auditUserId" jdbcType="BIGINT" javaType="Long"/> | ||||
|         <parameter property="auditFromTime" jdbcType="BIGINT" javaType="Long"/> | ||||
|         <parameter property="auditToTime" jdbcType="BIGINT" javaType="Long"/> | ||||
|         <parameter property="auditFromId" jdbcType="BIGINT" javaType="Long"/> | ||||
|         <parameter property="auditToId" jdbcType="BIGINT" javaType="Long"/> | ||||
|     </parameterMap> | ||||
|  | ||||
|     <parameterMap id="parameter_IdMap" type="map"> | ||||
|         <parameter property="id" jdbcType="BIGINT" javaType="java.lang.Long"/> | ||||
|     </parameterMap> | ||||
| @@ -291,6 +300,20 @@ | ||||
|         alf_audit_entry.audit_app_id = #{auditAppId} | ||||
|     </select> | ||||
|  | ||||
|     <select id="select_CountAuditEntryIdWithWhereClause" parameterMap="parameter_AuditAppId_WhereClauseMap" resultType="int"> | ||||
|         select | ||||
|             COUNT(entry.id) | ||||
|         from | ||||
|             alf_audit_entry as entry | ||||
|         <if test="auditAppNameId != null"> | ||||
|             join alf_audit_app app on (entry.audit_app_id = app.id) | ||||
|         </if> | ||||
|         <if test="keyOrValueSearch == true"> | ||||
|             join alf_prop_link sp_pl on (sp_pl.root_prop_id = entry.audit_values_id) | ||||
|         </if> | ||||
|         <include refid="select_AuditEntriesWhereSnippet"/> | ||||
|     </select> | ||||
|  | ||||
|     <!-- Get the maximum/minimum audit entry id for application --> | ||||
|     <select id="select_MinMaxAuditEntryId" parameterMap="parameter_IdMinMaxMap" resultMap="result_minMaxMap"> | ||||
|         select | ||||
|   | ||||
| @@ -3,7 +3,7 @@ | ||||
| repository.name=Main Repository | ||||
|  | ||||
| # Schema number | ||||
| version.schema=17000 | ||||
| version.schema=17100 | ||||
|  | ||||
| # Directory configuration | ||||
|  | ||||
| @@ -1351,3 +1351,18 @@ import.zip.compressionRatioThreshold=100 | ||||
| # "zip bomb" and the import extraction process cancelled. No value (or a negative long) will be taken to mean that no | ||||
| # limit should be applied. | ||||
| import.zip.uncompressedBytesLimit= | ||||
|  | ||||
| # Rhino optimization level | ||||
| scripts.execution.optimizationLevel=0 | ||||
|  | ||||
| # Max seconds a script is allowed to run | ||||
| scripts.execution.maxScriptExecutionSeconds=-1 | ||||
|  | ||||
| # Max call stack depth | ||||
| scripts.execution.maxStackDepth=-1 | ||||
|  | ||||
| # Max memory (bytes) a script can use | ||||
| scripts.execution.maxMemoryUsedInBytes=-1 | ||||
|  | ||||
| # Number of instructions that will trigger the observer | ||||
| scripts.execution.observerInstructionCount=-1 | ||||
|   | ||||
| @@ -45,6 +45,21 @@ | ||||
|         <property name="storePath"> | ||||
|             <value>${spaces.company_home.childname}</value> | ||||
|         </property> | ||||
|         <property name="optimizationLevel"> | ||||
|             <value>${scripts.execution.optimizationLevel}</value> | ||||
|         </property> | ||||
|         <property name="maxScriptExecutionSeconds"> | ||||
|             <value>${scripts.execution.maxScriptExecutionSeconds}</value> | ||||
|         </property> | ||||
|         <property name="maxStackDepth"> | ||||
|             <value>${scripts.execution.maxStackDepth}</value> | ||||
|         </property> | ||||
|         <property name="maxMemoryUsedInBytes"> | ||||
|             <value>${scripts.execution.maxMemoryUsedInBytes}</value> | ||||
|         </property> | ||||
|         <property name="observerInstructionCount"> | ||||
|             <value>${scripts.execution.observerInstructionCount}</value> | ||||
|         </property> | ||||
|     </bean> | ||||
|  | ||||
|     <!-- base config implementation that script extension beans extend from - for auto registration | ||||
|   | ||||
| @@ -44,7 +44,6 @@ import org.alfresco.service.cmr.repository.ContentService; | ||||
| import org.alfresco.service.cmr.repository.ContentWriter; | ||||
| import org.alfresco.service.cmr.repository.NodeRef; | ||||
| import org.alfresco.service.cmr.repository.NodeService; | ||||
| import org.alfresco.service.cmr.repository.ScriptProcessor; | ||||
| import org.alfresco.service.cmr.repository.ScriptService; | ||||
| import org.alfresco.service.cmr.repository.StoreRef; | ||||
| import org.alfresco.service.namespace.QName; | ||||
| @@ -53,8 +52,11 @@ import org.alfresco.test_category.OwnJVMTestsCategory; | ||||
| import org.alfresco.util.ApplicationContextHelper; | ||||
| import org.junit.experimental.categories.Category; | ||||
| import org.mozilla.javascript.Context; | ||||
| import org.mozilla.javascript.ImporterTopLevel; | ||||
| import org.mozilla.javascript.Scriptable; | ||||
| import org.mozilla.javascript.ScriptableObject; | ||||
| import org.mozilla.javascript.Undefined; | ||||
| import org.mozilla.javascript.UniqueTag; | ||||
| import org.springframework.context.ApplicationContext; | ||||
|  | ||||
| import junit.framework.TestCase; | ||||
| @@ -445,6 +447,67 @@ public class RhinoScriptTest extends TestCase | ||||
|         assertTrue("Script should have been executed (secure = true)", executed); | ||||
|     } | ||||
|  | ||||
|     // MNT-23158 | ||||
|     public void testScopeData() | ||||
|     { | ||||
|         transactionService.getRetryingTransactionHelper().doInTransaction( | ||||
|             new RetryingTransactionCallback<Object>() | ||||
|             { | ||||
|                 public Object execute() throws Exception | ||||
|                 { | ||||
|                     Context cx = Context.enter(); | ||||
|                     try | ||||
|                     { | ||||
|                         Scriptable sharedScope = new ImporterTopLevel(cx, true); | ||||
|                         Scriptable scope = cx.newObject(sharedScope); | ||||
|                         scope.setPrototype(sharedScope); | ||||
|                         scope.setParentScope(null); | ||||
|  | ||||
|                         // Executes a first script | ||||
|                         Object result = cx.evaluateString(scope, "var a = 10; var b = 20; var sum = a+b;", "TestJS1", 1, null); | ||||
|                         assertTrue(Undefined.isUndefined(result)); | ||||
|  | ||||
|                         // Test sum value | ||||
|                         Object sum = scope.get("sum", scope); | ||||
|                         assertEquals(30.0, Context.toNumber(sum)); | ||||
|  | ||||
|                         // No 'sum' property should be found in the shared scope | ||||
|                         sum = sharedScope.get("sum", sharedScope); | ||||
|                         assertEquals(sum, UniqueTag.NOT_FOUND); | ||||
|  | ||||
|                         // No 'b' property should be found in the shared scope | ||||
|                         Object b = ScriptableObject.getProperty(sharedScope, "b"); | ||||
|                         assertEquals(b, UniqueTag.NOT_FOUND); | ||||
|  | ||||
|                         // Cleans scope | ||||
|                         unsetScope(scope); | ||||
|  | ||||
|                         // Executes a second script using the same scope | ||||
|                         result = cx.evaluateString(scope, "var test = 'test';", "TestJS2", 1, null); | ||||
|  | ||||
|                         // 'sum' property should be null | ||||
|                         sum = scope.get("sum", scope); | ||||
|                         assertNull(sum); | ||||
|  | ||||
|                         // New scope initialization | ||||
|                         scope = cx.newObject(sharedScope); | ||||
|                         scope.setPrototype(sharedScope); | ||||
|                         scope.setParentScope(null); | ||||
|  | ||||
|                         // check 'test' property | ||||
|                         Object test = scope.get("test", scope); | ||||
|                         assertEquals(test, UniqueTag.NOT_FOUND); | ||||
|                     } | ||||
|                     finally | ||||
|                     { | ||||
|                         Context.exit(); | ||||
|                     } | ||||
|  | ||||
|                     return null; | ||||
|                 } | ||||
|             }); | ||||
|     } | ||||
|  | ||||
|     private boolean executeSecureScriptString(String script, Boolean secure) | ||||
|     { | ||||
|         return transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Boolean>() | ||||
| @@ -475,6 +538,41 @@ public class RhinoScriptTest extends TestCase | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     private void unsetScope(Scriptable scope) | ||||
|     { | ||||
|         if (scope != null) | ||||
|         { | ||||
|             Object[] ids = scope.getIds(); | ||||
|  | ||||
|             if (ids != null) | ||||
|             { | ||||
|                 for (Object id : ids) | ||||
|                 { | ||||
|                     try | ||||
|                     { | ||||
|                         deleteProperty(scope, id.toString()); | ||||
|                     } | ||||
|                     catch (Exception e) | ||||
|                     { | ||||
|                         // Do nothing | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private void deleteProperty(Scriptable scope, String name) | ||||
|     { | ||||
|         if (scope != null && name != null) | ||||
|         { | ||||
|             if (!ScriptableObject.deleteProperty(scope, name)) | ||||
|             { | ||||
|                 ScriptableObject.putProperty(scope, name, null); | ||||
|             } | ||||
|             scope.delete(name); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private static final String TESTSCRIPT_CLASSPATH1 = "org/alfresco/repo/jscript/test_script1.js"; | ||||
|     private static final String TESTSCRIPT_CLASSPATH2 = "org/alfresco/repo/jscript/test_script2.js"; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user