From 5a49ccfb0392f64e97337e6b65bd8d5d51c8d709 Mon Sep 17 00:00:00 2001 From: Vitali Ihnatsenka Date: Tue, 19 Mar 2024 13:18:24 +0100 Subject: [PATCH] #18 Provide a settings console instead of the OSGi config - threads per core --- .../core/services/data/UiConfigService.java | 1 + .../data/impl/GridResourcesGeneratorImpl.java | 35 +------------- .../data/impl/UiConfigServiceImpl.java | 8 ++++ .../data/impl/DataFeedServiceImplTest.java | 2 +- .../impl/GridResourcesGeneratorImplTest.java | 48 +++---------------- .../link-inspector-ui/css/console-ui.less | 4 +- .../link-inspector-ui/js/console-ui.filter.js | 18 ++++--- .../main/content/META-INF/vault/filter.xml | 1 + .../data/config/.content.xml | 23 +++++++++ 9 files changed, 55 insertions(+), 85 deletions(-) create mode 100644 ui.content/src/main/content/jcr_root/content/etoolbox-link-inspector/data/config/.content.xml diff --git a/core/src/main/java/com/exadel/etoolbox/linkinspector/core/services/data/UiConfigService.java b/core/src/main/java/com/exadel/etoolbox/linkinspector/core/services/data/UiConfigService.java index 0144935b..69819ae7 100644 --- a/core/src/main/java/com/exadel/etoolbox/linkinspector/core/services/data/UiConfigService.java +++ b/core/src/main/java/com/exadel/etoolbox/linkinspector/core/services/data/UiConfigService.java @@ -13,4 +13,5 @@ public interface UiConfigService { String getLinksType(); boolean isExcludeTags(); Integer[] getStatusCodes(); + Integer getThreadsPerCore(); } diff --git a/core/src/main/java/com/exadel/etoolbox/linkinspector/core/services/data/impl/GridResourcesGeneratorImpl.java b/core/src/main/java/com/exadel/etoolbox/linkinspector/core/services/data/impl/GridResourcesGeneratorImpl.java index 7943e59d..ae0fe194 100644 --- a/core/src/main/java/com/exadel/etoolbox/linkinspector/core/services/data/impl/GridResourcesGeneratorImpl.java +++ b/core/src/main/java/com/exadel/etoolbox/linkinspector/core/services/data/impl/GridResourcesGeneratorImpl.java @@ -26,7 +26,6 @@ import com.exadel.etoolbox.linkinspector.core.services.data.models.GridResource; import com.exadel.etoolbox.linkinspector.core.services.util.LinkInspectorResourceUtil; import com.exadel.etoolbox.linkinspector.core.services.util.LinksCounter; -import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.StopWatch; @@ -35,14 +34,9 @@ import org.apache.sling.api.resource.ResourceResolver; import org.apache.sling.api.resource.ResourceUtil; import org.apache.sling.jcr.resource.api.JcrResourceConstants; -import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Deactivate; -import org.osgi.service.component.annotations.Modified; import org.osgi.service.component.annotations.Reference; -import org.osgi.service.metatype.annotations.AttributeDefinition; -import org.osgi.service.metatype.annotations.Designate; -import org.osgi.service.metatype.annotations.ObjectClassDefinition; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -65,24 +59,9 @@ * generation and further adaptation the data feed to the models for building the UI grid */ @Component(service = GridResourcesGenerator.class) -@Designate(ocd = GridResourcesGeneratorImpl.Configuration.class) public class GridResourcesGeneratorImpl implements GridResourcesGenerator { - @ObjectClassDefinition( - name = "EToolbox Link Inspector - Grid Resources Generator", - description = "Finds broken links under the specified path for further outputting them in a report" - ) - @interface Configuration { - @AttributeDefinition( - name = "Threads per core", - description = "The number of threads created per each CPU core for validating links in parallel" - ) int threadsPerCore() default DEFAULT_THREADS_PER_CORE; - } - private static final Logger LOG = LoggerFactory.getLogger(GridResourcesGeneratorImpl.class); - private static final String DEFAULT_SEARCH_PATH = "/content"; - private static final int DEFAULT_THREADS_PER_CORE = 60; - private static final String TAGS_LOCATION = "/content/cq:tags"; private static final String STATS_RESOURCE_PATH = "/content/etoolbox-link-inspector/data/stats"; @@ -93,18 +72,6 @@ public class GridResourcesGeneratorImpl implements GridResourcesGenerator { private ExecutorService executorService; - private int threadsPerCore; - - /** - * Inits fields based on the service configuration - * @param configuration - the service configuration - */ - @Activate - @Modified - protected void activate(Configuration configuration) { - threadsPerCore = configuration.threadsPerCore(); - } - /** * {@inheritDoc} */ @@ -202,7 +169,7 @@ private Set validateLinksInParallel(Map> Set allBrokenLinkResources = new CopyOnWriteArraySet<>(); try { executorService = - Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * threadsPerCore); + Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * uiConfigService.getThreadsPerCore()); linkToGridResourcesMap.forEach((link, resources) -> submitLinkForValidation( link, diff --git a/core/src/main/java/com/exadel/etoolbox/linkinspector/core/services/data/impl/UiConfigServiceImpl.java b/core/src/main/java/com/exadel/etoolbox/linkinspector/core/services/data/impl/UiConfigServiceImpl.java index 5a0b301c..2ea221d4 100644 --- a/core/src/main/java/com/exadel/etoolbox/linkinspector/core/services/data/impl/UiConfigServiceImpl.java +++ b/core/src/main/java/com/exadel/etoolbox/linkinspector/core/services/data/impl/UiConfigServiceImpl.java @@ -26,6 +26,9 @@ public class UiConfigServiceImpl implements UiConfigService { private static final String PN_LINKS_TYPE = "linksType"; private static final String PN_EXCLUDE_TAGS = "excludeTags"; private static final String PN_STATUS_CODES = "statusCodes"; + private static final String PN_THREADS_PER_CORE = "threadsPerCore"; + private static final int DEFAULT_THREADS_PER_CORE = 60; + private static final String DEFAULT_PATH = "/content"; @Reference @@ -84,6 +87,11 @@ public Integer[] getStatusCodes() { return getProperty(PN_STATUS_CODES, Integer[].class).orElse(new Integer[]{}); } + @Override + public Integer getThreadsPerCore() { + return getProperty(PN_THREADS_PER_CORE, Integer.class).orElse(DEFAULT_THREADS_PER_CORE); + } + private Optional getProperty(String name, Class clazz){ try(ResourceResolver resourceResolver = repositoryHelper.getServiceResourceResolver()){ return Optional.ofNullable(resourceResolver.getResource(CONFIG_PATH)) diff --git a/core/src/test/java/com/exadel/etoolbox/linkinspector/core/services/data/impl/DataFeedServiceImplTest.java b/core/src/test/java/com/exadel/etoolbox/linkinspector/core/services/data/impl/DataFeedServiceImplTest.java index 6d45bc91..4bbefb49 100644 --- a/core/src/test/java/com/exadel/etoolbox/linkinspector/core/services/data/impl/DataFeedServiceImplTest.java +++ b/core/src/test/java/com/exadel/etoolbox/linkinspector/core/services/data/impl/DataFeedServiceImplTest.java @@ -189,8 +189,8 @@ private GridResourcesGeneratorImpl getGridResourcesGenerator() throws NoSuchFiel when(uiConfigService.getExcludedProperties()).thenReturn(new String[0]); when(uiConfigService.getLinksType()).thenReturn(GenerationStatsProps.REPORT_LINKS_TYPE_ALL); when(uiConfigService.getStatusCodes()).thenReturn(new Integer[]{HttpStatus.SC_NOT_FOUND}); + when(uiConfigService.getThreadsPerCore()).thenReturn(60); PrivateAccessor.setField(gridResourcesGenerator, UI_CONFIG_FIELD, uiConfigService); - GridResourcesGeneratorImplTest.setUpConfig(gridResourcesGenerator); when(externalLinkChecker.checkLink(anyString())).thenReturn(HttpStatus.SC_NOT_FOUND); diff --git a/core/src/test/java/com/exadel/etoolbox/linkinspector/core/services/data/impl/GridResourcesGeneratorImplTest.java b/core/src/test/java/com/exadel/etoolbox/linkinspector/core/services/data/impl/GridResourcesGeneratorImplTest.java index b500b7fe..9207df2b 100644 --- a/core/src/test/java/com/exadel/etoolbox/linkinspector/core/services/data/impl/GridResourcesGeneratorImplTest.java +++ b/core/src/test/java/com/exadel/etoolbox/linkinspector/core/services/data/impl/GridResourcesGeneratorImplTest.java @@ -149,12 +149,12 @@ void setup() throws NoSuchFieldException { when(uiConfigService.getLinksType()).thenReturn(GenerationStatsProps.REPORT_LINKS_TYPE_ALL); when(uiConfigService.isExcludeTags()).thenReturn(true); when(uiConfigService.getStatusCodes()).thenReturn(new Integer[]{HttpStatus.SC_NOT_FOUND}); + when(uiConfigService.getThreadsPerCore()).thenReturn(60); PrivateAccessor.setField(fixture, UI_CONFIG_FIELD, uiConfigService); } @Test void testGenerateGridResources() throws NoSuchFieldException, IOException, URISyntaxException { - setUpConfig(fixture); context.load().json(TEST_RESOURCES_TREE_PATH, TEST_FOLDER_PATH); when(externalLinkChecker.checkLink(anyString())).thenReturn(HttpStatus.SC_NOT_FOUND); @@ -166,7 +166,6 @@ void testGenerateGridResources() throws NoSuchFieldException, IOException, URISy @Test void testGenerateFilteredGridResources() throws NoSuchFieldException, IOException, URISyntaxException { - setUpConfig(fixture); context.load().json(TEST_RESOURCES_TREE_PATH, TEST_FOLDER_PATH); when(externalLinkChecker.checkLink(anyString())).thenReturn(HttpStatus.SC_NOT_FOUND); when(uiConfigService.getExcludedLinksPatterns()).thenReturn(new String[]{TEST_UI_EXCLUDED_PATTERN, TEST_EXCLUDED_PATTERN}); @@ -185,7 +184,6 @@ void testGenerateFilteredGridResources() throws NoSuchFieldException, IOExceptio @Test void testAllowedStatusCodes() throws IOException, URISyntaxException { - setUpConfig(fixture); context.load().json(TEST_RESOURCES_TREE_PATH, TEST_FOLDER_PATH); when(externalLinkChecker.checkLink(anyString())).thenReturn(HttpStatus.SC_BAD_REQUEST); @@ -200,7 +198,7 @@ void testAllowedStatusCodes() throws IOException, URISyntaxException { @Test void testAllowedStatusCodes_emptyConfig() throws IOException, URISyntaxException, NoSuchFieldException { - setUpConfigNoStatusCodes(fixture); + when(uiConfigService.getStatusCodes()).thenReturn(new Integer[]{}); context.load().json(TEST_RESOURCES_TREE_PATH, TEST_FOLDER_PATH); when(externalLinkChecker.checkLink(anyString())).thenReturn(HttpStatus.SC_BAD_REQUEST); @@ -213,7 +211,6 @@ void testAllowedStatusCodes_emptyConfig() throws IOException, URISyntaxException @Test void testExcludedPaths() throws IOException, URISyntaxException { - setUpConfig(fixture); context.load().json(TEST_RESOURCES_TREE_PATH, TEST_FOLDER_PATH); when(externalLinkChecker.checkLink(anyString())).thenReturn(HttpStatus.SC_BAD_REQUEST); @@ -229,7 +226,6 @@ void testExcludedPaths() throws IOException, URISyntaxException { @Test void testLastModified() { - setUpConfig(fixture); context.load().json(TEST_RESOURCES_TREE_PATH, TEST_FOLDER_PATH); List gridResources = fixture.generateGridResources(GRID_RESOURCE_TYPE, context.resourceResolver()); @@ -242,7 +238,7 @@ void testLastModified() { @Test void testExcludedPaths_emptyConfig() throws IOException, URISyntaxException { - setUpConfigNoExcludedPaths(fixture); + when(uiConfigService.getExcludedPaths()).thenReturn(ArrayUtils.EMPTY_STRING_ARRAY); context.load().json(TEST_RESOURCES_TREE_PATH, TEST_FOLDER_PATH); when(externalLinkChecker.checkLink(anyString())).thenReturn(HttpStatus.SC_BAD_REQUEST); @@ -260,7 +256,9 @@ void testExcludedPaths_emptyConfig() throws IOException, URISyntaxException { @Test void testActivationCheck() throws ParseException { - setUpConfigCheckActivation(fixture); + when(uiConfigService.getExcludedPaths()).thenReturn(new String[]{TEST_EXCLUDED_PATH}); + when(uiConfigService.isActivatedContent()).thenReturn(true); + when(uiConfigService.isSkipContentModifiedAfterActivation()).thenReturn(true); context.load().json(TEST_REPLICATED_RESOURCES_TREE_PATH, TEST_FOLDER_PATH); Resource rootResource = context.resourceResolver().getResource(TEST_FOLDER_PATH); @@ -286,14 +284,12 @@ void testActivationCheck() throws ParseException { @Test void testGenerateGridResources_rootResourceNull() { - setUpConfig(fixture); List gridResources = fixture.generateGridResources(GRID_RESOURCE_TYPE, context.resourceResolver()); assertTrue(gridResources.isEmpty()); } @Test void testGenerateGridResources_nothingFoundAfterTraversing() { - setUpConfig(fixture); context.create().resource(TEST_FOLDER_PATH, JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY, JcrResourceConstants.NT_SLING_FOLDER); @@ -313,7 +309,6 @@ void testDeactivate() throws NoSuchFieldException { @Test void testGenerateGridResources_interruptionException() throws InterruptedException { - setUpConfig(fixture); context.load().json(TEST_RESOURCES_TREE_PATH, TEST_FOLDER_PATH); try (MockedStatic executors = mockStatic(Executors.class)) { @@ -328,37 +323,6 @@ void testGenerateGridResources_interruptionException() throws InterruptedExcepti } } - static void setUpConfig(GridResourcesGeneratorImpl gridResourcesGenerator) { - GridResourcesGeneratorImpl.Configuration config = mockConfig(); - gridResourcesGenerator.activate(config); - } - - private void setUpConfigNoExcludedPaths(GridResourcesGeneratorImpl gridResourcesGenerator) { - GridResourcesGeneratorImpl.Configuration config = mockConfig(); - when(uiConfigService.getExcludedPaths()).thenReturn(ArrayUtils.EMPTY_STRING_ARRAY); - gridResourcesGenerator.activate(config); - } - - private void setUpConfigCheckActivation(GridResourcesGeneratorImpl gridResourcesGenerator) { - GridResourcesGeneratorImpl.Configuration config = mockConfig(); - when(uiConfigService.getExcludedPaths()).thenReturn(new String[]{TEST_EXCLUDED_PATH}); - when(uiConfigService.isActivatedContent()).thenReturn(true); - when(uiConfigService.isSkipContentModifiedAfterActivation()).thenReturn(true); - gridResourcesGenerator.activate(config); - } - - private void setUpConfigNoStatusCodes(GridResourcesGeneratorImpl gridResourcesGenerator) { - GridResourcesGeneratorImpl.Configuration config = mockConfig(); - when(uiConfigService.getStatusCodes()).thenReturn(new Integer[]{}); - gridResourcesGenerator.activate(config); - } - - private static GridResourcesGeneratorImpl.Configuration mockConfig() { - GridResourcesGeneratorImpl.Configuration config = mock(GridResourcesGeneratorImpl.Configuration.class); - when(config.threadsPerCore()).thenReturn(60); - return config; - } - private List buildExpectedGridResources() throws NoSuchFieldException { context.load().binaryFile(TEST_DATAFEED_PATH, REAL_DATAFEED_PATH); DataFeedService dataFeedService = setUpDataFeedService(getRepositoryHelperFromContext()); diff --git a/ui.apps/src/main/content/jcr_root/apps/etoolbox-link-inspector/clientlibs/link-inspector-ui/css/console-ui.less b/ui.apps/src/main/content/jcr_root/apps/etoolbox-link-inspector/clientlibs/link-inspector-ui/css/console-ui.less index 695a1739..74537f55 100644 --- a/ui.apps/src/main/content/jcr_root/apps/etoolbox-link-inspector/clientlibs/link-inspector-ui/css/console-ui.less +++ b/ui.apps/src/main/content/jcr_root/apps/etoolbox-link-inspector/clientlibs/link-inspector-ui/css/console-ui.less @@ -99,12 +99,12 @@ tr.elc-card { min-width: 50rem; } .coral3-Multifield{ - min-width: 48rem; + min-width: 100%; } .coral3-Checkbox{ display: block; } .coral3-Select{ - min-width: 48rem; + min-width: 100%; } } diff --git a/ui.apps/src/main/content/jcr_root/apps/etoolbox-link-inspector/clientlibs/link-inspector-ui/js/console-ui.filter.js b/ui.apps/src/main/content/jcr_root/apps/etoolbox-link-inspector/clientlibs/link-inspector-ui/js/console-ui.filter.js index 60c1dd2e..1092fa90 100644 --- a/ui.apps/src/main/content/jcr_root/apps/etoolbox-link-inspector/clientlibs/link-inspector-ui/js/console-ui.filter.js +++ b/ui.apps/src/main/content/jcr_root/apps/etoolbox-link-inspector/clientlibs/link-inspector-ui/js/console-ui.filter.js @@ -60,11 +60,7 @@ $cancelBtn.appendTo(dialog.footer); $updateBtn.appendTo(dialog.footer); - const filterMultifield = createMultifield(); - $('

').text("Filter").appendTo(dialog.content); - dialog.content.appendChild(filterMultifield); - - const $rootPathField = $(''); + const $rootPathField = $(''); $('

').text("Path(The content path for searching broken links. The search path should be located under /content)").appendTo(dialog.content); $rootPathField.appendTo(dialog.content); @@ -78,7 +74,11 @@ const $skipContentAfterActivationCheckbox = $('Skip content modified after activation(Works in conjunction with the \'Activated Content\' checkbox only. If checked, links will be retrieved from activated content that is not modified after activation (lastModified is before lastReplicated))'); $skipContentAfterActivationCheckbox.appendTo(dialog.content); - const $lastModifiedContentField = $(''); + const filterMultifield = createMultifield(); + $('

').text("Excluded links patterns(Links are excluded from processing if match any of the specified regex patterns)").appendTo(dialog.content); + dialog.content.appendChild(filterMultifield); + + const $lastModifiedContentField = $(''); $('

').text("Last Modified (The content modified before the specified date will be excluded. Tha date should has the ISO-like date-time format, such as '2011-12-03T10:15:30+01:00')").appendTo(dialog.content); $lastModifiedContentField.appendTo(dialog.content); @@ -120,6 +120,10 @@ $('

').text("Status codes (The list of status codes allowed for broken links in the report. Set a single negative value to allow all http error codes)").appendTo(dialog.content); dialog.content.appendChild(statusCodesMultifield); + const $threadsPerCoreField = $(''); + $('

').text("Threads per core (The number of threads created per each CPU core for validating links in parallel)").appendTo(dialog.content); + $threadsPerCoreField.appendTo(dialog.content); + $.ajax({ type: "GET", url: "/content/etoolbox-link-inspector/data/config.json" @@ -134,6 +138,7 @@ linksTypeSelect.value = data.linksType; $excludeTagsCheckbox.attr("checked", data.excludeTags); populateMultifield(statusCodesMultifield, data.statusCodes); + $threadsPerCoreField.val(data.threadsPerCore); }) function createMultifield(){ @@ -188,6 +193,7 @@ "excludeTags@TypeHint": "Boolean", "statusCodes": getMultifieldValues(statusCodesMultifield), "statusCodes@TypeHint": "String[]", + "threadsPerCore": $threadsPerCoreField.val() }, dataType: "json", encode: true diff --git a/ui.content/src/main/content/META-INF/vault/filter.xml b/ui.content/src/main/content/META-INF/vault/filter.xml index 7fed16c9..b74dbb17 100644 --- a/ui.content/src/main/content/META-INF/vault/filter.xml +++ b/ui.content/src/main/content/META-INF/vault/filter.xml @@ -17,4 +17,5 @@ + \ No newline at end of file diff --git a/ui.content/src/main/content/jcr_root/content/etoolbox-link-inspector/data/config/.content.xml b/ui.content/src/main/content/jcr_root/content/etoolbox-link-inspector/data/config/.content.xml new file mode 100644 index 00000000..d656abf0 --- /dev/null +++ b/ui.content/src/main/content/jcr_root/content/etoolbox-link-inspector/data/config/.content.xml @@ -0,0 +1,23 @@ + + + + \ No newline at end of file